Coverage Report

Created: 2023-03-26 06:14

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/valid.h>
35
#include <libxml/xpath.h>
36
#include <libxml/xpathInternals.h>
37
#include <libxml/parserInternals.h>
38
#include <libxml/hash.h>
39
#ifdef LIBXML_XPTR_LOCS_ENABLED
40
#include <libxml/xpointer.h>
41
#endif
42
#ifdef LIBXML_DEBUG_ENABLED
43
#include <libxml/debugXML.h>
44
#endif
45
#include <libxml/xmlerror.h>
46
#include <libxml/threads.h>
47
#include <libxml/globals.h>
48
#ifdef LIBXML_PATTERN_ENABLED
49
#include <libxml/pattern.h>
50
#endif
51
52
#include "private/buf.h"
53
#include "private/error.h"
54
#include "private/xpath.h"
55
56
#ifdef LIBXML_PATTERN_ENABLED
57
#define XPATH_STREAMING
58
#endif
59
60
#define TODO                \
61
635
    xmlGenericError(xmlGenericErrorContext,       \
62
635
      "Unimplemented block at %s:%d\n",       \
63
635
            __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
490k
#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
100
#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
241k
#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
28.0M
#define XPATH_MAX_RECURSION_DEPTH 500
134
#elif defined(_WIN32)
135
/* Windows typically limits stack size to 1MB. */
136
#define XPATH_MAX_RECURSION_DEPTH 1000
137
#else
138
#define XPATH_MAX_RECURSION_DEPTH 5000
139
#endif
140
141
/*
142
 * TODO:
143
 * There are a few spots where some tests are done which depend upon ascii
144
 * data.  These should be enhanced for full UTF8 support (see particularly
145
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
146
 */
147
148
static void
149
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
150
151
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
152
/**
153
 * xmlXPathCmpNodesExt:
154
 * @node1:  the first node
155
 * @node2:  the second node
156
 *
157
 * Compare two nodes w.r.t document order.
158
 * This one is optimized for handling of non-element nodes.
159
 *
160
 * Returns -2 in case of error 1 if first point < second point, 0 if
161
 *         it's the same node, -1 otherwise
162
 */
163
static int
164
5.69M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
165
5.69M
    int depth1, depth2;
166
5.69M
    int misc = 0, precedence1 = 0, precedence2 = 0;
167
5.69M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
168
5.69M
    xmlNodePtr cur, root;
169
5.69M
    ptrdiff_t l1, l2;
170
171
5.69M
    if ((node1 == NULL) || (node2 == NULL))
172
0
  return(-2);
173
174
5.69M
    if (node1 == node2)
175
0
  return(0);
176
177
    /*
178
     * a couple of optimizations which will avoid computations in most cases
179
     */
180
5.69M
    switch (node1->type) {
181
3.12M
  case XML_ELEMENT_NODE:
182
3.12M
      if (node2->type == XML_ELEMENT_NODE) {
183
2.03M
    if ((0 > (ptrdiff_t) node1->content) &&
184
2.03M
        (0 > (ptrdiff_t) node2->content) &&
185
2.03M
        (node1->doc == node2->doc))
186
1.41M
    {
187
1.41M
        l1 = -((ptrdiff_t) node1->content);
188
1.41M
        l2 = -((ptrdiff_t) node2->content);
189
1.41M
        if (l1 < l2)
190
1.07M
      return(1);
191
337k
        if (l1 > l2)
192
337k
      return(-1);
193
337k
    } else
194
618k
        goto turtle_comparison;
195
2.03M
      }
196
1.09M
      break;
197
1.09M
  case XML_ATTRIBUTE_NODE:
198
195k
      precedence1 = 1; /* element is owner */
199
195k
      miscNode1 = node1;
200
195k
      node1 = node1->parent;
201
195k
      misc = 1;
202
195k
      break;
203
1.89M
  case XML_TEXT_NODE:
204
1.89M
  case XML_CDATA_SECTION_NODE:
205
2.02M
  case XML_COMMENT_NODE:
206
2.04M
  case XML_PI_NODE: {
207
2.04M
      miscNode1 = node1;
208
      /*
209
      * Find nearest element node.
210
      */
211
2.04M
      if (node1->prev != NULL) {
212
1.75M
    do {
213
1.75M
        node1 = node1->prev;
214
1.75M
        if (node1->type == XML_ELEMENT_NODE) {
215
1.05M
      precedence1 = 3; /* element in prev-sibl axis */
216
1.05M
      break;
217
1.05M
        }
218
695k
        if (node1->prev == NULL) {
219
34.7k
      precedence1 = 2; /* element is parent */
220
      /*
221
      * URGENT TODO: Are there any cases, where the
222
      * parent of such a node is not an element node?
223
      */
224
34.7k
      node1 = node1->parent;
225
34.7k
      break;
226
34.7k
        }
227
695k
    } while (1);
228
1.09M
      } else {
229
955k
    precedence1 = 2; /* element is parent */
230
955k
    node1 = node1->parent;
231
955k
      }
232
2.04M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
233
2.04M
    (0 <= (ptrdiff_t) node1->content)) {
234
    /*
235
    * Fallback for whatever case.
236
    */
237
508k
    node1 = miscNode1;
238
508k
    precedence1 = 0;
239
508k
      } else
240
1.53M
    misc = 1;
241
2.04M
  }
242
0
      break;
243
267k
  case XML_NAMESPACE_DECL:
244
      /*
245
      * TODO: why do we return 1 for namespace nodes?
246
      */
247
267k
      return(1);
248
59.0k
  default:
249
59.0k
      break;
250
5.69M
    }
251
3.39M
    switch (node2->type) {
252
1.02M
  case XML_ELEMENT_NODE:
253
1.02M
      break;
254
109k
  case XML_ATTRIBUTE_NODE:
255
109k
      precedence2 = 1; /* element is owner */
256
109k
      miscNode2 = node2;
257
109k
      node2 = node2->parent;
258
109k
      misc = 1;
259
109k
      break;
260
1.99M
  case XML_TEXT_NODE:
261
1.99M
  case XML_CDATA_SECTION_NODE:
262
2.09M
  case XML_COMMENT_NODE:
263
2.15M
  case XML_PI_NODE: {
264
2.15M
      miscNode2 = node2;
265
2.15M
      if (node2->prev != NULL) {
266
1.87M
    do {
267
1.87M
        node2 = node2->prev;
268
1.87M
        if (node2->type == XML_ELEMENT_NODE) {
269
1.15M
      precedence2 = 3; /* element in prev-sibl axis */
270
1.15M
      break;
271
1.15M
        }
272
715k
        if (node2->prev == NULL) {
273
29.7k
      precedence2 = 2; /* element is parent */
274
29.7k
      node2 = node2->parent;
275
29.7k
      break;
276
29.7k
        }
277
715k
    } while (1);
278
1.18M
      } else {
279
969k
    precedence2 = 2; /* element is parent */
280
969k
    node2 = node2->parent;
281
969k
      }
282
2.15M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
283
2.15M
    (0 <= (ptrdiff_t) node2->content))
284
571k
      {
285
571k
    node2 = miscNode2;
286
571k
    precedence2 = 0;
287
571k
      } else
288
1.58M
    misc = 1;
289
2.15M
  }
290
0
      break;
291
72.1k
  case XML_NAMESPACE_DECL:
292
72.1k
      return(1);
293
34.9k
  default:
294
34.9k
      break;
295
3.39M
    }
296
3.32M
    if (misc) {
297
2.56M
  if (node1 == node2) {
298
676k
      if (precedence1 == precedence2) {
299
    /*
300
    * The ugly case; but normally there aren't many
301
    * adjacent non-element nodes around.
302
    */
303
71.5k
    cur = miscNode2->prev;
304
80.4k
    while (cur != NULL) {
305
75.5k
        if (cur == miscNode1)
306
60.3k
      return(1);
307
15.2k
        if (cur->type == XML_ELEMENT_NODE)
308
6.36k
      return(-1);
309
8.86k
        cur = cur->prev;
310
8.86k
    }
311
4.83k
    return (-1);
312
604k
      } else {
313
    /*
314
    * Evaluate based on higher precedence wrt to the element.
315
    * TODO: This assumes attributes are sorted before content.
316
    *   Is this 100% correct?
317
    */
318
604k
    if (precedence1 < precedence2)
319
468k
        return(1);
320
135k
    else
321
135k
        return(-1);
322
604k
      }
323
676k
  }
324
  /*
325
  * Special case: One of the helper-elements is contained by the other.
326
  * <foo>
327
  *   <node2>
328
  *     <node1>Text-1(precedence1 == 2)</node1>
329
  *   </node2>
330
  *   Text-6(precedence2 == 3)
331
  * </foo>
332
  */
333
1.88M
  if ((precedence2 == 3) && (precedence1 > 1)) {
334
323k
      cur = node1->parent;
335
1.46M
      while (cur) {
336
1.23M
    if (cur == node2)
337
94.4k
        return(1);
338
1.13M
    cur = cur->parent;
339
1.13M
      }
340
323k
  }
341
1.78M
  if ((precedence1 == 3) && (precedence2 > 1)) {
342
270k
      cur = node2->parent;
343
1.45M
      while (cur) {
344
1.22M
    if (cur == node1)
345
44.7k
        return(-1);
346
1.18M
    cur = cur->parent;
347
1.18M
      }
348
270k
  }
349
1.78M
    }
350
351
    /*
352
     * Speedup using document order if available.
353
     */
354
2.50M
    if ((node1->type == XML_ELEMENT_NODE) &&
355
2.50M
  (node2->type == XML_ELEMENT_NODE) &&
356
2.50M
  (0 > (ptrdiff_t) node1->content) &&
357
2.50M
  (0 > (ptrdiff_t) node2->content) &&
358
2.50M
  (node1->doc == node2->doc)) {
359
360
1.67M
  l1 = -((ptrdiff_t) node1->content);
361
1.67M
  l2 = -((ptrdiff_t) node2->content);
362
1.67M
  if (l1 < l2)
363
981k
      return(1);
364
696k
  if (l1 > l2)
365
696k
      return(-1);
366
696k
    }
367
368
1.44M
turtle_comparison:
369
370
1.44M
    if (node1 == node2->prev)
371
455k
  return(1);
372
993k
    if (node1 == node2->next)
373
25.9k
  return(-1);
374
    /*
375
     * compute depth to root
376
     */
377
3.12M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
378
2.28M
  if (cur->parent == node1)
379
130k
      return(1);
380
2.15M
  depth2++;
381
2.15M
    }
382
836k
    root = cur;
383
3.08M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
384
2.32M
  if (cur->parent == node2)
385
67.9k
      return(-1);
386
2.25M
  depth1++;
387
2.25M
    }
388
    /*
389
     * Distinct document (or distinct entities :-( ) case.
390
     */
391
768k
    if (root != cur) {
392
9.26k
  return(-2);
393
9.26k
    }
394
    /*
395
     * get the nearest common ancestor.
396
     */
397
1.29M
    while (depth1 > depth2) {
398
532k
  depth1--;
399
532k
  node1 = node1->parent;
400
532k
    }
401
1.12M
    while (depth2 > depth1) {
402
362k
  depth2--;
403
362k
  node2 = node2->parent;
404
362k
    }
405
1.09M
    while (node1->parent != node2->parent) {
406
333k
  node1 = node1->parent;
407
333k
  node2 = node2->parent;
408
  /* should not happen but just in case ... */
409
333k
  if ((node1 == NULL) || (node2 == NULL))
410
0
      return(-2);
411
333k
    }
412
    /*
413
     * Find who's first.
414
     */
415
759k
    if (node1 == node2->prev)
416
107k
  return(1);
417
652k
    if (node1 == node2->next)
418
97.3k
  return(-1);
419
    /*
420
     * Speedup using document order if available.
421
     */
422
554k
    if ((node1->type == XML_ELEMENT_NODE) &&
423
554k
  (node2->type == XML_ELEMENT_NODE) &&
424
554k
  (0 > (ptrdiff_t) node1->content) &&
425
554k
  (0 > (ptrdiff_t) node2->content) &&
426
554k
  (node1->doc == node2->doc)) {
427
428
0
  l1 = -((ptrdiff_t) node1->content);
429
0
  l2 = -((ptrdiff_t) node2->content);
430
0
  if (l1 < l2)
431
0
      return(1);
432
0
  if (l1 > l2)
433
0
      return(-1);
434
0
    }
435
436
15.1M
    for (cur = node1->next;cur != NULL;cur = cur->next)
437
14.8M
  if (cur == node2)
438
262k
      return(1);
439
291k
    return(-1); /* assume there is no sibling list corruption */
440
554k
}
441
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
442
443
/*
444
 * Wrapper for the Timsort algorithm from timsort.h
445
 */
446
#ifdef WITH_TIM_SORT
447
#define SORT_NAME libxml_domnode
448
1.55M
#define SORT_TYPE xmlNodePtr
449
/**
450
 * wrap_cmp:
451
 * @x: a node
452
 * @y: another node
453
 *
454
 * Comparison function for the Timsort implementation
455
 *
456
 * Returns -2 in case of error -1 if first point < second point, 0 if
457
 *         it's the same node, +1 otherwise
458
 */
459
static
460
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
461
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
462
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463
5.64M
    {
464
5.64M
        int res = xmlXPathCmpNodesExt(x, y);
465
5.64M
        return res == -2 ? res : -res;
466
5.64M
    }
467
#else
468
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
469
    {
470
        int res = xmlXPathCmpNodes(x, y);
471
        return res == -2 ? res : -res;
472
    }
473
#endif
474
5.64M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
475
#include "timsort.h"
476
#endif /* WITH_TIM_SORT */
477
478
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
479
480
/************************************************************************
481
 *                  *
482
 *      Floating point stuff        *
483
 *                  *
484
 ************************************************************************/
485
486
double xmlXPathNAN = 0.0;
487
double xmlXPathPINF = 0.0;
488
double xmlXPathNINF = 0.0;
489
490
/**
491
 * xmlXPathInit:
492
 *
493
 * DEPRECATED: Alias for xmlInitParser.
494
 */
495
void
496
0
xmlXPathInit(void) {
497
0
    xmlInitParser();
498
0
}
499
500
/**
501
 * xmlInitXPathInternal:
502
 *
503
 * Initialize the XPath environment
504
 */
505
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
506
void
507
4
xmlInitXPathInternal(void) {
508
4
#if defined(NAN) && defined(INFINITY)
509
4
    xmlXPathNAN = NAN;
510
4
    xmlXPathPINF = INFINITY;
511
4
    xmlXPathNINF = -INFINITY;
512
#else
513
    /* MSVC doesn't allow division by zero in constant expressions. */
514
    double zero = 0.0;
515
    xmlXPathNAN = 0.0 / zero;
516
    xmlXPathPINF = 1.0 / zero;
517
    xmlXPathNINF = -xmlXPathPINF;
518
#endif
519
4
}
520
521
/**
522
 * xmlXPathIsNaN:
523
 * @val:  a double value
524
 *
525
 * Returns 1 if the value is a NaN, 0 otherwise
526
 */
527
int
528
1.73M
xmlXPathIsNaN(double val) {
529
1.73M
#ifdef isnan
530
1.73M
    return isnan(val);
531
#else
532
    return !(val == val);
533
#endif
534
1.73M
}
535
536
/**
537
 * xmlXPathIsInf:
538
 * @val:  a double value
539
 *
540
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
541
 */
542
int
543
1.35M
xmlXPathIsInf(double val) {
544
1.35M
#ifdef isinf
545
1.35M
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
546
#else
547
    if (val >= xmlXPathPINF)
548
        return 1;
549
    if (val <= -xmlXPathPINF)
550
        return -1;
551
    return 0;
552
#endif
553
1.35M
}
554
555
#endif /* SCHEMAS or XPATH */
556
557
#ifdef LIBXML_XPATH_ENABLED
558
559
/*
560
 * TODO: when compatibility allows remove all "fake node libxslt" strings
561
 *       the test should just be name[0] = ' '
562
 */
563
#ifdef DEBUG_XPATH_EXPRESSION
564
#define DEBUG_STEP
565
#define DEBUG_EXPR
566
#define DEBUG_EVAL_COUNTS
567
#endif
568
569
static xmlNs xmlXPathXMLNamespaceStruct = {
570
    NULL,
571
    XML_NAMESPACE_DECL,
572
    XML_XML_NAMESPACE,
573
    BAD_CAST "xml",
574
    NULL,
575
    NULL
576
};
577
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578
#ifndef LIBXML_THREAD_ENABLED
579
/*
580
 * Optimizer is disabled only when threaded apps are detected while
581
 * the library ain't compiled for thread safety.
582
 */
583
static int xmlXPathDisableOptimizer = 0;
584
#endif
585
586
/************************************************************************
587
 *                  *
588
 *      Error handling routines       *
589
 *                  *
590
 ************************************************************************/
591
592
/**
593
 * XP_ERRORNULL:
594
 * @X:  the error code
595
 *
596
 * Macro to raise an XPath error and return NULL.
597
 */
598
#define XP_ERRORNULL(X)             \
599
46.8k
    { xmlXPathErr(ctxt, X); return(NULL); }
600
601
/*
602
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603
 */
604
static const char* const xmlXPathErrorMessages[] = {
605
    "Ok\n",
606
    "Number encoding\n",
607
    "Unfinished literal\n",
608
    "Start of literal\n",
609
    "Expected $ for variable reference\n",
610
    "Undefined variable\n",
611
    "Invalid predicate\n",
612
    "Invalid expression\n",
613
    "Missing closing curly brace\n",
614
    "Unregistered function\n",
615
    "Invalid operand\n",
616
    "Invalid type\n",
617
    "Invalid number of arguments\n",
618
    "Invalid context size\n",
619
    "Invalid context position\n",
620
    "Memory allocation error\n",
621
    "Syntax error\n",
622
    "Resource error\n",
623
    "Sub resource error\n",
624
    "Undefined namespace prefix\n",
625
    "Encoding error\n",
626
    "Char out of XML range\n",
627
    "Invalid or incomplete context\n",
628
    "Stack usage error\n",
629
    "Forbidden variable\n",
630
    "Operation limit exceeded\n",
631
    "Recursion limit exceeded\n",
632
    "?? Unknown error ??\n" /* Must be last in the list! */
633
};
634
496k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
635
496k
       sizeof(xmlXPathErrorMessages[0])) - 1)
636
/**
637
 * xmlXPathErrMemory:
638
 * @ctxt:  an XPath context
639
 * @extra:  extra information
640
 *
641
 * Handle a redefinition of attribute error
642
 */
643
static void
644
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
645
104k
{
646
104k
    if (ctxt != NULL) {
647
25.8k
        xmlResetError(&ctxt->lastError);
648
25.8k
        if (extra) {
649
24.6k
            xmlChar buf[200];
650
651
24.6k
            xmlStrPrintf(buf, 200,
652
24.6k
                         "Memory allocation failed : %s\n",
653
24.6k
                         extra);
654
24.6k
            ctxt->lastError.message = (char *) xmlStrdup(buf);
655
24.6k
        } else {
656
1.15k
            ctxt->lastError.message = (char *)
657
1.15k
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
658
1.15k
        }
659
25.8k
        ctxt->lastError.domain = XML_FROM_XPATH;
660
25.8k
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
661
25.8k
  if (ctxt->error != NULL)
662
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
663
78.2k
    } else {
664
78.2k
        if (extra)
665
78.2k
            __xmlRaiseError(NULL, NULL, NULL,
666
78.2k
                            NULL, NULL, XML_FROM_XPATH,
667
78.2k
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668
78.2k
                            extra, NULL, NULL, 0, 0,
669
78.2k
                            "Memory allocation failed : %s\n", extra);
670
0
        else
671
0
            __xmlRaiseError(NULL, NULL, NULL,
672
0
                            NULL, NULL, XML_FROM_XPATH,
673
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
674
0
                            NULL, NULL, NULL, 0, 0,
675
0
                            "Memory allocation failed\n");
676
78.2k
    }
677
104k
}
678
679
/**
680
 * xmlXPathPErrMemory:
681
 * @ctxt:  an XPath parser context
682
 * @extra:  extra information
683
 *
684
 * Handle a redefinition of attribute error
685
 */
686
static void
687
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
688
749
{
689
749
    if (ctxt == NULL)
690
0
  xmlXPathErrMemory(NULL, extra);
691
749
    else {
692
749
  ctxt->error = XPATH_MEMORY_ERROR;
693
749
  xmlXPathErrMemory(ctxt->context, extra);
694
749
    }
695
749
}
696
697
/**
698
 * xmlXPathErr:
699
 * @ctxt:  a XPath parser context
700
 * @error:  the error code
701
 *
702
 * Handle an XPath error
703
 */
704
void
705
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
706
496k
{
707
496k
    if ((error < 0) || (error > MAXERRNO))
708
0
  error = MAXERRNO;
709
496k
    if (ctxt == NULL) {
710
0
  __xmlRaiseError(NULL, NULL, NULL,
711
0
      NULL, NULL, XML_FROM_XPATH,
712
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713
0
      XML_ERR_ERROR, NULL, 0,
714
0
      NULL, NULL, NULL, 0, 0,
715
0
      "%s", xmlXPathErrorMessages[error]);
716
0
  return;
717
0
    }
718
    /* Only report the first error */
719
496k
    if (ctxt->error != 0)
720
40.0k
        return;
721
456k
    ctxt->error = error;
722
456k
    if (ctxt->context == NULL) {
723
0
  __xmlRaiseError(NULL, NULL, NULL,
724
0
      NULL, NULL, XML_FROM_XPATH,
725
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726
0
      XML_ERR_ERROR, NULL, 0,
727
0
      (const char *) ctxt->base, NULL, NULL,
728
0
      ctxt->cur - ctxt->base, 0,
729
0
      "%s", xmlXPathErrorMessages[error]);
730
0
  return;
731
0
    }
732
733
    /* cleanup current last error */
734
456k
    xmlResetError(&ctxt->context->lastError);
735
736
456k
    ctxt->context->lastError.domain = XML_FROM_XPATH;
737
456k
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
738
456k
                           XPATH_EXPRESSION_OK;
739
456k
    ctxt->context->lastError.level = XML_ERR_ERROR;
740
456k
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
741
456k
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
742
456k
    ctxt->context->lastError.node = ctxt->context->debugNode;
743
456k
    if (ctxt->context->error != NULL) {
744
0
  ctxt->context->error(ctxt->context->userData,
745
0
                       &ctxt->context->lastError);
746
456k
    } else {
747
456k
  __xmlRaiseError(NULL, NULL, NULL,
748
456k
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
749
456k
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
750
456k
      XML_ERR_ERROR, NULL, 0,
751
456k
      (const char *) ctxt->base, NULL, NULL,
752
456k
      ctxt->cur - ctxt->base, 0,
753
456k
      "%s", xmlXPathErrorMessages[error]);
754
456k
    }
755
756
456k
}
757
758
/**
759
 * xmlXPatherror:
760
 * @ctxt:  the XPath Parser context
761
 * @file:  the file name
762
 * @line:  the line number
763
 * @no:  the error number
764
 *
765
 * Formats an error message.
766
 */
767
void
768
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
769
81.6k
              int line ATTRIBUTE_UNUSED, int no) {
770
81.6k
    xmlXPathErr(ctxt, no);
771
81.6k
}
772
773
/**
774
 * xmlXPathCheckOpLimit:
775
 * @ctxt:  the XPath Parser context
776
 * @opCount:  the number of operations to be added
777
 *
778
 * Adds opCount to the running total of operations and returns -1 if the
779
 * operation limit is exceeded. Returns 0 otherwise.
780
 */
781
static int
782
34.1M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
783
34.1M
    xmlXPathContextPtr xpctxt = ctxt->context;
784
785
34.1M
    if ((opCount > xpctxt->opLimit) ||
786
34.1M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
787
11.1k
        xpctxt->opCount = xpctxt->opLimit;
788
11.1k
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
789
11.1k
        return(-1);
790
11.1k
    }
791
792
34.1M
    xpctxt->opCount += opCount;
793
34.1M
    return(0);
794
34.1M
}
795
796
#define OP_LIMIT_EXCEEDED(ctxt, n) \
797
33.6M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
798
799
/************************************************************************
800
 *                  *
801
 *      Utilities         *
802
 *                  *
803
 ************************************************************************/
804
805
/**
806
 * xsltPointerList:
807
 *
808
 * Pointer-list for various purposes.
809
 */
810
typedef struct _xmlPointerList xmlPointerList;
811
typedef xmlPointerList *xmlPointerListPtr;
812
struct _xmlPointerList {
813
    void **items;
814
    int number;
815
    int size;
816
};
817
/*
818
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
819
* and here, we should make the functions public.
820
*/
821
static int
822
xmlPointerListAddSize(xmlPointerListPtr list,
823
           void *item,
824
           int initialSize)
825
8.90M
{
826
8.90M
    if (list->size <= list->number) {
827
50.7k
        void **tmp;
828
50.7k
        size_t newSize;
829
830
50.7k
        if (list->size == 0) {
831
23.1k
            if (initialSize <= 0)
832
252
                initialSize = 1;
833
23.1k
            newSize = initialSize;
834
27.5k
        } else {
835
27.5k
            if (list->size > 50000000) {
836
0
                xmlXPathErrMemory(NULL,
837
0
                    "xmlPointerListAddSize: re-allocating item\n");
838
0
                return(-1);
839
0
            }
840
27.5k
      newSize = list->size * 2;
841
27.5k
        }
842
50.7k
  tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
843
50.7k
  if (tmp == NULL) {
844
14.7k
      xmlXPathErrMemory(NULL,
845
14.7k
    "xmlPointerListAddSize: re-allocating item\n");
846
14.7k
      return(-1);
847
14.7k
  }
848
36.0k
        list->items = tmp;
849
36.0k
        list->size = newSize;
850
36.0k
    }
851
8.89M
    list->items[list->number++] = item;
852
8.89M
    return(0);
853
8.90M
}
854
855
/**
856
 * xsltPointerListCreate:
857
 *
858
 * Creates an xsltPointerList structure.
859
 *
860
 * Returns a xsltPointerList structure or NULL in case of an error.
861
 */
862
static xmlPointerListPtr
863
xmlPointerListCreate(int initialSize)
864
26.7k
{
865
26.7k
    xmlPointerListPtr ret;
866
867
26.7k
    ret = xmlMalloc(sizeof(xmlPointerList));
868
26.7k
    if (ret == NULL) {
869
3.84k
  xmlXPathErrMemory(NULL,
870
3.84k
      "xmlPointerListCreate: allocating item\n");
871
3.84k
  return (NULL);
872
3.84k
    }
873
22.9k
    memset(ret, 0, sizeof(xmlPointerList));
874
22.9k
    if (initialSize > 0) {
875
22.9k
  xmlPointerListAddSize(ret, NULL, initialSize);
876
22.9k
  ret->number = 0;
877
22.9k
    }
878
22.9k
    return (ret);
879
26.7k
}
880
881
/**
882
 * xsltPointerListFree:
883
 *
884
 * Frees the xsltPointerList structure. This does not free
885
 * the content of the list.
886
 */
887
static void
888
xmlPointerListFree(xmlPointerListPtr list)
889
22.9k
{
890
22.9k
    if (list == NULL)
891
0
  return;
892
22.9k
    if (list->items != NULL)
893
22.8k
  xmlFree(list->items);
894
22.9k
    xmlFree(list);
895
22.9k
}
896
897
/************************************************************************
898
 *                  *
899
 *      Parser Types          *
900
 *                  *
901
 ************************************************************************/
902
903
/*
904
 * Types are private:
905
 */
906
907
typedef enum {
908
    XPATH_OP_END=0,
909
    XPATH_OP_AND,
910
    XPATH_OP_OR,
911
    XPATH_OP_EQUAL,
912
    XPATH_OP_CMP,
913
    XPATH_OP_PLUS,
914
    XPATH_OP_MULT,
915
    XPATH_OP_UNION,
916
    XPATH_OP_ROOT,
917
    XPATH_OP_NODE,
918
    XPATH_OP_COLLECT,
919
    XPATH_OP_VALUE, /* 11 */
920
    XPATH_OP_VARIABLE,
921
    XPATH_OP_FUNCTION,
922
    XPATH_OP_ARG,
923
    XPATH_OP_PREDICATE,
924
    XPATH_OP_FILTER, /* 16 */
925
    XPATH_OP_SORT /* 17 */
926
#ifdef LIBXML_XPTR_LOCS_ENABLED
927
    ,XPATH_OP_RANGETO
928
#endif
929
} xmlXPathOp;
930
931
typedef enum {
932
    AXIS_ANCESTOR = 1,
933
    AXIS_ANCESTOR_OR_SELF,
934
    AXIS_ATTRIBUTE,
935
    AXIS_CHILD,
936
    AXIS_DESCENDANT,
937
    AXIS_DESCENDANT_OR_SELF,
938
    AXIS_FOLLOWING,
939
    AXIS_FOLLOWING_SIBLING,
940
    AXIS_NAMESPACE,
941
    AXIS_PARENT,
942
    AXIS_PRECEDING,
943
    AXIS_PRECEDING_SIBLING,
944
    AXIS_SELF
945
} xmlXPathAxisVal;
946
947
typedef enum {
948
    NODE_TEST_NONE = 0,
949
    NODE_TEST_TYPE = 1,
950
    NODE_TEST_PI = 2,
951
    NODE_TEST_ALL = 3,
952
    NODE_TEST_NS = 4,
953
    NODE_TEST_NAME = 5
954
} xmlXPathTestVal;
955
956
typedef enum {
957
    NODE_TYPE_NODE = 0,
958
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
959
    NODE_TYPE_TEXT = XML_TEXT_NODE,
960
    NODE_TYPE_PI = XML_PI_NODE
961
} xmlXPathTypeVal;
962
963
typedef struct _xmlXPathStepOp xmlXPathStepOp;
964
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
965
struct _xmlXPathStepOp {
966
    xmlXPathOp op;    /* The identifier of the operation */
967
    int ch1;      /* First child */
968
    int ch2;      /* Second child */
969
    int value;
970
    int value2;
971
    int value3;
972
    void *value4;
973
    void *value5;
974
    xmlXPathFunction cache;
975
    void *cacheURI;
976
};
977
978
struct _xmlXPathCompExpr {
979
    int nbStep;     /* Number of steps in this expression */
980
    int maxStep;    /* Maximum number of steps allocated */
981
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
982
    int last;     /* index of last step in expression */
983
    xmlChar *expr;    /* the expression being computed */
984
    xmlDictPtr dict;    /* the dictionary to use if any */
985
#ifdef DEBUG_EVAL_COUNTS
986
    int nb;
987
    xmlChar *string;
988
#endif
989
#ifdef XPATH_STREAMING
990
    xmlPatternPtr stream;
991
#endif
992
};
993
994
/************************************************************************
995
 *                  *
996
 *      Forward declarations        *
997
 *                  *
998
 ************************************************************************/
999
static void
1000
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
1001
static void
1002
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
1003
static int
1004
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1005
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
1006
static int
1007
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1008
          xmlXPathStepOpPtr op,
1009
          int isPredicate);
1010
static void
1011
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1012
1013
/************************************************************************
1014
 *                  *
1015
 *      Parser Type functions       *
1016
 *                  *
1017
 ************************************************************************/
1018
1019
/**
1020
 * xmlXPathNewCompExpr:
1021
 *
1022
 * Create a new Xpath component
1023
 *
1024
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1025
 */
1026
static xmlXPathCompExprPtr
1027
952k
xmlXPathNewCompExpr(void) {
1028
952k
    xmlXPathCompExprPtr cur;
1029
1030
952k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1031
952k
    if (cur == NULL) {
1032
78
        xmlXPathErrMemory(NULL, "allocating component\n");
1033
78
  return(NULL);
1034
78
    }
1035
952k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1036
952k
    cur->maxStep = 10;
1037
952k
    cur->nbStep = 0;
1038
952k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1039
952k
                                     sizeof(xmlXPathStepOp));
1040
952k
    if (cur->steps == NULL) {
1041
90
        xmlXPathErrMemory(NULL, "allocating steps\n");
1042
90
  xmlFree(cur);
1043
90
  return(NULL);
1044
90
    }
1045
952k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1046
952k
    cur->last = -1;
1047
#ifdef DEBUG_EVAL_COUNTS
1048
    cur->nb = 0;
1049
#endif
1050
952k
    return(cur);
1051
952k
}
1052
1053
/**
1054
 * xmlXPathFreeCompExpr:
1055
 * @comp:  an XPATH comp
1056
 *
1057
 * Free up the memory allocated by @comp
1058
 */
1059
void
1060
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1061
952k
{
1062
952k
    xmlXPathStepOpPtr op;
1063
952k
    int i;
1064
1065
952k
    if (comp == NULL)
1066
308
        return;
1067
952k
    if (comp->dict == NULL) {
1068
13.6M
  for (i = 0; i < comp->nbStep; i++) {
1069
12.9M
      op = &comp->steps[i];
1070
12.9M
      if (op->value4 != NULL) {
1071
1.14M
    if (op->op == XPATH_OP_VALUE)
1072
348k
        xmlXPathFreeObject(op->value4);
1073
792k
    else
1074
792k
        xmlFree(op->value4);
1075
1.14M
      }
1076
12.9M
      if (op->value5 != NULL)
1077
2.24M
    xmlFree(op->value5);
1078
12.9M
  }
1079
697k
    } else {
1080
13.1M
  for (i = 0; i < comp->nbStep; i++) {
1081
12.8M
      op = &comp->steps[i];
1082
12.8M
      if (op->value4 != NULL) {
1083
191k
    if (op->op == XPATH_OP_VALUE)
1084
56.0k
        xmlXPathFreeObject(op->value4);
1085
191k
      }
1086
12.8M
  }
1087
254k
        xmlDictFree(comp->dict);
1088
254k
    }
1089
952k
    if (comp->steps != NULL) {
1090
952k
        xmlFree(comp->steps);
1091
952k
    }
1092
#ifdef DEBUG_EVAL_COUNTS
1093
    if (comp->string != NULL) {
1094
        xmlFree(comp->string);
1095
    }
1096
#endif
1097
952k
#ifdef XPATH_STREAMING
1098
952k
    if (comp->stream != NULL) {
1099
186k
        xmlFreePatternList(comp->stream);
1100
186k
    }
1101
952k
#endif
1102
952k
    if (comp->expr != NULL) {
1103
293k
        xmlFree(comp->expr);
1104
293k
    }
1105
1106
952k
    xmlFree(comp);
1107
952k
}
1108
1109
/**
1110
 * xmlXPathCompExprAdd:
1111
 * @comp:  the compiled expression
1112
 * @ch1: first child index
1113
 * @ch2: second child index
1114
 * @op:  an op
1115
 * @value:  the first int value
1116
 * @value2:  the second int value
1117
 * @value3:  the third int value
1118
 * @value4:  the first string value
1119
 * @value5:  the second string value
1120
 *
1121
 * Add a step to an XPath Compiled Expression
1122
 *
1123
 * Returns -1 in case of failure, the index otherwise
1124
 */
1125
static int
1126
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1127
   xmlXPathOp op, int value,
1128
25.8M
   int value2, int value3, void *value4, void *value5) {
1129
25.8M
    xmlXPathCompExprPtr comp = ctxt->comp;
1130
25.8M
    if (comp->nbStep >= comp->maxStep) {
1131
490k
  xmlXPathStepOp *real;
1132
1133
490k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1134
3
      xmlXPathPErrMemory(ctxt, "adding step\n");
1135
3
      return(-1);
1136
3
        }
1137
490k
  comp->maxStep *= 2;
1138
490k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1139
490k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1140
490k
  if (real == NULL) {
1141
584
      comp->maxStep /= 2;
1142
584
      xmlXPathPErrMemory(ctxt, "adding step\n");
1143
584
      return(-1);
1144
584
  }
1145
490k
  comp->steps = real;
1146
490k
    }
1147
25.8M
    comp->last = comp->nbStep;
1148
25.8M
    comp->steps[comp->nbStep].ch1 = ch1;
1149
25.8M
    comp->steps[comp->nbStep].ch2 = ch2;
1150
25.8M
    comp->steps[comp->nbStep].op = op;
1151
25.8M
    comp->steps[comp->nbStep].value = value;
1152
25.8M
    comp->steps[comp->nbStep].value2 = value2;
1153
25.8M
    comp->steps[comp->nbStep].value3 = value3;
1154
25.8M
    if ((comp->dict != NULL) &&
1155
25.8M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1156
12.8M
   (op == XPATH_OP_COLLECT))) {
1157
4.29M
        if (value4 != NULL) {
1158
135k
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1159
135k
          (void *)xmlDictLookup(comp->dict, value4, -1);
1160
135k
      xmlFree(value4);
1161
135k
  } else
1162
4.15M
      comp->steps[comp->nbStep].value4 = NULL;
1163
4.29M
        if (value5 != NULL) {
1164
286k
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1165
286k
          (void *)xmlDictLookup(comp->dict, value5, -1);
1166
286k
      xmlFree(value5);
1167
286k
  } else
1168
4.00M
      comp->steps[comp->nbStep].value5 = NULL;
1169
21.5M
    } else {
1170
21.5M
  comp->steps[comp->nbStep].value4 = value4;
1171
21.5M
  comp->steps[comp->nbStep].value5 = value5;
1172
21.5M
    }
1173
25.8M
    comp->steps[comp->nbStep].cache = NULL;
1174
25.8M
    return(comp->nbStep++);
1175
25.8M
}
1176
1177
/**
1178
 * xmlXPathCompSwap:
1179
 * @comp:  the compiled expression
1180
 * @op: operation index
1181
 *
1182
 * Swaps 2 operations in the compiled expression
1183
 */
1184
static void
1185
6.78k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1186
6.78k
    int tmp;
1187
1188
#ifndef LIBXML_THREAD_ENABLED
1189
    /*
1190
     * Since this manipulates possibly shared variables, this is
1191
     * disabled if one detects that the library is used in a multithreaded
1192
     * application
1193
     */
1194
    if (xmlXPathDisableOptimizer)
1195
  return;
1196
#endif
1197
1198
6.78k
    tmp = op->ch1;
1199
6.78k
    op->ch1 = op->ch2;
1200
6.78k
    op->ch2 = tmp;
1201
6.78k
}
1202
1203
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1204
6.69M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1205
6.69M
                  (op), (val), (val2), (val3), (val4), (val5))
1206
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1207
1.55M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1208
1.55M
                  (op), (val), (val2), (val3), (val4), (val5))
1209
1210
7.85M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1211
7.85M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1212
1213
1.94M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1214
1.94M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1215
1216
7.76M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1217
7.76M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1218
7.76M
      (val), (val2), 0 ,NULL ,NULL)
1219
1220
/************************************************************************
1221
 *                  *
1222
 *    XPath object cache structures       *
1223
 *                  *
1224
 ************************************************************************/
1225
1226
/* #define XP_DEFAULT_CACHE_ON */
1227
1228
1.03M
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1229
1230
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1231
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1232
struct _xmlXPathContextCache {
1233
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1234
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1235
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1236
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1237
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1238
    int maxNodeset;
1239
    int maxString;
1240
    int maxBoolean;
1241
    int maxNumber;
1242
    int maxMisc;
1243
#ifdef XP_DEBUG_OBJ_USAGE
1244
    int dbgCachedAll;
1245
    int dbgCachedNodeset;
1246
    int dbgCachedString;
1247
    int dbgCachedBool;
1248
    int dbgCachedNumber;
1249
    int dbgCachedPoint;
1250
    int dbgCachedRange;
1251
    int dbgCachedLocset;
1252
    int dbgCachedUsers;
1253
    int dbgCachedXSLTTree;
1254
    int dbgCachedUndefined;
1255
1256
1257
    int dbgReusedAll;
1258
    int dbgReusedNodeset;
1259
    int dbgReusedString;
1260
    int dbgReusedBool;
1261
    int dbgReusedNumber;
1262
    int dbgReusedPoint;
1263
    int dbgReusedRange;
1264
    int dbgReusedLocset;
1265
    int dbgReusedUsers;
1266
    int dbgReusedXSLTTree;
1267
    int dbgReusedUndefined;
1268
1269
#endif
1270
};
1271
1272
/************************************************************************
1273
 *                  *
1274
 *    Debugging related functions       *
1275
 *                  *
1276
 ************************************************************************/
1277
1278
#define STRANGE             \
1279
0
    xmlGenericError(xmlGenericErrorContext,       \
1280
0
      "Internal error at %s:%d\n",        \
1281
0
            __FILE__, __LINE__);
1282
1283
#ifdef LIBXML_DEBUG_ENABLED
1284
static void
1285
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1286
0
    int i;
1287
0
    char shift[100];
1288
1289
0
    for (i = 0;((i < depth) && (i < 25));i++)
1290
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1291
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1292
0
    if (cur == NULL) {
1293
0
  fprintf(output, "%s", shift);
1294
0
  fprintf(output, "Node is NULL !\n");
1295
0
  return;
1296
1297
0
    }
1298
1299
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1300
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1301
0
  fprintf(output, "%s", shift);
1302
0
  fprintf(output, " /\n");
1303
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1304
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1305
0
    else
1306
0
  xmlDebugDumpOneNode(output, cur, depth);
1307
0
}
1308
static void
1309
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1310
0
    xmlNodePtr tmp;
1311
0
    int i;
1312
0
    char shift[100];
1313
1314
0
    for (i = 0;((i < depth) && (i < 25));i++)
1315
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1316
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1317
0
    if (cur == NULL) {
1318
0
  fprintf(output, "%s", shift);
1319
0
  fprintf(output, "Node is NULL !\n");
1320
0
  return;
1321
1322
0
    }
1323
1324
0
    while (cur != NULL) {
1325
0
  tmp = cur;
1326
0
  cur = cur->next;
1327
0
  xmlDebugDumpOneNode(output, tmp, depth);
1328
0
    }
1329
0
}
1330
1331
static void
1332
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1333
0
    int i;
1334
0
    char shift[100];
1335
1336
0
    for (i = 0;((i < depth) && (i < 25));i++)
1337
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1338
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1339
1340
0
    if (cur == NULL) {
1341
0
  fprintf(output, "%s", shift);
1342
0
  fprintf(output, "NodeSet is NULL !\n");
1343
0
  return;
1344
1345
0
    }
1346
1347
0
    if (cur != NULL) {
1348
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1349
0
  for (i = 0;i < cur->nodeNr;i++) {
1350
0
      fprintf(output, "%s", shift);
1351
0
      fprintf(output, "%d", i + 1);
1352
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1353
0
  }
1354
0
    }
1355
0
}
1356
1357
static void
1358
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1359
0
    int i;
1360
0
    char shift[100];
1361
1362
0
    for (i = 0;((i < depth) && (i < 25));i++)
1363
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1364
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1365
1366
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1367
0
  fprintf(output, "%s", shift);
1368
0
  fprintf(output, "Value Tree is NULL !\n");
1369
0
  return;
1370
1371
0
    }
1372
1373
0
    fprintf(output, "%s", shift);
1374
0
    fprintf(output, "%d", i + 1);
1375
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1376
0
}
1377
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1378
static void
1379
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1380
    int i;
1381
    char shift[100];
1382
1383
    for (i = 0;((i < depth) && (i < 25));i++)
1384
        shift[2 * i] = shift[2 * i + 1] = ' ';
1385
    shift[2 * i] = shift[2 * i + 1] = 0;
1386
1387
    if (cur == NULL) {
1388
  fprintf(output, "%s", shift);
1389
  fprintf(output, "LocationSet is NULL !\n");
1390
  return;
1391
1392
    }
1393
1394
    for (i = 0;i < cur->locNr;i++) {
1395
  fprintf(output, "%s", shift);
1396
        fprintf(output, "%d : ", i + 1);
1397
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1398
    }
1399
}
1400
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1401
1402
/**
1403
 * xmlXPathDebugDumpObject:
1404
 * @output:  the FILE * to dump the output
1405
 * @cur:  the object to inspect
1406
 * @depth:  indentation level
1407
 *
1408
 * Dump the content of the object for debugging purposes
1409
 */
1410
void
1411
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1412
0
    int i;
1413
0
    char shift[100];
1414
1415
0
    if (output == NULL) return;
1416
1417
0
    for (i = 0;((i < depth) && (i < 25));i++)
1418
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1419
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1420
1421
1422
0
    fprintf(output, "%s", shift);
1423
1424
0
    if (cur == NULL) {
1425
0
        fprintf(output, "Object is empty (NULL)\n");
1426
0
  return;
1427
0
    }
1428
0
    switch(cur->type) {
1429
0
        case XPATH_UNDEFINED:
1430
0
      fprintf(output, "Object is uninitialized\n");
1431
0
      break;
1432
0
        case XPATH_NODESET:
1433
0
      fprintf(output, "Object is a Node Set :\n");
1434
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1435
0
      break;
1436
0
  case XPATH_XSLT_TREE:
1437
0
      fprintf(output, "Object is an XSLT value tree :\n");
1438
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1439
0
      break;
1440
0
        case XPATH_BOOLEAN:
1441
0
      fprintf(output, "Object is a Boolean : ");
1442
0
      if (cur->boolval) fprintf(output, "true\n");
1443
0
      else fprintf(output, "false\n");
1444
0
      break;
1445
0
        case XPATH_NUMBER:
1446
0
      switch (xmlXPathIsInf(cur->floatval)) {
1447
0
      case 1:
1448
0
    fprintf(output, "Object is a number : Infinity\n");
1449
0
    break;
1450
0
      case -1:
1451
0
    fprintf(output, "Object is a number : -Infinity\n");
1452
0
    break;
1453
0
      default:
1454
0
    if (xmlXPathIsNaN(cur->floatval)) {
1455
0
        fprintf(output, "Object is a number : NaN\n");
1456
0
    } else if (cur->floatval == 0) {
1457
                    /* Omit sign for negative zero. */
1458
0
        fprintf(output, "Object is a number : 0\n");
1459
0
    } else {
1460
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1461
0
    }
1462
0
      }
1463
0
      break;
1464
0
        case XPATH_STRING:
1465
0
      fprintf(output, "Object is a string : ");
1466
0
      xmlDebugDumpString(output, cur->stringval);
1467
0
      fprintf(output, "\n");
1468
0
      break;
1469
#ifdef LIBXML_XPTR_LOCS_ENABLED
1470
  case XPATH_POINT:
1471
      fprintf(output, "Object is a point : index %d in node", cur->index);
1472
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1473
      fprintf(output, "\n");
1474
      break;
1475
  case XPATH_RANGE:
1476
      if ((cur->user2 == NULL) ||
1477
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1478
    fprintf(output, "Object is a collapsed range :\n");
1479
    fprintf(output, "%s", shift);
1480
    if (cur->index >= 0)
1481
        fprintf(output, "index %d in ", cur->index);
1482
    fprintf(output, "node\n");
1483
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1484
                    depth + 1);
1485
      } else  {
1486
    fprintf(output, "Object is a range :\n");
1487
    fprintf(output, "%s", shift);
1488
    fprintf(output, "From ");
1489
    if (cur->index >= 0)
1490
        fprintf(output, "index %d in ", cur->index);
1491
    fprintf(output, "node\n");
1492
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1493
                    depth + 1);
1494
    fprintf(output, "%s", shift);
1495
    fprintf(output, "To ");
1496
    if (cur->index2 >= 0)
1497
        fprintf(output, "index %d in ", cur->index2);
1498
    fprintf(output, "node\n");
1499
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1500
                    depth + 1);
1501
    fprintf(output, "\n");
1502
      }
1503
      break;
1504
  case XPATH_LOCATIONSET:
1505
      fprintf(output, "Object is a Location Set:\n");
1506
      xmlXPathDebugDumpLocationSet(output,
1507
        (xmlLocationSetPtr) cur->user, depth);
1508
      break;
1509
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1510
0
  case XPATH_USERS:
1511
0
      fprintf(output, "Object is user defined\n");
1512
0
      break;
1513
0
    }
1514
0
}
1515
1516
static void
1517
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1518
0
                       xmlXPathStepOpPtr op, int depth) {
1519
0
    int i;
1520
0
    char shift[100];
1521
1522
0
    for (i = 0;((i < depth) && (i < 25));i++)
1523
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1524
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1525
1526
0
    fprintf(output, "%s", shift);
1527
0
    if (op == NULL) {
1528
0
  fprintf(output, "Step is NULL\n");
1529
0
  return;
1530
0
    }
1531
0
    switch (op->op) {
1532
0
        case XPATH_OP_END:
1533
0
      fprintf(output, "END"); break;
1534
0
        case XPATH_OP_AND:
1535
0
      fprintf(output, "AND"); break;
1536
0
        case XPATH_OP_OR:
1537
0
      fprintf(output, "OR"); break;
1538
0
        case XPATH_OP_EQUAL:
1539
0
       if (op->value)
1540
0
     fprintf(output, "EQUAL =");
1541
0
       else
1542
0
     fprintf(output, "EQUAL !=");
1543
0
       break;
1544
0
        case XPATH_OP_CMP:
1545
0
       if (op->value)
1546
0
     fprintf(output, "CMP <");
1547
0
       else
1548
0
     fprintf(output, "CMP >");
1549
0
       if (!op->value2)
1550
0
     fprintf(output, "=");
1551
0
       break;
1552
0
        case XPATH_OP_PLUS:
1553
0
       if (op->value == 0)
1554
0
     fprintf(output, "PLUS -");
1555
0
       else if (op->value == 1)
1556
0
     fprintf(output, "PLUS +");
1557
0
       else if (op->value == 2)
1558
0
     fprintf(output, "PLUS unary -");
1559
0
       else if (op->value == 3)
1560
0
     fprintf(output, "PLUS unary - -");
1561
0
       break;
1562
0
        case XPATH_OP_MULT:
1563
0
       if (op->value == 0)
1564
0
     fprintf(output, "MULT *");
1565
0
       else if (op->value == 1)
1566
0
     fprintf(output, "MULT div");
1567
0
       else
1568
0
     fprintf(output, "MULT mod");
1569
0
       break;
1570
0
        case XPATH_OP_UNION:
1571
0
       fprintf(output, "UNION"); break;
1572
0
        case XPATH_OP_ROOT:
1573
0
       fprintf(output, "ROOT"); break;
1574
0
        case XPATH_OP_NODE:
1575
0
       fprintf(output, "NODE"); break;
1576
0
        case XPATH_OP_SORT:
1577
0
       fprintf(output, "SORT"); break;
1578
0
        case XPATH_OP_COLLECT: {
1579
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1580
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1581
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1582
0
      const xmlChar *prefix = op->value4;
1583
0
      const xmlChar *name = op->value5;
1584
1585
0
      fprintf(output, "COLLECT ");
1586
0
      switch (axis) {
1587
0
    case AXIS_ANCESTOR:
1588
0
        fprintf(output, " 'ancestors' "); break;
1589
0
    case AXIS_ANCESTOR_OR_SELF:
1590
0
        fprintf(output, " 'ancestors-or-self' "); break;
1591
0
    case AXIS_ATTRIBUTE:
1592
0
        fprintf(output, " 'attributes' "); break;
1593
0
    case AXIS_CHILD:
1594
0
        fprintf(output, " 'child' "); break;
1595
0
    case AXIS_DESCENDANT:
1596
0
        fprintf(output, " 'descendant' "); break;
1597
0
    case AXIS_DESCENDANT_OR_SELF:
1598
0
        fprintf(output, " 'descendant-or-self' "); break;
1599
0
    case AXIS_FOLLOWING:
1600
0
        fprintf(output, " 'following' "); break;
1601
0
    case AXIS_FOLLOWING_SIBLING:
1602
0
        fprintf(output, " 'following-siblings' "); break;
1603
0
    case AXIS_NAMESPACE:
1604
0
        fprintf(output, " 'namespace' "); break;
1605
0
    case AXIS_PARENT:
1606
0
        fprintf(output, " 'parent' "); break;
1607
0
    case AXIS_PRECEDING:
1608
0
        fprintf(output, " 'preceding' "); break;
1609
0
    case AXIS_PRECEDING_SIBLING:
1610
0
        fprintf(output, " 'preceding-sibling' "); break;
1611
0
    case AXIS_SELF:
1612
0
        fprintf(output, " 'self' "); break;
1613
0
      }
1614
0
      switch (test) {
1615
0
                case NODE_TEST_NONE:
1616
0
        fprintf(output, "'none' "); break;
1617
0
                case NODE_TEST_TYPE:
1618
0
        fprintf(output, "'type' "); break;
1619
0
                case NODE_TEST_PI:
1620
0
        fprintf(output, "'PI' "); break;
1621
0
                case NODE_TEST_ALL:
1622
0
        fprintf(output, "'all' "); break;
1623
0
                case NODE_TEST_NS:
1624
0
        fprintf(output, "'namespace' "); break;
1625
0
                case NODE_TEST_NAME:
1626
0
        fprintf(output, "'name' "); break;
1627
0
      }
1628
0
      switch (type) {
1629
0
                case NODE_TYPE_NODE:
1630
0
        fprintf(output, "'node' "); break;
1631
0
                case NODE_TYPE_COMMENT:
1632
0
        fprintf(output, "'comment' "); break;
1633
0
                case NODE_TYPE_TEXT:
1634
0
        fprintf(output, "'text' "); break;
1635
0
                case NODE_TYPE_PI:
1636
0
        fprintf(output, "'PI' "); break;
1637
0
      }
1638
0
      if (prefix != NULL)
1639
0
    fprintf(output, "%s:", prefix);
1640
0
      if (name != NULL)
1641
0
    fprintf(output, "%s", (const char *) name);
1642
0
      break;
1643
1644
0
        }
1645
0
  case XPATH_OP_VALUE: {
1646
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1647
1648
0
      fprintf(output, "ELEM ");
1649
0
      xmlXPathDebugDumpObject(output, object, 0);
1650
0
      goto finish;
1651
0
  }
1652
0
  case XPATH_OP_VARIABLE: {
1653
0
      const xmlChar *prefix = op->value5;
1654
0
      const xmlChar *name = op->value4;
1655
1656
0
      if (prefix != NULL)
1657
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1658
0
      else
1659
0
    fprintf(output, "VARIABLE %s", name);
1660
0
      break;
1661
0
  }
1662
0
  case XPATH_OP_FUNCTION: {
1663
0
      int nbargs = op->value;
1664
0
      const xmlChar *prefix = op->value5;
1665
0
      const xmlChar *name = op->value4;
1666
1667
0
      if (prefix != NULL)
1668
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1669
0
      prefix, name, nbargs);
1670
0
      else
1671
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1672
0
      break;
1673
0
  }
1674
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1675
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1676
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1677
#ifdef LIBXML_XPTR_LOCS_ENABLED
1678
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1679
#endif
1680
0
  default:
1681
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1682
0
    }
1683
0
    fprintf(output, "\n");
1684
0
finish:
1685
0
    if (op->ch1 >= 0)
1686
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1687
0
    if (op->ch2 >= 0)
1688
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1689
0
}
1690
1691
/**
1692
 * xmlXPathDebugDumpCompExpr:
1693
 * @output:  the FILE * for the output
1694
 * @comp:  the precompiled XPath expression
1695
 * @depth:  the indentation level.
1696
 *
1697
 * Dumps the tree of the compiled XPath expression.
1698
 */
1699
void
1700
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1701
0
                    int depth) {
1702
0
    int i;
1703
0
    char shift[100];
1704
1705
0
    if ((output == NULL) || (comp == NULL)) return;
1706
1707
0
    for (i = 0;((i < depth) && (i < 25));i++)
1708
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1709
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1710
1711
0
    fprintf(output, "%s", shift);
1712
1713
0
#ifdef XPATH_STREAMING
1714
0
    if (comp->stream) {
1715
0
        fprintf(output, "Streaming Expression\n");
1716
0
    } else
1717
0
#endif
1718
0
    {
1719
0
        fprintf(output, "Compiled Expression : %d elements\n",
1720
0
                comp->nbStep);
1721
0
        i = comp->last;
1722
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1723
0
    }
1724
0
}
1725
1726
#ifdef XP_DEBUG_OBJ_USAGE
1727
1728
/*
1729
* XPath object usage related debugging variables.
1730
*/
1731
static int xmlXPathDebugObjCounterUndefined = 0;
1732
static int xmlXPathDebugObjCounterNodeset = 0;
1733
static int xmlXPathDebugObjCounterBool = 0;
1734
static int xmlXPathDebugObjCounterNumber = 0;
1735
static int xmlXPathDebugObjCounterString = 0;
1736
static int xmlXPathDebugObjCounterPoint = 0;
1737
static int xmlXPathDebugObjCounterRange = 0;
1738
static int xmlXPathDebugObjCounterLocset = 0;
1739
static int xmlXPathDebugObjCounterUsers = 0;
1740
static int xmlXPathDebugObjCounterXSLTTree = 0;
1741
static int xmlXPathDebugObjCounterAll = 0;
1742
1743
static int xmlXPathDebugObjTotalUndefined = 0;
1744
static int xmlXPathDebugObjTotalNodeset = 0;
1745
static int xmlXPathDebugObjTotalBool = 0;
1746
static int xmlXPathDebugObjTotalNumber = 0;
1747
static int xmlXPathDebugObjTotalString = 0;
1748
static int xmlXPathDebugObjTotalPoint = 0;
1749
static int xmlXPathDebugObjTotalRange = 0;
1750
static int xmlXPathDebugObjTotalLocset = 0;
1751
static int xmlXPathDebugObjTotalUsers = 0;
1752
static int xmlXPathDebugObjTotalXSLTTree = 0;
1753
static int xmlXPathDebugObjTotalAll = 0;
1754
1755
static int xmlXPathDebugObjMaxUndefined = 0;
1756
static int xmlXPathDebugObjMaxNodeset = 0;
1757
static int xmlXPathDebugObjMaxBool = 0;
1758
static int xmlXPathDebugObjMaxNumber = 0;
1759
static int xmlXPathDebugObjMaxString = 0;
1760
static int xmlXPathDebugObjMaxPoint = 0;
1761
static int xmlXPathDebugObjMaxRange = 0;
1762
static int xmlXPathDebugObjMaxLocset = 0;
1763
static int xmlXPathDebugObjMaxUsers = 0;
1764
static int xmlXPathDebugObjMaxXSLTTree = 0;
1765
static int xmlXPathDebugObjMaxAll = 0;
1766
1767
static void
1768
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1769
{
1770
    if (ctxt != NULL) {
1771
  if (ctxt->cache != NULL) {
1772
      xmlXPathContextCachePtr cache =
1773
    (xmlXPathContextCachePtr) ctxt->cache;
1774
1775
      cache->dbgCachedAll = 0;
1776
      cache->dbgCachedNodeset = 0;
1777
      cache->dbgCachedString = 0;
1778
      cache->dbgCachedBool = 0;
1779
      cache->dbgCachedNumber = 0;
1780
      cache->dbgCachedPoint = 0;
1781
      cache->dbgCachedRange = 0;
1782
      cache->dbgCachedLocset = 0;
1783
      cache->dbgCachedUsers = 0;
1784
      cache->dbgCachedXSLTTree = 0;
1785
      cache->dbgCachedUndefined = 0;
1786
1787
      cache->dbgReusedAll = 0;
1788
      cache->dbgReusedNodeset = 0;
1789
      cache->dbgReusedString = 0;
1790
      cache->dbgReusedBool = 0;
1791
      cache->dbgReusedNumber = 0;
1792
      cache->dbgReusedPoint = 0;
1793
      cache->dbgReusedRange = 0;
1794
      cache->dbgReusedLocset = 0;
1795
      cache->dbgReusedUsers = 0;
1796
      cache->dbgReusedXSLTTree = 0;
1797
      cache->dbgReusedUndefined = 0;
1798
  }
1799
    }
1800
1801
    xmlXPathDebugObjCounterUndefined = 0;
1802
    xmlXPathDebugObjCounterNodeset = 0;
1803
    xmlXPathDebugObjCounterBool = 0;
1804
    xmlXPathDebugObjCounterNumber = 0;
1805
    xmlXPathDebugObjCounterString = 0;
1806
    xmlXPathDebugObjCounterPoint = 0;
1807
    xmlXPathDebugObjCounterRange = 0;
1808
    xmlXPathDebugObjCounterLocset = 0;
1809
    xmlXPathDebugObjCounterUsers = 0;
1810
    xmlXPathDebugObjCounterXSLTTree = 0;
1811
    xmlXPathDebugObjCounterAll = 0;
1812
1813
    xmlXPathDebugObjTotalUndefined = 0;
1814
    xmlXPathDebugObjTotalNodeset = 0;
1815
    xmlXPathDebugObjTotalBool = 0;
1816
    xmlXPathDebugObjTotalNumber = 0;
1817
    xmlXPathDebugObjTotalString = 0;
1818
    xmlXPathDebugObjTotalPoint = 0;
1819
    xmlXPathDebugObjTotalRange = 0;
1820
    xmlXPathDebugObjTotalLocset = 0;
1821
    xmlXPathDebugObjTotalUsers = 0;
1822
    xmlXPathDebugObjTotalXSLTTree = 0;
1823
    xmlXPathDebugObjTotalAll = 0;
1824
1825
    xmlXPathDebugObjMaxUndefined = 0;
1826
    xmlXPathDebugObjMaxNodeset = 0;
1827
    xmlXPathDebugObjMaxBool = 0;
1828
    xmlXPathDebugObjMaxNumber = 0;
1829
    xmlXPathDebugObjMaxString = 0;
1830
    xmlXPathDebugObjMaxPoint = 0;
1831
    xmlXPathDebugObjMaxRange = 0;
1832
    xmlXPathDebugObjMaxLocset = 0;
1833
    xmlXPathDebugObjMaxUsers = 0;
1834
    xmlXPathDebugObjMaxXSLTTree = 0;
1835
    xmlXPathDebugObjMaxAll = 0;
1836
1837
}
1838
1839
static void
1840
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1841
            xmlXPathObjectType objType)
1842
{
1843
    int isCached = 0;
1844
1845
    if (ctxt != NULL) {
1846
  if (ctxt->cache != NULL) {
1847
      xmlXPathContextCachePtr cache =
1848
    (xmlXPathContextCachePtr) ctxt->cache;
1849
1850
      isCached = 1;
1851
1852
      cache->dbgReusedAll++;
1853
      switch (objType) {
1854
    case XPATH_UNDEFINED:
1855
        cache->dbgReusedUndefined++;
1856
        break;
1857
    case XPATH_NODESET:
1858
        cache->dbgReusedNodeset++;
1859
        break;
1860
    case XPATH_BOOLEAN:
1861
        cache->dbgReusedBool++;
1862
        break;
1863
    case XPATH_NUMBER:
1864
        cache->dbgReusedNumber++;
1865
        break;
1866
    case XPATH_STRING:
1867
        cache->dbgReusedString++;
1868
        break;
1869
#ifdef LIBXML_XPTR_LOCS_ENABLED
1870
    case XPATH_POINT:
1871
        cache->dbgReusedPoint++;
1872
        break;
1873
    case XPATH_RANGE:
1874
        cache->dbgReusedRange++;
1875
        break;
1876
    case XPATH_LOCATIONSET:
1877
        cache->dbgReusedLocset++;
1878
        break;
1879
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1880
    case XPATH_USERS:
1881
        cache->dbgReusedUsers++;
1882
        break;
1883
    case XPATH_XSLT_TREE:
1884
        cache->dbgReusedXSLTTree++;
1885
        break;
1886
    default:
1887
        break;
1888
      }
1889
  }
1890
    }
1891
1892
    switch (objType) {
1893
  case XPATH_UNDEFINED:
1894
      if (! isCached)
1895
    xmlXPathDebugObjTotalUndefined++;
1896
      xmlXPathDebugObjCounterUndefined++;
1897
      if (xmlXPathDebugObjCounterUndefined >
1898
    xmlXPathDebugObjMaxUndefined)
1899
    xmlXPathDebugObjMaxUndefined =
1900
        xmlXPathDebugObjCounterUndefined;
1901
      break;
1902
  case XPATH_NODESET:
1903
      if (! isCached)
1904
    xmlXPathDebugObjTotalNodeset++;
1905
      xmlXPathDebugObjCounterNodeset++;
1906
      if (xmlXPathDebugObjCounterNodeset >
1907
    xmlXPathDebugObjMaxNodeset)
1908
    xmlXPathDebugObjMaxNodeset =
1909
        xmlXPathDebugObjCounterNodeset;
1910
      break;
1911
  case XPATH_BOOLEAN:
1912
      if (! isCached)
1913
    xmlXPathDebugObjTotalBool++;
1914
      xmlXPathDebugObjCounterBool++;
1915
      if (xmlXPathDebugObjCounterBool >
1916
    xmlXPathDebugObjMaxBool)
1917
    xmlXPathDebugObjMaxBool =
1918
        xmlXPathDebugObjCounterBool;
1919
      break;
1920
  case XPATH_NUMBER:
1921
      if (! isCached)
1922
    xmlXPathDebugObjTotalNumber++;
1923
      xmlXPathDebugObjCounterNumber++;
1924
      if (xmlXPathDebugObjCounterNumber >
1925
    xmlXPathDebugObjMaxNumber)
1926
    xmlXPathDebugObjMaxNumber =
1927
        xmlXPathDebugObjCounterNumber;
1928
      break;
1929
  case XPATH_STRING:
1930
      if (! isCached)
1931
    xmlXPathDebugObjTotalString++;
1932
      xmlXPathDebugObjCounterString++;
1933
      if (xmlXPathDebugObjCounterString >
1934
    xmlXPathDebugObjMaxString)
1935
    xmlXPathDebugObjMaxString =
1936
        xmlXPathDebugObjCounterString;
1937
      break;
1938
#ifdef LIBXML_XPTR_LOCS_ENABLED
1939
  case XPATH_POINT:
1940
      if (! isCached)
1941
    xmlXPathDebugObjTotalPoint++;
1942
      xmlXPathDebugObjCounterPoint++;
1943
      if (xmlXPathDebugObjCounterPoint >
1944
    xmlXPathDebugObjMaxPoint)
1945
    xmlXPathDebugObjMaxPoint =
1946
        xmlXPathDebugObjCounterPoint;
1947
      break;
1948
  case XPATH_RANGE:
1949
      if (! isCached)
1950
    xmlXPathDebugObjTotalRange++;
1951
      xmlXPathDebugObjCounterRange++;
1952
      if (xmlXPathDebugObjCounterRange >
1953
    xmlXPathDebugObjMaxRange)
1954
    xmlXPathDebugObjMaxRange =
1955
        xmlXPathDebugObjCounterRange;
1956
      break;
1957
  case XPATH_LOCATIONSET:
1958
      if (! isCached)
1959
    xmlXPathDebugObjTotalLocset++;
1960
      xmlXPathDebugObjCounterLocset++;
1961
      if (xmlXPathDebugObjCounterLocset >
1962
    xmlXPathDebugObjMaxLocset)
1963
    xmlXPathDebugObjMaxLocset =
1964
        xmlXPathDebugObjCounterLocset;
1965
      break;
1966
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1967
  case XPATH_USERS:
1968
      if (! isCached)
1969
    xmlXPathDebugObjTotalUsers++;
1970
      xmlXPathDebugObjCounterUsers++;
1971
      if (xmlXPathDebugObjCounterUsers >
1972
    xmlXPathDebugObjMaxUsers)
1973
    xmlXPathDebugObjMaxUsers =
1974
        xmlXPathDebugObjCounterUsers;
1975
      break;
1976
  case XPATH_XSLT_TREE:
1977
      if (! isCached)
1978
    xmlXPathDebugObjTotalXSLTTree++;
1979
      xmlXPathDebugObjCounterXSLTTree++;
1980
      if (xmlXPathDebugObjCounterXSLTTree >
1981
    xmlXPathDebugObjMaxXSLTTree)
1982
    xmlXPathDebugObjMaxXSLTTree =
1983
        xmlXPathDebugObjCounterXSLTTree;
1984
      break;
1985
  default:
1986
      break;
1987
    }
1988
    if (! isCached)
1989
  xmlXPathDebugObjTotalAll++;
1990
    xmlXPathDebugObjCounterAll++;
1991
    if (xmlXPathDebugObjCounterAll >
1992
  xmlXPathDebugObjMaxAll)
1993
  xmlXPathDebugObjMaxAll =
1994
      xmlXPathDebugObjCounterAll;
1995
}
1996
1997
static void
1998
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1999
            xmlXPathObjectType objType)
2000
{
2001
    int isCached = 0;
2002
2003
    if (ctxt != NULL) {
2004
  if (ctxt->cache != NULL) {
2005
      xmlXPathContextCachePtr cache =
2006
    (xmlXPathContextCachePtr) ctxt->cache;
2007
2008
      isCached = 1;
2009
2010
      cache->dbgCachedAll++;
2011
      switch (objType) {
2012
    case XPATH_UNDEFINED:
2013
        cache->dbgCachedUndefined++;
2014
        break;
2015
    case XPATH_NODESET:
2016
        cache->dbgCachedNodeset++;
2017
        break;
2018
    case XPATH_BOOLEAN:
2019
        cache->dbgCachedBool++;
2020
        break;
2021
    case XPATH_NUMBER:
2022
        cache->dbgCachedNumber++;
2023
        break;
2024
    case XPATH_STRING:
2025
        cache->dbgCachedString++;
2026
        break;
2027
#ifdef LIBXML_XPTR_LOCS_ENABLED
2028
    case XPATH_POINT:
2029
        cache->dbgCachedPoint++;
2030
        break;
2031
    case XPATH_RANGE:
2032
        cache->dbgCachedRange++;
2033
        break;
2034
    case XPATH_LOCATIONSET:
2035
        cache->dbgCachedLocset++;
2036
        break;
2037
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2038
    case XPATH_USERS:
2039
        cache->dbgCachedUsers++;
2040
        break;
2041
    case XPATH_XSLT_TREE:
2042
        cache->dbgCachedXSLTTree++;
2043
        break;
2044
    default:
2045
        break;
2046
      }
2047
2048
  }
2049
    }
2050
    switch (objType) {
2051
  case XPATH_UNDEFINED:
2052
      xmlXPathDebugObjCounterUndefined--;
2053
      break;
2054
  case XPATH_NODESET:
2055
      xmlXPathDebugObjCounterNodeset--;
2056
      break;
2057
  case XPATH_BOOLEAN:
2058
      xmlXPathDebugObjCounterBool--;
2059
      break;
2060
  case XPATH_NUMBER:
2061
      xmlXPathDebugObjCounterNumber--;
2062
      break;
2063
  case XPATH_STRING:
2064
      xmlXPathDebugObjCounterString--;
2065
      break;
2066
#ifdef LIBXML_XPTR_LOCS_ENABLED
2067
  case XPATH_POINT:
2068
      xmlXPathDebugObjCounterPoint--;
2069
      break;
2070
  case XPATH_RANGE:
2071
      xmlXPathDebugObjCounterRange--;
2072
      break;
2073
  case XPATH_LOCATIONSET:
2074
      xmlXPathDebugObjCounterLocset--;
2075
      break;
2076
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2077
  case XPATH_USERS:
2078
      xmlXPathDebugObjCounterUsers--;
2079
      break;
2080
  case XPATH_XSLT_TREE:
2081
      xmlXPathDebugObjCounterXSLTTree--;
2082
      break;
2083
  default:
2084
      break;
2085
    }
2086
    xmlXPathDebugObjCounterAll--;
2087
}
2088
2089
static void
2090
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2091
{
2092
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2093
  reqXSLTTree, reqUndefined;
2094
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2095
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2096
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2097
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2098
    int leftObjs = xmlXPathDebugObjCounterAll;
2099
2100
    reqAll = xmlXPathDebugObjTotalAll;
2101
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2102
    reqString = xmlXPathDebugObjTotalString;
2103
    reqBool = xmlXPathDebugObjTotalBool;
2104
    reqNumber = xmlXPathDebugObjTotalNumber;
2105
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2106
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2107
2108
    printf("# XPath object usage:\n");
2109
2110
    if (ctxt != NULL) {
2111
  if (ctxt->cache != NULL) {
2112
      xmlXPathContextCachePtr cache =
2113
    (xmlXPathContextCachePtr) ctxt->cache;
2114
2115
      reAll = cache->dbgReusedAll;
2116
      reqAll += reAll;
2117
      reNodeset = cache->dbgReusedNodeset;
2118
      reqNodeset += reNodeset;
2119
      reString = cache->dbgReusedString;
2120
      reqString += reString;
2121
      reBool = cache->dbgReusedBool;
2122
      reqBool += reBool;
2123
      reNumber = cache->dbgReusedNumber;
2124
      reqNumber += reNumber;
2125
      reXSLTTree = cache->dbgReusedXSLTTree;
2126
      reqXSLTTree += reXSLTTree;
2127
      reUndefined = cache->dbgReusedUndefined;
2128
      reqUndefined += reUndefined;
2129
2130
      caAll = cache->dbgCachedAll;
2131
      caBool = cache->dbgCachedBool;
2132
      caNodeset = cache->dbgCachedNodeset;
2133
      caString = cache->dbgCachedString;
2134
      caNumber = cache->dbgCachedNumber;
2135
      caXSLTTree = cache->dbgCachedXSLTTree;
2136
      caUndefined = cache->dbgCachedUndefined;
2137
2138
      if (cache->nodesetObjs)
2139
    leftObjs -= cache->nodesetObjs->number;
2140
      if (cache->stringObjs)
2141
    leftObjs -= cache->stringObjs->number;
2142
      if (cache->booleanObjs)
2143
    leftObjs -= cache->booleanObjs->number;
2144
      if (cache->numberObjs)
2145
    leftObjs -= cache->numberObjs->number;
2146
      if (cache->miscObjs)
2147
    leftObjs -= cache->miscObjs->number;
2148
  }
2149
    }
2150
2151
    printf("# all\n");
2152
    printf("#   total  : %d\n", reqAll);
2153
    printf("#   left  : %d\n", leftObjs);
2154
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2155
    printf("#   reused : %d\n", reAll);
2156
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2157
2158
    printf("# node-sets\n");
2159
    printf("#   total  : %d\n", reqNodeset);
2160
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2161
    printf("#   reused : %d\n", reNodeset);
2162
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2163
2164
    printf("# strings\n");
2165
    printf("#   total  : %d\n", reqString);
2166
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2167
    printf("#   reused : %d\n", reString);
2168
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2169
2170
    printf("# booleans\n");
2171
    printf("#   total  : %d\n", reqBool);
2172
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2173
    printf("#   reused : %d\n", reBool);
2174
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2175
2176
    printf("# numbers\n");
2177
    printf("#   total  : %d\n", reqNumber);
2178
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2179
    printf("#   reused : %d\n", reNumber);
2180
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2181
2182
    printf("# XSLT result tree fragments\n");
2183
    printf("#   total  : %d\n", reqXSLTTree);
2184
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2185
    printf("#   reused : %d\n", reXSLTTree);
2186
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2187
2188
    printf("# undefined\n");
2189
    printf("#   total  : %d\n", reqUndefined);
2190
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2191
    printf("#   reused : %d\n", reUndefined);
2192
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2193
2194
}
2195
2196
#endif /* XP_DEBUG_OBJ_USAGE */
2197
2198
#endif /* LIBXML_DEBUG_ENABLED */
2199
2200
/************************************************************************
2201
 *                  *
2202
 *      XPath object caching        *
2203
 *                  *
2204
 ************************************************************************/
2205
2206
/**
2207
 * xmlXPathNewCache:
2208
 *
2209
 * Create a new object cache
2210
 *
2211
 * Returns the xmlXPathCache just allocated.
2212
 */
2213
static xmlXPathContextCachePtr
2214
xmlXPathNewCache(void)
2215
33.2k
{
2216
33.2k
    xmlXPathContextCachePtr ret;
2217
2218
33.2k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2219
33.2k
    if (ret == NULL) {
2220
23
        xmlXPathErrMemory(NULL, "creating object cache\n");
2221
23
  return(NULL);
2222
23
    }
2223
33.2k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2224
33.2k
    ret->maxNodeset = 100;
2225
33.2k
    ret->maxString = 100;
2226
33.2k
    ret->maxBoolean = 100;
2227
33.2k
    ret->maxNumber = 100;
2228
33.2k
    ret->maxMisc = 100;
2229
33.2k
    return(ret);
2230
33.2k
}
2231
2232
static void
2233
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2234
22.9k
{
2235
22.9k
    int i;
2236
22.9k
    xmlXPathObjectPtr obj;
2237
2238
22.9k
    if (list == NULL)
2239
0
  return;
2240
2241
338k
    for (i = 0; i < list->number; i++) {
2242
315k
  obj = list->items[i];
2243
  /*
2244
  * Note that it is already assured that we don't need to
2245
  * look out for namespace nodes in the node-set.
2246
  */
2247
315k
  if (obj->nodesetval != NULL) {
2248
259k
      if (obj->nodesetval->nodeTab != NULL)
2249
232k
    xmlFree(obj->nodesetval->nodeTab);
2250
259k
      xmlFree(obj->nodesetval);
2251
259k
  }
2252
315k
  xmlFree(obj);
2253
#ifdef XP_DEBUG_OBJ_USAGE
2254
  xmlXPathDebugObjCounterAll--;
2255
#endif
2256
315k
    }
2257
22.9k
    xmlPointerListFree(list);
2258
22.9k
}
2259
2260
static void
2261
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2262
33.2k
{
2263
33.2k
    if (cache == NULL)
2264
0
  return;
2265
33.2k
    if (cache->nodesetObjs)
2266
9.43k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2267
33.2k
    if (cache->stringObjs)
2268
2.38k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2269
33.2k
    if (cache->booleanObjs)
2270
2.86k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2271
33.2k
    if (cache->numberObjs)
2272
3.29k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2273
33.2k
    if (cache->miscObjs)
2274
4.91k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2275
33.2k
    xmlFree(cache);
2276
33.2k
}
2277
2278
/**
2279
 * xmlXPathContextSetCache:
2280
 *
2281
 * @ctxt:  the XPath context
2282
 * @active: enables/disables (creates/frees) the cache
2283
 * @value: a value with semantics dependent on @options
2284
 * @options: options (currently only the value 0 is used)
2285
 *
2286
 * Creates/frees an object cache on the XPath context.
2287
 * If activates XPath objects (xmlXPathObject) will be cached internally
2288
 * to be reused.
2289
 * @options:
2290
 *   0: This will set the XPath object caching:
2291
 *      @value:
2292
 *        This will set the maximum number of XPath objects
2293
 *        to be cached per slot
2294
 *        There are 5 slots for: node-set, string, number, boolean, and
2295
 *        misc objects. Use <0 for the default number (100).
2296
 *   Other values for @options have currently no effect.
2297
 *
2298
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2299
 */
2300
int
2301
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2302
      int active,
2303
      int value,
2304
      int options)
2305
33.2k
{
2306
33.2k
    if (ctxt == NULL)
2307
0
  return(-1);
2308
33.2k
    if (active) {
2309
33.2k
  xmlXPathContextCachePtr cache;
2310
2311
33.2k
  if (ctxt->cache == NULL) {
2312
33.2k
      ctxt->cache = xmlXPathNewCache();
2313
33.2k
      if (ctxt->cache == NULL)
2314
23
    return(-1);
2315
33.2k
  }
2316
33.2k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2317
33.2k
  if (options == 0) {
2318
33.2k
      if (value < 0)
2319
33.2k
    value = 100;
2320
33.2k
      cache->maxNodeset = value;
2321
33.2k
      cache->maxString = value;
2322
33.2k
      cache->maxNumber = value;
2323
33.2k
      cache->maxBoolean = value;
2324
33.2k
      cache->maxMisc = value;
2325
33.2k
  }
2326
33.2k
    } else if (ctxt->cache != NULL) {
2327
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2328
0
  ctxt->cache = NULL;
2329
0
    }
2330
33.2k
    return(0);
2331
33.2k
}
2332
2333
/**
2334
 * xmlXPathCacheWrapNodeSet:
2335
 * @ctxt: the XPath context
2336
 * @val:  the NodePtr value
2337
 *
2338
 * This is the cached version of xmlXPathWrapNodeSet().
2339
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2340
 *
2341
 * Returns the created or reused object.
2342
 *
2343
 * In case of error the node set is destroyed and NULL is returned.
2344
 */
2345
static xmlXPathObjectPtr
2346
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2347
2.23M
{
2348
2.23M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2349
2.23M
  xmlXPathContextCachePtr cache =
2350
2.23M
      (xmlXPathContextCachePtr) ctxt->cache;
2351
2352
2.23M
  if ((cache->miscObjs != NULL) &&
2353
2.23M
      (cache->miscObjs->number != 0))
2354
1.60M
  {
2355
1.60M
      xmlXPathObjectPtr ret;
2356
2357
1.60M
      ret = (xmlXPathObjectPtr)
2358
1.60M
    cache->miscObjs->items[--cache->miscObjs->number];
2359
1.60M
      ret->type = XPATH_NODESET;
2360
1.60M
      ret->nodesetval = val;
2361
#ifdef XP_DEBUG_OBJ_USAGE
2362
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2363
#endif
2364
1.60M
      return(ret);
2365
1.60M
  }
2366
2.23M
    }
2367
2368
634k
    return(xmlXPathWrapNodeSet(val));
2369
2370
2.23M
}
2371
2372
/**
2373
 * xmlXPathCacheWrapString:
2374
 * @ctxt: the XPath context
2375
 * @val:  the xmlChar * value
2376
 *
2377
 * This is the cached version of xmlXPathWrapString().
2378
 * Wraps the @val string into an XPath object.
2379
 *
2380
 * Returns the created or reused object.
2381
 */
2382
static xmlXPathObjectPtr
2383
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2384
238k
{
2385
238k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2386
238k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2387
2388
238k
  if ((cache->stringObjs != NULL) &&
2389
238k
      (cache->stringObjs->number != 0))
2390
200k
  {
2391
2392
200k
      xmlXPathObjectPtr ret;
2393
2394
200k
      ret = (xmlXPathObjectPtr)
2395
200k
    cache->stringObjs->items[--cache->stringObjs->number];
2396
200k
      ret->type = XPATH_STRING;
2397
200k
      ret->stringval = val;
2398
#ifdef XP_DEBUG_OBJ_USAGE
2399
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2400
#endif
2401
200k
      return(ret);
2402
200k
  } else if ((cache->miscObjs != NULL) &&
2403
37.1k
      (cache->miscObjs->number != 0))
2404
32.1k
  {
2405
32.1k
      xmlXPathObjectPtr ret;
2406
      /*
2407
      * Fallback to misc-cache.
2408
      */
2409
32.1k
      ret = (xmlXPathObjectPtr)
2410
32.1k
    cache->miscObjs->items[--cache->miscObjs->number];
2411
2412
32.1k
      ret->type = XPATH_STRING;
2413
32.1k
      ret->stringval = val;
2414
#ifdef XP_DEBUG_OBJ_USAGE
2415
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2416
#endif
2417
32.1k
      return(ret);
2418
32.1k
  }
2419
238k
    }
2420
4.94k
    return(xmlXPathWrapString(val));
2421
238k
}
2422
2423
/**
2424
 * xmlXPathCacheNewNodeSet:
2425
 * @ctxt: the XPath context
2426
 * @val:  the NodePtr value
2427
 *
2428
 * This is the cached version of xmlXPathNewNodeSet().
2429
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2430
 * it with the single Node @val
2431
 *
2432
 * Returns the created or reused object.
2433
 */
2434
static xmlXPathObjectPtr
2435
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2436
4.46M
{
2437
4.46M
    if ((ctxt != NULL) && (ctxt->cache)) {
2438
4.46M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2439
2440
4.46M
  if ((cache->nodesetObjs != NULL) &&
2441
4.46M
      (cache->nodesetObjs->number != 0))
2442
3.09M
  {
2443
3.09M
      xmlXPathObjectPtr ret;
2444
      /*
2445
      * Use the nodeset-cache.
2446
      */
2447
3.09M
      ret = (xmlXPathObjectPtr)
2448
3.09M
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2449
3.09M
      ret->type = XPATH_NODESET;
2450
3.09M
      ret->boolval = 0;
2451
3.09M
      if (val) {
2452
2.86M
    if ((ret->nodesetval->nodeMax == 0) ||
2453
2.86M
        (val->type == XML_NAMESPACE_DECL))
2454
511k
    {
2455
                    /* TODO: Check memory error. */
2456
511k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2457
2.35M
    } else {
2458
2.35M
        ret->nodesetval->nodeTab[0] = val;
2459
2.35M
        ret->nodesetval->nodeNr = 1;
2460
2.35M
    }
2461
2.86M
      }
2462
#ifdef XP_DEBUG_OBJ_USAGE
2463
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2464
#endif
2465
3.09M
      return(ret);
2466
3.09M
  } else if ((cache->miscObjs != NULL) &&
2467
1.36M
      (cache->miscObjs->number != 0))
2468
34.4k
  {
2469
34.4k
      xmlXPathObjectPtr ret;
2470
34.4k
            xmlNodeSetPtr set;
2471
      /*
2472
      * Fallback to misc-cache.
2473
      */
2474
2475
34.4k
      set = xmlXPathNodeSetCreate(val);
2476
34.4k
      if (set == NULL) {
2477
152
    ctxt->lastError.domain = XML_FROM_XPATH;
2478
152
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2479
152
    return(NULL);
2480
152
      }
2481
2482
34.3k
      ret = (xmlXPathObjectPtr)
2483
34.3k
    cache->miscObjs->items[--cache->miscObjs->number];
2484
2485
34.3k
      ret->type = XPATH_NODESET;
2486
34.3k
      ret->boolval = 0;
2487
34.3k
      ret->nodesetval = set;
2488
#ifdef XP_DEBUG_OBJ_USAGE
2489
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2490
#endif
2491
34.3k
      return(ret);
2492
34.4k
  }
2493
4.46M
    }
2494
1.33M
    return(xmlXPathNewNodeSet(val));
2495
4.46M
}
2496
2497
/**
2498
 * xmlXPathCacheNewString:
2499
 * @ctxt: the XPath context
2500
 * @val:  the xmlChar * value
2501
 *
2502
 * This is the cached version of xmlXPathNewString().
2503
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2504
 *
2505
 * Returns the created or reused object.
2506
 */
2507
static xmlXPathObjectPtr
2508
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2509
704k
{
2510
704k
    if ((ctxt != NULL) && (ctxt->cache)) {
2511
704k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2512
2513
704k
  if ((cache->stringObjs != NULL) &&
2514
704k
      (cache->stringObjs->number != 0))
2515
589k
  {
2516
589k
      xmlXPathObjectPtr ret;
2517
589k
            xmlChar *copy;
2518
2519
589k
            if (val == NULL)
2520
3.86k
                val = BAD_CAST "";
2521
589k
            copy = xmlStrdup(val);
2522
589k
            if (copy == NULL) {
2523
1.01k
                xmlXPathErrMemory(ctxt, NULL);
2524
1.01k
                return(NULL);
2525
1.01k
            }
2526
2527
588k
      ret = (xmlXPathObjectPtr)
2528
588k
    cache->stringObjs->items[--cache->stringObjs->number];
2529
588k
      ret->type = XPATH_STRING;
2530
588k
            ret->stringval = copy;
2531
#ifdef XP_DEBUG_OBJ_USAGE
2532
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533
#endif
2534
588k
      return(ret);
2535
589k
  } else if ((cache->miscObjs != NULL) &&
2536
115k
      (cache->miscObjs->number != 0))
2537
45.4k
  {
2538
45.4k
      xmlXPathObjectPtr ret;
2539
45.4k
            xmlChar *copy;
2540
2541
45.4k
            if (val == NULL)
2542
1
                val = BAD_CAST "";
2543
45.4k
            copy = xmlStrdup(val);
2544
45.4k
            if (copy == NULL) {
2545
117
                xmlXPathErrMemory(ctxt, NULL);
2546
117
                return(NULL);
2547
117
            }
2548
2549
45.3k
      ret = (xmlXPathObjectPtr)
2550
45.3k
    cache->miscObjs->items[--cache->miscObjs->number];
2551
2552
45.3k
      ret->type = XPATH_STRING;
2553
45.3k
            ret->stringval = copy;
2554
#ifdef XP_DEBUG_OBJ_USAGE
2555
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556
#endif
2557
45.3k
      return(ret);
2558
45.4k
  }
2559
704k
    }
2560
70.1k
    return(xmlXPathNewString(val));
2561
704k
}
2562
2563
/**
2564
 * xmlXPathCacheNewCString:
2565
 * @ctxt: the XPath context
2566
 * @val:  the char * value
2567
 *
2568
 * This is the cached version of xmlXPathNewCString().
2569
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2570
 *
2571
 * Returns the created or reused object.
2572
 */
2573
static xmlXPathObjectPtr
2574
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2575
10.8k
{
2576
10.8k
    return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2577
10.8k
}
2578
2579
/**
2580
 * xmlXPathCacheNewBoolean:
2581
 * @ctxt: the XPath context
2582
 * @val:  the boolean value
2583
 *
2584
 * This is the cached version of xmlXPathNewBoolean().
2585
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2586
 *
2587
 * Returns the created or reused object.
2588
 */
2589
static xmlXPathObjectPtr
2590
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591
1.20M
{
2592
1.20M
    if ((ctxt != NULL) && (ctxt->cache)) {
2593
1.20M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595
1.20M
  if ((cache->booleanObjs != NULL) &&
2596
1.20M
      (cache->booleanObjs->number != 0))
2597
1.08M
  {
2598
1.08M
      xmlXPathObjectPtr ret;
2599
2600
1.08M
      ret = (xmlXPathObjectPtr)
2601
1.08M
    cache->booleanObjs->items[--cache->booleanObjs->number];
2602
1.08M
      ret->type = XPATH_BOOLEAN;
2603
1.08M
      ret->boolval = (val != 0);
2604
#ifdef XP_DEBUG_OBJ_USAGE
2605
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606
#endif
2607
1.08M
      return(ret);
2608
1.08M
  } else if ((cache->miscObjs != NULL) &&
2609
117k
      (cache->miscObjs->number != 0))
2610
70.9k
  {
2611
70.9k
      xmlXPathObjectPtr ret;
2612
2613
70.9k
      ret = (xmlXPathObjectPtr)
2614
70.9k
    cache->miscObjs->items[--cache->miscObjs->number];
2615
2616
70.9k
      ret->type = XPATH_BOOLEAN;
2617
70.9k
      ret->boolval = (val != 0);
2618
#ifdef XP_DEBUG_OBJ_USAGE
2619
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620
#endif
2621
70.9k
      return(ret);
2622
70.9k
  }
2623
1.20M
    }
2624
46.4k
    return(xmlXPathNewBoolean(val));
2625
1.20M
}
2626
2627
/**
2628
 * xmlXPathCacheNewFloat:
2629
 * @ctxt: the XPath context
2630
 * @val:  the double value
2631
 *
2632
 * This is the cached version of xmlXPathNewFloat().
2633
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2634
 *
2635
 * Returns the created or reused object.
2636
 */
2637
static xmlXPathObjectPtr
2638
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639
2.07M
{
2640
2.07M
     if ((ctxt != NULL) && (ctxt->cache)) {
2641
2.07M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643
2.07M
  if ((cache->numberObjs != NULL) &&
2644
2.07M
      (cache->numberObjs->number != 0))
2645
1.64M
  {
2646
1.64M
      xmlXPathObjectPtr ret;
2647
2648
1.64M
      ret = (xmlXPathObjectPtr)
2649
1.64M
    cache->numberObjs->items[--cache->numberObjs->number];
2650
1.64M
      ret->type = XPATH_NUMBER;
2651
1.64M
      ret->floatval = val;
2652
#ifdef XP_DEBUG_OBJ_USAGE
2653
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654
#endif
2655
1.64M
      return(ret);
2656
1.64M
  } else if ((cache->miscObjs != NULL) &&
2657
429k
      (cache->miscObjs->number != 0))
2658
154k
  {
2659
154k
      xmlXPathObjectPtr ret;
2660
2661
154k
      ret = (xmlXPathObjectPtr)
2662
154k
    cache->miscObjs->items[--cache->miscObjs->number];
2663
2664
154k
      ret->type = XPATH_NUMBER;
2665
154k
      ret->floatval = val;
2666
#ifdef XP_DEBUG_OBJ_USAGE
2667
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668
#endif
2669
154k
      return(ret);
2670
154k
  }
2671
2.07M
    }
2672
275k
    return(xmlXPathNewFloat(val));
2673
2.07M
}
2674
2675
/**
2676
 * xmlXPathCacheConvertString:
2677
 * @ctxt: the XPath context
2678
 * @val:  an XPath object
2679
 *
2680
 * This is the cached version of xmlXPathConvertString().
2681
 * Converts an existing object to its string() equivalent
2682
 *
2683
 * Returns a created or reused object, the old one is freed (cached)
2684
 *         (or the operation is done directly on @val)
2685
 */
2686
2687
static xmlXPathObjectPtr
2688
281k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689
281k
    xmlChar *res = NULL;
2690
2691
281k
    if (val == NULL)
2692
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694
281k
    switch (val->type) {
2695
0
    case XPATH_UNDEFINED:
2696
#ifdef DEBUG_EXPR
2697
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698
#endif
2699
0
  break;
2700
46.8k
    case XPATH_NODESET:
2701
46.9k
    case XPATH_XSLT_TREE:
2702
46.9k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2703
46.9k
  break;
2704
61.8k
    case XPATH_STRING:
2705
61.8k
  return(val);
2706
85.7k
    case XPATH_BOOLEAN:
2707
85.7k
  res = xmlXPathCastBooleanToString(val->boolval);
2708
85.7k
  break;
2709
87.2k
    case XPATH_NUMBER:
2710
87.2k
  res = xmlXPathCastNumberToString(val->floatval);
2711
87.2k
  break;
2712
0
    case XPATH_USERS:
2713
#ifdef LIBXML_XPTR_LOCS_ENABLED
2714
    case XPATH_POINT:
2715
    case XPATH_RANGE:
2716
    case XPATH_LOCATIONSET:
2717
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2718
0
  TODO;
2719
0
  break;
2720
281k
    }
2721
219k
    xmlXPathReleaseObject(ctxt, val);
2722
219k
    if (res == NULL)
2723
52
  return(xmlXPathCacheNewCString(ctxt, ""));
2724
219k
    return(xmlXPathCacheWrapString(ctxt, res));
2725
219k
}
2726
2727
/**
2728
 * xmlXPathCacheObjectCopy:
2729
 * @ctxt: the XPath context
2730
 * @val:  the original object
2731
 *
2732
 * This is the cached version of xmlXPathObjectCopy().
2733
 * Acquire a copy of a given object
2734
 *
2735
 * Returns a created or reused created object.
2736
 */
2737
static xmlXPathObjectPtr
2738
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739
1.03M
{
2740
1.03M
    if (val == NULL)
2741
0
  return(NULL);
2742
2743
1.03M
    if (XP_HAS_CACHE(ctxt)) {
2744
1.03M
  switch (val->type) {
2745
0
      case XPATH_NODESET:
2746
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2747
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748
307k
      case XPATH_STRING:
2749
307k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2750
0
      case XPATH_BOOLEAN:
2751
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752
730k
      case XPATH_NUMBER:
2753
730k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754
0
      default:
2755
0
    break;
2756
1.03M
  }
2757
1.03M
    }
2758
0
    return(xmlXPathObjectCopy(val));
2759
1.03M
}
2760
2761
/**
2762
 * xmlXPathCacheConvertBoolean:
2763
 * @ctxt: the XPath context
2764
 * @val:  an XPath object
2765
 *
2766
 * This is the cached version of xmlXPathConvertBoolean().
2767
 * Converts an existing object to its boolean() equivalent
2768
 *
2769
 * Returns a created or reused object, the old one is freed (or the operation
2770
 *         is done directly on @val)
2771
 */
2772
static xmlXPathObjectPtr
2773
383k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774
383k
    xmlXPathObjectPtr ret;
2775
2776
383k
    if (val == NULL)
2777
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2778
383k
    if (val->type == XPATH_BOOLEAN)
2779
39.3k
  return(val);
2780
344k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781
344k
    xmlXPathReleaseObject(ctxt, val);
2782
344k
    return(ret);
2783
383k
}
2784
2785
/**
2786
 * xmlXPathCacheConvertNumber:
2787
 * @ctxt: the XPath context
2788
 * @val:  an XPath object
2789
 *
2790
 * This is the cached version of xmlXPathConvertNumber().
2791
 * Converts an existing object to its number() equivalent
2792
 *
2793
 * Returns a created or reused object, the old one is freed (or the operation
2794
 *         is done directly on @val)
2795
 */
2796
static xmlXPathObjectPtr
2797
835k
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798
835k
    xmlXPathObjectPtr ret;
2799
2800
835k
    if (val == NULL)
2801
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802
835k
    if (val->type == XPATH_NUMBER)
2803
9.85k
  return(val);
2804
826k
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805
826k
    xmlXPathReleaseObject(ctxt, val);
2806
826k
    return(ret);
2807
835k
}
2808
2809
/************************************************************************
2810
 *                  *
2811
 *    Parser stacks related functions and macros    *
2812
 *                  *
2813
 ************************************************************************/
2814
2815
/**
2816
 * valuePop:
2817
 * @ctxt: an XPath evaluation context
2818
 *
2819
 * Pops the top XPath object from the value stack
2820
 *
2821
 * Returns the XPath object just removed
2822
 */
2823
xmlXPathObjectPtr
2824
valuePop(xmlXPathParserContextPtr ctxt)
2825
13.0M
{
2826
13.0M
    xmlXPathObjectPtr ret;
2827
2828
13.0M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2829
29.0k
        return (NULL);
2830
2831
13.0M
    ctxt->valueNr--;
2832
13.0M
    if (ctxt->valueNr > 0)
2833
6.10M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834
6.92M
    else
2835
6.92M
        ctxt->value = NULL;
2836
13.0M
    ret = ctxt->valueTab[ctxt->valueNr];
2837
13.0M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2838
13.0M
    return (ret);
2839
13.0M
}
2840
/**
2841
 * valuePush:
2842
 * @ctxt:  an XPath evaluation context
2843
 * @value:  the XPath object
2844
 *
2845
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2846
 * a memory error is recorded in the parser context.
2847
 *
2848
 * Returns the number of items on the value stack, or -1 in case of error.
2849
 *
2850
 * The object is destroyed in case of error.
2851
 */
2852
int
2853
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854
13.2M
{
2855
13.2M
    if (ctxt == NULL) return(-1);
2856
13.2M
    if (value == NULL) {
2857
        /*
2858
         * A NULL value typically indicates that a memory allocation failed,
2859
         * so we set ctxt->error here to propagate the error.
2860
         */
2861
22.1k
  ctxt->error = XPATH_MEMORY_ERROR;
2862
22.1k
        return(-1);
2863
22.1k
    }
2864
13.1M
    if (ctxt->valueNr >= ctxt->valueMax) {
2865
100
        xmlXPathObjectPtr *tmp;
2866
2867
100
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2868
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2869
0
            xmlXPathFreeObject(value);
2870
0
            return (-1);
2871
0
        }
2872
100
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2873
100
                                             2 * ctxt->valueMax *
2874
100
                                             sizeof(ctxt->valueTab[0]));
2875
100
        if (tmp == NULL) {
2876
11
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2877
11
            xmlXPathFreeObject(value);
2878
11
            return (-1);
2879
11
        }
2880
89
        ctxt->valueMax *= 2;
2881
89
  ctxt->valueTab = tmp;
2882
89
    }
2883
13.1M
    ctxt->valueTab[ctxt->valueNr] = value;
2884
13.1M
    ctxt->value = value;
2885
13.1M
    return (ctxt->valueNr++);
2886
13.1M
}
2887
2888
/**
2889
 * xmlXPathPopBoolean:
2890
 * @ctxt:  an XPath parser context
2891
 *
2892
 * Pops a boolean from the stack, handling conversion if needed.
2893
 * Check error with #xmlXPathCheckError.
2894
 *
2895
 * Returns the boolean
2896
 */
2897
int
2898
980
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2899
980
    xmlXPathObjectPtr obj;
2900
980
    int ret;
2901
2902
980
    obj = valuePop(ctxt);
2903
980
    if (obj == NULL) {
2904
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905
0
  return(0);
2906
0
    }
2907
980
    if (obj->type != XPATH_BOOLEAN)
2908
81
  ret = xmlXPathCastToBoolean(obj);
2909
899
    else
2910
899
        ret = obj->boolval;
2911
980
    xmlXPathReleaseObject(ctxt->context, obj);
2912
980
    return(ret);
2913
980
}
2914
2915
/**
2916
 * xmlXPathPopNumber:
2917
 * @ctxt:  an XPath parser context
2918
 *
2919
 * Pops a number from the stack, handling conversion if needed.
2920
 * Check error with #xmlXPathCheckError.
2921
 *
2922
 * Returns the number
2923
 */
2924
double
2925
8.63k
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2926
8.63k
    xmlXPathObjectPtr obj;
2927
8.63k
    double ret;
2928
2929
8.63k
    obj = valuePop(ctxt);
2930
8.63k
    if (obj == NULL) {
2931
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932
0
  return(0);
2933
0
    }
2934
8.63k
    if (obj->type != XPATH_NUMBER)
2935
8.49k
  ret = xmlXPathCastToNumber(obj);
2936
145
    else
2937
145
        ret = obj->floatval;
2938
8.63k
    xmlXPathReleaseObject(ctxt->context, obj);
2939
8.63k
    return(ret);
2940
8.63k
}
2941
2942
/**
2943
 * xmlXPathPopString:
2944
 * @ctxt:  an XPath parser context
2945
 *
2946
 * Pops a string from the stack, handling conversion if needed.
2947
 * Check error with #xmlXPathCheckError.
2948
 *
2949
 * Returns the string
2950
 */
2951
xmlChar *
2952
1.20M
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2953
1.20M
    xmlXPathObjectPtr obj;
2954
1.20M
    xmlChar * ret;
2955
2956
1.20M
    obj = valuePop(ctxt);
2957
1.20M
    if (obj == NULL) {
2958
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959
0
  return(NULL);
2960
0
    }
2961
1.20M
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2962
    /* TODO: needs refactoring somewhere else */
2963
1.20M
    if (obj->stringval == ret)
2964
2.65k
  obj->stringval = NULL;
2965
1.20M
    xmlXPathReleaseObject(ctxt->context, obj);
2966
1.20M
    return(ret);
2967
1.20M
}
2968
2969
/**
2970
 * xmlXPathPopNodeSet:
2971
 * @ctxt:  an XPath parser context
2972
 *
2973
 * Pops a node-set from the stack, handling conversion if needed.
2974
 * Check error with #xmlXPathCheckError.
2975
 *
2976
 * Returns the node-set
2977
 */
2978
xmlNodeSetPtr
2979
497k
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2980
497k
    xmlXPathObjectPtr obj;
2981
497k
    xmlNodeSetPtr ret;
2982
2983
497k
    if (ctxt == NULL) return(NULL);
2984
497k
    if (ctxt->value == NULL) {
2985
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986
0
  return(NULL);
2987
0
    }
2988
497k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2989
3.09k
  xmlXPathSetTypeError(ctxt);
2990
3.09k
  return(NULL);
2991
3.09k
    }
2992
494k
    obj = valuePop(ctxt);
2993
494k
    ret = obj->nodesetval;
2994
#if 0
2995
    /* to fix memory leak of not clearing obj->user */
2996
    if (obj->boolval && obj->user != NULL)
2997
        xmlFreeNodeList((xmlNodePtr) obj->user);
2998
#endif
2999
494k
    obj->nodesetval = NULL;
3000
494k
    xmlXPathReleaseObject(ctxt->context, obj);
3001
494k
    return(ret);
3002
497k
}
3003
3004
/**
3005
 * xmlXPathPopExternal:
3006
 * @ctxt:  an XPath parser context
3007
 *
3008
 * Pops an external object from the stack, handling conversion if needed.
3009
 * Check error with #xmlXPathCheckError.
3010
 *
3011
 * Returns the object
3012
 */
3013
void *
3014
40.4k
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3015
40.4k
    xmlXPathObjectPtr obj;
3016
40.4k
    void * ret;
3017
3018
40.4k
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3019
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3020
0
  return(NULL);
3021
0
    }
3022
40.4k
    if (ctxt->value->type != XPATH_USERS) {
3023
0
  xmlXPathSetTypeError(ctxt);
3024
0
  return(NULL);
3025
0
    }
3026
40.4k
    obj = valuePop(ctxt);
3027
40.4k
    ret = obj->user;
3028
40.4k
    obj->user = NULL;
3029
40.4k
    xmlXPathReleaseObject(ctxt->context, obj);
3030
40.4k
    return(ret);
3031
40.4k
}
3032
3033
/*
3034
 * Macros for accessing the content. Those should be used only by the parser,
3035
 * and not exported.
3036
 *
3037
 * Dirty macros, i.e. one need to make assumption on the context to use them
3038
 *
3039
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3040
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3041
 *           in ISO-Latin or UTF-8.
3042
 *           This should be used internally by the parser
3043
 *           only to compare to ASCII values otherwise it would break when
3044
 *           running with UTF-8 encoding.
3045
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3046
 *           to compare on ASCII based substring.
3047
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3048
 *           strings within the parser.
3049
 *   CURRENT Returns the current char value, with the full decoding of
3050
 *           UTF-8 if we are using this mode. It returns an int.
3051
 *   NEXT    Skip to the next character, this does the proper decoding
3052
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3053
 *           It returns the pointer to the current xmlChar.
3054
 */
3055
3056
233M
#define CUR (*ctxt->cur)
3057
564k
#define SKIP(val) ctxt->cur += (val)
3058
19.4M
#define NXT(val) ctxt->cur[(val)]
3059
202k
#define CUR_PTR ctxt->cur
3060
32.0M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3061
3062
#define COPY_BUF(l,b,i,v)                                              \
3063
13.4M
    if (l == 1) b[i++] = v;                                            \
3064
13.4M
    else i += xmlCopyChar(l,&b[i],v)
3065
3066
27.8M
#define NEXTL(l)  ctxt->cur += l
3067
3068
#define SKIP_BLANKS             \
3069
120M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3070
3071
#define CURRENT (*ctxt->cur)
3072
124M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3073
3074
3075
#ifndef DBL_DIG
3076
#define DBL_DIG 16
3077
#endif
3078
#ifndef DBL_EPSILON
3079
#define DBL_EPSILON 1E-9
3080
#endif
3081
3082
10.3k
#define UPPER_DOUBLE 1E9
3083
4.52k
#define LOWER_DOUBLE 1E-5
3084
#define LOWER_DOUBLE_EXP 5
3085
3086
#define INTEGER_DIGITS DBL_DIG
3087
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3088
8.02k
#define EXPONENT_DIGITS (3 + 2)
3089
3090
/**
3091
 * xmlXPathFormatNumber:
3092
 * @number:     number to format
3093
 * @buffer:     output buffer
3094
 * @buffersize: size of output buffer
3095
 *
3096
 * Convert the number into a string representation.
3097
 */
3098
static void
3099
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3100
141k
{
3101
141k
    switch (xmlXPathIsInf(number)) {
3102
0
    case 1:
3103
0
  if (buffersize > (int)sizeof("Infinity"))
3104
0
      snprintf(buffer, buffersize, "Infinity");
3105
0
  break;
3106
0
    case -1:
3107
0
  if (buffersize > (int)sizeof("-Infinity"))
3108
0
      snprintf(buffer, buffersize, "-Infinity");
3109
0
  break;
3110
141k
    default:
3111
141k
  if (xmlXPathIsNaN(number)) {
3112
0
      if (buffersize > (int)sizeof("NaN"))
3113
0
    snprintf(buffer, buffersize, "NaN");
3114
141k
  } else if (number == 0) {
3115
            /* Omit sign for negative zero. */
3116
0
      snprintf(buffer, buffersize, "0");
3117
141k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3118
141k
                   (number == (int) number)) {
3119
131k
      char work[30];
3120
131k
      char *ptr, *cur;
3121
131k
      int value = (int) number;
3122
3123
131k
            ptr = &buffer[0];
3124
131k
      if (value == 0) {
3125
0
    *ptr++ = '0';
3126
131k
      } else {
3127
131k
    snprintf(work, 29, "%d", value);
3128
131k
    cur = &work[0];
3129
386k
    while ((*cur) && (ptr - buffer < buffersize)) {
3130
255k
        *ptr++ = *cur++;
3131
255k
    }
3132
131k
      }
3133
131k
      if (ptr - buffer < buffersize) {
3134
131k
    *ptr = 0;
3135
131k
      } else if (buffersize > 0) {
3136
0
    ptr--;
3137
0
    *ptr = 0;
3138
0
      }
3139
131k
  } else {
3140
      /*
3141
        For the dimension of work,
3142
            DBL_DIG is number of significant digits
3143
      EXPONENT is only needed for "scientific notation"
3144
            3 is sign, decimal point, and terminating zero
3145
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3146
        Note that this dimension is slightly (a few characters)
3147
        larger than actually necessary.
3148
      */
3149
10.3k
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3150
10.3k
      int integer_place, fraction_place;
3151
10.3k
      char *ptr;
3152
10.3k
      char *after_fraction;
3153
10.3k
      double absolute_value;
3154
10.3k
      int size;
3155
3156
10.3k
      absolute_value = fabs(number);
3157
3158
      /*
3159
       * First choose format - scientific or regular floating point.
3160
       * In either case, result is in work, and after_fraction points
3161
       * just past the fractional part.
3162
      */
3163
10.3k
      if ( ((absolute_value > UPPER_DOUBLE) ||
3164
10.3k
      (absolute_value < LOWER_DOUBLE)) &&
3165
10.3k
     (absolute_value != 0.0) ) {
3166
    /* Use scientific notation */
3167
8.02k
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3168
8.02k
    fraction_place = DBL_DIG - 1;
3169
8.02k
    size = snprintf(work, sizeof(work),"%*.*e",
3170
8.02k
       integer_place, fraction_place, number);
3171
40.4k
    while ((size > 0) && (work[size] != 'e')) size--;
3172
3173
8.02k
      }
3174
2.36k
      else {
3175
    /* Use regular notation */
3176
2.36k
    if (absolute_value > 0.0) {
3177
2.36k
        integer_place = (int)log10(absolute_value);
3178
2.36k
        if (integer_place > 0)
3179
1.28k
            fraction_place = DBL_DIG - integer_place - 1;
3180
1.07k
        else
3181
1.07k
            fraction_place = DBL_DIG - integer_place;
3182
2.36k
    } else {
3183
0
        fraction_place = 1;
3184
0
    }
3185
2.36k
    size = snprintf(work, sizeof(work), "%0.*f",
3186
2.36k
        fraction_place, number);
3187
2.36k
      }
3188
3189
      /* Remove leading spaces sometimes inserted by snprintf */
3190
15.8k
      while (work[0] == ' ') {
3191
114k
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3192
5.46k
    size--;
3193
5.46k
      }
3194
3195
      /* Remove fractional trailing zeroes */
3196
10.3k
      after_fraction = work + size;
3197
10.3k
      ptr = after_fraction;
3198
95.3k
      while (*(--ptr) == '0')
3199
84.9k
    ;
3200
10.3k
      if (*ptr != '.')
3201
6.72k
          ptr++;
3202
42.8k
      while ((*ptr++ = *after_fraction++) != 0);
3203
3204
      /* Finally copy result back to caller */
3205
10.3k
      size = strlen(work) + 1;
3206
10.3k
      if (size > buffersize) {
3207
0
    work[buffersize - 1] = 0;
3208
0
    size = buffersize;
3209
0
      }
3210
10.3k
      memmove(buffer, work, size);
3211
10.3k
  }
3212
141k
  break;
3213
141k
    }
3214
141k
}
3215
3216
3217
/************************************************************************
3218
 *                  *
3219
 *      Routines to handle NodeSets     *
3220
 *                  *
3221
 ************************************************************************/
3222
3223
/**
3224
 * xmlXPathOrderDocElems:
3225
 * @doc:  an input document
3226
 *
3227
 * Call this routine to speed up XPath computation on static documents.
3228
 * This stamps all the element nodes with the document order
3229
 * Like for line information, the order is kept in the element->content
3230
 * field, the value stored is actually - the node number (starting at -1)
3231
 * to be able to differentiate from line numbers.
3232
 *
3233
 * Returns the number of elements found in the document or -1 in case
3234
 *    of error.
3235
 */
3236
long
3237
12.3k
xmlXPathOrderDocElems(xmlDocPtr doc) {
3238
12.3k
    ptrdiff_t count = 0;
3239
12.3k
    xmlNodePtr cur;
3240
3241
12.3k
    if (doc == NULL)
3242
0
  return(-1);
3243
12.3k
    cur = doc->children;
3244
585k
    while (cur != NULL) {
3245
573k
  if (cur->type == XML_ELEMENT_NODE) {
3246
289k
      cur->content = (void *) (-(++count));
3247
289k
      if (cur->children != NULL) {
3248
114k
    cur = cur->children;
3249
114k
    continue;
3250
114k
      }
3251
289k
  }
3252
458k
  if (cur->next != NULL) {
3253
364k
      cur = cur->next;
3254
364k
      continue;
3255
364k
  }
3256
126k
  do {
3257
126k
      cur = cur->parent;
3258
126k
      if (cur == NULL)
3259
0
    break;
3260
126k
      if (cur == (xmlNodePtr) doc) {
3261
12.3k
    cur = NULL;
3262
12.3k
    break;
3263
12.3k
      }
3264
114k
      if (cur->next != NULL) {
3265
82.1k
    cur = cur->next;
3266
82.1k
    break;
3267
82.1k
      }
3268
114k
  } while (cur != NULL);
3269
94.4k
    }
3270
12.3k
    return(count);
3271
12.3k
}
3272
3273
/**
3274
 * xmlXPathCmpNodes:
3275
 * @node1:  the first node
3276
 * @node2:  the second node
3277
 *
3278
 * Compare two nodes w.r.t document order
3279
 *
3280
 * Returns -2 in case of error 1 if first point < second point, 0 if
3281
 *         it's the same node, -1 otherwise
3282
 */
3283
int
3284
169k
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3285
169k
    int depth1, depth2;
3286
169k
    int attr1 = 0, attr2 = 0;
3287
169k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3288
169k
    xmlNodePtr cur, root;
3289
3290
169k
    if ((node1 == NULL) || (node2 == NULL))
3291
0
  return(-2);
3292
    /*
3293
     * a couple of optimizations which will avoid computations in most cases
3294
     */
3295
169k
    if (node1 == node2)    /* trivial case */
3296
0
  return(0);
3297
169k
    if (node1->type == XML_ATTRIBUTE_NODE) {
3298
0
  attr1 = 1;
3299
0
  attrNode1 = node1;
3300
0
  node1 = node1->parent;
3301
0
    }
3302
169k
    if (node2->type == XML_ATTRIBUTE_NODE) {
3303
0
  attr2 = 1;
3304
0
  attrNode2 = node2;
3305
0
  node2 = node2->parent;
3306
0
    }
3307
169k
    if (node1 == node2) {
3308
0
  if (attr1 == attr2) {
3309
      /* not required, but we keep attributes in order */
3310
0
      if (attr1 != 0) {
3311
0
          cur = attrNode2->prev;
3312
0
    while (cur != NULL) {
3313
0
        if (cur == attrNode1)
3314
0
            return (1);
3315
0
        cur = cur->prev;
3316
0
    }
3317
0
    return (-1);
3318
0
      }
3319
0
      return(0);
3320
0
  }
3321
0
  if (attr2 == 1)
3322
0
      return(1);
3323
0
  return(-1);
3324
0
    }
3325
169k
    if ((node1->type == XML_NAMESPACE_DECL) ||
3326
169k
        (node2->type == XML_NAMESPACE_DECL))
3327
2.14k
  return(1);
3328
167k
    if (node1 == node2->prev)
3329
629
  return(1);
3330
166k
    if (node1 == node2->next)
3331
0
  return(-1);
3332
3333
    /*
3334
     * Speedup using document order if available.
3335
     */
3336
166k
    if ((node1->type == XML_ELEMENT_NODE) &&
3337
166k
  (node2->type == XML_ELEMENT_NODE) &&
3338
166k
  (0 > (ptrdiff_t) node1->content) &&
3339
166k
  (0 > (ptrdiff_t) node2->content) &&
3340
166k
  (node1->doc == node2->doc)) {
3341
529
  ptrdiff_t l1, l2;
3342
3343
529
  l1 = -((ptrdiff_t) node1->content);
3344
529
  l2 = -((ptrdiff_t) node2->content);
3345
529
  if (l1 < l2)
3346
529
      return(1);
3347
0
  if (l1 > l2)
3348
0
      return(-1);
3349
0
    }
3350
3351
    /*
3352
     * compute depth to root
3353
     */
3354
370k
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3355
205k
  if (cur->parent == node1)
3356
811
      return(1);
3357
204k
  depth2++;
3358
204k
    }
3359
165k
    root = cur;
3360
349k
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3361
184k
  if (cur->parent == node2)
3362
0
      return(-1);
3363
184k
  depth1++;
3364
184k
    }
3365
    /*
3366
     * Distinct document (or distinct entities :-( ) case.
3367
     */
3368
165k
    if (root != cur) {
3369
75
  return(-2);
3370
75
    }
3371
    /*
3372
     * get the nearest common ancestor.
3373
     */
3374
165k
    while (depth1 > depth2) {
3375
150
  depth1--;
3376
150
  node1 = node1->parent;
3377
150
    }
3378
173k
    while (depth2 > depth1) {
3379
8.52k
  depth2--;
3380
8.52k
  node2 = node2->parent;
3381
8.52k
    }
3382
168k
    while (node1->parent != node2->parent) {
3383
3.06k
  node1 = node1->parent;
3384
3.06k
  node2 = node2->parent;
3385
  /* should not happen but just in case ... */
3386
3.06k
  if ((node1 == NULL) || (node2 == NULL))
3387
0
      return(-2);
3388
3.06k
    }
3389
    /*
3390
     * Find who's first.
3391
     */
3392
165k
    if (node1 == node2->prev)
3393
36
  return(1);
3394
165k
    if (node1 == node2->next)
3395
0
  return(-1);
3396
    /*
3397
     * Speedup using document order if available.
3398
     */
3399
165k
    if ((node1->type == XML_ELEMENT_NODE) &&
3400
165k
  (node2->type == XML_ELEMENT_NODE) &&
3401
165k
  (0 > (ptrdiff_t) node1->content) &&
3402
165k
  (0 > (ptrdiff_t) node2->content) &&
3403
165k
  (node1->doc == node2->doc)) {
3404
634
  ptrdiff_t l1, l2;
3405
3406
634
  l1 = -((ptrdiff_t) node1->content);
3407
634
  l2 = -((ptrdiff_t) node2->content);
3408
634
  if (l1 < l2)
3409
634
      return(1);
3410
0
  if (l1 > l2)
3411
0
      return(-1);
3412
0
    }
3413
3414
21.7M
    for (cur = node1->next;cur != NULL;cur = cur->next)
3415
21.7M
  if (cur == node2)
3416
164k
      return(1);
3417
0
    return(-1); /* assume there is no sibling list corruption */
3418
164k
}
3419
3420
/**
3421
 * xmlXPathNodeSetSort:
3422
 * @set:  the node set
3423
 *
3424
 * Sort the node set in document order
3425
 */
3426
void
3427
475k
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3428
#ifndef WITH_TIM_SORT
3429
    int i, j, incr, len;
3430
    xmlNodePtr tmp;
3431
#endif
3432
3433
475k
    if (set == NULL)
3434
0
  return;
3435
3436
#ifndef WITH_TIM_SORT
3437
    /*
3438
     * Use the old Shell's sort implementation to sort the node-set
3439
     * Timsort ought to be quite faster
3440
     */
3441
    len = set->nodeNr;
3442
    for (incr = len / 2; incr > 0; incr /= 2) {
3443
  for (i = incr; i < len; i++) {
3444
      j = i - incr;
3445
      while (j >= 0) {
3446
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3447
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3448
      set->nodeTab[j + incr]) == -1)
3449
#else
3450
    if (xmlXPathCmpNodes(set->nodeTab[j],
3451
      set->nodeTab[j + incr]) == -1)
3452
#endif
3453
    {
3454
        tmp = set->nodeTab[j];
3455
        set->nodeTab[j] = set->nodeTab[j + incr];
3456
        set->nodeTab[j + incr] = tmp;
3457
        j -= incr;
3458
    } else
3459
        break;
3460
      }
3461
  }
3462
    }
3463
#else /* WITH_TIM_SORT */
3464
475k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3465
475k
#endif /* WITH_TIM_SORT */
3466
475k
}
3467
3468
8.83M
#define XML_NODESET_DEFAULT 10
3469
/**
3470
 * xmlXPathNodeSetDupNs:
3471
 * @node:  the parent node of the namespace XPath node
3472
 * @ns:  the libxml namespace declaration node.
3473
 *
3474
 * Namespace node in libxml don't match the XPath semantic. In a node set
3475
 * the namespace nodes are duplicated and the next pointer is set to the
3476
 * parent node in the XPath semantic.
3477
 *
3478
 * Returns the newly created object.
3479
 */
3480
static xmlNodePtr
3481
657k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3482
657k
    xmlNsPtr cur;
3483
3484
657k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3485
0
  return(NULL);
3486
657k
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3487
0
  return((xmlNodePtr) ns);
3488
3489
    /*
3490
     * Allocate a new Namespace and fill the fields.
3491
     */
3492
657k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3493
657k
    if (cur == NULL) {
3494
639
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3495
639
  return(NULL);
3496
639
    }
3497
657k
    memset(cur, 0, sizeof(xmlNs));
3498
657k
    cur->type = XML_NAMESPACE_DECL;
3499
657k
    if (ns->href != NULL)
3500
657k
  cur->href = xmlStrdup(ns->href);
3501
657k
    if (ns->prefix != NULL)
3502
632k
  cur->prefix = xmlStrdup(ns->prefix);
3503
657k
    cur->next = (xmlNsPtr) node;
3504
657k
    return((xmlNodePtr) cur);
3505
657k
}
3506
3507
/**
3508
 * xmlXPathNodeSetFreeNs:
3509
 * @ns:  the XPath namespace node found in a nodeset.
3510
 *
3511
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3512
 * the namespace nodes are duplicated and the next pointer is set to the
3513
 * parent node in the XPath semantic. Check if such a node needs to be freed
3514
 */
3515
void
3516
657k
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3517
657k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3518
0
  return;
3519
3520
657k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3521
657k
  if (ns->href != NULL)
3522
657k
      xmlFree((xmlChar *)ns->href);
3523
657k
  if (ns->prefix != NULL)
3524
632k
      xmlFree((xmlChar *)ns->prefix);
3525
657k
  xmlFree(ns);
3526
657k
    }
3527
657k
}
3528
3529
/**
3530
 * xmlXPathNodeSetCreate:
3531
 * @val:  an initial xmlNodePtr, or NULL
3532
 *
3533
 * Create a new xmlNodeSetPtr of type double and of value @val
3534
 *
3535
 * Returns the newly created object.
3536
 */
3537
xmlNodeSetPtr
3538
4.12M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3539
4.12M
    xmlNodeSetPtr ret;
3540
3541
4.12M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3542
4.12M
    if (ret == NULL) {
3543
16.9k
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3544
16.9k
  return(NULL);
3545
16.9k
    }
3546
4.10M
    memset(ret, 0 , sizeof(xmlNodeSet));
3547
4.10M
    if (val != NULL) {
3548
221k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3549
221k
               sizeof(xmlNodePtr));
3550
221k
  if (ret->nodeTab == NULL) {
3551
75
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3552
75
      xmlFree(ret);
3553
75
      return(NULL);
3554
75
  }
3555
221k
  memset(ret->nodeTab, 0 ,
3556
221k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3557
221k
        ret->nodeMax = XML_NODESET_DEFAULT;
3558
221k
  if (val->type == XML_NAMESPACE_DECL) {
3559
1.23k
      xmlNsPtr ns = (xmlNsPtr) val;
3560
1.23k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3561
3562
1.23k
            if (nsNode == NULL) {
3563
1
                xmlXPathFreeNodeSet(ret);
3564
1
                return(NULL);
3565
1
            }
3566
1.23k
      ret->nodeTab[ret->nodeNr++] = nsNode;
3567
1.23k
  } else
3568
220k
      ret->nodeTab[ret->nodeNr++] = val;
3569
221k
    }
3570
4.10M
    return(ret);
3571
4.10M
}
3572
3573
/**
3574
 * xmlXPathNodeSetContains:
3575
 * @cur:  the node-set
3576
 * @val:  the node
3577
 *
3578
 * checks whether @cur contains @val
3579
 *
3580
 * Returns true (1) if @cur contains @val, false (0) otherwise
3581
 */
3582
int
3583
10.9k
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3584
10.9k
    int i;
3585
3586
10.9k
    if ((cur == NULL) || (val == NULL)) return(0);
3587
10.9k
    if (val->type == XML_NAMESPACE_DECL) {
3588
22.4k
  for (i = 0; i < cur->nodeNr; i++) {
3589
21.0k
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3590
17.1k
    xmlNsPtr ns1, ns2;
3591
3592
17.1k
    ns1 = (xmlNsPtr) val;
3593
17.1k
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3594
17.1k
    if (ns1 == ns2)
3595
0
        return(1);
3596
17.1k
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3597
17.1k
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3598
85
        return(1);
3599
17.1k
      }
3600
21.0k
  }
3601
9.41k
    } else {
3602
580k
  for (i = 0; i < cur->nodeNr; i++) {
3603
575k
      if (cur->nodeTab[i] == val)
3604
4.29k
    return(1);
3605
575k
  }
3606
9.41k
    }
3607
6.57k
    return(0);
3608
10.9k
}
3609
3610
/**
3611
 * xmlXPathNodeSetAddNs:
3612
 * @cur:  the initial node set
3613
 * @node:  the hosting node
3614
 * @ns:  a the namespace node
3615
 *
3616
 * add a new namespace node to an existing NodeSet
3617
 *
3618
 * Returns 0 in case of success and -1 in case of error
3619
 */
3620
int
3621
411k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3622
411k
    int i;
3623
411k
    xmlNodePtr nsNode;
3624
3625
411k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3626
411k
        (ns->type != XML_NAMESPACE_DECL) ||
3627
411k
  (node->type != XML_ELEMENT_NODE))
3628
0
  return(-1);
3629
3630
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3631
    /*
3632
     * prevent duplicates
3633
     */
3634
1.07M
    for (i = 0;i < cur->nodeNr;i++) {
3635
663k
        if ((cur->nodeTab[i] != NULL) &&
3636
663k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3637
663k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3638
663k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3639
3
      return(0);
3640
663k
    }
3641
3642
    /*
3643
     * grow the nodeTab if needed
3644
     */
3645
411k
    if (cur->nodeMax == 0) {
3646
57.6k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3647
57.6k
               sizeof(xmlNodePtr));
3648
57.6k
  if (cur->nodeTab == NULL) {
3649
12
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3650
12
      return(-1);
3651
12
  }
3652
57.6k
  memset(cur->nodeTab, 0 ,
3653
57.6k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3654
57.6k
        cur->nodeMax = XML_NODESET_DEFAULT;
3655
353k
    } else if (cur->nodeNr == cur->nodeMax) {
3656
306
        xmlNodePtr *temp;
3657
3658
306
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3659
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3660
0
            return(-1);
3661
0
        }
3662
306
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3663
306
              sizeof(xmlNodePtr));
3664
306
  if (temp == NULL) {
3665
1
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3666
1
      return(-1);
3667
1
  }
3668
305
        cur->nodeMax *= 2;
3669
305
  cur->nodeTab = temp;
3670
305
    }
3671
411k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
3672
411k
    if(nsNode == NULL)
3673
87
        return(-1);
3674
411k
    cur->nodeTab[cur->nodeNr++] = nsNode;
3675
411k
    return(0);
3676
411k
}
3677
3678
/**
3679
 * xmlXPathNodeSetAdd:
3680
 * @cur:  the initial node set
3681
 * @val:  a new xmlNodePtr
3682
 *
3683
 * add a new xmlNodePtr to an existing NodeSet
3684
 *
3685
 * Returns 0 in case of success, and -1 in case of error
3686
 */
3687
int
3688
148k
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3689
148k
    int i;
3690
3691
148k
    if ((cur == NULL) || (val == NULL)) return(-1);
3692
3693
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3694
    /*
3695
     * prevent duplicates
3696
     */
3697
7.50M
    for (i = 0;i < cur->nodeNr;i++)
3698
7.44M
        if (cur->nodeTab[i] == val) return(0);
3699
3700
    /*
3701
     * grow the nodeTab if needed
3702
     */
3703
56.0k
    if (cur->nodeMax == 0) {
3704
3.21k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3705
3.21k
               sizeof(xmlNodePtr));
3706
3.21k
  if (cur->nodeTab == NULL) {
3707
349
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3708
349
      return(-1);
3709
349
  }
3710
2.86k
  memset(cur->nodeTab, 0 ,
3711
2.86k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3712
2.86k
        cur->nodeMax = XML_NODESET_DEFAULT;
3713
52.8k
    } else if (cur->nodeNr == cur->nodeMax) {
3714
2.60k
        xmlNodePtr *temp;
3715
3716
2.60k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3717
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3718
0
            return(-1);
3719
0
        }
3720
2.60k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3721
2.60k
              sizeof(xmlNodePtr));
3722
2.60k
  if (temp == NULL) {
3723
366
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3724
366
      return(-1);
3725
366
  }
3726
2.23k
        cur->nodeMax *= 2;
3727
2.23k
  cur->nodeTab = temp;
3728
2.23k
    }
3729
55.3k
    if (val->type == XML_NAMESPACE_DECL) {
3730
3.16k
  xmlNsPtr ns = (xmlNsPtr) val;
3731
3.16k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3732
3733
3.16k
        if (nsNode == NULL)
3734
260
            return(-1);
3735
2.90k
  cur->nodeTab[cur->nodeNr++] = nsNode;
3736
2.90k
    } else
3737
52.1k
  cur->nodeTab[cur->nodeNr++] = val;
3738
55.0k
    return(0);
3739
55.3k
}
3740
3741
/**
3742
 * xmlXPathNodeSetAddUnique:
3743
 * @cur:  the initial node set
3744
 * @val:  a new xmlNodePtr
3745
 *
3746
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3747
 * when we are sure the node is not already in the set.
3748
 *
3749
 * Returns 0 in case of success and -1 in case of failure
3750
 */
3751
int
3752
13.6M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3753
13.6M
    if ((cur == NULL) || (val == NULL)) return(-1);
3754
3755
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3756
    /*
3757
     * grow the nodeTab if needed
3758
     */
3759
13.6M
    if (cur->nodeMax == 0) {
3760
2.49M
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3761
2.49M
               sizeof(xmlNodePtr));
3762
2.49M
  if (cur->nodeTab == NULL) {
3763
18.3k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3764
18.3k
      return(-1);
3765
18.3k
  }
3766
2.47M
  memset(cur->nodeTab, 0 ,
3767
2.47M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3768
2.47M
        cur->nodeMax = XML_NODESET_DEFAULT;
3769
11.1M
    } else if (cur->nodeNr == cur->nodeMax) {
3770
170k
        xmlNodePtr *temp;
3771
3772
170k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3773
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3774
0
            return(-1);
3775
0
        }
3776
170k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3777
170k
              sizeof(xmlNodePtr));
3778
170k
  if (temp == NULL) {
3779
1.24k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3780
1.24k
      return(-1);
3781
1.24k
  }
3782
168k
  cur->nodeTab = temp;
3783
168k
        cur->nodeMax *= 2;
3784
168k
    }
3785
13.5M
    if (val->type == XML_NAMESPACE_DECL) {
3786
51.5k
  xmlNsPtr ns = (xmlNsPtr) val;
3787
51.5k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3788
3789
51.5k
        if (nsNode == NULL)
3790
269
            return(-1);
3791
51.2k
  cur->nodeTab[cur->nodeNr++] = nsNode;
3792
51.2k
    } else
3793
13.5M
  cur->nodeTab[cur->nodeNr++] = val;
3794
13.5M
    return(0);
3795
13.5M
}
3796
3797
/**
3798
 * xmlXPathNodeSetMerge:
3799
 * @val1:  the first NodeSet or NULL
3800
 * @val2:  the second NodeSet
3801
 *
3802
 * Merges two nodesets, all nodes from @val2 are added to @val1
3803
 * if @val1 is NULL, a new set is created and copied from @val2
3804
 *
3805
 * Returns @val1 once extended or NULL in case of error.
3806
 *
3807
 * Frees @val1 in case of error.
3808
 */
3809
xmlNodeSetPtr
3810
292k
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3811
292k
    int i, j, initNr, skip;
3812
292k
    xmlNodePtr n1, n2;
3813
3814
292k
    if (val2 == NULL) return(val1);
3815
252k
    if (val1 == NULL) {
3816
85.1k
  val1 = xmlXPathNodeSetCreate(NULL);
3817
85.1k
        if (val1 == NULL)
3818
318
            return (NULL);
3819
85.1k
    }
3820
3821
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822
252k
    initNr = val1->nodeNr;
3823
3824
2.30M
    for (i = 0;i < val2->nodeNr;i++) {
3825
2.04M
  n2 = val2->nodeTab[i];
3826
  /*
3827
   * check against duplicates
3828
   */
3829
2.04M
  skip = 0;
3830
279M
  for (j = 0; j < initNr; j++) {
3831
277M
      n1 = val1->nodeTab[j];
3832
277M
      if (n1 == n2) {
3833
50.9k
    skip = 1;
3834
50.9k
    break;
3835
277M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3836
277M
           (n2->type == XML_NAMESPACE_DECL)) {
3837
71.2k
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3838
71.2k
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3839
16.5k
      ((xmlNsPtr) n2)->prefix)))
3840
6.25k
    {
3841
6.25k
        skip = 1;
3842
6.25k
        break;
3843
6.25k
    }
3844
71.2k
      }
3845
277M
  }
3846
2.04M
  if (skip)
3847
57.2k
      continue;
3848
3849
  /*
3850
   * grow the nodeTab if needed
3851
   */
3852
1.99M
  if (val1->nodeMax == 0) {
3853
130k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3854
130k
                sizeof(xmlNodePtr));
3855
130k
      if (val1->nodeTab == NULL) {
3856
209
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3857
209
    goto error;
3858
209
      }
3859
129k
      memset(val1->nodeTab, 0 ,
3860
129k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3861
129k
      val1->nodeMax = XML_NODESET_DEFAULT;
3862
1.86M
  } else if (val1->nodeNr == val1->nodeMax) {
3863
46.9k
      xmlNodePtr *temp;
3864
3865
46.9k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3866
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3867
0
                goto error;
3868
0
            }
3869
46.9k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3870
46.9k
               sizeof(xmlNodePtr));
3871
46.9k
      if (temp == NULL) {
3872
26
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3873
26
    goto error;
3874
26
      }
3875
46.9k
      val1->nodeTab = temp;
3876
46.9k
      val1->nodeMax *= 2;
3877
46.9k
  }
3878
1.99M
  if (n2->type == XML_NAMESPACE_DECL) {
3879
190k
      xmlNsPtr ns = (xmlNsPtr) n2;
3880
190k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3881
3882
190k
            if (nsNode == NULL)
3883
22
                goto error;
3884
190k
      val1->nodeTab[val1->nodeNr++] = nsNode;
3885
190k
  } else
3886
1.80M
      val1->nodeTab[val1->nodeNr++] = n2;
3887
1.99M
    }
3888
3889
252k
    return(val1);
3890
3891
257
error:
3892
257
    xmlXPathFreeNodeSet(val1);
3893
257
    return(NULL);
3894
252k
}
3895
3896
3897
/**
3898
 * xmlXPathNodeSetMergeAndClear:
3899
 * @set1:  the first NodeSet or NULL
3900
 * @set2:  the second NodeSet
3901
 *
3902
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3903
 * Checks for duplicate nodes. Clears set2.
3904
 *
3905
 * Returns @set1 once extended or NULL in case of error.
3906
 *
3907
 * Frees @set1 in case of error.
3908
 */
3909
static xmlNodeSetPtr
3910
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3911
152k
{
3912
152k
    {
3913
152k
  int i, j, initNbSet1;
3914
152k
  xmlNodePtr n1, n2;
3915
3916
152k
  initNbSet1 = set1->nodeNr;
3917
855k
  for (i = 0;i < set2->nodeNr;i++) {
3918
703k
      n2 = set2->nodeTab[i];
3919
      /*
3920
      * Skip duplicates.
3921
      */
3922
376M
      for (j = 0; j < initNbSet1; j++) {
3923
376M
    n1 = set1->nodeTab[j];
3924
376M
    if (n1 == n2) {
3925
648k
        goto skip_node;
3926
375M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3927
375M
        (n2->type == XML_NAMESPACE_DECL))
3928
143M
    {
3929
143M
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3930
143M
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3931
91.0k
      ((xmlNsPtr) n2)->prefix)))
3932
0
        {
3933
      /*
3934
      * Free the namespace node.
3935
      */
3936
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3937
0
      goto skip_node;
3938
0
        }
3939
143M
    }
3940
376M
      }
3941
      /*
3942
      * grow the nodeTab if needed
3943
      */
3944
54.6k
      if (set1->nodeMax == 0) {
3945
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3946
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3947
0
    if (set1->nodeTab == NULL) {
3948
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3949
0
        goto error;
3950
0
    }
3951
0
    memset(set1->nodeTab, 0,
3952
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3953
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3954
54.6k
      } else if (set1->nodeNr >= set1->nodeMax) {
3955
1.36k
    xmlNodePtr *temp;
3956
3957
1.36k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3958
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3959
0
                    goto error;
3960
0
                }
3961
1.36k
    temp = (xmlNodePtr *) xmlRealloc(
3962
1.36k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3963
1.36k
    if (temp == NULL) {
3964
8
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3965
8
        goto error;
3966
8
    }
3967
1.36k
    set1->nodeTab = temp;
3968
1.36k
    set1->nodeMax *= 2;
3969
1.36k
      }
3970
54.5k
      set1->nodeTab[set1->nodeNr++] = n2;
3971
703k
skip_node:
3972
703k
            set2->nodeTab[i] = NULL;
3973
703k
  }
3974
152k
    }
3975
152k
    set2->nodeNr = 0;
3976
152k
    return(set1);
3977
3978
8
error:
3979
8
    xmlXPathFreeNodeSet(set1);
3980
8
    xmlXPathNodeSetClear(set2, 1);
3981
8
    return(NULL);
3982
152k
}
3983
3984
/**
3985
 * xmlXPathNodeSetMergeAndClearNoDupls:
3986
 * @set1:  the first NodeSet or NULL
3987
 * @set2:  the second NodeSet
3988
 *
3989
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3990
 * Doesn't check for duplicate nodes. Clears set2.
3991
 *
3992
 * Returns @set1 once extended or NULL in case of error.
3993
 *
3994
 * Frees @set1 in case of error.
3995
 */
3996
static xmlNodeSetPtr
3997
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3998
214k
{
3999
214k
    {
4000
214k
  int i;
4001
214k
  xmlNodePtr n2;
4002
4003
814k
  for (i = 0;i < set2->nodeNr;i++) {
4004
599k
      n2 = set2->nodeTab[i];
4005
599k
      if (set1->nodeMax == 0) {
4006
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008
0
    if (set1->nodeTab == NULL) {
4009
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4010
0
        goto error;
4011
0
    }
4012
0
    memset(set1->nodeTab, 0,
4013
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4015
599k
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
20.4k
    xmlNodePtr *temp;
4017
4018
20.4k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    goto error;
4021
0
                }
4022
20.4k
    temp = (xmlNodePtr *) xmlRealloc(
4023
20.4k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
20.4k
    if (temp == NULL) {
4025
45
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
45
        goto error;
4027
45
    }
4028
20.4k
    set1->nodeTab = temp;
4029
20.4k
    set1->nodeMax *= 2;
4030
20.4k
      }
4031
599k
      set1->nodeTab[set1->nodeNr++] = n2;
4032
599k
            set2->nodeTab[i] = NULL;
4033
599k
  }
4034
214k
    }
4035
214k
    set2->nodeNr = 0;
4036
214k
    return(set1);
4037
4038
45
error:
4039
45
    xmlXPathFreeNodeSet(set1);
4040
45
    xmlXPathNodeSetClear(set2, 1);
4041
45
    return(NULL);
4042
214k
}
4043
4044
/**
4045
 * xmlXPathNodeSetDel:
4046
 * @cur:  the initial node set
4047
 * @val:  an xmlNodePtr
4048
 *
4049
 * Removes an xmlNodePtr from an existing NodeSet
4050
 */
4051
void
4052
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4053
0
    int i;
4054
4055
0
    if (cur == NULL) return;
4056
0
    if (val == NULL) return;
4057
4058
    /*
4059
     * find node in nodeTab
4060
     */
4061
0
    for (i = 0;i < cur->nodeNr;i++)
4062
0
        if (cur->nodeTab[i] == val) break;
4063
4064
0
    if (i >= cur->nodeNr) { /* not found */
4065
#ifdef DEBUG
4066
        xmlGenericError(xmlGenericErrorContext,
4067
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4068
    val->name);
4069
#endif
4070
0
        return;
4071
0
    }
4072
0
    if ((cur->nodeTab[i] != NULL) &&
4073
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4074
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4075
0
    cur->nodeNr--;
4076
0
    for (;i < cur->nodeNr;i++)
4077
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4078
0
    cur->nodeTab[cur->nodeNr] = NULL;
4079
0
}
4080
4081
/**
4082
 * xmlXPathNodeSetRemove:
4083
 * @cur:  the initial node set
4084
 * @val:  the index to remove
4085
 *
4086
 * Removes an entry from an existing NodeSet list.
4087
 */
4088
void
4089
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4090
0
    if (cur == NULL) return;
4091
0
    if (val >= cur->nodeNr) return;
4092
0
    if ((cur->nodeTab[val] != NULL) &&
4093
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4094
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4095
0
    cur->nodeNr--;
4096
0
    for (;val < cur->nodeNr;val++)
4097
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4098
0
    cur->nodeTab[cur->nodeNr] = NULL;
4099
0
}
4100
4101
/**
4102
 * xmlXPathFreeNodeSet:
4103
 * @obj:  the xmlNodeSetPtr to free
4104
 *
4105
 * Free the NodeSet compound (not the actual nodes !).
4106
 */
4107
void
4108
3.86M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4109
3.86M
    if (obj == NULL) return;
4110
3.84M
    if (obj->nodeTab != NULL) {
4111
2.65M
  int i;
4112
4113
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114
15.1M
  for (i = 0;i < obj->nodeNr;i++)
4115
12.4M
      if ((obj->nodeTab[i] != NULL) &&
4116
12.4M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4117
409k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4118
2.65M
  xmlFree(obj->nodeTab);
4119
2.65M
    }
4120
3.84M
    xmlFree(obj);
4121
3.84M
}
4122
4123
/**
4124
 * xmlXPathNodeSetClearFromPos:
4125
 * @set: the node set to be cleared
4126
 * @pos: the start position to clear from
4127
 *
4128
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4129
 * are feed) starting with the entry at @pos, but does *not* free the list
4130
 * itself. Sets the length of the list to @pos.
4131
 */
4132
static void
4133
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4134
8.04k
{
4135
8.04k
    if ((set == NULL) || (pos >= set->nodeNr))
4136
0
  return;
4137
8.04k
    else if ((hasNsNodes)) {
4138
7.52k
  int i;
4139
7.52k
  xmlNodePtr node;
4140
4141
118k
  for (i = pos; i < set->nodeNr; i++) {
4142
110k
      node = set->nodeTab[i];
4143
110k
      if ((node != NULL) &&
4144
110k
    (node->type == XML_NAMESPACE_DECL))
4145
46.1k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4146
110k
  }
4147
7.52k
    }
4148
8.04k
    set->nodeNr = pos;
4149
8.04k
}
4150
4151
/**
4152
 * xmlXPathNodeSetClear:
4153
 * @set:  the node set to clear
4154
 *
4155
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4156
 * are feed), but does *not* free the list itself. Sets the length of the
4157
 * list to 0.
4158
 */
4159
static void
4160
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4161
7.77k
{
4162
7.77k
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4163
7.77k
}
4164
4165
/**
4166
 * xmlXPathNodeSetKeepLast:
4167
 * @set: the node set to be cleared
4168
 *
4169
 * Move the last node to the first position and clear temporary XPath objects
4170
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4171
 * to 1.
4172
 */
4173
static void
4174
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4175
6.57k
{
4176
6.57k
    int i;
4177
6.57k
    xmlNodePtr node;
4178
4179
6.57k
    if ((set == NULL) || (set->nodeNr <= 1))
4180
0
  return;
4181
166k
    for (i = 0; i < set->nodeNr - 1; i++) {
4182
160k
        node = set->nodeTab[i];
4183
160k
        if ((node != NULL) &&
4184
160k
            (node->type == XML_NAMESPACE_DECL))
4185
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
160k
    }
4187
6.57k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4188
6.57k
    set->nodeNr = 1;
4189
6.57k
}
4190
4191
/**
4192
 * xmlXPathFreeValueTree:
4193
 * @obj:  the xmlNodeSetPtr to free
4194
 *
4195
 * Free the NodeSet compound and the actual tree, this is different
4196
 * from xmlXPathFreeNodeSet()
4197
 */
4198
static void
4199
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4200
0
    int i;
4201
4202
0
    if (obj == NULL) return;
4203
4204
0
    if (obj->nodeTab != NULL) {
4205
0
  for (i = 0;i < obj->nodeNr;i++) {
4206
0
      if (obj->nodeTab[i] != NULL) {
4207
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4208
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4209
0
    } else {
4210
0
        xmlFreeNodeList(obj->nodeTab[i]);
4211
0
    }
4212
0
      }
4213
0
  }
4214
0
  xmlFree(obj->nodeTab);
4215
0
    }
4216
0
    xmlFree(obj);
4217
0
}
4218
4219
#if defined(DEBUG) || defined(DEBUG_STEP)
4220
/**
4221
 * xmlGenericErrorContextNodeSet:
4222
 * @output:  a FILE * for the output
4223
 * @obj:  the xmlNodeSetPtr to display
4224
 *
4225
 * Quick display of a NodeSet
4226
 */
4227
void
4228
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4229
    int i;
4230
4231
    if (output == NULL) output = xmlGenericErrorContext;
4232
    if (obj == NULL)  {
4233
        fprintf(output, "NodeSet == NULL !\n");
4234
  return;
4235
    }
4236
    if (obj->nodeNr == 0) {
4237
        fprintf(output, "NodeSet is empty\n");
4238
  return;
4239
    }
4240
    if (obj->nodeTab == NULL) {
4241
  fprintf(output, " nodeTab == NULL !\n");
4242
  return;
4243
    }
4244
    for (i = 0; i < obj->nodeNr; i++) {
4245
        if (obj->nodeTab[i] == NULL) {
4246
      fprintf(output, " NULL !\n");
4247
      return;
4248
        }
4249
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4250
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4251
      fprintf(output, " /");
4252
  else if (obj->nodeTab[i]->name == NULL)
4253
      fprintf(output, " noname!");
4254
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4255
    }
4256
    fprintf(output, "\n");
4257
}
4258
#endif
4259
4260
/**
4261
 * xmlXPathNewNodeSet:
4262
 * @val:  the NodePtr value
4263
 *
4264
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4265
 * it with the single Node @val
4266
 *
4267
 * Returns the newly created object.
4268
 */
4269
xmlXPathObjectPtr
4270
2.01M
xmlXPathNewNodeSet(xmlNodePtr val) {
4271
2.01M
    xmlXPathObjectPtr ret;
4272
4273
2.01M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4274
2.01M
    if (ret == NULL) {
4275
4.24k
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4276
4.24k
  return(NULL);
4277
4.24k
    }
4278
2.00M
    memset(ret, 0 , sizeof(xmlXPathObject));
4279
2.00M
    ret->type = XPATH_NODESET;
4280
2.00M
    ret->boolval = 0;
4281
    /* TODO: Check memory error. */
4282
2.00M
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4283
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4284
#ifdef XP_DEBUG_OBJ_USAGE
4285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4286
#endif
4287
2.00M
    return(ret);
4288
2.01M
}
4289
4290
/**
4291
 * xmlXPathNewValueTree:
4292
 * @val:  the NodePtr value
4293
 *
4294
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4295
 * it with the tree root @val
4296
 *
4297
 * Returns the newly created object.
4298
 */
4299
xmlXPathObjectPtr
4300
21.1k
xmlXPathNewValueTree(xmlNodePtr val) {
4301
21.1k
    xmlXPathObjectPtr ret;
4302
4303
21.1k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304
21.1k
    if (ret == NULL) {
4305
1.07k
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4306
1.07k
  return(NULL);
4307
1.07k
    }
4308
20.0k
    memset(ret, 0 , sizeof(xmlXPathObject));
4309
20.0k
    ret->type = XPATH_XSLT_TREE;
4310
20.0k
    ret->boolval = 1;
4311
20.0k
    ret->user = (void *) val;
4312
20.0k
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4313
#ifdef XP_DEBUG_OBJ_USAGE
4314
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4315
#endif
4316
20.0k
    return(ret);
4317
21.1k
}
4318
4319
/**
4320
 * xmlXPathNewNodeSetList:
4321
 * @val:  an existing NodeSet
4322
 *
4323
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4324
 * it with the Nodeset @val
4325
 *
4326
 * Returns the newly created object.
4327
 */
4328
xmlXPathObjectPtr
4329
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4330
0
{
4331
0
    xmlXPathObjectPtr ret;
4332
0
    int i;
4333
4334
0
    if (val == NULL)
4335
0
        ret = NULL;
4336
0
    else if (val->nodeTab == NULL)
4337
0
        ret = xmlXPathNewNodeSet(NULL);
4338
0
    else {
4339
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4340
0
        if (ret) {
4341
0
            for (i = 1; i < val->nodeNr; ++i) {
4342
                /* TODO: Propagate memory error. */
4343
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4344
0
        < 0) break;
4345
0
      }
4346
0
  }
4347
0
    }
4348
4349
0
    return (ret);
4350
0
}
4351
4352
/**
4353
 * xmlXPathWrapNodeSet:
4354
 * @val:  the NodePtr value
4355
 *
4356
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4357
 *
4358
 * Returns the newly created object.
4359
 *
4360
 * In case of error the node set is destroyed and NULL is returned.
4361
 */
4362
xmlXPathObjectPtr
4363
658k
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4364
658k
    xmlXPathObjectPtr ret;
4365
4366
658k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4367
658k
    if (ret == NULL) {
4368
6.22k
        xmlXPathErrMemory(NULL, "creating node set object\n");
4369
6.22k
        xmlXPathFreeNodeSet(val);
4370
6.22k
  return(NULL);
4371
6.22k
    }
4372
652k
    memset(ret, 0 , sizeof(xmlXPathObject));
4373
652k
    ret->type = XPATH_NODESET;
4374
652k
    ret->nodesetval = val;
4375
#ifdef XP_DEBUG_OBJ_USAGE
4376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4377
#endif
4378
652k
    return(ret);
4379
658k
}
4380
4381
/**
4382
 * xmlXPathFreeNodeSetList:
4383
 * @obj:  an existing NodeSetList object
4384
 *
4385
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4386
 * the list contrary to xmlXPathFreeObject().
4387
 */
4388
void
4389
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4390
0
    if (obj == NULL) return;
4391
#ifdef XP_DEBUG_OBJ_USAGE
4392
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4393
#endif
4394
0
    xmlFree(obj);
4395
0
}
4396
4397
/**
4398
 * xmlXPathDifference:
4399
 * @nodes1:  a node-set
4400
 * @nodes2:  a node-set
4401
 *
4402
 * Implements the EXSLT - Sets difference() function:
4403
 *    node-set set:difference (node-set, node-set)
4404
 *
4405
 * Returns the difference between the two node sets, or nodes1 if
4406
 *         nodes2 is empty
4407
 */
4408
xmlNodeSetPtr
4409
521
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4410
521
    xmlNodeSetPtr ret;
4411
521
    int i, l1;
4412
521
    xmlNodePtr cur;
4413
4414
521
    if (xmlXPathNodeSetIsEmpty(nodes2))
4415
259
  return(nodes1);
4416
4417
    /* TODO: Check memory error. */
4418
262
    ret = xmlXPathNodeSetCreate(NULL);
4419
262
    if (xmlXPathNodeSetIsEmpty(nodes1))
4420
67
  return(ret);
4421
4422
195
    l1 = xmlXPathNodeSetGetLength(nodes1);
4423
4424
7.86k
    for (i = 0; i < l1; i++) {
4425
7.67k
  cur = xmlXPathNodeSetItem(nodes1, i);
4426
7.67k
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4427
            /* TODO: Propagate memory error. */
4428
4.15k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4429
1
          break;
4430
4.15k
  }
4431
7.67k
    }
4432
195
    return(ret);
4433
262
}
4434
4435
/**
4436
 * xmlXPathIntersection:
4437
 * @nodes1:  a node-set
4438
 * @nodes2:  a node-set
4439
 *
4440
 * Implements the EXSLT - Sets intersection() function:
4441
 *    node-set set:intersection (node-set, node-set)
4442
 *
4443
 * Returns a node set comprising the nodes that are within both the
4444
 *         node sets passed as arguments
4445
 */
4446
xmlNodeSetPtr
4447
352
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4448
352
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4449
352
    int i, l1;
4450
352
    xmlNodePtr cur;
4451
4452
352
    if (ret == NULL)
4453
1
        return(ret);
4454
351
    if (xmlXPathNodeSetIsEmpty(nodes1))
4455
247
  return(ret);
4456
104
    if (xmlXPathNodeSetIsEmpty(nodes2))
4457
32
  return(ret);
4458
4459
72
    l1 = xmlXPathNodeSetGetLength(nodes1);
4460
4461
1.16k
    for (i = 0; i < l1; i++) {
4462
1.09k
  cur = xmlXPathNodeSetItem(nodes1, i);
4463
1.09k
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4464
            /* TODO: Propagate memory error. */
4465
414
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4466
0
          break;
4467
414
  }
4468
1.09k
    }
4469
72
    return(ret);
4470
104
}
4471
4472
/**
4473
 * xmlXPathDistinctSorted:
4474
 * @nodes:  a node-set, sorted by document order
4475
 *
4476
 * Implements the EXSLT - Sets distinct() function:
4477
 *    node-set set:distinct (node-set)
4478
 *
4479
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4480
 *         it is empty
4481
 */
4482
xmlNodeSetPtr
4483
438
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4484
438
    xmlNodeSetPtr ret;
4485
438
    xmlHashTablePtr hash;
4486
438
    int i, l;
4487
438
    xmlChar * strval;
4488
438
    xmlNodePtr cur;
4489
4490
438
    if (xmlXPathNodeSetIsEmpty(nodes))
4491
159
  return(nodes);
4492
4493
279
    ret = xmlXPathNodeSetCreate(NULL);
4494
279
    if (ret == NULL)
4495
1
        return(ret);
4496
278
    l = xmlXPathNodeSetGetLength(nodes);
4497
278
    hash = xmlHashCreate (l);
4498
9.57k
    for (i = 0; i < l; i++) {
4499
9.30k
  cur = xmlXPathNodeSetItem(nodes, i);
4500
9.30k
  strval = xmlXPathCastNodeToString(cur);
4501
9.30k
  if (xmlHashLookup(hash, strval) == NULL) {
4502
1.88k
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
4503
10
                xmlFree(strval);
4504
10
                goto error;
4505
10
            }
4506
1.87k
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4507
1
          goto error;
4508
7.42k
  } else {
4509
7.42k
      xmlFree(strval);
4510
7.42k
  }
4511
9.30k
    }
4512
267
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4513
267
    return(ret);
4514
4515
11
error:
4516
11
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4517
11
    xmlXPathFreeNodeSet(ret);
4518
11
    return(NULL);
4519
278
}
4520
4521
/**
4522
 * xmlXPathDistinct:
4523
 * @nodes:  a node-set
4524
 *
4525
 * Implements the EXSLT - Sets distinct() function:
4526
 *    node-set set:distinct (node-set)
4527
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4528
 * is called with the sorted node-set
4529
 *
4530
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4531
 *         it is empty
4532
 */
4533
xmlNodeSetPtr
4534
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4535
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
0
  return(nodes);
4537
4538
0
    xmlXPathNodeSetSort(nodes);
4539
0
    return(xmlXPathDistinctSorted(nodes));
4540
0
}
4541
4542
/**
4543
 * xmlXPathHasSameNodes:
4544
 * @nodes1:  a node-set
4545
 * @nodes2:  a node-set
4546
 *
4547
 * Implements the EXSLT - Sets has-same-nodes function:
4548
 *    boolean set:has-same-node(node-set, node-set)
4549
 *
4550
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4551
 *         otherwise
4552
 */
4553
int
4554
2.18k
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4555
2.18k
    int i, l;
4556
2.18k
    xmlNodePtr cur;
4557
4558
2.18k
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4559
2.18k
  xmlXPathNodeSetIsEmpty(nodes2))
4560
1.83k
  return(0);
4561
4562
352
    l = xmlXPathNodeSetGetLength(nodes1);
4563
1.88k
    for (i = 0; i < l; i++) {
4564
1.75k
  cur = xmlXPathNodeSetItem(nodes1, i);
4565
1.75k
  if (xmlXPathNodeSetContains(nodes2, cur))
4566
220
      return(1);
4567
1.75k
    }
4568
132
    return(0);
4569
352
}
4570
4571
/**
4572
 * xmlXPathNodeLeadingSorted:
4573
 * @nodes: a node-set, sorted by document order
4574
 * @node: a node
4575
 *
4576
 * Implements the EXSLT - Sets leading() function:
4577
 *    node-set set:leading (node-set, node-set)
4578
 *
4579
 * Returns the nodes in @nodes that precede @node in document order,
4580
 *         @nodes if @node is NULL or an empty node-set if @nodes
4581
 *         doesn't contain @node
4582
 */
4583
xmlNodeSetPtr
4584
296
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4585
296
    int i, l;
4586
296
    xmlNodePtr cur;
4587
296
    xmlNodeSetPtr ret;
4588
4589
296
    if (node == NULL)
4590
0
  return(nodes);
4591
4592
296
    ret = xmlXPathNodeSetCreate(NULL);
4593
296
    if (ret == NULL)
4594
1
        return(ret);
4595
295
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4596
295
  (!xmlXPathNodeSetContains(nodes, node)))
4597
178
  return(ret);
4598
4599
117
    l = xmlXPathNodeSetGetLength(nodes);
4600
622
    for (i = 0; i < l; i++) {
4601
622
  cur = xmlXPathNodeSetItem(nodes, i);
4602
622
  if (cur == node)
4603
116
      break;
4604
        /* TODO: Propagate memory error. */
4605
506
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4606
1
      break;
4607
506
    }
4608
117
    return(ret);
4609
295
}
4610
4611
/**
4612
 * xmlXPathNodeLeading:
4613
 * @nodes:  a node-set
4614
 * @node:  a node
4615
 *
4616
 * Implements the EXSLT - Sets leading() function:
4617
 *    node-set set:leading (node-set, node-set)
4618
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4619
 * is called.
4620
 *
4621
 * Returns the nodes in @nodes that precede @node in document order,
4622
 *         @nodes if @node is NULL or an empty node-set if @nodes
4623
 *         doesn't contain @node
4624
 */
4625
xmlNodeSetPtr
4626
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627
0
    xmlXPathNodeSetSort(nodes);
4628
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4629
0
}
4630
4631
/**
4632
 * xmlXPathLeadingSorted:
4633
 * @nodes1:  a node-set, sorted by document order
4634
 * @nodes2:  a node-set, sorted by document order
4635
 *
4636
 * Implements the EXSLT - Sets leading() function:
4637
 *    node-set set:leading (node-set, node-set)
4638
 *
4639
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4640
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4641
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4642
 */
4643
xmlNodeSetPtr
4644
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4646
0
  return(nodes1);
4647
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4648
0
             xmlXPathNodeSetItem(nodes2, 1)));
4649
0
}
4650
4651
/**
4652
 * xmlXPathLeading:
4653
 * @nodes1:  a node-set
4654
 * @nodes2:  a node-set
4655
 *
4656
 * Implements the EXSLT - Sets leading() function:
4657
 *    node-set set:leading (node-set, node-set)
4658
 * @nodes1 and @nodes2 are sorted by document order, then
4659
 * #exslSetsLeadingSorted is called.
4660
 *
4661
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4662
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4663
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4664
 */
4665
xmlNodeSetPtr
4666
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4668
0
  return(nodes1);
4669
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4670
0
  return(xmlXPathNodeSetCreate(NULL));
4671
0
    xmlXPathNodeSetSort(nodes1);
4672
0
    xmlXPathNodeSetSort(nodes2);
4673
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4674
0
             xmlXPathNodeSetItem(nodes2, 1)));
4675
0
}
4676
4677
/**
4678
 * xmlXPathNodeTrailingSorted:
4679
 * @nodes: a node-set, sorted by document order
4680
 * @node: a node
4681
 *
4682
 * Implements the EXSLT - Sets trailing() function:
4683
 *    node-set set:trailing (node-set, node-set)
4684
 *
4685
 * Returns the nodes in @nodes that follow @node in document order,
4686
 *         @nodes if @node is NULL or an empty node-set if @nodes
4687
 *         doesn't contain @node
4688
 */
4689
xmlNodeSetPtr
4690
271
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4691
271
    int i, l;
4692
271
    xmlNodePtr cur;
4693
271
    xmlNodeSetPtr ret;
4694
4695
271
    if (node == NULL)
4696
0
  return(nodes);
4697
4698
271
    ret = xmlXPathNodeSetCreate(NULL);
4699
271
    if (ret == NULL)
4700
1
        return(ret);
4701
270
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4702
270
  (!xmlXPathNodeSetContains(nodes, node)))
4703
166
  return(ret);
4704
4705
104
    l = xmlXPathNodeSetGetLength(nodes);
4706
1.81k
    for (i = l - 1; i >= 0; i--) {
4707
1.81k
  cur = xmlXPathNodeSetItem(nodes, i);
4708
1.81k
  if (cur == node)
4709
103
      break;
4710
        /* TODO: Propagate memory error. */
4711
1.71k
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4712
1
      break;
4713
1.71k
    }
4714
104
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4715
104
    return(ret);
4716
270
}
4717
4718
/**
4719
 * xmlXPathNodeTrailing:
4720
 * @nodes:  a node-set
4721
 * @node:  a node
4722
 *
4723
 * Implements the EXSLT - Sets trailing() function:
4724
 *    node-set set:trailing (node-set, node-set)
4725
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4726
 * is called.
4727
 *
4728
 * Returns the nodes in @nodes that follow @node in document order,
4729
 *         @nodes if @node is NULL or an empty node-set if @nodes
4730
 *         doesn't contain @node
4731
 */
4732
xmlNodeSetPtr
4733
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4734
0
    xmlXPathNodeSetSort(nodes);
4735
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4736
0
}
4737
4738
/**
4739
 * xmlXPathTrailingSorted:
4740
 * @nodes1:  a node-set, sorted by document order
4741
 * @nodes2:  a node-set, sorted by document order
4742
 *
4743
 * Implements the EXSLT - Sets trailing() function:
4744
 *    node-set set:trailing (node-set, node-set)
4745
 *
4746
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4747
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4748
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4749
 */
4750
xmlNodeSetPtr
4751
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4752
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4753
0
  return(nodes1);
4754
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4755
0
              xmlXPathNodeSetItem(nodes2, 0)));
4756
0
}
4757
4758
/**
4759
 * xmlXPathTrailing:
4760
 * @nodes1:  a node-set
4761
 * @nodes2:  a node-set
4762
 *
4763
 * Implements the EXSLT - Sets trailing() function:
4764
 *    node-set set:trailing (node-set, node-set)
4765
 * @nodes1 and @nodes2 are sorted by document order, then
4766
 * #xmlXPathTrailingSorted is called.
4767
 *
4768
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4769
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4770
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4771
 */
4772
xmlNodeSetPtr
4773
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4774
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4775
0
  return(nodes1);
4776
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4777
0
  return(xmlXPathNodeSetCreate(NULL));
4778
0
    xmlXPathNodeSetSort(nodes1);
4779
0
    xmlXPathNodeSetSort(nodes2);
4780
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4781
0
              xmlXPathNodeSetItem(nodes2, 0)));
4782
0
}
4783
4784
/************************************************************************
4785
 *                  *
4786
 *    Routines to handle extra functions      *
4787
 *                  *
4788
 ************************************************************************/
4789
4790
/**
4791
 * xmlXPathRegisterFunc:
4792
 * @ctxt:  the XPath context
4793
 * @name:  the function name
4794
 * @f:  the function implementation or NULL
4795
 *
4796
 * Register a new function. If @f is NULL it unregisters the function
4797
 *
4798
 * Returns 0 in case of success, -1 in case of error
4799
 */
4800
int
4801
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4802
1.00M
         xmlXPathFunction f) {
4803
1.00M
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4804
1.00M
}
4805
4806
/**
4807
 * xmlXPathRegisterFuncNS:
4808
 * @ctxt:  the XPath context
4809
 * @name:  the function name
4810
 * @ns_uri:  the function namespace URI
4811
 * @f:  the function implementation or NULL
4812
 *
4813
 * Register a new function. If @f is NULL it unregisters the function
4814
 *
4815
 * Returns 0 in case of success, -1 in case of error
4816
 */
4817
int
4818
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4819
1.04M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4820
1.04M
    if (ctxt == NULL)
4821
0
  return(-1);
4822
1.04M
    if (name == NULL)
4823
0
  return(-1);
4824
4825
1.04M
    if (ctxt->funcHash == NULL)
4826
56
  ctxt->funcHash = xmlHashCreate(0);
4827
1.04M
    if (ctxt->funcHash == NULL)
4828
56
  return(-1);
4829
1.04M
    if (f == NULL)
4830
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4831
1.04M
XML_IGNORE_FPTR_CAST_WARNINGS
4832
1.04M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4833
1.04M
XML_POP_WARNINGS
4834
1.04M
}
4835
4836
/**
4837
 * xmlXPathRegisterFuncLookup:
4838
 * @ctxt:  the XPath context
4839
 * @f:  the lookup function
4840
 * @funcCtxt:  the lookup data
4841
 *
4842
 * Registers an external mechanism to do function lookup.
4843
 */
4844
void
4845
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4846
          xmlXPathFuncLookupFunc f,
4847
12.3k
          void *funcCtxt) {
4848
12.3k
    if (ctxt == NULL)
4849
0
  return;
4850
12.3k
    ctxt->funcLookupFunc = f;
4851
12.3k
    ctxt->funcLookupData = funcCtxt;
4852
12.3k
}
4853
4854
/**
4855
 * xmlXPathFunctionLookup:
4856
 * @ctxt:  the XPath context
4857
 * @name:  the function name
4858
 *
4859
 * Search in the Function array of the context for the given
4860
 * function.
4861
 *
4862
 * Returns the xmlXPathFunction or NULL if not found
4863
 */
4864
xmlXPathFunction
4865
33.3k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4866
33.3k
    if (ctxt == NULL)
4867
0
  return (NULL);
4868
4869
33.3k
    if (ctxt->funcLookupFunc != NULL) {
4870
33.3k
  xmlXPathFunction ret;
4871
33.3k
  xmlXPathFuncLookupFunc f;
4872
4873
33.3k
  f = ctxt->funcLookupFunc;
4874
33.3k
  ret = f(ctxt->funcLookupData, name, NULL);
4875
33.3k
  if (ret != NULL)
4876
0
      return(ret);
4877
33.3k
    }
4878
33.3k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4879
33.3k
}
4880
4881
/**
4882
 * xmlXPathFunctionLookupNS:
4883
 * @ctxt:  the XPath context
4884
 * @name:  the function name
4885
 * @ns_uri:  the function namespace URI
4886
 *
4887
 * Search in the Function array of the context for the given
4888
 * function.
4889
 *
4890
 * Returns the xmlXPathFunction or NULL if not found
4891
 */
4892
xmlXPathFunction
4893
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4894
486k
       const xmlChar *ns_uri) {
4895
486k
    xmlXPathFunction ret;
4896
4897
486k
    if (ctxt == NULL)
4898
0
  return(NULL);
4899
486k
    if (name == NULL)
4900
1
  return(NULL);
4901
4902
486k
    if (ctxt->funcLookupFunc != NULL) {
4903
486k
  xmlXPathFuncLookupFunc f;
4904
4905
486k
  f = ctxt->funcLookupFunc;
4906
486k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4907
486k
  if (ret != NULL)
4908
445k
      return(ret);
4909
486k
    }
4910
4911
40.8k
    if (ctxt->funcHash == NULL)
4912
0
  return(NULL);
4913
4914
40.8k
XML_IGNORE_FPTR_CAST_WARNINGS
4915
40.8k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4916
40.8k
XML_POP_WARNINGS
4917
40.8k
    return(ret);
4918
40.8k
}
4919
4920
/**
4921
 * xmlXPathRegisteredFuncsCleanup:
4922
 * @ctxt:  the XPath context
4923
 *
4924
 * Cleanup the XPath context data associated to registered functions
4925
 */
4926
void
4927
33.2k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4928
33.2k
    if (ctxt == NULL)
4929
0
  return;
4930
4931
33.2k
    xmlHashFree(ctxt->funcHash, NULL);
4932
33.2k
    ctxt->funcHash = NULL;
4933
33.2k
}
4934
4935
/************************************************************************
4936
 *                  *
4937
 *      Routines to handle Variables      *
4938
 *                  *
4939
 ************************************************************************/
4940
4941
/**
4942
 * xmlXPathRegisterVariable:
4943
 * @ctxt:  the XPath context
4944
 * @name:  the variable name
4945
 * @value:  the variable value or NULL
4946
 *
4947
 * Register a new variable value. If @value is NULL it unregisters
4948
 * the variable
4949
 *
4950
 * Returns 0 in case of success, -1 in case of error
4951
 */
4952
int
4953
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4954
608
       xmlXPathObjectPtr value) {
4955
608
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4956
608
}
4957
4958
/**
4959
 * xmlXPathRegisterVariableNS:
4960
 * @ctxt:  the XPath context
4961
 * @name:  the variable name
4962
 * @ns_uri:  the variable namespace URI
4963
 * @value:  the variable value or NULL
4964
 *
4965
 * Register a new variable value. If @value is NULL it unregisters
4966
 * the variable
4967
 *
4968
 * Returns 0 in case of success, -1 in case of error
4969
 */
4970
int
4971
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4972
         const xmlChar *ns_uri,
4973
608
         xmlXPathObjectPtr value) {
4974
608
    if (ctxt == NULL)
4975
0
  return(-1);
4976
608
    if (name == NULL)
4977
0
  return(-1);
4978
4979
608
    if (ctxt->varHash == NULL)
4980
152
  ctxt->varHash = xmlHashCreate(0);
4981
608
    if (ctxt->varHash == NULL)
4982
0
  return(-1);
4983
608
    if (value == NULL)
4984
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4985
0
                             xmlXPathFreeObjectEntry));
4986
608
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4987
608
             (void *) value, xmlXPathFreeObjectEntry));
4988
608
}
4989
4990
/**
4991
 * xmlXPathRegisterVariableLookup:
4992
 * @ctxt:  the XPath context
4993
 * @f:  the lookup function
4994
 * @data:  the lookup data
4995
 *
4996
 * register an external mechanism to do variable lookup
4997
 */
4998
void
4999
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5000
12.3k
   xmlXPathVariableLookupFunc f, void *data) {
5001
12.3k
    if (ctxt == NULL)
5002
0
  return;
5003
12.3k
    ctxt->varLookupFunc = f;
5004
12.3k
    ctxt->varLookupData = data;
5005
12.3k
}
5006
5007
/**
5008
 * xmlXPathVariableLookup:
5009
 * @ctxt:  the XPath context
5010
 * @name:  the variable name
5011
 *
5012
 * Search in the Variable array of the context for the given
5013
 * variable value.
5014
 *
5015
 * Returns a copy of the value or NULL if not found
5016
 */
5017
xmlXPathObjectPtr
5018
99.0k
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5019
99.0k
    if (ctxt == NULL)
5020
0
  return(NULL);
5021
5022
99.0k
    if (ctxt->varLookupFunc != NULL) {
5023
99.0k
  xmlXPathObjectPtr ret;
5024
5025
99.0k
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5026
99.0k
          (ctxt->varLookupData, name, NULL);
5027
99.0k
  return(ret);
5028
99.0k
    }
5029
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5030
99.0k
}
5031
5032
/**
5033
 * xmlXPathVariableLookupNS:
5034
 * @ctxt:  the XPath context
5035
 * @name:  the variable name
5036
 * @ns_uri:  the variable namespace URI
5037
 *
5038
 * Search in the Variable array of the context for the given
5039
 * variable value.
5040
 *
5041
 * Returns the a copy of the value or NULL if not found
5042
 */
5043
xmlXPathObjectPtr
5044
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5045
138
       const xmlChar *ns_uri) {
5046
138
    if (ctxt == NULL)
5047
0
  return(NULL);
5048
5049
138
    if (ctxt->varLookupFunc != NULL) {
5050
138
  xmlXPathObjectPtr ret;
5051
5052
138
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5053
138
          (ctxt->varLookupData, name, ns_uri);
5054
138
  if (ret != NULL) return(ret);
5055
138
    }
5056
5057
138
    if (ctxt->varHash == NULL)
5058
138
  return(NULL);
5059
0
    if (name == NULL)
5060
0
  return(NULL);
5061
5062
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5063
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5064
0
}
5065
5066
/**
5067
 * xmlXPathRegisteredVariablesCleanup:
5068
 * @ctxt:  the XPath context
5069
 *
5070
 * Cleanup the XPath context data associated to registered variables
5071
 */
5072
void
5073
33.2k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5074
33.2k
    if (ctxt == NULL)
5075
0
  return;
5076
5077
33.2k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5078
33.2k
    ctxt->varHash = NULL;
5079
33.2k
}
5080
5081
/**
5082
 * xmlXPathRegisterNs:
5083
 * @ctxt:  the XPath context
5084
 * @prefix:  the namespace prefix cannot be NULL or empty string
5085
 * @ns_uri:  the namespace name
5086
 *
5087
 * Register a new namespace. If @ns_uri is NULL it unregisters
5088
 * the namespace
5089
 *
5090
 * Returns 0 in case of success, -1 in case of error
5091
 */
5092
int
5093
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5094
1.67k
         const xmlChar *ns_uri) {
5095
1.67k
    xmlChar *copy;
5096
5097
1.67k
    if (ctxt == NULL)
5098
0
  return(-1);
5099
1.67k
    if (prefix == NULL)
5100
0
  return(-1);
5101
1.67k
    if (prefix[0] == 0)
5102
0
  return(-1);
5103
5104
1.67k
    if (ctxt->nsHash == NULL)
5105
152
  ctxt->nsHash = xmlHashCreate(10);
5106
1.67k
    if (ctxt->nsHash == NULL)
5107
0
  return(-1);
5108
1.67k
    if (ns_uri == NULL)
5109
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5110
0
                            xmlHashDefaultDeallocator));
5111
5112
1.67k
    copy = xmlStrdup(ns_uri);
5113
1.67k
    if (copy == NULL)
5114
0
        return(-1);
5115
1.67k
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
5116
1.67k
                           xmlHashDefaultDeallocator) < 0) {
5117
0
        xmlFree(copy);
5118
0
        return(-1);
5119
0
    }
5120
5121
1.67k
    return(0);
5122
1.67k
}
5123
5124
/**
5125
 * xmlXPathNsLookup:
5126
 * @ctxt:  the XPath context
5127
 * @prefix:  the namespace prefix value
5128
 *
5129
 * Search in the namespace declaration array of the context for the given
5130
 * namespace name associated to the given prefix
5131
 *
5132
 * Returns the value or NULL if not found
5133
 */
5134
const xmlChar *
5135
525k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136
525k
    if (ctxt == NULL)
5137
0
  return(NULL);
5138
525k
    if (prefix == NULL)
5139
0
  return(NULL);
5140
5141
525k
#ifdef XML_XML_NAMESPACE
5142
525k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143
5.02k
  return(XML_XML_NAMESPACE);
5144
520k
#endif
5145
5146
520k
    if (ctxt->namespaces != NULL) {
5147
513k
  int i;
5148
5149
1.84M
  for (i = 0;i < ctxt->nsNr;i++) {
5150
1.81M
      if ((ctxt->namespaces[i] != NULL) &&
5151
1.81M
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5152
482k
    return(ctxt->namespaces[i]->href);
5153
1.81M
  }
5154
513k
    }
5155
5156
37.8k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157
520k
}
5158
5159
/**
5160
 * xmlXPathRegisteredNsCleanup:
5161
 * @ctxt:  the XPath context
5162
 *
5163
 * Cleanup the XPath context data associated to registered variables
5164
 */
5165
void
5166
33.4k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167
33.4k
    if (ctxt == NULL)
5168
8
  return;
5169
5170
33.4k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5171
33.4k
    ctxt->nsHash = NULL;
5172
33.4k
}
5173
5174
/************************************************************************
5175
 *                  *
5176
 *      Routines to handle Values     *
5177
 *                  *
5178
 ************************************************************************/
5179
5180
/* Allocations are terrible, one needs to optimize all this !!! */
5181
5182
/**
5183
 * xmlXPathNewFloat:
5184
 * @val:  the double value
5185
 *
5186
 * Create a new xmlXPathObjectPtr of type double and of value @val
5187
 *
5188
 * Returns the newly created object.
5189
 */
5190
xmlXPathObjectPtr
5191
568k
xmlXPathNewFloat(double val) {
5192
568k
    xmlXPathObjectPtr ret;
5193
5194
568k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195
568k
    if (ret == NULL) {
5196
4.03k
        xmlXPathErrMemory(NULL, "creating float object\n");
5197
4.03k
  return(NULL);
5198
4.03k
    }
5199
564k
    memset(ret, 0 , sizeof(xmlXPathObject));
5200
564k
    ret->type = XPATH_NUMBER;
5201
564k
    ret->floatval = val;
5202
#ifdef XP_DEBUG_OBJ_USAGE
5203
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204
#endif
5205
564k
    return(ret);
5206
568k
}
5207
5208
/**
5209
 * xmlXPathNewBoolean:
5210
 * @val:  the boolean value
5211
 *
5212
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5213
 *
5214
 * Returns the newly created object.
5215
 */
5216
xmlXPathObjectPtr
5217
62.3k
xmlXPathNewBoolean(int val) {
5218
62.3k
    xmlXPathObjectPtr ret;
5219
5220
62.3k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221
62.3k
    if (ret == NULL) {
5222
1.39k
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5223
1.39k
  return(NULL);
5224
1.39k
    }
5225
60.9k
    memset(ret, 0 , sizeof(xmlXPathObject));
5226
60.9k
    ret->type = XPATH_BOOLEAN;
5227
60.9k
    ret->boolval = (val != 0);
5228
#ifdef XP_DEBUG_OBJ_USAGE
5229
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230
#endif
5231
60.9k
    return(ret);
5232
62.3k
}
5233
5234
/**
5235
 * xmlXPathNewString:
5236
 * @val:  the xmlChar * value
5237
 *
5238
 * Create a new xmlXPathObjectPtr of type string and of value @val
5239
 *
5240
 * Returns the newly created object.
5241
 */
5242
xmlXPathObjectPtr
5243
188k
xmlXPathNewString(const xmlChar *val) {
5244
188k
    xmlXPathObjectPtr ret;
5245
5246
188k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247
188k
    if (ret == NULL) {
5248
3.67k
        xmlXPathErrMemory(NULL, "creating string object\n");
5249
3.67k
  return(NULL);
5250
3.67k
    }
5251
184k
    memset(ret, 0 , sizeof(xmlXPathObject));
5252
184k
    ret->type = XPATH_STRING;
5253
184k
    if (val == NULL)
5254
177
        val = BAD_CAST "";
5255
184k
    ret->stringval = xmlStrdup(val);
5256
184k
    if (ret->stringval == NULL) {
5257
44
        xmlFree(ret);
5258
44
        return(NULL);
5259
44
    }
5260
#ifdef XP_DEBUG_OBJ_USAGE
5261
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5262
#endif
5263
184k
    return(ret);
5264
184k
}
5265
5266
/**
5267
 * xmlXPathWrapString:
5268
 * @val:  the xmlChar * value
5269
 *
5270
 * Wraps the @val string into an XPath object.
5271
 *
5272
 * Returns the newly created object.
5273
 *
5274
 * Frees @val in case of error.
5275
 */
5276
xmlXPathObjectPtr
5277
1.40M
xmlXPathWrapString (xmlChar *val) {
5278
1.40M
    xmlXPathObjectPtr ret;
5279
5280
1.40M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281
1.40M
    if (ret == NULL) {
5282
58
        xmlXPathErrMemory(NULL, "creating string object\n");
5283
58
        xmlFree(val);
5284
58
  return(NULL);
5285
58
    }
5286
1.40M
    memset(ret, 0 , sizeof(xmlXPathObject));
5287
1.40M
    ret->type = XPATH_STRING;
5288
1.40M
    ret->stringval = val;
5289
#ifdef XP_DEBUG_OBJ_USAGE
5290
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5291
#endif
5292
1.40M
    return(ret);
5293
1.40M
}
5294
5295
/**
5296
 * xmlXPathNewCString:
5297
 * @val:  the char * value
5298
 *
5299
 * Create a new xmlXPathObjectPtr of type string and of value @val
5300
 *
5301
 * Returns the newly created object.
5302
 */
5303
xmlXPathObjectPtr
5304
54.0k
xmlXPathNewCString(const char *val) {
5305
54.0k
    return(xmlXPathNewString(BAD_CAST val));
5306
54.0k
}
5307
5308
/**
5309
 * xmlXPathWrapCString:
5310
 * @val:  the char * value
5311
 *
5312
 * Wraps a string into an XPath object.
5313
 *
5314
 * Returns the newly created object.
5315
 */
5316
xmlXPathObjectPtr
5317
0
xmlXPathWrapCString (char * val) {
5318
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5319
0
}
5320
5321
/**
5322
 * xmlXPathWrapExternal:
5323
 * @val:  the user data
5324
 *
5325
 * Wraps the @val data into an XPath object.
5326
 *
5327
 * Returns the newly created object.
5328
 */
5329
xmlXPathObjectPtr
5330
41.0k
xmlXPathWrapExternal (void *val) {
5331
41.0k
    xmlXPathObjectPtr ret;
5332
5333
41.0k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5334
41.0k
    if (ret == NULL) {
5335
4
        xmlXPathErrMemory(NULL, "creating user object\n");
5336
4
  return(NULL);
5337
4
    }
5338
41.0k
    memset(ret, 0 , sizeof(xmlXPathObject));
5339
41.0k
    ret->type = XPATH_USERS;
5340
41.0k
    ret->user = val;
5341
#ifdef XP_DEBUG_OBJ_USAGE
5342
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5343
#endif
5344
41.0k
    return(ret);
5345
41.0k
}
5346
5347
/**
5348
 * xmlXPathObjectCopy:
5349
 * @val:  the original object
5350
 *
5351
 * allocate a new copy of a given object
5352
 *
5353
 * Returns the newly created object.
5354
 */
5355
xmlXPathObjectPtr
5356
110k
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5357
110k
    xmlXPathObjectPtr ret;
5358
5359
110k
    if (val == NULL)
5360
1
  return(NULL);
5361
5362
110k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5363
110k
    if (ret == NULL) {
5364
426
        xmlXPathErrMemory(NULL, "copying object\n");
5365
426
  return(NULL);
5366
426
    }
5367
109k
    memcpy(ret, val , sizeof(xmlXPathObject));
5368
#ifdef XP_DEBUG_OBJ_USAGE
5369
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5370
#endif
5371
109k
    switch (val->type) {
5372
41
  case XPATH_BOOLEAN:
5373
1.60k
  case XPATH_NUMBER:
5374
#ifdef LIBXML_XPTR_LOCS_ENABLED
5375
  case XPATH_POINT:
5376
  case XPATH_RANGE:
5377
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5378
1.60k
      break;
5379
42.6k
  case XPATH_STRING:
5380
42.6k
      ret->stringval = xmlStrdup(val->stringval);
5381
42.6k
            if (ret->stringval == NULL) {
5382
18
                xmlFree(ret);
5383
18
                return(NULL);
5384
18
            }
5385
42.6k
      break;
5386
46.3k
  case XPATH_XSLT_TREE:
5387
#if 0
5388
/*
5389
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5390
  this previous handling is no longer correct, and can cause some serious
5391
  problems (ref. bug 145547)
5392
*/
5393
      if ((val->nodesetval != NULL) &&
5394
    (val->nodesetval->nodeTab != NULL)) {
5395
    xmlNodePtr cur, tmp;
5396
    xmlDocPtr top;
5397
5398
    ret->boolval = 1;
5399
    top =  xmlNewDoc(NULL);
5400
    top->name = (char *)
5401
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5402
    ret->user = top;
5403
    if (top != NULL) {
5404
        top->doc = top;
5405
        cur = val->nodesetval->nodeTab[0]->children;
5406
        while (cur != NULL) {
5407
      tmp = xmlDocCopyNode(cur, top, 1);
5408
      xmlAddChild((xmlNodePtr) top, tmp);
5409
      cur = cur->next;
5410
        }
5411
    }
5412
5413
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5414
      } else
5415
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5416
      /* Deallocate the copied tree value */
5417
      break;
5418
#endif
5419
65.3k
  case XPATH_NODESET:
5420
            /* TODO: Check memory error. */
5421
65.3k
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5422
      /* Do not deallocate the copied tree value */
5423
65.3k
      ret->boolval = 0;
5424
65.3k
      break;
5425
#ifdef LIBXML_XPTR_LOCS_ENABLED
5426
  case XPATH_LOCATIONSET:
5427
  {
5428
      xmlLocationSetPtr loc = val->user;
5429
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5430
      break;
5431
  }
5432
#endif
5433
0
        case XPATH_USERS:
5434
0
      ret->user = val->user;
5435
0
      break;
5436
0
        case XPATH_UNDEFINED:
5437
0
      xmlGenericError(xmlGenericErrorContext,
5438
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5439
0
        val->type);
5440
0
      break;
5441
109k
    }
5442
109k
    return(ret);
5443
109k
}
5444
5445
/**
5446
 * xmlXPathFreeObject:
5447
 * @obj:  the object to free
5448
 *
5449
 * Free up an xmlXPathObjectPtr object.
5450
 */
5451
void
5452
4.68M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453
4.68M
    if (obj == NULL) return;
5454
4.59M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5455
2.10M
  if (obj->boolval) {
5456
#if 0
5457
      if (obj->user != NULL) {
5458
                xmlXPathFreeNodeSet(obj->nodesetval);
5459
    xmlFreeNodeList((xmlNodePtr) obj->user);
5460
      } else
5461
#endif
5462
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5463
0
      if (obj->nodesetval != NULL)
5464
0
    xmlXPathFreeValueTree(obj->nodesetval);
5465
2.10M
  } else {
5466
2.10M
      if (obj->nodesetval != NULL)
5467
1.85M
    xmlXPathFreeNodeSet(obj->nodesetval);
5468
2.10M
  }
5469
#ifdef LIBXML_XPTR_LOCS_ENABLED
5470
    } else if (obj->type == XPATH_LOCATIONSET) {
5471
  if (obj->user != NULL)
5472
      xmlXPtrFreeLocationSet(obj->user);
5473
#endif
5474
2.49M
    } else if (obj->type == XPATH_STRING) {
5475
1.66M
  if (obj->stringval != NULL)
5476
1.63M
      xmlFree(obj->stringval);
5477
1.66M
    }
5478
#ifdef XP_DEBUG_OBJ_USAGE
5479
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480
#endif
5481
4.59M
    xmlFree(obj);
5482
4.59M
}
5483
5484
static void
5485
608
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5486
608
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5487
608
}
5488
5489
/**
5490
 * xmlXPathReleaseObject:
5491
 * @obj:  the xmlXPathObjectPtr to free or to cache
5492
 *
5493
 * Depending on the state of the cache this frees the given
5494
 * XPath object or stores it in the cache.
5495
 */
5496
static void
5497
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5498
9.02M
{
5499
9.02M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500
26.7k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501
8.88M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5502
5503
10.2M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5504
5505
9.02M
    if (obj == NULL)
5506
28.1k
  return;
5507
9.00M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5508
1
   xmlXPathFreeObject(obj);
5509
9.00M
    } else {
5510
9.00M
  xmlXPathContextCachePtr cache =
5511
9.00M
      (xmlXPathContextCachePtr) ctxt->cache;
5512
5513
9.00M
  switch (obj->type) {
5514
5.34M
      case XPATH_NODESET:
5515
5.37M
      case XPATH_XSLT_TREE:
5516
5.37M
    if (obj->nodesetval != NULL) {
5517
4.63M
        if (obj->boolval) {
5518
      /*
5519
      * It looks like the @boolval is used for
5520
      * evaluation if this an XSLT Result Tree Fragment.
5521
      * TODO: Check if this assumption is correct.
5522
      */
5523
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5524
0
      xmlXPathFreeValueTree(obj->nodesetval);
5525
0
      obj->nodesetval = NULL;
5526
4.63M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5527
4.63M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5528
4.61M
          cache->maxNodeset)))
5529
3.36M
        {
5530
3.36M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5531
3.35M
      goto obj_cached;
5532
3.36M
        } else {
5533
1.26M
      xmlXPathFreeNodeSet(obj->nodesetval);
5534
1.26M
      obj->nodesetval = NULL;
5535
1.26M
        }
5536
4.63M
    }
5537
2.00M
    break;
5538
2.00M
      case XPATH_STRING:
5539
831k
    if (obj->stringval != NULL)
5540
831k
        xmlFree(obj->stringval);
5541
5542
831k
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5543
806k
        XP_CACHE_ADD(cache->stringObjs, obj);
5544
805k
        goto obj_cached;
5545
806k
    }
5546
24.9k
    break;
5547
1.09M
      case XPATH_BOOLEAN:
5548
1.09M
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5549
1.09M
        XP_CACHE_ADD(cache->booleanObjs, obj);
5550
1.09M
        goto obj_cached;
5551
1.09M
    }
5552
762
    break;
5553
1.66M
      case XPATH_NUMBER:
5554
1.66M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5555
1.65M
        XP_CACHE_ADD(cache->numberObjs, obj);
5556
1.65M
        goto obj_cached;
5557
1.65M
    }
5558
4.62k
    break;
5559
#ifdef LIBXML_XPTR_LOCS_ENABLED
5560
      case XPATH_LOCATIONSET:
5561
    if (obj->user != NULL) {
5562
        xmlXPtrFreeLocationSet(obj->user);
5563
    }
5564
    goto free_obj;
5565
#endif
5566
41.0k
      default:
5567
41.0k
    goto free_obj;
5568
9.00M
  }
5569
5570
  /*
5571
  * Fallback to adding to the misc-objects slot.
5572
  */
5573
2.03M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5574
1.96M
      XP_CACHE_ADD(cache->miscObjs, obj);
5575
1.96M
  } else
5576
70.0k
      goto free_obj;
5577
5578
8.87M
obj_cached:
5579
5580
#ifdef XP_DEBUG_OBJ_USAGE
5581
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5582
#endif
5583
5584
8.87M
  if (obj->nodesetval != NULL) {
5585
3.35M
      xmlNodeSetPtr tmpset = obj->nodesetval;
5586
5587
      /*
5588
      * TODO: Due to those nasty ns-nodes, we need to traverse
5589
      *  the list and free the ns-nodes.
5590
      * URGENT TODO: Check if it's actually slowing things down.
5591
      *  Maybe we shouldn't try to preserve the list.
5592
      */
5593
3.35M
      if (tmpset->nodeNr > 1) {
5594
108k
    int i;
5595
108k
    xmlNodePtr node;
5596
5597
991k
    for (i = 0; i < tmpset->nodeNr; i++) {
5598
883k
        node = tmpset->nodeTab[i];
5599
883k
        if ((node != NULL) &&
5600
883k
      (node->type == XML_NAMESPACE_DECL))
5601
116k
        {
5602
116k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5603
116k
        }
5604
883k
    }
5605
3.24M
      } else if (tmpset->nodeNr == 1) {
5606
2.61M
    if ((tmpset->nodeTab[0] != NULL) &&
5607
2.61M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5608
26.1k
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5609
2.61M
      }
5610
3.35M
      tmpset->nodeNr = 0;
5611
3.35M
      memset(obj, 0, sizeof(xmlXPathObject));
5612
3.35M
      obj->nodesetval = tmpset;
5613
3.35M
  } else
5614
5.51M
      memset(obj, 0, sizeof(xmlXPathObject));
5615
5616
8.87M
  return;
5617
5618
129k
free_obj:
5619
  /*
5620
  * Cache is full; free the object.
5621
  */
5622
129k
  if (obj->nodesetval != NULL)
5623
8.87k
      xmlXPathFreeNodeSet(obj->nodesetval);
5624
#ifdef XP_DEBUG_OBJ_USAGE
5625
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5626
#endif
5627
129k
  xmlFree(obj);
5628
129k
    }
5629
129k
    return;
5630
9.00M
}
5631
5632
5633
/************************************************************************
5634
 *                  *
5635
 *      Type Casting Routines       *
5636
 *                  *
5637
 ************************************************************************/
5638
5639
/**
5640
 * xmlXPathCastBooleanToString:
5641
 * @val:  a boolean
5642
 *
5643
 * Converts a boolean to its string value.
5644
 *
5645
 * Returns a newly allocated string.
5646
 */
5647
xmlChar *
5648
240k
xmlXPathCastBooleanToString (int val) {
5649
240k
    xmlChar *ret;
5650
240k
    if (val)
5651
14.2k
  ret = xmlStrdup((const xmlChar *) "true");
5652
225k
    else
5653
225k
  ret = xmlStrdup((const xmlChar *) "false");
5654
240k
    return(ret);
5655
240k
}
5656
5657
/**
5658
 * xmlXPathCastNumberToString:
5659
 * @val:  a number
5660
 *
5661
 * Converts a number to its string value.
5662
 *
5663
 * Returns a newly allocated string.
5664
 */
5665
xmlChar *
5666
430k
xmlXPathCastNumberToString (double val) {
5667
430k
    xmlChar *ret;
5668
430k
    switch (xmlXPathIsInf(val)) {
5669
548
    case 1:
5670
548
  ret = xmlStrdup((const xmlChar *) "Infinity");
5671
548
  break;
5672
333
    case -1:
5673
333
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5674
333
  break;
5675
429k
    default:
5676
429k
  if (xmlXPathIsNaN(val)) {
5677
283k
      ret = xmlStrdup((const xmlChar *) "NaN");
5678
283k
  } else if (val == 0) {
5679
            /* Omit sign for negative zero. */
5680
4.29k
      ret = xmlStrdup((const xmlChar *) "0");
5681
141k
  } else {
5682
      /* could be improved */
5683
141k
      char buf[100];
5684
141k
      xmlXPathFormatNumber(val, buf, 99);
5685
141k
      buf[99] = 0;
5686
141k
      ret = xmlStrdup((const xmlChar *) buf);
5687
141k
  }
5688
430k
    }
5689
430k
    return(ret);
5690
430k
}
5691
5692
/**
5693
 * xmlXPathCastNodeToString:
5694
 * @node:  a node
5695
 *
5696
 * Converts a node to its string value.
5697
 *
5698
 * Returns a newly allocated string.
5699
 */
5700
xmlChar *
5701
2.49M
xmlXPathCastNodeToString (xmlNodePtr node) {
5702
2.49M
xmlChar *ret;
5703
2.49M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5704
10.0k
  ret = xmlStrdup((const xmlChar *) "");
5705
2.49M
    return(ret);
5706
2.49M
}
5707
5708
/**
5709
 * xmlXPathCastNodeSetToString:
5710
 * @ns:  a node-set
5711
 *
5712
 * Converts a node-set to its string value.
5713
 *
5714
 * Returns a newly allocated string.
5715
 */
5716
xmlChar *
5717
2.90M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5718
2.90M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5719
770k
  return(xmlStrdup((const xmlChar *) ""));
5720
5721
2.13M
    if (ns->nodeNr > 1)
5722
68.2k
  xmlXPathNodeSetSort(ns);
5723
2.13M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5724
2.90M
}
5725
5726
/**
5727
 * xmlXPathCastToString:
5728
 * @val:  an XPath object
5729
 *
5730
 * Converts an existing object to its string() equivalent
5731
 *
5732
 * Returns the allocated string value of the object, NULL in case of error.
5733
 *         It's up to the caller to free the string memory with xmlFree().
5734
 */
5735
xmlChar *
5736
1.98M
xmlXPathCastToString(xmlXPathObjectPtr val) {
5737
1.98M
    xmlChar *ret = NULL;
5738
5739
1.98M
    if (val == NULL)
5740
0
  return(xmlStrdup((const xmlChar *) ""));
5741
1.98M
    switch (val->type) {
5742
0
  case XPATH_UNDEFINED:
5743
#ifdef DEBUG_EXPR
5744
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5745
#endif
5746
0
      ret = xmlStrdup((const xmlChar *) "");
5747
0
      break;
5748
1.28M
        case XPATH_NODESET:
5749
1.28M
        case XPATH_XSLT_TREE:
5750
1.28M
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5751
1.28M
      break;
5752
209k
  case XPATH_STRING:
5753
209k
      return(xmlStrdup(val->stringval));
5754
153k
        case XPATH_BOOLEAN:
5755
153k
      ret = xmlXPathCastBooleanToString(val->boolval);
5756
153k
      break;
5757
332k
  case XPATH_NUMBER: {
5758
332k
      ret = xmlXPathCastNumberToString(val->floatval);
5759
332k
      break;
5760
1.28M
  }
5761
0
  case XPATH_USERS:
5762
#ifdef LIBXML_XPTR_LOCS_ENABLED
5763
  case XPATH_POINT:
5764
  case XPATH_RANGE:
5765
  case XPATH_LOCATIONSET:
5766
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5767
0
      TODO
5768
0
      ret = xmlStrdup((const xmlChar *) "");
5769
0
      break;
5770
1.98M
    }
5771
1.77M
    return(ret);
5772
1.98M
}
5773
5774
/**
5775
 * xmlXPathConvertString:
5776
 * @val:  an XPath object
5777
 *
5778
 * Converts an existing object to its string() equivalent
5779
 *
5780
 * Returns the new object, the old one is freed (or the operation
5781
 *         is done directly on @val)
5782
 */
5783
xmlXPathObjectPtr
5784
1.21M
xmlXPathConvertString(xmlXPathObjectPtr val) {
5785
1.21M
    xmlChar *res = NULL;
5786
5787
1.21M
    if (val == NULL)
5788
0
  return(xmlXPathNewCString(""));
5789
5790
1.21M
    switch (val->type) {
5791
0
    case XPATH_UNDEFINED:
5792
#ifdef DEBUG_EXPR
5793
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5794
#endif
5795
0
  break;
5796
1.21M
    case XPATH_NODESET:
5797
1.21M
    case XPATH_XSLT_TREE:
5798
1.21M
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5799
1.21M
  break;
5800
0
    case XPATH_STRING:
5801
0
  return(val);
5802
671
    case XPATH_BOOLEAN:
5803
671
  res = xmlXPathCastBooleanToString(val->boolval);
5804
671
  break;
5805
1.89k
    case XPATH_NUMBER:
5806
1.89k
  res = xmlXPathCastNumberToString(val->floatval);
5807
1.89k
  break;
5808
0
    case XPATH_USERS:
5809
#ifdef LIBXML_XPTR_LOCS_ENABLED
5810
    case XPATH_POINT:
5811
    case XPATH_RANGE:
5812
    case XPATH_LOCATIONSET:
5813
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5814
0
  TODO;
5815
0
  break;
5816
1.21M
    }
5817
1.21M
    xmlXPathFreeObject(val);
5818
1.21M
    if (res == NULL)
5819
76
  return(xmlXPathNewCString(""));
5820
1.21M
    return(xmlXPathWrapString(res));
5821
1.21M
}
5822
5823
/**
5824
 * xmlXPathCastBooleanToNumber:
5825
 * @val:  a boolean
5826
 *
5827
 * Converts a boolean to its number value
5828
 *
5829
 * Returns the number value
5830
 */
5831
double
5832
315k
xmlXPathCastBooleanToNumber(int val) {
5833
315k
    if (val)
5834
25.7k
  return(1.0);
5835
289k
    return(0.0);
5836
315k
}
5837
5838
/**
5839
 * xmlXPathCastStringToNumber:
5840
 * @val:  a string
5841
 *
5842
 * Converts a string to its number value
5843
 *
5844
 * Returns the number value
5845
 */
5846
double
5847
728k
xmlXPathCastStringToNumber(const xmlChar * val) {
5848
728k
    return(xmlXPathStringEvalNumber(val));
5849
728k
}
5850
5851
/**
5852
 * xmlXPathCastNodeToNumber:
5853
 * @node:  a node
5854
 *
5855
 * Converts a node to its number value
5856
 *
5857
 * Returns the number value
5858
 */
5859
double
5860
38.1k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861
38.1k
    xmlChar *strval;
5862
38.1k
    double ret;
5863
5864
38.1k
    if (node == NULL)
5865
0
  return(xmlXPathNAN);
5866
38.1k
    strval = xmlXPathCastNodeToString(node);
5867
38.1k
    if (strval == NULL)
5868
994
  return(xmlXPathNAN);
5869
37.1k
    ret = xmlXPathCastStringToNumber(strval);
5870
37.1k
    xmlFree(strval);
5871
5872
37.1k
    return(ret);
5873
38.1k
}
5874
5875
/**
5876
 * xmlXPathCastNodeSetToNumber:
5877
 * @ns:  a node-set
5878
 *
5879
 * Converts a node-set to its number value
5880
 *
5881
 * Returns the number value
5882
 */
5883
double
5884
391k
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885
391k
    xmlChar *str;
5886
391k
    double ret;
5887
5888
391k
    if (ns == NULL)
5889
30.9k
  return(xmlXPathNAN);
5890
360k
    str = xmlXPathCastNodeSetToString(ns);
5891
360k
    ret = xmlXPathCastStringToNumber(str);
5892
360k
    xmlFree(str);
5893
360k
    return(ret);
5894
391k
}
5895
5896
/**
5897
 * xmlXPathCastToNumber:
5898
 * @val:  an XPath object
5899
 *
5900
 * Converts an XPath object to its number value
5901
 *
5902
 * Returns the number value
5903
 */
5904
double
5905
1.14M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906
1.14M
    double ret = 0.0;
5907
5908
1.14M
    if (val == NULL)
5909
0
  return(xmlXPathNAN);
5910
1.14M
    switch (val->type) {
5911
0
    case XPATH_UNDEFINED:
5912
#ifdef DEBUG_EXPR
5913
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5914
#endif
5915
0
  ret = xmlXPathNAN;
5916
0
  break;
5917
391k
    case XPATH_NODESET:
5918
391k
    case XPATH_XSLT_TREE:
5919
391k
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920
391k
  break;
5921
324k
    case XPATH_STRING:
5922
324k
  ret = xmlXPathCastStringToNumber(val->stringval);
5923
324k
  break;
5924
109k
    case XPATH_NUMBER:
5925
109k
  ret = val->floatval;
5926
109k
  break;
5927
315k
    case XPATH_BOOLEAN:
5928
315k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5929
315k
  break;
5930
634
    case XPATH_USERS:
5931
#ifdef LIBXML_XPTR_LOCS_ENABLED
5932
    case XPATH_POINT:
5933
    case XPATH_RANGE:
5934
    case XPATH_LOCATIONSET:
5935
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5936
634
  TODO;
5937
634
  ret = xmlXPathNAN;
5938
634
  break;
5939
1.14M
    }
5940
1.14M
    return(ret);
5941
1.14M
}
5942
5943
/**
5944
 * xmlXPathConvertNumber:
5945
 * @val:  an XPath object
5946
 *
5947
 * Converts an existing object to its number() equivalent
5948
 *
5949
 * Returns the new object, the old one is freed (or the operation
5950
 *         is done directly on @val)
5951
 */
5952
xmlXPathObjectPtr
5953
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954
0
    xmlXPathObjectPtr ret;
5955
5956
0
    if (val == NULL)
5957
0
  return(xmlXPathNewFloat(0.0));
5958
0
    if (val->type == XPATH_NUMBER)
5959
0
  return(val);
5960
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961
0
    xmlXPathFreeObject(val);
5962
0
    return(ret);
5963
0
}
5964
5965
/**
5966
 * xmlXPathCastNumberToBoolean:
5967
 * @val:  a number
5968
 *
5969
 * Converts a number to its boolean value
5970
 *
5971
 * Returns the boolean value
5972
 */
5973
int
5974
151k
xmlXPathCastNumberToBoolean (double val) {
5975
151k
     if (xmlXPathIsNaN(val) || (val == 0.0))
5976
26.2k
   return(0);
5977
124k
     return(1);
5978
151k
}
5979
5980
/**
5981
 * xmlXPathCastStringToBoolean:
5982
 * @val:  a string
5983
 *
5984
 * Converts a string to its boolean value
5985
 *
5986
 * Returns the boolean value
5987
 */
5988
int
5989
83.6k
xmlXPathCastStringToBoolean (const xmlChar *val) {
5990
83.6k
    if ((val == NULL) || (xmlStrlen(val) == 0))
5991
82.9k
  return(0);
5992
645
    return(1);
5993
83.6k
}
5994
5995
/**
5996
 * xmlXPathCastNodeSetToBoolean:
5997
 * @ns:  a node-set
5998
 *
5999
 * Converts a node-set to its boolean value
6000
 *
6001
 * Returns the boolean value
6002
 */
6003
int
6004
162k
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005
162k
    if ((ns == NULL) || (ns->nodeNr == 0))
6006
136k
  return(0);
6007
26.4k
    return(1);
6008
162k
}
6009
6010
/**
6011
 * xmlXPathCastToBoolean:
6012
 * @val:  an XPath object
6013
 *
6014
 * Converts an XPath object to its boolean value
6015
 *
6016
 * Returns the boolean value
6017
 */
6018
int
6019
347k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020
347k
    int ret = 0;
6021
6022
347k
    if (val == NULL)
6023
0
  return(0);
6024
347k
    switch (val->type) {
6025
0
    case XPATH_UNDEFINED:
6026
#ifdef DEBUG_EXPR
6027
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028
#endif
6029
0
  ret = 0;
6030
0
  break;
6031
162k
    case XPATH_NODESET:
6032
162k
    case XPATH_XSLT_TREE:
6033
162k
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034
162k
  break;
6035
83.6k
    case XPATH_STRING:
6036
83.6k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6037
83.6k
  break;
6038
100k
    case XPATH_NUMBER:
6039
100k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6040
100k
  break;
6041
0
    case XPATH_BOOLEAN:
6042
0
  ret = val->boolval;
6043
0
  break;
6044
0
    case XPATH_USERS:
6045
#ifdef LIBXML_XPTR_LOCS_ENABLED
6046
    case XPATH_POINT:
6047
    case XPATH_RANGE:
6048
    case XPATH_LOCATIONSET:
6049
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6050
0
  TODO;
6051
0
  ret = 0;
6052
0
  break;
6053
347k
    }
6054
347k
    return(ret);
6055
347k
}
6056
6057
6058
/**
6059
 * xmlXPathConvertBoolean:
6060
 * @val:  an XPath object
6061
 *
6062
 * Converts an existing object to its boolean() equivalent
6063
 *
6064
 * Returns the new object, the old one is freed (or the operation
6065
 *         is done directly on @val)
6066
 */
6067
xmlXPathObjectPtr
6068
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6069
0
    xmlXPathObjectPtr ret;
6070
6071
0
    if (val == NULL)
6072
0
  return(xmlXPathNewBoolean(0));
6073
0
    if (val->type == XPATH_BOOLEAN)
6074
0
  return(val);
6075
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6076
0
    xmlXPathFreeObject(val);
6077
0
    return(ret);
6078
0
}
6079
6080
/************************************************************************
6081
 *                  *
6082
 *    Routines to handle XPath contexts     *
6083
 *                  *
6084
 ************************************************************************/
6085
6086
/**
6087
 * xmlXPathNewContext:
6088
 * @doc:  the XML document
6089
 *
6090
 * Create a new xmlXPathContext
6091
 *
6092
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6093
 */
6094
xmlXPathContextPtr
6095
33.2k
xmlXPathNewContext(xmlDocPtr doc) {
6096
33.2k
    xmlXPathContextPtr ret;
6097
6098
33.2k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6099
33.2k
    if (ret == NULL) {
6100
8
        xmlXPathErrMemory(NULL, "creating context\n");
6101
8
  return(NULL);
6102
8
    }
6103
33.2k
    memset(ret, 0 , sizeof(xmlXPathContext));
6104
33.2k
    ret->doc = doc;
6105
33.2k
    ret->node = NULL;
6106
6107
33.2k
    ret->varHash = NULL;
6108
6109
33.2k
    ret->nb_types = 0;
6110
33.2k
    ret->max_types = 0;
6111
33.2k
    ret->types = NULL;
6112
6113
33.2k
    ret->funcHash = xmlHashCreate(0);
6114
6115
33.2k
    ret->nb_axis = 0;
6116
33.2k
    ret->max_axis = 0;
6117
33.2k
    ret->axis = NULL;
6118
6119
33.2k
    ret->nsHash = NULL;
6120
33.2k
    ret->user = NULL;
6121
6122
33.2k
    ret->contextSize = -1;
6123
33.2k
    ret->proximityPosition = -1;
6124
6125
#ifdef XP_DEFAULT_CACHE_ON
6126
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6127
  xmlXPathFreeContext(ret);
6128
  return(NULL);
6129
    }
6130
#endif
6131
6132
33.2k
    xmlXPathRegisterAllFunctions(ret);
6133
6134
33.2k
    return(ret);
6135
33.2k
}
6136
6137
/**
6138
 * xmlXPathFreeContext:
6139
 * @ctxt:  the context to free
6140
 *
6141
 * Free up an xmlXPathContext
6142
 */
6143
void
6144
33.2k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6145
33.2k
    if (ctxt == NULL) return;
6146
6147
33.2k
    if (ctxt->cache != NULL)
6148
33.2k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6149
33.2k
    xmlXPathRegisteredNsCleanup(ctxt);
6150
33.2k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6151
33.2k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6152
33.2k
    xmlResetError(&ctxt->lastError);
6153
33.2k
    xmlFree(ctxt);
6154
33.2k
}
6155
6156
/************************************************************************
6157
 *                  *
6158
 *    Routines to handle XPath parser contexts    *
6159
 *                  *
6160
 ************************************************************************/
6161
6162
#define CHECK_CTXT(ctxt)            \
6163
186k
    if (ctxt == NULL) {           \
6164
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6165
0
    NULL, NULL, XML_FROM_XPATH,       \
6166
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6167
0
    __FILE__, __LINE__,         \
6168
0
    NULL, NULL, NULL, 0, 0,         \
6169
0
    "NULL context pointer\n");        \
6170
0
  return(NULL);             \
6171
0
    }                  \
6172
6173
#define CHECK_CTXT_NEG(ctxt)            \
6174
2.60M
    if (ctxt == NULL) {           \
6175
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6176
0
    NULL, NULL, XML_FROM_XPATH,       \
6177
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6178
0
    __FILE__, __LINE__,         \
6179
0
    NULL, NULL, NULL, 0, 0,         \
6180
0
    "NULL context pointer\n");        \
6181
0
  return(-1);             \
6182
0
    }                  \
6183
6184
6185
#define CHECK_CONTEXT(ctxt)           \
6186
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6187
        (ctxt->doc->children == NULL)) {        \
6188
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6189
  return(NULL);             \
6190
    }
6191
6192
6193
/**
6194
 * xmlXPathNewParserContext:
6195
 * @str:  the XPath expression
6196
 * @ctxt:  the XPath context
6197
 *
6198
 * Create a new xmlXPathParserContext
6199
 *
6200
 * Returns the xmlXPathParserContext just allocated.
6201
 */
6202
xmlXPathParserContextPtr
6203
743k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6204
743k
    xmlXPathParserContextPtr ret;
6205
6206
743k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6207
743k
    if (ret == NULL) {
6208
5.57k
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6209
5.57k
  return(NULL);
6210
5.57k
    }
6211
737k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6212
737k
    ret->cur = ret->base = str;
6213
737k
    ret->context = ctxt;
6214
6215
737k
    ret->comp = xmlXPathNewCompExpr();
6216
737k
    if (ret->comp == NULL) {
6217
151
  xmlFree(ret->valueTab);
6218
151
  xmlFree(ret);
6219
151
  return(NULL);
6220
151
    }
6221
737k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6222
229k
        ret->comp->dict = ctxt->dict;
6223
229k
  xmlDictReference(ret->comp->dict);
6224
229k
    }
6225
6226
737k
    return(ret);
6227
737k
}
6228
6229
/**
6230
 * xmlXPathCompParserContext:
6231
 * @comp:  the XPath compiled expression
6232
 * @ctxt:  the XPath context
6233
 *
6234
 * Create a new xmlXPathParserContext when processing a compiled expression
6235
 *
6236
 * Returns the xmlXPathParserContext just allocated.
6237
 */
6238
static xmlXPathParserContextPtr
6239
2.60M
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6240
2.60M
    xmlXPathParserContextPtr ret;
6241
6242
2.60M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6243
2.60M
    if (ret == NULL) {
6244
18.0k
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6245
18.0k
  return(NULL);
6246
18.0k
    }
6247
2.58M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6248
6249
    /* Allocate the value stack */
6250
2.58M
    ret->valueTab = (xmlXPathObjectPtr *)
6251
2.58M
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6252
2.58M
    if (ret->valueTab == NULL) {
6253
221
  xmlFree(ret);
6254
221
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6255
221
  return(NULL);
6256
221
    }
6257
2.58M
    ret->valueNr = 0;
6258
2.58M
    ret->valueMax = 10;
6259
2.58M
    ret->value = NULL;
6260
6261
2.58M
    ret->context = ctxt;
6262
2.58M
    ret->comp = comp;
6263
6264
2.58M
    return(ret);
6265
2.58M
}
6266
6267
/**
6268
 * xmlXPathFreeParserContext:
6269
 * @ctxt:  the context to free
6270
 *
6271
 * Free up an xmlXPathParserContext
6272
 */
6273
void
6274
3.32M
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6275
3.32M
    int i;
6276
6277
3.32M
    if (ctxt->valueTab != NULL) {
6278
2.82M
        for (i = 0; i < ctxt->valueNr; i++) {
6279
159k
            if (ctxt->context)
6280
159k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281
0
            else
6282
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6283
159k
        }
6284
2.66M
        xmlFree(ctxt->valueTab);
6285
2.66M
    }
6286
3.32M
    if (ctxt->comp != NULL) {
6287
443k
#ifdef XPATH_STREAMING
6288
443k
  if (ctxt->comp->stream != NULL) {
6289
28.1k
      xmlFreePatternList(ctxt->comp->stream);
6290
28.1k
      ctxt->comp->stream = NULL;
6291
28.1k
  }
6292
443k
#endif
6293
443k
  xmlXPathFreeCompExpr(ctxt->comp);
6294
443k
    }
6295
3.32M
    xmlFree(ctxt);
6296
3.32M
}
6297
6298
/************************************************************************
6299
 *                  *
6300
 *    The implicit core function library      *
6301
 *                  *
6302
 ************************************************************************/
6303
6304
/**
6305
 * xmlXPathNodeValHash:
6306
 * @node:  a node pointer
6307
 *
6308
 * Function computing the beginning of the string value of the node,
6309
 * used to speed up comparisons
6310
 *
6311
 * Returns an int usable as a hash
6312
 */
6313
static unsigned int
6314
95.9k
xmlXPathNodeValHash(xmlNodePtr node) {
6315
95.9k
    int len = 2;
6316
95.9k
    const xmlChar * string = NULL;
6317
95.9k
    xmlNodePtr tmp = NULL;
6318
95.9k
    unsigned int ret = 0;
6319
6320
95.9k
    if (node == NULL)
6321
0
  return(0);
6322
6323
95.9k
    if (node->type == XML_DOCUMENT_NODE) {
6324
38.4k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325
38.4k
  if (tmp == NULL)
6326
26.2k
      node = node->children;
6327
12.2k
  else
6328
12.2k
      node = tmp;
6329
6330
38.4k
  if (node == NULL)
6331
721
      return(0);
6332
38.4k
    }
6333
6334
95.2k
    switch (node->type) {
6335
591
  case XML_COMMENT_NODE:
6336
1.20k
  case XML_PI_NODE:
6337
1.20k
  case XML_CDATA_SECTION_NODE:
6338
33.7k
  case XML_TEXT_NODE:
6339
33.7k
      string = node->content;
6340
33.7k
      if (string == NULL)
6341
339
    return(0);
6342
33.4k
      if (string[0] == 0)
6343
291
    return(0);
6344
33.1k
      return(string[0] + (string[1] << 8));
6345
944
  case XML_NAMESPACE_DECL:
6346
944
      string = ((xmlNsPtr)node)->href;
6347
944
      if (string == NULL)
6348
0
    return(0);
6349
944
      if (string[0] == 0)
6350
0
    return(0);
6351
944
      return(string[0] + (string[1] << 8));
6352
33.3k
  case XML_ATTRIBUTE_NODE:
6353
33.3k
      tmp = ((xmlAttrPtr) node)->children;
6354
33.3k
      break;
6355
27.0k
  case XML_ELEMENT_NODE:
6356
27.0k
      tmp = node->children;
6357
27.0k
      break;
6358
0
  default:
6359
0
      return(0);
6360
95.2k
    }
6361
666k
    while (tmp != NULL) {
6362
652k
  switch (tmp->type) {
6363
0
      case XML_CDATA_SECTION_NODE:
6364
56.3k
      case XML_TEXT_NODE:
6365
56.3k
    string = tmp->content;
6366
56.3k
    break;
6367
596k
      default:
6368
596k
                string = NULL;
6369
596k
    break;
6370
652k
  }
6371
652k
  if ((string != NULL) && (string[0] != 0)) {
6372
55.8k
      if (len == 1) {
6373
2.84k
    return(ret + (string[0] << 8));
6374
2.84k
      }
6375
52.9k
      if (string[1] == 0) {
6376
9.02k
    len = 1;
6377
9.02k
    ret = string[0];
6378
43.9k
      } else {
6379
43.9k
    return(string[0] + (string[1] << 8));
6380
43.9k
      }
6381
52.9k
  }
6382
  /*
6383
   * Skip to next node
6384
   */
6385
605k
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6386
93.9k
      if (tmp->children->type != XML_ENTITY_DECL) {
6387
93.9k
    tmp = tmp->children;
6388
93.9k
    continue;
6389
93.9k
      }
6390
93.9k
  }
6391
511k
  if (tmp == node)
6392
0
      break;
6393
6394
511k
  if (tmp->next != NULL) {
6395
417k
      tmp = tmp->next;
6396
417k
      continue;
6397
417k
  }
6398
6399
96.0k
  do {
6400
96.0k
      tmp = tmp->parent;
6401
96.0k
      if (tmp == NULL)
6402
0
    break;
6403
96.0k
      if (tmp == node) {
6404
8.23k
    tmp = NULL;
6405
8.23k
    break;
6406
8.23k
      }
6407
87.8k
      if (tmp->next != NULL) {
6408
85.8k
    tmp = tmp->next;
6409
85.8k
    break;
6410
85.8k
      }
6411
87.8k
  } while (tmp != NULL);
6412
94.0k
    }
6413
13.6k
    return(ret);
6414
60.4k
}
6415
6416
/**
6417
 * xmlXPathStringHash:
6418
 * @string:  a string
6419
 *
6420
 * Function computing the beginning of the string value of the node,
6421
 * used to speed up comparisons
6422
 *
6423
 * Returns an int usable as a hash
6424
 */
6425
static unsigned int
6426
9.23k
xmlXPathStringHash(const xmlChar * string) {
6427
9.23k
    if (string == NULL)
6428
0
  return(0);
6429
9.23k
    if (string[0] == 0)
6430
642
  return(0);
6431
8.59k
    return(string[0] + (string[1] << 8));
6432
9.23k
}
6433
6434
/**
6435
 * xmlXPathCompareNodeSetFloat:
6436
 * @ctxt:  the XPath Parser context
6437
 * @inf:  less than (1) or greater than (0)
6438
 * @strict:  is the comparison strict
6439
 * @arg:  the node set
6440
 * @f:  the value
6441
 *
6442
 * Implement the compare operation between a nodeset and a number
6443
 *     @ns < @val    (1, 1, ...
6444
 *     @ns <= @val   (1, 0, ...
6445
 *     @ns > @val    (0, 1, ...
6446
 *     @ns >= @val   (0, 0, ...
6447
 *
6448
 * If one object to be compared is a node-set and the other is a number,
6449
 * then the comparison will be true if and only if there is a node in the
6450
 * node-set such that the result of performing the comparison on the number
6451
 * to be compared and on the result of converting the string-value of that
6452
 * node to a number using the number function is true.
6453
 *
6454
 * Returns 0 or 1 depending on the results of the test.
6455
 */
6456
static int
6457
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6458
98.5k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6459
98.5k
    int i, ret = 0;
6460
98.5k
    xmlNodeSetPtr ns;
6461
98.5k
    xmlChar *str2;
6462
6463
98.5k
    if ((f == NULL) || (arg == NULL) ||
6464
98.5k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6465
0
  xmlXPathReleaseObject(ctxt->context, arg);
6466
0
  xmlXPathReleaseObject(ctxt->context, f);
6467
0
        return(0);
6468
0
    }
6469
98.5k
    ns = arg->nodesetval;
6470
98.5k
    if (ns != NULL) {
6471
208k
  for (i = 0;i < ns->nodeNr;i++) {
6472
116k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6473
116k
       if (str2 != NULL) {
6474
115k
     valuePush(ctxt,
6475
115k
         xmlXPathCacheNewString(ctxt->context, str2));
6476
115k
     xmlFree(str2);
6477
115k
     xmlXPathNumberFunction(ctxt, 1);
6478
115k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6479
115k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6480
115k
     if (ret)
6481
514
         break;
6482
115k
       }
6483
116k
  }
6484
92.0k
    }
6485
98.5k
    xmlXPathReleaseObject(ctxt->context, arg);
6486
98.5k
    xmlXPathReleaseObject(ctxt->context, f);
6487
98.5k
    return(ret);
6488
98.5k
}
6489
6490
/**
6491
 * xmlXPathCompareNodeSetString:
6492
 * @ctxt:  the XPath Parser context
6493
 * @inf:  less than (1) or greater than (0)
6494
 * @strict:  is the comparison strict
6495
 * @arg:  the node set
6496
 * @s:  the value
6497
 *
6498
 * Implement the compare operation between a nodeset and a string
6499
 *     @ns < @val    (1, 1, ...
6500
 *     @ns <= @val   (1, 0, ...
6501
 *     @ns > @val    (0, 1, ...
6502
 *     @ns >= @val   (0, 0, ...
6503
 *
6504
 * If one object to be compared is a node-set and the other is a string,
6505
 * then the comparison will be true if and only if there is a node in
6506
 * the node-set such that the result of performing the comparison on the
6507
 * string-value of the node and the other string is true.
6508
 *
6509
 * Returns 0 or 1 depending on the results of the test.
6510
 */
6511
static int
6512
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6513
20.3k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6514
20.3k
    int i, ret = 0;
6515
20.3k
    xmlNodeSetPtr ns;
6516
20.3k
    xmlChar *str2;
6517
6518
20.3k
    if ((s == NULL) || (arg == NULL) ||
6519
20.3k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6520
0
  xmlXPathReleaseObject(ctxt->context, arg);
6521
0
  xmlXPathReleaseObject(ctxt->context, s);
6522
0
        return(0);
6523
0
    }
6524
20.3k
    ns = arg->nodesetval;
6525
20.3k
    if (ns != NULL) {
6526
39.4k
  for (i = 0;i < ns->nodeNr;i++) {
6527
22.1k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6528
22.1k
       if (str2 != NULL) {
6529
21.9k
     valuePush(ctxt,
6530
21.9k
         xmlXPathCacheNewString(ctxt->context, str2));
6531
21.9k
     xmlFree(str2);
6532
21.9k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6533
21.9k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6534
21.9k
     if (ret)
6535
0
         break;
6536
21.9k
       }
6537
22.1k
  }
6538
17.3k
    }
6539
20.3k
    xmlXPathReleaseObject(ctxt->context, arg);
6540
20.3k
    xmlXPathReleaseObject(ctxt->context, s);
6541
20.3k
    return(ret);
6542
20.3k
}
6543
6544
/**
6545
 * xmlXPathCompareNodeSets:
6546
 * @inf:  less than (1) or greater than (0)
6547
 * @strict:  is the comparison strict
6548
 * @arg1:  the first node set object
6549
 * @arg2:  the second node set object
6550
 *
6551
 * Implement the compare operation on nodesets:
6552
 *
6553
 * If both objects to be compared are node-sets, then the comparison
6554
 * will be true if and only if there is a node in the first node-set
6555
 * and a node in the second node-set such that the result of performing
6556
 * the comparison on the string-values of the two nodes is true.
6557
 * ....
6558
 * When neither object to be compared is a node-set and the operator
6559
 * is <=, <, >= or >, then the objects are compared by converting both
6560
 * objects to numbers and comparing the numbers according to IEEE 754.
6561
 * ....
6562
 * The number function converts its argument to a number as follows:
6563
 *  - a string that consists of optional whitespace followed by an
6564
 *    optional minus sign followed by a Number followed by whitespace
6565
 *    is converted to the IEEE 754 number that is nearest (according
6566
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6567
 *    represented by the string; any other string is converted to NaN
6568
 *
6569
 * Conclusion all nodes need to be converted first to their string value
6570
 * and then the comparison must be done when possible
6571
 */
6572
static int
6573
xmlXPathCompareNodeSets(int inf, int strict,
6574
113k
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6575
113k
    int i, j, init = 0;
6576
113k
    double val1;
6577
113k
    double *values2;
6578
113k
    int ret = 0;
6579
113k
    xmlNodeSetPtr ns1;
6580
113k
    xmlNodeSetPtr ns2;
6581
6582
113k
    if ((arg1 == NULL) ||
6583
113k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6584
0
  xmlXPathFreeObject(arg2);
6585
0
        return(0);
6586
0
    }
6587
113k
    if ((arg2 == NULL) ||
6588
113k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6589
0
  xmlXPathFreeObject(arg1);
6590
0
  xmlXPathFreeObject(arg2);
6591
0
        return(0);
6592
0
    }
6593
6594
113k
    ns1 = arg1->nodesetval;
6595
113k
    ns2 = arg2->nodesetval;
6596
6597
113k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6598
106k
  xmlXPathFreeObject(arg1);
6599
106k
  xmlXPathFreeObject(arg2);
6600
106k
  return(0);
6601
106k
    }
6602
6.90k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6603
4.03k
  xmlXPathFreeObject(arg1);
6604
4.03k
  xmlXPathFreeObject(arg2);
6605
4.03k
  return(0);
6606
4.03k
    }
6607
6608
2.87k
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6609
2.87k
    if (values2 == NULL) {
6610
        /* TODO: Propagate memory error. */
6611
10
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6612
10
  xmlXPathFreeObject(arg1);
6613
10
  xmlXPathFreeObject(arg2);
6614
10
  return(0);
6615
10
    }
6616
20.5k
    for (i = 0;i < ns1->nodeNr;i++) {
6617
17.8k
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6618
17.8k
  if (xmlXPathIsNaN(val1))
6619
17.3k
      continue;
6620
5.18k
  for (j = 0;j < ns2->nodeNr;j++) {
6621
4.83k
      if (init == 0) {
6622
3.13k
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6623
3.13k
      }
6624
4.83k
      if (xmlXPathIsNaN(values2[j]))
6625
4.13k
    continue;
6626
702
      if (inf && strict)
6627
0
    ret = (val1 < values2[j]);
6628
702
      else if (inf && !strict)
6629
0
    ret = (val1 <= values2[j]);
6630
702
      else if (!inf && strict)
6631
702
    ret = (val1 > values2[j]);
6632
0
      else if (!inf && !strict)
6633
0
    ret = (val1 >= values2[j]);
6634
702
      if (ret)
6635
137
    break;
6636
702
  }
6637
488
  if (ret)
6638
137
      break;
6639
351
  init = 1;
6640
351
    }
6641
2.86k
    xmlFree(values2);
6642
2.86k
    xmlXPathFreeObject(arg1);
6643
2.86k
    xmlXPathFreeObject(arg2);
6644
2.86k
    return(ret);
6645
2.87k
}
6646
6647
/**
6648
 * xmlXPathCompareNodeSetValue:
6649
 * @ctxt:  the XPath Parser context
6650
 * @inf:  less than (1) or greater than (0)
6651
 * @strict:  is the comparison strict
6652
 * @arg:  the node set
6653
 * @val:  the value
6654
 *
6655
 * Implement the compare operation between a nodeset and a value
6656
 *     @ns < @val    (1, 1, ...
6657
 *     @ns <= @val   (1, 0, ...
6658
 *     @ns > @val    (0, 1, ...
6659
 *     @ns >= @val   (0, 0, ...
6660
 *
6661
 * If one object to be compared is a node-set and the other is a boolean,
6662
 * then the comparison will be true if and only if the result of performing
6663
 * the comparison on the boolean and on the result of converting
6664
 * the node-set to a boolean using the boolean function is true.
6665
 *
6666
 * Returns 0 or 1 depending on the results of the test.
6667
 */
6668
static int
6669
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6670
269k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6671
269k
    if ((val == NULL) || (arg == NULL) ||
6672
269k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6673
0
        return(0);
6674
6675
269k
    switch(val->type) {
6676
98.5k
        case XPATH_NUMBER:
6677
98.5k
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6678
0
        case XPATH_NODESET:
6679
0
        case XPATH_XSLT_TREE:
6680
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6681
20.3k
        case XPATH_STRING:
6682
20.3k
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6683
150k
        case XPATH_BOOLEAN:
6684
150k
      valuePush(ctxt, arg);
6685
150k
      xmlXPathBooleanFunction(ctxt, 1);
6686
150k
      valuePush(ctxt, val);
6687
150k
      return(xmlXPathCompareValues(ctxt, inf, strict));
6688
0
  default:
6689
0
            xmlGenericError(xmlGenericErrorContext,
6690
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6691
0
                    "and object of type %d\n",
6692
0
                    val->type);
6693
0
            xmlXPathReleaseObject(ctxt->context, arg);
6694
0
            xmlXPathReleaseObject(ctxt->context, val);
6695
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6696
269k
    }
6697
0
    return(0);
6698
269k
}
6699
6700
/**
6701
 * xmlXPathEqualNodeSetString:
6702
 * @arg:  the nodeset object argument
6703
 * @str:  the string to compare to.
6704
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6705
 *
6706
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6707
 * If one object to be compared is a node-set and the other is a string,
6708
 * then the comparison will be true if and only if there is a node in
6709
 * the node-set such that the result of performing the comparison on the
6710
 * string-value of the node and the other string is true.
6711
 *
6712
 * Returns 0 or 1 depending on the results of the test.
6713
 */
6714
static int
6715
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6716
12.3k
{
6717
12.3k
    int i;
6718
12.3k
    xmlNodeSetPtr ns;
6719
12.3k
    xmlChar *str2;
6720
12.3k
    unsigned int hash;
6721
6722
12.3k
    if ((str == NULL) || (arg == NULL) ||
6723
12.3k
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6724
0
        return (0);
6725
12.3k
    ns = arg->nodesetval;
6726
    /*
6727
     * A NULL nodeset compared with a string is always false
6728
     * (since there is no node equal, and no node not equal)
6729
     */
6730
12.3k
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6731
3.10k
        return (0);
6732
9.23k
    hash = xmlXPathStringHash(str);
6733
15.4k
    for (i = 0; i < ns->nodeNr; i++) {
6734
10.0k
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6735
3.97k
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6736
3.97k
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6737
3.12k
                xmlFree(str2);
6738
3.12k
    if (neq)
6739
480
        continue;
6740
2.64k
                return (1);
6741
3.12k
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6742
1
    if (neq)
6743
1
        continue;
6744
0
                return (1);
6745
845
            } else if (neq) {
6746
0
    if (str2 != NULL)
6747
0
        xmlFree(str2);
6748
0
    return (1);
6749
0
      }
6750
845
            if (str2 != NULL)
6751
844
                xmlFree(str2);
6752
6.03k
        } else if (neq)
6753
1.12k
      return (1);
6754
10.0k
    }
6755
5.47k
    return (0);
6756
9.23k
}
6757
6758
/**
6759
 * xmlXPathEqualNodeSetFloat:
6760
 * @arg:  the nodeset object argument
6761
 * @f:  the float to compare to
6762
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6763
 *
6764
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6765
 * If one object to be compared is a node-set and the other is a number,
6766
 * then the comparison will be true if and only if there is a node in
6767
 * the node-set such that the result of performing the comparison on the
6768
 * number to be compared and on the result of converting the string-value
6769
 * of that node to a number using the number function is true.
6770
 *
6771
 * Returns 0 or 1 depending on the results of the test.
6772
 */
6773
static int
6774
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6775
34.0k
    xmlXPathObjectPtr arg, double f, int neq) {
6776
34.0k
  int i, ret=0;
6777
34.0k
  xmlNodeSetPtr ns;
6778
34.0k
  xmlChar *str2;
6779
34.0k
  xmlXPathObjectPtr val;
6780
34.0k
  double v;
6781
6782
34.0k
    if ((arg == NULL) ||
6783
34.0k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6784
0
        return(0);
6785
6786
34.0k
    ns = arg->nodesetval;
6787
34.0k
    if (ns != NULL) {
6788
73.0k
  for (i=0;i<ns->nodeNr;i++) {
6789
40.9k
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6790
40.9k
      if (str2 != NULL) {
6791
39.3k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6792
39.3k
    xmlFree(str2);
6793
39.3k
    xmlXPathNumberFunction(ctxt, 1);
6794
39.3k
                CHECK_ERROR0;
6795
39.3k
    val = valuePop(ctxt);
6796
39.3k
    v = val->floatval;
6797
39.3k
    xmlXPathReleaseObject(ctxt->context, val);
6798
39.3k
    if (!xmlXPathIsNaN(v)) {
6799
1.46k
        if ((!neq) && (v==f)) {
6800
412
      ret = 1;
6801
412
      break;
6802
1.05k
        } else if ((neq) && (v!=f)) {
6803
356
      ret = 1;
6804
356
      break;
6805
356
        }
6806
37.8k
    } else { /* NaN is unequal to any value */
6807
37.8k
        if (neq)
6808
17.9k
      ret = 1;
6809
37.8k
    }
6810
39.3k
      }
6811
40.9k
  }
6812
32.8k
    }
6813
6814
34.0k
    return(ret);
6815
34.0k
}
6816
6817
6818
/**
6819
 * xmlXPathEqualNodeSets:
6820
 * @arg1:  first nodeset object argument
6821
 * @arg2:  second nodeset object argument
6822
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6823
 *
6824
 * Implement the equal / not equal operation on XPath nodesets:
6825
 * @arg1 == @arg2  or  @arg1 != @arg2
6826
 * If both objects to be compared are node-sets, then the comparison
6827
 * will be true if and only if there is a node in the first node-set and
6828
 * a node in the second node-set such that the result of performing the
6829
 * comparison on the string-values of the two nodes is true.
6830
 *
6831
 * (needless to say, this is a costly operation)
6832
 *
6833
 * Returns 0 or 1 depending on the results of the test.
6834
 */
6835
static int
6836
149k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6837
149k
    int i, j;
6838
149k
    unsigned int *hashs1;
6839
149k
    unsigned int *hashs2;
6840
149k
    xmlChar **values1;
6841
149k
    xmlChar **values2;
6842
149k
    int ret = 0;
6843
149k
    xmlNodeSetPtr ns1;
6844
149k
    xmlNodeSetPtr ns2;
6845
6846
149k
    if ((arg1 == NULL) ||
6847
149k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6848
0
        return(0);
6849
149k
    if ((arg2 == NULL) ||
6850
149k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6851
0
        return(0);
6852
6853
149k
    ns1 = arg1->nodesetval;
6854
149k
    ns2 = arg2->nodesetval;
6855
6856
149k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6857
28.0k
  return(0);
6858
121k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6859
81.1k
  return(0);
6860
6861
    /*
6862
     * for equal, check if there is a node pertaining to both sets
6863
     */
6864
40.4k
    if (neq == 0)
6865
71.1k
  for (i = 0;i < ns1->nodeNr;i++)
6866
105k
      for (j = 0;j < ns2->nodeNr;j++)
6867
65.6k
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6868
898
        return(1);
6869
6870
39.5k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6871
39.5k
    if (values1 == NULL) {
6872
        /* TODO: Propagate memory error. */
6873
91
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6874
91
  return(0);
6875
91
    }
6876
39.4k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6877
39.4k
    if (hashs1 == NULL) {
6878
        /* TODO: Propagate memory error. */
6879
10
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6880
10
  xmlFree(values1);
6881
10
  return(0);
6882
10
    }
6883
39.4k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6884
39.4k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6885
39.4k
    if (values2 == NULL) {
6886
        /* TODO: Propagate memory error. */
6887
8
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6888
8
  xmlFree(hashs1);
6889
8
  xmlFree(values1);
6890
8
  return(0);
6891
8
    }
6892
39.4k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6893
39.4k
    if (hashs2 == NULL) {
6894
        /* TODO: Propagate memory error. */
6895
7
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896
7
  xmlFree(hashs1);
6897
7
  xmlFree(values1);
6898
7
  xmlFree(values2);
6899
7
  return(0);
6900
7
    }
6901
39.4k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902
64.2k
    for (i = 0;i < ns1->nodeNr;i++) {
6903
42.6k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6904
76.0k
  for (j = 0;j < ns2->nodeNr;j++) {
6905
51.2k
      if (i == 0)
6906
43.2k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6907
51.2k
      if (hashs1[i] != hashs2[j]) {
6908
37.9k
    if (neq) {
6909
7.17k
        ret = 1;
6910
7.17k
        break;
6911
7.17k
    }
6912
37.9k
      }
6913
13.2k
      else {
6914
13.2k
    if (values1[i] == NULL)
6915
12.3k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916
13.2k
    if (values2[j] == NULL)
6917
12.2k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6918
13.2k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6919
13.2k
    if (ret)
6920
10.7k
        break;
6921
13.2k
      }
6922
51.2k
  }
6923
42.6k
  if (ret)
6924
17.8k
      break;
6925
42.6k
    }
6926
87.8k
    for (i = 0;i < ns1->nodeNr;i++)
6927
48.3k
  if (values1[i] != NULL)
6928
11.6k
      xmlFree(values1[i]);
6929
97.7k
    for (j = 0;j < ns2->nodeNr;j++)
6930
58.2k
  if (values2[j] != NULL)
6931
12.2k
      xmlFree(values2[j]);
6932
39.4k
    xmlFree(values1);
6933
39.4k
    xmlFree(values2);
6934
39.4k
    xmlFree(hashs1);
6935
39.4k
    xmlFree(hashs2);
6936
39.4k
    return(ret);
6937
39.4k
}
6938
6939
static int
6940
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941
195k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6942
195k
    int ret = 0;
6943
    /*
6944
     *At this point we are assured neither arg1 nor arg2
6945
     *is a nodeset, so we can just pick the appropriate routine.
6946
     */
6947
195k
    switch (arg1->type) {
6948
0
        case XPATH_UNDEFINED:
6949
#ifdef DEBUG_EXPR
6950
      xmlGenericError(xmlGenericErrorContext,
6951
        "Equal: undefined\n");
6952
#endif
6953
0
      break;
6954
62.4k
        case XPATH_BOOLEAN:
6955
62.4k
      switch (arg2->type) {
6956
0
          case XPATH_UNDEFINED:
6957
#ifdef DEBUG_EXPR
6958
        xmlGenericError(xmlGenericErrorContext,
6959
          "Equal: undefined\n");
6960
#endif
6961
0
        break;
6962
7.59k
    case XPATH_BOOLEAN:
6963
#ifdef DEBUG_EXPR
6964
        xmlGenericError(xmlGenericErrorContext,
6965
          "Equal: %d boolean %d \n",
6966
          arg1->boolval, arg2->boolval);
6967
#endif
6968
7.59k
        ret = (arg1->boolval == arg2->boolval);
6969
7.59k
        break;
6970
44.8k
    case XPATH_NUMBER:
6971
44.8k
        ret = (arg1->boolval ==
6972
44.8k
         xmlXPathCastNumberToBoolean(arg2->floatval));
6973
44.8k
        break;
6974
10.0k
    case XPATH_STRING:
6975
10.0k
        if ((arg2->stringval == NULL) ||
6976
10.0k
      (arg2->stringval[0] == 0)) ret = 0;
6977
7.14k
        else
6978
7.14k
      ret = 1;
6979
10.0k
        ret = (arg1->boolval == ret);
6980
10.0k
        break;
6981
0
    case XPATH_USERS:
6982
#ifdef LIBXML_XPTR_LOCS_ENABLED
6983
    case XPATH_POINT:
6984
    case XPATH_RANGE:
6985
    case XPATH_LOCATIONSET:
6986
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6987
0
        TODO
6988
0
        break;
6989
0
    case XPATH_NODESET:
6990
0
    case XPATH_XSLT_TREE:
6991
0
        break;
6992
62.4k
      }
6993
62.4k
      break;
6994
116k
        case XPATH_NUMBER:
6995
116k
      switch (arg2->type) {
6996
0
          case XPATH_UNDEFINED:
6997
#ifdef DEBUG_EXPR
6998
        xmlGenericError(xmlGenericErrorContext,
6999
          "Equal: undefined\n");
7000
#endif
7001
0
        break;
7002
5.60k
    case XPATH_BOOLEAN:
7003
5.60k
        ret = (arg2->boolval==
7004
5.60k
         xmlXPathCastNumberToBoolean(arg1->floatval));
7005
5.60k
        break;
7006
15.4k
    case XPATH_STRING:
7007
15.4k
        valuePush(ctxt, arg2);
7008
15.4k
        xmlXPathNumberFunction(ctxt, 1);
7009
15.4k
        arg2 = valuePop(ctxt);
7010
15.4k
                    if (ctxt->error)
7011
1
                        break;
7012
                    /* Falls through. */
7013
111k
    case XPATH_NUMBER:
7014
        /* Hand check NaN and Infinity equalities */
7015
111k
        if (xmlXPathIsNaN(arg1->floatval) ||
7016
111k
          xmlXPathIsNaN(arg2->floatval)) {
7017
20.3k
            ret = 0;
7018
90.8k
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7019
293
            if (xmlXPathIsInf(arg2->floatval) == 1)
7020
135
          ret = 1;
7021
158
      else
7022
158
          ret = 0;
7023
90.5k
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7024
289
      if (xmlXPathIsInf(arg2->floatval) == -1)
7025
145
          ret = 1;
7026
144
      else
7027
144
          ret = 0;
7028
90.2k
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7029
228
      if (xmlXPathIsInf(arg1->floatval) == 1)
7030
0
          ret = 1;
7031
228
      else
7032
228
          ret = 0;
7033
90.0k
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7034
77
      if (xmlXPathIsInf(arg1->floatval) == -1)
7035
0
          ret = 1;
7036
77
      else
7037
77
          ret = 0;
7038
89.9k
        } else {
7039
89.9k
            ret = (arg1->floatval == arg2->floatval);
7040
89.9k
        }
7041
111k
        break;
7042
0
    case XPATH_USERS:
7043
#ifdef LIBXML_XPTR_LOCS_ENABLED
7044
    case XPATH_POINT:
7045
    case XPATH_RANGE:
7046
    case XPATH_LOCATIONSET:
7047
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7048
0
        TODO
7049
0
        break;
7050
0
    case XPATH_NODESET:
7051
0
    case XPATH_XSLT_TREE:
7052
0
        break;
7053
116k
      }
7054
116k
      break;
7055
116k
        case XPATH_STRING:
7056
16.7k
      switch (arg2->type) {
7057
0
          case XPATH_UNDEFINED:
7058
#ifdef DEBUG_EXPR
7059
        xmlGenericError(xmlGenericErrorContext,
7060
          "Equal: undefined\n");
7061
#endif
7062
0
        break;
7063
1
    case XPATH_BOOLEAN:
7064
1
        if ((arg1->stringval == NULL) ||
7065
1
      (arg1->stringval[0] == 0)) ret = 0;
7066
1
        else
7067
1
      ret = 1;
7068
1
        ret = (arg2->boolval == ret);
7069
1
        break;
7070
15.7k
    case XPATH_STRING:
7071
15.7k
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7072
15.7k
        break;
7073
962
    case XPATH_NUMBER:
7074
962
        valuePush(ctxt, arg1);
7075
962
        xmlXPathNumberFunction(ctxt, 1);
7076
962
        arg1 = valuePop(ctxt);
7077
962
                    if (ctxt->error)
7078
1
                        break;
7079
        /* Hand check NaN and Infinity equalities */
7080
961
        if (xmlXPathIsNaN(arg1->floatval) ||
7081
961
          xmlXPathIsNaN(arg2->floatval)) {
7082
941
            ret = 0;
7083
941
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7084
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7085
0
          ret = 1;
7086
0
      else
7087
0
          ret = 0;
7088
20
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7089
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7090
0
          ret = 1;
7091
0
      else
7092
0
          ret = 0;
7093
20
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7094
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7095
0
          ret = 1;
7096
0
      else
7097
0
          ret = 0;
7098
20
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7099
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7100
0
          ret = 1;
7101
0
      else
7102
0
          ret = 0;
7103
20
        } else {
7104
20
            ret = (arg1->floatval == arg2->floatval);
7105
20
        }
7106
961
        break;
7107
0
    case XPATH_USERS:
7108
#ifdef LIBXML_XPTR_LOCS_ENABLED
7109
    case XPATH_POINT:
7110
    case XPATH_RANGE:
7111
    case XPATH_LOCATIONSET:
7112
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7113
0
        TODO
7114
0
        break;
7115
0
    case XPATH_NODESET:
7116
0
    case XPATH_XSLT_TREE:
7117
0
        break;
7118
16.7k
      }
7119
16.7k
      break;
7120
16.7k
        case XPATH_USERS:
7121
#ifdef LIBXML_XPTR_LOCS_ENABLED
7122
  case XPATH_POINT:
7123
  case XPATH_RANGE:
7124
  case XPATH_LOCATIONSET:
7125
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7126
0
      TODO
7127
0
      break;
7128
0
  case XPATH_NODESET:
7129
0
  case XPATH_XSLT_TREE:
7130
0
      break;
7131
195k
    }
7132
195k
    xmlXPathReleaseObject(ctxt->context, arg1);
7133
195k
    xmlXPathReleaseObject(ctxt->context, arg2);
7134
195k
    return(ret);
7135
195k
}
7136
7137
/**
7138
 * xmlXPathEqualValues:
7139
 * @ctxt:  the XPath Parser context
7140
 *
7141
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7142
 *
7143
 * Returns 0 or 1 depending on the results of the test.
7144
 */
7145
int
7146
370k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7147
370k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7148
370k
    int ret = 0;
7149
7150
370k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7151
370k
    arg2 = valuePop(ctxt);
7152
370k
    arg1 = valuePop(ctxt);
7153
370k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7154
0
  if (arg1 != NULL)
7155
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7156
0
  else
7157
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7158
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7159
0
    }
7160
7161
370k
    if (arg1 == arg2) {
7162
#ifdef DEBUG_EXPR
7163
        xmlGenericError(xmlGenericErrorContext,
7164
    "Equal: by pointer\n");
7165
#endif
7166
0
  xmlXPathFreeObject(arg1);
7167
0
        return(1);
7168
0
    }
7169
7170
    /*
7171
     *If either argument is a nodeset, it's a 'special case'
7172
     */
7173
370k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7174
370k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7175
  /*
7176
   *Hack it to assure arg1 is the nodeset
7177
   */
7178
186k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7179
20.4k
    argtmp = arg2;
7180
20.4k
    arg2 = arg1;
7181
20.4k
    arg1 = argtmp;
7182
20.4k
  }
7183
186k
  switch (arg2->type) {
7184
0
      case XPATH_UNDEFINED:
7185
#ifdef DEBUG_EXPR
7186
    xmlGenericError(xmlGenericErrorContext,
7187
      "Equal: undefined\n");
7188
#endif
7189
0
    break;
7190
94.7k
      case XPATH_NODESET:
7191
121k
      case XPATH_XSLT_TREE:
7192
121k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7193
121k
    break;
7194
33.8k
      case XPATH_BOOLEAN:
7195
33.8k
    if ((arg1->nodesetval == NULL) ||
7196
33.8k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7197
11.9k
    else
7198
11.9k
        ret = 1;
7199
33.8k
    ret = (ret == arg2->boolval);
7200
33.8k
    break;
7201
20.6k
      case XPATH_NUMBER:
7202
20.6k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7203
20.6k
    break;
7204
10.6k
      case XPATH_STRING:
7205
10.6k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7206
10.6k
    break;
7207
0
      case XPATH_USERS:
7208
#ifdef LIBXML_XPTR_LOCS_ENABLED
7209
      case XPATH_POINT:
7210
      case XPATH_RANGE:
7211
      case XPATH_LOCATIONSET:
7212
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7213
0
    TODO
7214
0
    break;
7215
186k
  }
7216
186k
  xmlXPathReleaseObject(ctxt->context, arg1);
7217
186k
  xmlXPathReleaseObject(ctxt->context, arg2);
7218
186k
  return(ret);
7219
186k
    }
7220
7221
184k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7222
370k
}
7223
7224
/**
7225
 * xmlXPathNotEqualValues:
7226
 * @ctxt:  the XPath Parser context
7227
 *
7228
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7229
 *
7230
 * Returns 0 or 1 depending on the results of the test.
7231
 */
7232
int
7233
64.3k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7234
64.3k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7235
64.3k
    int ret = 0;
7236
7237
64.3k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7238
64.3k
    arg2 = valuePop(ctxt);
7239
64.3k
    arg1 = valuePop(ctxt);
7240
64.3k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7241
0
  if (arg1 != NULL)
7242
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7243
0
  else
7244
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7245
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7246
0
    }
7247
7248
64.3k
    if (arg1 == arg2) {
7249
#ifdef DEBUG_EXPR
7250
        xmlGenericError(xmlGenericErrorContext,
7251
    "NotEqual: by pointer\n");
7252
#endif
7253
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7254
0
        return(0);
7255
0
    }
7256
7257
    /*
7258
     *If either argument is a nodeset, it's a 'special case'
7259
     */
7260
64.3k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7261
64.3k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7262
  /*
7263
   *Hack it to assure arg1 is the nodeset
7264
   */
7265
52.5k
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7266
14.9k
    argtmp = arg2;
7267
14.9k
    arg2 = arg1;
7268
14.9k
    arg1 = argtmp;
7269
14.9k
  }
7270
52.5k
  switch (arg2->type) {
7271
0
      case XPATH_UNDEFINED:
7272
#ifdef DEBUG_EXPR
7273
    xmlGenericError(xmlGenericErrorContext,
7274
      "NotEqual: undefined\n");
7275
#endif
7276
0
    break;
7277
26.9k
      case XPATH_NODESET:
7278
27.9k
      case XPATH_XSLT_TREE:
7279
27.9k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7280
27.9k
    break;
7281
9.38k
      case XPATH_BOOLEAN:
7282
9.38k
    if ((arg1->nodesetval == NULL) ||
7283
9.38k
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7284
2.05k
    else
7285
2.05k
        ret = 1;
7286
9.38k
    ret = (ret != arg2->boolval);
7287
9.38k
    break;
7288
13.4k
      case XPATH_NUMBER:
7289
13.4k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7290
13.4k
    break;
7291
1.71k
      case XPATH_STRING:
7292
1.71k
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7293
1.71k
    break;
7294
1
      case XPATH_USERS:
7295
#ifdef LIBXML_XPTR_LOCS_ENABLED
7296
      case XPATH_POINT:
7297
      case XPATH_RANGE:
7298
      case XPATH_LOCATIONSET:
7299
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7300
1
    TODO
7301
1
    break;
7302
52.5k
  }
7303
52.5k
  xmlXPathReleaseObject(ctxt->context, arg1);
7304
52.5k
  xmlXPathReleaseObject(ctxt->context, arg2);
7305
52.5k
  return(ret);
7306
52.5k
    }
7307
7308
11.7k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7309
64.3k
}
7310
7311
/**
7312
 * xmlXPathCompareValues:
7313
 * @ctxt:  the XPath Parser context
7314
 * @inf:  less than (1) or greater than (0)
7315
 * @strict:  is the comparison strict
7316
 *
7317
 * Implement the compare operation on XPath objects:
7318
 *     @arg1 < @arg2    (1, 1, ...
7319
 *     @arg1 <= @arg2   (1, 0, ...
7320
 *     @arg1 > @arg2    (0, 1, ...
7321
 *     @arg1 >= @arg2   (0, 0, ...
7322
 *
7323
 * When neither object to be compared is a node-set and the operator is
7324
 * <=, <, >=, >, then the objects are compared by converted both objects
7325
 * to numbers and comparing the numbers according to IEEE 754. The <
7326
 * comparison will be true if and only if the first number is less than the
7327
 * second number. The <= comparison will be true if and only if the first
7328
 * number is less than or equal to the second number. The > comparison
7329
 * will be true if and only if the first number is greater than the second
7330
 * number. The >= comparison will be true if and only if the first number
7331
 * is greater than or equal to the second number.
7332
 *
7333
 * Returns 1 if the comparison succeeded, 0 if it failed
7334
 */
7335
int
7336
693k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7337
693k
    int ret = 0, arg1i = 0, arg2i = 0;
7338
693k
    xmlXPathObjectPtr arg1, arg2;
7339
7340
693k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7341
693k
    arg2 = valuePop(ctxt);
7342
693k
    arg1 = valuePop(ctxt);
7343
693k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7344
163
  if (arg1 != NULL)
7345
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7346
163
  else
7347
163
      xmlXPathReleaseObject(ctxt->context, arg2);
7348
163
  XP_ERROR0(XPATH_INVALID_OPERAND);
7349
0
    }
7350
7351
693k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7352
693k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7353
  /*
7354
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7355
   * are not freed from within this routine; they will be freed from the
7356
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7357
   */
7358
382k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7359
382k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7360
113k
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7361
269k
  } else {
7362
269k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7363
91.8k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7364
91.8k
                                arg1, arg2);
7365
177k
      } else {
7366
177k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7367
177k
                                arg2, arg1);
7368
177k
      }
7369
269k
  }
7370
382k
  return(ret);
7371
382k
    }
7372
7373
310k
    if (arg1->type != XPATH_NUMBER) {
7374
188k
  valuePush(ctxt, arg1);
7375
188k
  xmlXPathNumberFunction(ctxt, 1);
7376
188k
  arg1 = valuePop(ctxt);
7377
188k
    }
7378
310k
    if (arg2->type != XPATH_NUMBER) {
7379
172k
  valuePush(ctxt, arg2);
7380
172k
  xmlXPathNumberFunction(ctxt, 1);
7381
172k
  arg2 = valuePop(ctxt);
7382
172k
    }
7383
310k
    if (ctxt->error)
7384
178
        goto error;
7385
    /*
7386
     * Add tests for infinity and nan
7387
     * => feedback on 3.4 for Inf and NaN
7388
     */
7389
    /* Hand check NaN and Infinity comparisons */
7390
310k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7391
153k
  ret=0;
7392
156k
    } else {
7393
156k
  arg1i=xmlXPathIsInf(arg1->floatval);
7394
156k
  arg2i=xmlXPathIsInf(arg2->floatval);
7395
156k
  if (inf && strict) {
7396
150k
      if ((arg1i == -1 && arg2i != -1) ||
7397
150k
    (arg2i == 1 && arg1i != 1)) {
7398
0
    ret = 1;
7399
150k
      } else if (arg1i == 0 && arg2i == 0) {
7400
150k
    ret = (arg1->floatval < arg2->floatval);
7401
150k
      } else {
7402
432
    ret = 0;
7403
432
      }
7404
150k
  }
7405
5.67k
  else if (inf && !strict) {
7406
426
      if (arg1i == -1 || arg2i == 1) {
7407
0
    ret = 1;
7408
426
      } else if (arg1i == 0 && arg2i == 0) {
7409
426
    ret = (arg1->floatval <= arg2->floatval);
7410
426
      } else {
7411
0
    ret = 0;
7412
0
      }
7413
426
  }
7414
5.24k
  else if (!inf && strict) {
7415
4.81k
      if ((arg1i == 1 && arg2i != 1) ||
7416
4.81k
    (arg2i == -1 && arg1i != -1)) {
7417
478
    ret = 1;
7418
4.33k
      } else if (arg1i == 0 && arg2i == 0) {
7419
3.69k
    ret = (arg1->floatval > arg2->floatval);
7420
3.69k
      } else {
7421
639
    ret = 0;
7422
639
      }
7423
4.81k
  }
7424
435
  else if (!inf && !strict) {
7425
435
      if (arg1i == 1 || arg2i == -1) {
7426
265
    ret = 1;
7427
265
      } else if (arg1i == 0 && arg2i == 0) {
7428
97
    ret = (arg1->floatval >= arg2->floatval);
7429
97
      } else {
7430
73
    ret = 0;
7431
73
      }
7432
435
  }
7433
156k
    }
7434
310k
error:
7435
310k
    xmlXPathReleaseObject(ctxt->context, arg1);
7436
310k
    xmlXPathReleaseObject(ctxt->context, arg2);
7437
310k
    return(ret);
7438
310k
}
7439
7440
/**
7441
 * xmlXPathValueFlipSign:
7442
 * @ctxt:  the XPath Parser context
7443
 *
7444
 * Implement the unary - operation on an XPath object
7445
 * The numeric operators convert their operands to numbers as if
7446
 * by calling the number function.
7447
 */
7448
void
7449
205k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7450
205k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7451
205k
    CAST_TO_NUMBER;
7452
205k
    CHECK_TYPE(XPATH_NUMBER);
7453
204k
    ctxt->value->floatval = -ctxt->value->floatval;
7454
204k
}
7455
7456
/**
7457
 * xmlXPathAddValues:
7458
 * @ctxt:  the XPath Parser context
7459
 *
7460
 * Implement the add operation on XPath objects:
7461
 * The numeric operators convert their operands to numbers as if
7462
 * by calling the number function.
7463
 */
7464
void
7465
54.6k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7466
54.6k
    xmlXPathObjectPtr arg;
7467
54.6k
    double val;
7468
7469
54.6k
    arg = valuePop(ctxt);
7470
54.6k
    if (arg == NULL)
7471
54.6k
  XP_ERROR(XPATH_INVALID_OPERAND);
7472
54.6k
    val = xmlXPathCastToNumber(arg);
7473
54.6k
    xmlXPathReleaseObject(ctxt->context, arg);
7474
54.6k
    CAST_TO_NUMBER;
7475
54.6k
    CHECK_TYPE(XPATH_NUMBER);
7476
54.2k
    ctxt->value->floatval += val;
7477
54.2k
}
7478
7479
/**
7480
 * xmlXPathSubValues:
7481
 * @ctxt:  the XPath Parser context
7482
 *
7483
 * Implement the subtraction operation on XPath objects:
7484
 * The numeric operators convert their operands to numbers as if
7485
 * by calling the number function.
7486
 */
7487
void
7488
75.5k
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7489
75.5k
    xmlXPathObjectPtr arg;
7490
75.5k
    double val;
7491
7492
75.5k
    arg = valuePop(ctxt);
7493
75.5k
    if (arg == NULL)
7494
75.5k
  XP_ERROR(XPATH_INVALID_OPERAND);
7495
75.5k
    val = xmlXPathCastToNumber(arg);
7496
75.5k
    xmlXPathReleaseObject(ctxt->context, arg);
7497
75.5k
    CAST_TO_NUMBER;
7498
75.5k
    CHECK_TYPE(XPATH_NUMBER);
7499
74.5k
    ctxt->value->floatval -= val;
7500
74.5k
}
7501
7502
/**
7503
 * xmlXPathMultValues:
7504
 * @ctxt:  the XPath Parser context
7505
 *
7506
 * Implement the multiply operation on XPath objects:
7507
 * The numeric operators convert their operands to numbers as if
7508
 * by calling the number function.
7509
 */
7510
void
7511
119k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7512
119k
    xmlXPathObjectPtr arg;
7513
119k
    double val;
7514
7515
119k
    arg = valuePop(ctxt);
7516
119k
    if (arg == NULL)
7517
119k
  XP_ERROR(XPATH_INVALID_OPERAND);
7518
119k
    val = xmlXPathCastToNumber(arg);
7519
119k
    xmlXPathReleaseObject(ctxt->context, arg);
7520
119k
    CAST_TO_NUMBER;
7521
119k
    CHECK_TYPE(XPATH_NUMBER);
7522
119k
    ctxt->value->floatval *= val;
7523
119k
}
7524
7525
/**
7526
 * xmlXPathDivValues:
7527
 * @ctxt:  the XPath Parser context
7528
 *
7529
 * Implement the div operation on XPath objects @arg1 / @arg2:
7530
 * The numeric operators convert their operands to numbers as if
7531
 * by calling the number function.
7532
 */
7533
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7534
void
7535
1.02k
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7536
1.02k
    xmlXPathObjectPtr arg;
7537
1.02k
    double val;
7538
7539
1.02k
    arg = valuePop(ctxt);
7540
1.02k
    if (arg == NULL)
7541
1.02k
  XP_ERROR(XPATH_INVALID_OPERAND);
7542
1.02k
    val = xmlXPathCastToNumber(arg);
7543
1.02k
    xmlXPathReleaseObject(ctxt->context, arg);
7544
1.02k
    CAST_TO_NUMBER;
7545
1.02k
    CHECK_TYPE(XPATH_NUMBER);
7546
1.02k
    ctxt->value->floatval /= val;
7547
1.02k
}
7548
7549
/**
7550
 * xmlXPathModValues:
7551
 * @ctxt:  the XPath Parser context
7552
 *
7553
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7554
 * The numeric operators convert their operands to numbers as if
7555
 * by calling the number function.
7556
 */
7557
void
7558
56.0k
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7559
56.0k
    xmlXPathObjectPtr arg;
7560
56.0k
    double arg1, arg2;
7561
7562
56.0k
    arg = valuePop(ctxt);
7563
56.0k
    if (arg == NULL)
7564
56.0k
  XP_ERROR(XPATH_INVALID_OPERAND);
7565
56.0k
    arg2 = xmlXPathCastToNumber(arg);
7566
56.0k
    xmlXPathReleaseObject(ctxt->context, arg);
7567
56.0k
    CAST_TO_NUMBER;
7568
56.0k
    CHECK_TYPE(XPATH_NUMBER);
7569
55.7k
    arg1 = ctxt->value->floatval;
7570
55.7k
    if (arg2 == 0)
7571
3.50k
  ctxt->value->floatval = xmlXPathNAN;
7572
52.2k
    else {
7573
52.2k
  ctxt->value->floatval = fmod(arg1, arg2);
7574
52.2k
    }
7575
55.7k
}
7576
7577
/************************************************************************
7578
 *                  *
7579
 *    The traversal functions         *
7580
 *                  *
7581
 ************************************************************************/
7582
7583
/*
7584
 * A traversal function enumerates nodes along an axis.
7585
 * Initially it must be called with NULL, and it indicates
7586
 * termination on the axis by returning NULL.
7587
 */
7588
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7589
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7590
7591
/*
7592
 * xmlXPathTraversalFunctionExt:
7593
 * A traversal function enumerates nodes along an axis.
7594
 * Initially it must be called with NULL, and it indicates
7595
 * termination on the axis by returning NULL.
7596
 * The context node of the traversal is specified via @contextNode.
7597
 */
7598
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7599
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7600
7601
/*
7602
 * xmlXPathNodeSetMergeFunction:
7603
 * Used for merging node sets in xmlXPathCollectAndTest().
7604
 */
7605
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7606
        (xmlNodeSetPtr, xmlNodeSetPtr);
7607
7608
7609
/**
7610
 * xmlXPathNextSelf:
7611
 * @ctxt:  the XPath Parser context
7612
 * @cur:  the current node in the traversal
7613
 *
7614
 * Traversal function for the "self" direction
7615
 * The self axis contains just the context node itself
7616
 *
7617
 * Returns the next element following that axis
7618
 */
7619
xmlNodePtr
7620
2.88k
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7621
2.88k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7622
2.88k
    if (cur == NULL)
7623
1.44k
        return(ctxt->context->node);
7624
1.44k
    return(NULL);
7625
2.88k
}
7626
7627
/**
7628
 * xmlXPathNextChild:
7629
 * @ctxt:  the XPath Parser context
7630
 * @cur:  the current node in the traversal
7631
 *
7632
 * Traversal function for the "child" direction
7633
 * The child axis contains the children of the context node in document order.
7634
 *
7635
 * Returns the next element following that axis
7636
 */
7637
xmlNodePtr
7638
1.20M
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7639
1.20M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7640
1.20M
    if (cur == NULL) {
7641
619k
  if (ctxt->context->node == NULL) return(NULL);
7642
619k
  switch (ctxt->context->node->type) {
7643
333k
            case XML_ELEMENT_NODE:
7644
563k
            case XML_TEXT_NODE:
7645
563k
            case XML_CDATA_SECTION_NODE:
7646
563k
            case XML_ENTITY_REF_NODE:
7647
563k
            case XML_ENTITY_NODE:
7648
566k
            case XML_PI_NODE:
7649
574k
            case XML_COMMENT_NODE:
7650
574k
            case XML_NOTATION_NODE:
7651
574k
            case XML_DTD_NODE:
7652
574k
    return(ctxt->context->node->children);
7653
12.2k
            case XML_DOCUMENT_NODE:
7654
12.2k
            case XML_DOCUMENT_TYPE_NODE:
7655
12.2k
            case XML_DOCUMENT_FRAG_NODE:
7656
12.2k
            case XML_HTML_DOCUMENT_NODE:
7657
12.2k
    return(((xmlDocPtr) ctxt->context->node)->children);
7658
0
      case XML_ELEMENT_DECL:
7659
0
      case XML_ATTRIBUTE_DECL:
7660
0
      case XML_ENTITY_DECL:
7661
1.89k
            case XML_ATTRIBUTE_NODE:
7662
32.8k
      case XML_NAMESPACE_DECL:
7663
32.8k
      case XML_XINCLUDE_START:
7664
32.8k
      case XML_XINCLUDE_END:
7665
32.8k
    return(NULL);
7666
619k
  }
7667
0
  return(NULL);
7668
619k
    }
7669
582k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7670
582k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7671
0
  return(NULL);
7672
582k
    return(cur->next);
7673
582k
}
7674
7675
/**
7676
 * xmlXPathNextChildElement:
7677
 * @ctxt:  the XPath Parser context
7678
 * @cur:  the current node in the traversal
7679
 *
7680
 * Traversal function for the "child" direction and nodes of type element.
7681
 * The child axis contains the children of the context node in document order.
7682
 *
7683
 * Returns the next element following that axis
7684
 */
7685
static xmlNodePtr
7686
4.57M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687
4.57M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688
4.57M
    if (cur == NULL) {
7689
1.32M
  cur = ctxt->context->node;
7690
1.32M
  if (cur == NULL) return(NULL);
7691
  /*
7692
  * Get the first element child.
7693
  */
7694
1.32M
  switch (cur->type) {
7695
921k
            case XML_ELEMENT_NODE:
7696
921k
      case XML_DOCUMENT_FRAG_NODE:
7697
921k
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698
921k
            case XML_ENTITY_NODE:
7699
921k
    cur = cur->children;
7700
921k
    if (cur != NULL) {
7701
504k
        if (cur->type == XML_ELEMENT_NODE)
7702
74.0k
      return(cur);
7703
497k
        do {
7704
497k
      cur = cur->next;
7705
497k
        } while ((cur != NULL) &&
7706
497k
      (cur->type != XML_ELEMENT_NODE));
7707
430k
        return(cur);
7708
504k
    }
7709
416k
    return(NULL);
7710
223k
            case XML_DOCUMENT_NODE:
7711
223k
            case XML_HTML_DOCUMENT_NODE:
7712
223k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7713
185k
      default:
7714
185k
    return(NULL);
7715
1.32M
  }
7716
0
  return(NULL);
7717
1.32M
    }
7718
    /*
7719
    * Get the next sibling element node.
7720
    */
7721
3.24M
    switch (cur->type) {
7722
3.24M
  case XML_ELEMENT_NODE:
7723
3.24M
  case XML_TEXT_NODE:
7724
3.24M
  case XML_ENTITY_REF_NODE:
7725
3.24M
  case XML_ENTITY_NODE:
7726
3.24M
  case XML_CDATA_SECTION_NODE:
7727
3.24M
  case XML_PI_NODE:
7728
3.24M
  case XML_COMMENT_NODE:
7729
3.24M
  case XML_XINCLUDE_END:
7730
3.24M
      break;
7731
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7732
0
  default:
7733
0
      return(NULL);
7734
3.24M
    }
7735
3.24M
    if (cur->next != NULL) {
7736
2.96M
  if (cur->next->type == XML_ELEMENT_NODE)
7737
2.39M
      return(cur->next);
7738
572k
  cur = cur->next;
7739
804k
  do {
7740
804k
      cur = cur->next;
7741
804k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7742
572k
  return(cur);
7743
2.96M
    }
7744
283k
    return(NULL);
7745
3.24M
}
7746
7747
#if 0
7748
/**
7749
 * xmlXPathNextDescendantOrSelfElemParent:
7750
 * @ctxt:  the XPath Parser context
7751
 * @cur:  the current node in the traversal
7752
 *
7753
 * Traversal function for the "descendant-or-self" axis.
7754
 * Additionally it returns only nodes which can be parents of
7755
 * element nodes.
7756
 *
7757
 *
7758
 * Returns the next element following that axis
7759
 */
7760
static xmlNodePtr
7761
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7762
               xmlNodePtr contextNode)
7763
{
7764
    if (cur == NULL) {
7765
  if (contextNode == NULL)
7766
      return(NULL);
7767
  switch (contextNode->type) {
7768
      case XML_ELEMENT_NODE:
7769
      case XML_XINCLUDE_START:
7770
      case XML_DOCUMENT_FRAG_NODE:
7771
      case XML_DOCUMENT_NODE:
7772
      case XML_HTML_DOCUMENT_NODE:
7773
    return(contextNode);
7774
      default:
7775
    return(NULL);
7776
  }
7777
  return(NULL);
7778
    } else {
7779
  xmlNodePtr start = cur;
7780
7781
  while (cur != NULL) {
7782
      switch (cur->type) {
7783
    case XML_ELEMENT_NODE:
7784
    /* TODO: OK to have XInclude here? */
7785
    case XML_XINCLUDE_START:
7786
    case XML_DOCUMENT_FRAG_NODE:
7787
        if (cur != start)
7788
      return(cur);
7789
        if (cur->children != NULL) {
7790
      cur = cur->children;
7791
      continue;
7792
        }
7793
        break;
7794
    /* Not sure if we need those here. */
7795
    case XML_DOCUMENT_NODE:
7796
    case XML_HTML_DOCUMENT_NODE:
7797
        if (cur != start)
7798
      return(cur);
7799
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7800
    default:
7801
        break;
7802
      }
7803
7804
next_sibling:
7805
      if ((cur == NULL) || (cur == contextNode))
7806
    return(NULL);
7807
      if (cur->next != NULL) {
7808
    cur = cur->next;
7809
      } else {
7810
    cur = cur->parent;
7811
    goto next_sibling;
7812
      }
7813
  }
7814
    }
7815
    return(NULL);
7816
}
7817
#endif
7818
7819
/**
7820
 * xmlXPathNextDescendant:
7821
 * @ctxt:  the XPath Parser context
7822
 * @cur:  the current node in the traversal
7823
 *
7824
 * Traversal function for the "descendant" direction
7825
 * the descendant axis contains the descendants of the context node in document
7826
 * order; a descendant is a child or a child of a child and so on.
7827
 *
7828
 * Returns the next element following that axis
7829
 */
7830
xmlNodePtr
7831
8.37M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7832
8.37M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7833
8.37M
    if (cur == NULL) {
7834
179k
  if (ctxt->context->node == NULL)
7835
0
      return(NULL);
7836
179k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7837
179k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7838
601
      return(NULL);
7839
7840
179k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7841
124k
      return(ctxt->context->doc->children);
7842
54.0k
        return(ctxt->context->node->children);
7843
179k
    }
7844
7845
8.19M
    if (cur->type == XML_NAMESPACE_DECL)
7846
0
        return(NULL);
7847
8.19M
    if (cur->children != NULL) {
7848
  /*
7849
   * Do not descend on entities declarations
7850
   */
7851
1.52M
  if (cur->children->type != XML_ENTITY_DECL) {
7852
1.52M
      cur = cur->children;
7853
      /*
7854
       * Skip DTDs
7855
       */
7856
1.52M
      if (cur->type != XML_DTD_NODE)
7857
1.52M
    return(cur);
7858
1.52M
  }
7859
1.52M
    }
7860
7861
6.67M
    if (cur == ctxt->context->node) return(NULL);
7862
7863
6.67M
    while (cur->next != NULL) {
7864
5.53M
  cur = cur->next;
7865
5.53M
  if ((cur->type != XML_ENTITY_DECL) &&
7866
5.53M
      (cur->type != XML_DTD_NODE))
7867
5.53M
      return(cur);
7868
5.53M
    }
7869
7870
1.65M
    do {
7871
1.65M
        cur = cur->parent;
7872
1.65M
  if (cur == NULL) break;
7873
1.65M
  if (cur == ctxt->context->node) return(NULL);
7874
1.48M
  if (cur->next != NULL) {
7875
962k
      cur = cur->next;
7876
962k
      return(cur);
7877
962k
  }
7878
1.48M
    } while (cur != NULL);
7879
0
    return(cur);
7880
1.13M
}
7881
7882
/**
7883
 * xmlXPathNextDescendantOrSelf:
7884
 * @ctxt:  the XPath Parser context
7885
 * @cur:  the current node in the traversal
7886
 *
7887
 * Traversal function for the "descendant-or-self" direction
7888
 * the descendant-or-self axis contains the context node and the descendants
7889
 * of the context node in document order; thus the context node is the first
7890
 * node on the axis, and the first child of the context node is the second node
7891
 * on the axis
7892
 *
7893
 * Returns the next element following that axis
7894
 */
7895
xmlNodePtr
7896
2.00M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7897
2.00M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7898
2.00M
    if (cur == NULL)
7899
121k
        return(ctxt->context->node);
7900
7901
1.88M
    if (ctxt->context->node == NULL)
7902
0
        return(NULL);
7903
1.88M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7904
1.88M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7905
29.4k
        return(NULL);
7906
7907
1.85M
    return(xmlXPathNextDescendant(ctxt, cur));
7908
1.88M
}
7909
7910
/**
7911
 * xmlXPathNextParent:
7912
 * @ctxt:  the XPath Parser context
7913
 * @cur:  the current node in the traversal
7914
 *
7915
 * Traversal function for the "parent" direction
7916
 * The parent axis contains the parent of the context node, if there is one.
7917
 *
7918
 * Returns the next element following that axis
7919
 */
7920
xmlNodePtr
7921
276k
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922
276k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923
    /*
7924
     * the parent of an attribute or namespace node is the element
7925
     * to which the attribute or namespace node is attached
7926
     * Namespace handling !!!
7927
     */
7928
276k
    if (cur == NULL) {
7929
143k
  if (ctxt->context->node == NULL) return(NULL);
7930
143k
  switch (ctxt->context->node->type) {
7931
69.4k
            case XML_ELEMENT_NODE:
7932
111k
            case XML_TEXT_NODE:
7933
111k
            case XML_CDATA_SECTION_NODE:
7934
111k
            case XML_ENTITY_REF_NODE:
7935
111k
            case XML_ENTITY_NODE:
7936
116k
            case XML_PI_NODE:
7937
119k
            case XML_COMMENT_NODE:
7938
119k
            case XML_NOTATION_NODE:
7939
119k
            case XML_DTD_NODE:
7940
119k
      case XML_ELEMENT_DECL:
7941
119k
      case XML_ATTRIBUTE_DECL:
7942
119k
      case XML_XINCLUDE_START:
7943
119k
      case XML_XINCLUDE_END:
7944
119k
      case XML_ENTITY_DECL:
7945
119k
    if (ctxt->context->node->parent == NULL)
7946
0
        return((xmlNodePtr) ctxt->context->doc);
7947
119k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7948
119k
        ((ctxt->context->node->parent->name[0] == ' ') ||
7949
111k
         (xmlStrEqual(ctxt->context->node->parent->name,
7950
111k
         BAD_CAST "fake node libxslt"))))
7951
0
        return(NULL);
7952
119k
    return(ctxt->context->node->parent);
7953
392
            case XML_ATTRIBUTE_NODE: {
7954
392
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7955
7956
392
    return(att->parent);
7957
119k
      }
7958
10.3k
            case XML_DOCUMENT_NODE:
7959
10.3k
            case XML_DOCUMENT_TYPE_NODE:
7960
10.3k
            case XML_DOCUMENT_FRAG_NODE:
7961
10.3k
            case XML_HTML_DOCUMENT_NODE:
7962
10.3k
                return(NULL);
7963
13.0k
      case XML_NAMESPACE_DECL: {
7964
13.0k
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7965
7966
13.0k
    if ((ns->next != NULL) &&
7967
13.0k
        (ns->next->type != XML_NAMESPACE_DECL))
7968
13.0k
        return((xmlNodePtr) ns->next);
7969
0
                return(NULL);
7970
13.0k
      }
7971
143k
  }
7972
143k
    }
7973
133k
    return(NULL);
7974
276k
}
7975
7976
/**
7977
 * xmlXPathNextAncestor:
7978
 * @ctxt:  the XPath Parser context
7979
 * @cur:  the current node in the traversal
7980
 *
7981
 * Traversal function for the "ancestor" direction
7982
 * the ancestor axis contains the ancestors of the context node; the ancestors
7983
 * of the context node consist of the parent of context node and the parent's
7984
 * parent and so on; the nodes are ordered in reverse document order; thus the
7985
 * parent is the first node on the axis, and the parent's parent is the second
7986
 * node on the axis
7987
 *
7988
 * Returns the next element following that axis
7989
 */
7990
xmlNodePtr
7991
52.6k
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7992
52.6k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7993
    /*
7994
     * the parent of an attribute or namespace node is the element
7995
     * to which the attribute or namespace node is attached
7996
     * !!!!!!!!!!!!!
7997
     */
7998
52.6k
    if (cur == NULL) {
7999
392
  if (ctxt->context->node == NULL) return(NULL);
8000
392
  switch (ctxt->context->node->type) {
8001
392
            case XML_ELEMENT_NODE:
8002
392
            case XML_TEXT_NODE:
8003
392
            case XML_CDATA_SECTION_NODE:
8004
392
            case XML_ENTITY_REF_NODE:
8005
392
            case XML_ENTITY_NODE:
8006
392
            case XML_PI_NODE:
8007
392
            case XML_COMMENT_NODE:
8008
392
      case XML_DTD_NODE:
8009
392
      case XML_ELEMENT_DECL:
8010
392
      case XML_ATTRIBUTE_DECL:
8011
392
      case XML_ENTITY_DECL:
8012
392
            case XML_NOTATION_NODE:
8013
392
      case XML_XINCLUDE_START:
8014
392
      case XML_XINCLUDE_END:
8015
392
    if (ctxt->context->node->parent == NULL)
8016
0
        return((xmlNodePtr) ctxt->context->doc);
8017
392
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8018
392
        ((ctxt->context->node->parent->name[0] == ' ') ||
8019
391
         (xmlStrEqual(ctxt->context->node->parent->name,
8020
391
         BAD_CAST "fake node libxslt"))))
8021
0
        return(NULL);
8022
392
    return(ctxt->context->node->parent);
8023
0
            case XML_ATTRIBUTE_NODE: {
8024
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8025
8026
0
    return(tmp->parent);
8027
392
      }
8028
0
            case XML_DOCUMENT_NODE:
8029
0
            case XML_DOCUMENT_TYPE_NODE:
8030
0
            case XML_DOCUMENT_FRAG_NODE:
8031
0
            case XML_HTML_DOCUMENT_NODE:
8032
0
                return(NULL);
8033
0
      case XML_NAMESPACE_DECL: {
8034
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8035
8036
0
    if ((ns->next != NULL) &&
8037
0
        (ns->next->type != XML_NAMESPACE_DECL))
8038
0
        return((xmlNodePtr) ns->next);
8039
    /* Bad, how did that namespace end up here ? */
8040
0
                return(NULL);
8041
0
      }
8042
392
  }
8043
0
  return(NULL);
8044
392
    }
8045
52.2k
    if (cur == ctxt->context->doc->children)
8046
4.52k
  return((xmlNodePtr) ctxt->context->doc);
8047
47.7k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8048
623
  return(NULL);
8049
47.0k
    switch (cur->type) {
8050
45.7k
  case XML_ELEMENT_NODE:
8051
47.0k
  case XML_TEXT_NODE:
8052
47.0k
  case XML_CDATA_SECTION_NODE:
8053
47.0k
  case XML_ENTITY_REF_NODE:
8054
47.0k
  case XML_ENTITY_NODE:
8055
47.0k
  case XML_PI_NODE:
8056
47.0k
  case XML_COMMENT_NODE:
8057
47.0k
  case XML_NOTATION_NODE:
8058
47.0k
  case XML_DTD_NODE:
8059
47.0k
        case XML_ELEMENT_DECL:
8060
47.0k
        case XML_ATTRIBUTE_DECL:
8061
47.0k
        case XML_ENTITY_DECL:
8062
47.0k
  case XML_XINCLUDE_START:
8063
47.0k
  case XML_XINCLUDE_END:
8064
47.0k
      if (cur->parent == NULL)
8065
0
    return(NULL);
8066
47.0k
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8067
47.0k
    ((cur->parent->name[0] == ' ') ||
8068
47.0k
     (xmlStrEqual(cur->parent->name,
8069
47.0k
            BAD_CAST "fake node libxslt"))))
8070
0
    return(NULL);
8071
47.0k
      return(cur->parent);
8072
0
  case XML_ATTRIBUTE_NODE: {
8073
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8074
8075
0
      return(att->parent);
8076
47.0k
  }
8077
0
  case XML_NAMESPACE_DECL: {
8078
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8079
8080
0
      if ((ns->next != NULL) &&
8081
0
          (ns->next->type != XML_NAMESPACE_DECL))
8082
0
          return((xmlNodePtr) ns->next);
8083
      /* Bad, how did that namespace end up here ? */
8084
0
            return(NULL);
8085
0
  }
8086
0
  case XML_DOCUMENT_NODE:
8087
0
  case XML_DOCUMENT_TYPE_NODE:
8088
0
  case XML_DOCUMENT_FRAG_NODE:
8089
0
  case XML_HTML_DOCUMENT_NODE:
8090
0
      return(NULL);
8091
47.0k
    }
8092
0
    return(NULL);
8093
47.0k
}
8094
8095
/**
8096
 * xmlXPathNextAncestorOrSelf:
8097
 * @ctxt:  the XPath Parser context
8098
 * @cur:  the current node in the traversal
8099
 *
8100
 * Traversal function for the "ancestor-or-self" direction
8101
 * he ancestor-or-self axis contains the context node and ancestors of
8102
 * the context node in reverse document order; thus the context node is
8103
 * the first node on the axis, and the context node's parent the second;
8104
 * parent here is defined the same as with the parent axis.
8105
 *
8106
 * Returns the next element following that axis
8107
 */
8108
xmlNodePtr
8109
5.68k
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8110
5.68k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8111
5.68k
    if (cur == NULL)
8112
232
        return(ctxt->context->node);
8113
5.45k
    return(xmlXPathNextAncestor(ctxt, cur));
8114
5.68k
}
8115
8116
/**
8117
 * xmlXPathNextFollowingSibling:
8118
 * @ctxt:  the XPath Parser context
8119
 * @cur:  the current node in the traversal
8120
 *
8121
 * Traversal function for the "following-sibling" direction
8122
 * The following-sibling axis contains the following siblings of the context
8123
 * node in document order.
8124
 *
8125
 * Returns the next element following that axis
8126
 */
8127
xmlNodePtr
8128
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8129
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8130
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8131
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8132
0
  return(NULL);
8133
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8134
0
        return(NULL);
8135
0
    if (cur == NULL)
8136
0
        return(ctxt->context->node->next);
8137
0
    return(cur->next);
8138
0
}
8139
8140
/**
8141
 * xmlXPathNextPrecedingSibling:
8142
 * @ctxt:  the XPath Parser context
8143
 * @cur:  the current node in the traversal
8144
 *
8145
 * Traversal function for the "preceding-sibling" direction
8146
 * The preceding-sibling axis contains the preceding siblings of the context
8147
 * node in reverse document order; the first preceding sibling is first on the
8148
 * axis; the sibling preceding that node is the second on the axis and so on.
8149
 *
8150
 * Returns the next element following that axis
8151
 */
8152
xmlNodePtr
8153
365k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154
365k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155
365k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156
365k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8157
416
  return(NULL);
8158
365k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8159
0
        return(NULL);
8160
365k
    if (cur == NULL)
8161
260
        return(ctxt->context->node->prev);
8162
365k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8163
0
  cur = cur->prev;
8164
0
  if (cur == NULL)
8165
0
      return(ctxt->context->node->prev);
8166
0
    }
8167
365k
    return(cur->prev);
8168
365k
}
8169
8170
/**
8171
 * xmlXPathNextFollowing:
8172
 * @ctxt:  the XPath Parser context
8173
 * @cur:  the current node in the traversal
8174
 *
8175
 * Traversal function for the "following" direction
8176
 * The following axis contains all nodes in the same document as the context
8177
 * node that are after the context node in document order, excluding any
8178
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8179
 * are ordered in document order
8180
 *
8181
 * Returns the next element following that axis
8182
 */
8183
xmlNodePtr
8184
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8185
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8186
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8187
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8188
0
        return(cur->children);
8189
8190
0
    if (cur == NULL) {
8191
0
        cur = ctxt->context->node;
8192
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8193
0
            cur = cur->parent;
8194
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8195
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8196
8197
0
            if ((ns->next == NULL) ||
8198
0
                (ns->next->type == XML_NAMESPACE_DECL))
8199
0
                return (NULL);
8200
0
            cur = (xmlNodePtr) ns->next;
8201
0
        }
8202
0
    }
8203
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8204
0
    if (cur->next != NULL) return(cur->next) ;
8205
0
    do {
8206
0
        cur = cur->parent;
8207
0
        if (cur == NULL) break;
8208
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8209
0
        if (cur->next != NULL) return(cur->next);
8210
0
    } while (cur != NULL);
8211
0
    return(cur);
8212
0
}
8213
8214
/*
8215
 * xmlXPathIsAncestor:
8216
 * @ancestor:  the ancestor node
8217
 * @node:  the current node
8218
 *
8219
 * Check that @ancestor is a @node's ancestor
8220
 *
8221
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8222
 */
8223
static int
8224
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8225
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8226
0
    if (node->type == XML_NAMESPACE_DECL)
8227
0
        return(0);
8228
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8229
0
        return(0);
8230
    /* nodes need to be in the same document */
8231
0
    if (ancestor->doc != node->doc) return(0);
8232
    /* avoid searching if ancestor or node is the root node */
8233
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8234
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8235
0
    while (node->parent != NULL) {
8236
0
        if (node->parent == ancestor)
8237
0
            return(1);
8238
0
  node = node->parent;
8239
0
    }
8240
0
    return(0);
8241
0
}
8242
8243
/**
8244
 * xmlXPathNextPreceding:
8245
 * @ctxt:  the XPath Parser context
8246
 * @cur:  the current node in the traversal
8247
 *
8248
 * Traversal function for the "preceding" direction
8249
 * the preceding axis contains all nodes in the same document as the context
8250
 * node that are before the context node in document order, excluding any
8251
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8252
 * ordered in reverse document order
8253
 *
8254
 * Returns the next element following that axis
8255
 */
8256
xmlNodePtr
8257
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8258
0
{
8259
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8260
0
    if (cur == NULL) {
8261
0
        cur = ctxt->context->node;
8262
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8263
0
            cur = cur->parent;
8264
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8265
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8266
8267
0
            if ((ns->next == NULL) ||
8268
0
                (ns->next->type == XML_NAMESPACE_DECL))
8269
0
                return (NULL);
8270
0
            cur = (xmlNodePtr) ns->next;
8271
0
        }
8272
0
    }
8273
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8274
0
  return (NULL);
8275
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8276
0
  cur = cur->prev;
8277
0
    do {
8278
0
        if (cur->prev != NULL) {
8279
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8280
0
            return (cur);
8281
0
        }
8282
8283
0
        cur = cur->parent;
8284
0
        if (cur == NULL)
8285
0
            return (NULL);
8286
0
        if (cur == ctxt->context->doc->children)
8287
0
            return (NULL);
8288
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8289
0
    return (cur);
8290
0
}
8291
8292
/**
8293
 * xmlXPathNextPrecedingInternal:
8294
 * @ctxt:  the XPath Parser context
8295
 * @cur:  the current node in the traversal
8296
 *
8297
 * Traversal function for the "preceding" direction
8298
 * the preceding axis contains all nodes in the same document as the context
8299
 * node that are before the context node in document order, excluding any
8300
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8301
 * ordered in reverse document order
8302
 * This is a faster implementation but internal only since it requires a
8303
 * state kept in the parser context: ctxt->ancestor.
8304
 *
8305
 * Returns the next element following that axis
8306
 */
8307
static xmlNodePtr
8308
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8309
                              xmlNodePtr cur)
8310
30
{
8311
30
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8312
30
    if (cur == NULL) {
8313
18
        cur = ctxt->context->node;
8314
18
        if (cur == NULL)
8315
0
            return (NULL);
8316
18
        if (cur->type == XML_ATTRIBUTE_NODE) {
8317
0
            cur = cur->parent;
8318
18
        } else if (cur->type == XML_NAMESPACE_DECL) {
8319
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8320
8321
0
            if ((ns->next == NULL) ||
8322
0
                (ns->next->type == XML_NAMESPACE_DECL))
8323
0
                return (NULL);
8324
0
            cur = (xmlNodePtr) ns->next;
8325
0
        }
8326
18
        ctxt->ancestor = cur->parent;
8327
18
    }
8328
30
    if (cur->type == XML_NAMESPACE_DECL)
8329
0
        return(NULL);
8330
30
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8331
0
  cur = cur->prev;
8332
42
    while (cur->prev == NULL) {
8333
36
        cur = cur->parent;
8334
36
        if (cur == NULL)
8335
12
            return (NULL);
8336
24
        if (cur == ctxt->context->doc->children)
8337
6
            return (NULL);
8338
18
        if (cur != ctxt->ancestor)
8339
6
            return (cur);
8340
12
        ctxt->ancestor = cur->parent;
8341
12
    }
8342
6
    cur = cur->prev;
8343
12
    while (cur->last != NULL)
8344
6
        cur = cur->last;
8345
6
    return (cur);
8346
30
}
8347
8348
/**
8349
 * xmlXPathNextNamespace:
8350
 * @ctxt:  the XPath Parser context
8351
 * @cur:  the current attribute in the traversal
8352
 *
8353
 * Traversal function for the "namespace" direction
8354
 * the namespace axis contains the namespace nodes of the context node;
8355
 * the order of nodes on this axis is implementation-defined; the axis will
8356
 * be empty unless the context node is an element
8357
 *
8358
 * We keep the XML namespace node at the end of the list.
8359
 *
8360
 * Returns the next element following that axis
8361
 */
8362
xmlNodePtr
8363
727k
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8364
727k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8365
727k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8366
698k
    if (cur == NULL) {
8367
151k
        if (ctxt->context->tmpNsList != NULL)
8368
11.7k
      xmlFree(ctxt->context->tmpNsList);
8369
151k
  ctxt->context->tmpNsList =
8370
151k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8371
151k
  ctxt->context->tmpNsNr = 0;
8372
151k
  if (ctxt->context->tmpNsList != NULL) {
8373
589k
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8374
438k
    ctxt->context->tmpNsNr++;
8375
438k
      }
8376
150k
  }
8377
151k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8378
151k
    }
8379
547k
    if (ctxt->context->tmpNsNr > 0) {
8380
415k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8381
415k
    } else {
8382
131k
  if (ctxt->context->tmpNsList != NULL)
8383
130k
      xmlFree(ctxt->context->tmpNsList);
8384
131k
  ctxt->context->tmpNsList = NULL;
8385
131k
  return(NULL);
8386
131k
    }
8387
547k
}
8388
8389
/**
8390
 * xmlXPathNextAttribute:
8391
 * @ctxt:  the XPath Parser context
8392
 * @cur:  the current attribute in the traversal
8393
 *
8394
 * Traversal function for the "attribute" direction
8395
 * TODO: support DTD inherited default attributes
8396
 *
8397
 * Returns the next element following that axis
8398
 */
8399
xmlNodePtr
8400
1.55M
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8401
1.55M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8402
1.55M
    if (ctxt->context->node == NULL)
8403
0
  return(NULL);
8404
1.55M
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8405
39.0k
  return(NULL);
8406
1.52M
    if (cur == NULL) {
8407
716k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8408
0
      return(NULL);
8409
716k
        return((xmlNodePtr)ctxt->context->node->properties);
8410
716k
    }
8411
803k
    return((xmlNodePtr)cur->next);
8412
1.52M
}
8413
8414
/************************************************************************
8415
 *                  *
8416
 *    NodeTest Functions          *
8417
 *                  *
8418
 ************************************************************************/
8419
8420
#define IS_FUNCTION     200
8421
8422
8423
/************************************************************************
8424
 *                  *
8425
 *    Implicit tree core function library     *
8426
 *                  *
8427
 ************************************************************************/
8428
8429
/**
8430
 * xmlXPathRoot:
8431
 * @ctxt:  the XPath Parser context
8432
 *
8433
 * Initialize the context to the root of the document
8434
 */
8435
void
8436
751k
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8437
751k
    if ((ctxt == NULL) || (ctxt->context == NULL))
8438
0
  return;
8439
751k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8440
751k
  (xmlNodePtr) ctxt->context->doc));
8441
751k
}
8442
8443
/************************************************************************
8444
 *                  *
8445
 *    The explicit core function library      *
8446
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8447
 *                  *
8448
 ************************************************************************/
8449
8450
8451
/**
8452
 * xmlXPathLastFunction:
8453
 * @ctxt:  the XPath Parser context
8454
 * @nargs:  the number of arguments
8455
 *
8456
 * Implement the last() XPath function
8457
 *    number last()
8458
 * The last function returns the number of nodes in the context node list.
8459
 */
8460
void
8461
114k
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8462
342k
    CHECK_ARITY(0);
8463
342k
    if (ctxt->context->contextSize >= 0) {
8464
114k
  valuePush(ctxt,
8465
114k
      xmlXPathCacheNewFloat(ctxt->context,
8466
114k
    (double) ctxt->context->contextSize));
8467
#ifdef DEBUG_EXPR
8468
  xmlGenericError(xmlGenericErrorContext,
8469
    "last() : %d\n", ctxt->context->contextSize);
8470
#endif
8471
114k
    } else {
8472
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8473
0
    }
8474
342k
}
8475
8476
/**
8477
 * xmlXPathPositionFunction:
8478
 * @ctxt:  the XPath Parser context
8479
 * @nargs:  the number of arguments
8480
 *
8481
 * Implement the position() XPath function
8482
 *    number position()
8483
 * The position function returns the position of the context node in the
8484
 * context node list. The first position is 1, and so the last position
8485
 * will be equal to last().
8486
 */
8487
void
8488
77.4k
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8489
231k
    CHECK_ARITY(0);
8490
231k
    if (ctxt->context->proximityPosition >= 0) {
8491
77.2k
  valuePush(ctxt,
8492
77.2k
        xmlXPathCacheNewFloat(ctxt->context,
8493
77.2k
    (double) ctxt->context->proximityPosition));
8494
#ifdef DEBUG_EXPR
8495
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8496
    ctxt->context->proximityPosition);
8497
#endif
8498
77.2k
    } else {
8499
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8500
0
    }
8501
231k
}
8502
8503
/**
8504
 * xmlXPathCountFunction:
8505
 * @ctxt:  the XPath Parser context
8506
 * @nargs:  the number of arguments
8507
 *
8508
 * Implement the count() XPath function
8509
 *    number count(node-set)
8510
 */
8511
void
8512
4.33k
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8513
4.33k
    xmlXPathObjectPtr cur;
8514
8515
12.9k
    CHECK_ARITY(1);
8516
12.9k
    if ((ctxt->value == NULL) ||
8517
4.32k
  ((ctxt->value->type != XPATH_NODESET) &&
8518
4.32k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8519
4.30k
  XP_ERROR(XPATH_INVALID_TYPE);
8520
4.30k
    cur = valuePop(ctxt);
8521
8522
4.30k
    if ((cur == NULL) || (cur->nodesetval == NULL))
8523
1.83k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8524
2.46k
    else
8525
2.46k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8526
2.46k
      (double) cur->nodesetval->nodeNr));
8527
4.30k
    xmlXPathReleaseObject(ctxt->context, cur);
8528
4.30k
}
8529
8530
/**
8531
 * xmlXPathGetElementsByIds:
8532
 * @doc:  the document
8533
 * @ids:  a whitespace separated list of IDs
8534
 *
8535
 * Selects elements by their unique ID.
8536
 *
8537
 * Returns a node-set of selected elements.
8538
 */
8539
static xmlNodeSetPtr
8540
970
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8541
970
    xmlNodeSetPtr ret;
8542
970
    const xmlChar *cur = ids;
8543
970
    xmlChar *ID;
8544
970
    xmlAttrPtr attr;
8545
970
    xmlNodePtr elem = NULL;
8546
8547
970
    if (ids == NULL) return(NULL);
8548
8549
911
    ret = xmlXPathNodeSetCreate(NULL);
8550
911
    if (ret == NULL)
8551
6
        return(ret);
8552
8553
919
    while (IS_BLANK_CH(*cur)) cur++;
8554
2.97k
    while (*cur != 0) {
8555
63.9k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8556
61.8k
      cur++;
8557
8558
2.07k
        ID = xmlStrndup(ids, cur - ids);
8559
2.07k
  if (ID != NULL) {
8560
      /*
8561
       * We used to check the fact that the value passed
8562
       * was an NCName, but this generated much troubles for
8563
       * me and Aleksey Sanin, people blatantly violated that
8564
       * constraint, like Visa3D spec.
8565
       * if (xmlValidateNCName(ID, 1) == 0)
8566
       */
8567
1.81k
      attr = xmlGetID(doc, ID);
8568
1.81k
      if (attr != NULL) {
8569
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8570
0
        elem = attr->parent;
8571
0
    else if (attr->type == XML_ELEMENT_NODE)
8572
0
        elem = (xmlNodePtr) attr;
8573
0
    else
8574
0
        elem = NULL;
8575
                /* TODO: Check memory error. */
8576
0
    if (elem != NULL)
8577
0
        xmlXPathNodeSetAdd(ret, elem);
8578
0
      }
8579
1.81k
      xmlFree(ID);
8580
1.81k
  }
8581
8582
4.59k
  while (IS_BLANK_CH(*cur)) cur++;
8583
2.07k
  ids = cur;
8584
2.07k
    }
8585
905
    return(ret);
8586
911
}
8587
8588
/**
8589
 * xmlXPathIdFunction:
8590
 * @ctxt:  the XPath Parser context
8591
 * @nargs:  the number of arguments
8592
 *
8593
 * Implement the id() XPath function
8594
 *    node-set id(object)
8595
 * The id function selects elements by their unique ID
8596
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8597
 * then the result is the union of the result of applying id to the
8598
 * string value of each of the nodes in the argument node-set. When the
8599
 * argument to id is of any other type, the argument is converted to a
8600
 * string as if by a call to the string function; the string is split
8601
 * into a whitespace-separated list of tokens (whitespace is any sequence
8602
 * of characters matching the production S); the result is a node-set
8603
 * containing the elements in the same document as the context node that
8604
 * have a unique ID equal to any of the tokens in the list.
8605
 */
8606
void
8607
1.32k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8608
1.32k
    xmlChar *tokens;
8609
1.32k
    xmlNodeSetPtr ret;
8610
1.32k
    xmlXPathObjectPtr obj;
8611
8612
3.95k
    CHECK_ARITY(1);
8613
3.95k
    obj = valuePop(ctxt);
8614
3.95k
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8615
1.31k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8616
979
  xmlNodeSetPtr ns;
8617
979
  int i;
8618
8619
        /* TODO: Check memory error. */
8620
979
  ret = xmlXPathNodeSetCreate(NULL);
8621
8622
979
  if (obj->nodesetval != NULL) {
8623
1.43k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8624
636
    tokens =
8625
636
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8626
636
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8627
                /* TODO: Check memory error. */
8628
636
    ret = xmlXPathNodeSetMerge(ret, ns);
8629
636
    xmlXPathFreeNodeSet(ns);
8630
636
    if (tokens != NULL)
8631
577
        xmlFree(tokens);
8632
636
      }
8633
800
  }
8634
979
  xmlXPathReleaseObject(ctxt->context, obj);
8635
979
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8636
979
  return;
8637
979
    }
8638
337
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8639
337
    if (obj == NULL) return;
8640
334
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8641
334
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8642
334
    xmlXPathReleaseObject(ctxt->context, obj);
8643
334
    return;
8644
337
}
8645
8646
/**
8647
 * xmlXPathLocalNameFunction:
8648
 * @ctxt:  the XPath Parser context
8649
 * @nargs:  the number of arguments
8650
 *
8651
 * Implement the local-name() XPath function
8652
 *    string local-name(node-set?)
8653
 * The local-name function returns a string containing the local part
8654
 * of the name of the node in the argument node-set that is first in
8655
 * document order. If the node-set is empty or the first node has no
8656
 * name, an empty string is returned. If the argument is omitted it
8657
 * defaults to the context node.
8658
 */
8659
void
8660
15.4k
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8661
15.4k
    xmlXPathObjectPtr cur;
8662
8663
15.4k
    if (ctxt == NULL) return;
8664
8665
15.4k
    if (nargs == 0) {
8666
13.0k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8667
13.0k
      ctxt->context->node));
8668
13.0k
  nargs = 1;
8669
13.0k
    }
8670
8671
46.3k
    CHECK_ARITY(1);
8672
46.3k
    if ((ctxt->value == NULL) ||
8673
15.4k
  ((ctxt->value->type != XPATH_NODESET) &&
8674
15.4k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8675
15.4k
  XP_ERROR(XPATH_INVALID_TYPE);
8676
15.4k
    cur = valuePop(ctxt);
8677
8678
15.4k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8679
4
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8680
15.4k
    } else {
8681
15.4k
  int i = 0; /* Should be first in document order !!!!! */
8682
15.4k
  switch (cur->nodesetval->nodeTab[i]->type) {
8683
3.98k
  case XML_ELEMENT_NODE:
8684
3.98k
  case XML_ATTRIBUTE_NODE:
8685
4.72k
  case XML_PI_NODE:
8686
4.72k
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8687
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8688
4.72k
      else
8689
4.72k
    valuePush(ctxt,
8690
4.72k
          xmlXPathCacheNewString(ctxt->context,
8691
4.72k
      cur->nodesetval->nodeTab[i]->name));
8692
4.72k
      break;
8693
2.07k
  case XML_NAMESPACE_DECL:
8694
2.07k
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8695
2.07k
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8696
2.07k
      break;
8697
8.65k
  default:
8698
8.65k
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8699
15.4k
  }
8700
15.4k
    }
8701
15.4k
    xmlXPathReleaseObject(ctxt->context, cur);
8702
15.4k
}
8703
8704
/**
8705
 * xmlXPathNamespaceURIFunction:
8706
 * @ctxt:  the XPath Parser context
8707
 * @nargs:  the number of arguments
8708
 *
8709
 * Implement the namespace-uri() XPath function
8710
 *    string namespace-uri(node-set?)
8711
 * The namespace-uri function returns a string containing the
8712
 * namespace URI of the expanded name of the node in the argument
8713
 * node-set that is first in document order. If the node-set is empty,
8714
 * the first node has no name, or the expanded name has no namespace
8715
 * URI, an empty string is returned. If the argument is omitted it
8716
 * defaults to the context node.
8717
 */
8718
void
8719
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8720
0
    xmlXPathObjectPtr cur;
8721
8722
0
    if (ctxt == NULL) return;
8723
8724
0
    if (nargs == 0) {
8725
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8726
0
      ctxt->context->node));
8727
0
  nargs = 1;
8728
0
    }
8729
0
    CHECK_ARITY(1);
8730
0
    if ((ctxt->value == NULL) ||
8731
0
  ((ctxt->value->type != XPATH_NODESET) &&
8732
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8733
0
  XP_ERROR(XPATH_INVALID_TYPE);
8734
0
    cur = valuePop(ctxt);
8735
8736
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8737
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8738
0
    } else {
8739
0
  int i = 0; /* Should be first in document order !!!!! */
8740
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8741
0
  case XML_ELEMENT_NODE:
8742
0
  case XML_ATTRIBUTE_NODE:
8743
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8744
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8745
0
      else
8746
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8747
0
        cur->nodesetval->nodeTab[i]->ns->href));
8748
0
      break;
8749
0
  default:
8750
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8751
0
  }
8752
0
    }
8753
0
    xmlXPathReleaseObject(ctxt->context, cur);
8754
0
}
8755
8756
/**
8757
 * xmlXPathNameFunction:
8758
 * @ctxt:  the XPath Parser context
8759
 * @nargs:  the number of arguments
8760
 *
8761
 * Implement the name() XPath function
8762
 *    string name(node-set?)
8763
 * The name function returns a string containing a QName representing
8764
 * the name of the node in the argument node-set that is first in document
8765
 * order. The QName must represent the name with respect to the namespace
8766
 * declarations in effect on the node whose name is being represented.
8767
 * Typically, this will be the form in which the name occurred in the XML
8768
 * source. This need not be the case if there are namespace declarations
8769
 * in effect on the node that associate multiple prefixes with the same
8770
 * namespace. However, an implementation may include information about
8771
 * the original prefix in its representation of nodes; in this case, an
8772
 * implementation can ensure that the returned string is always the same
8773
 * as the QName used in the XML source. If the argument it omitted it
8774
 * defaults to the context node.
8775
 * Libxml keep the original prefix so the "real qualified name" used is
8776
 * returned.
8777
 */
8778
static void
8779
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8780
21.9k
{
8781
21.9k
    xmlXPathObjectPtr cur;
8782
8783
21.9k
    if (nargs == 0) {
8784
21.1k
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8785
21.1k
      ctxt->context->node));
8786
21.1k
        nargs = 1;
8787
21.1k
    }
8788
8789
65.7k
    CHECK_ARITY(1);
8790
65.7k
    if ((ctxt->value == NULL) ||
8791
21.8k
        ((ctxt->value->type != XPATH_NODESET) &&
8792
21.8k
         (ctxt->value->type != XPATH_XSLT_TREE)))
8793
21.6k
        XP_ERROR(XPATH_INVALID_TYPE);
8794
21.6k
    cur = valuePop(ctxt);
8795
8796
21.6k
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8797
201
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8798
21.4k
    } else {
8799
21.4k
        int i = 0;              /* Should be first in document order !!!!! */
8800
8801
21.4k
        switch (cur->nodesetval->nodeTab[i]->type) {
8802
18.8k
            case XML_ELEMENT_NODE:
8803
19.0k
            case XML_ATTRIBUTE_NODE:
8804
19.0k
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8805
0
        valuePush(ctxt,
8806
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8807
19.0k
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8808
19.0k
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8809
808
        valuePush(ctxt,
8810
808
            xmlXPathCacheNewString(ctxt->context,
8811
808
          cur->nodesetval->nodeTab[i]->name));
8812
18.2k
    } else {
8813
18.2k
        xmlChar *fullname;
8814
8815
18.2k
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8816
18.2k
             cur->nodesetval->nodeTab[i]->ns->prefix,
8817
18.2k
             NULL, 0);
8818
18.2k
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8819
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8820
18.2k
        if (fullname == NULL)
8821
2
                        xmlXPathPErrMemory(ctxt, NULL);
8822
18.2k
        valuePush(ctxt, xmlXPathCacheWrapString(
8823
18.2k
      ctxt->context, fullname));
8824
18.2k
                }
8825
19.0k
                break;
8826
2.41k
            default:
8827
2.41k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8828
2.41k
        cur->nodesetval->nodeTab[i]));
8829
2.41k
                xmlXPathLocalNameFunction(ctxt, 1);
8830
21.4k
        }
8831
21.4k
    }
8832
21.6k
    xmlXPathReleaseObject(ctxt->context, cur);
8833
21.6k
}
8834
8835
8836
/**
8837
 * xmlXPathStringFunction:
8838
 * @ctxt:  the XPath Parser context
8839
 * @nargs:  the number of arguments
8840
 *
8841
 * Implement the string() XPath function
8842
 *    string string(object?)
8843
 * The string function converts an object to a string as follows:
8844
 *    - A node-set is converted to a string by returning the value of
8845
 *      the node in the node-set that is first in document order.
8846
 *      If the node-set is empty, an empty string is returned.
8847
 *    - A number is converted to a string as follows
8848
 *      + NaN is converted to the string NaN
8849
 *      + positive zero is converted to the string 0
8850
 *      + negative zero is converted to the string 0
8851
 *      + positive infinity is converted to the string Infinity
8852
 *      + negative infinity is converted to the string -Infinity
8853
 *      + if the number is an integer, the number is represented in
8854
 *        decimal form as a Number with no decimal point and no leading
8855
 *        zeros, preceded by a minus sign (-) if the number is negative
8856
 *      + otherwise, the number is represented in decimal form as a
8857
 *        Number including a decimal point with at least one digit
8858
 *        before the decimal point and at least one digit after the
8859
 *        decimal point, preceded by a minus sign (-) if the number
8860
 *        is negative; there must be no leading zeros before the decimal
8861
 *        point apart possibly from the one required digit immediately
8862
 *        before the decimal point; beyond the one required digit
8863
 *        after the decimal point there must be as many, but only as
8864
 *        many, more digits as are needed to uniquely distinguish the
8865
 *        number from all other IEEE 754 numeric values.
8866
 *    - The boolean false value is converted to the string false.
8867
 *      The boolean true value is converted to the string true.
8868
 *
8869
 * If the argument is omitted, it defaults to a node-set with the
8870
 * context node as its only member.
8871
 */
8872
void
8873
282k
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8874
282k
    xmlXPathObjectPtr cur;
8875
8876
282k
    if (ctxt == NULL) return;
8877
282k
    if (nargs == 0) {
8878
12
    valuePush(ctxt,
8879
12
  xmlXPathCacheWrapString(ctxt->context,
8880
12
      xmlXPathCastNodeToString(ctxt->context->node)));
8881
12
  return;
8882
12
    }
8883
8884
1.12M
    CHECK_ARITY(1);
8885
1.12M
    cur = valuePop(ctxt);
8886
1.12M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8887
281k
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8888
281k
}
8889
8890
/**
8891
 * xmlXPathStringLengthFunction:
8892
 * @ctxt:  the XPath Parser context
8893
 * @nargs:  the number of arguments
8894
 *
8895
 * Implement the string-length() XPath function
8896
 *    number string-length(string?)
8897
 * The string-length returns the number of characters in the string
8898
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8899
 * the context node converted to a string, in other words the value
8900
 * of the context node.
8901
 */
8902
void
8903
434
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8904
434
    xmlXPathObjectPtr cur;
8905
8906
434
    if (nargs == 0) {
8907
32
        if ((ctxt == NULL) || (ctxt->context == NULL))
8908
0
      return;
8909
32
  if (ctxt->context->node == NULL) {
8910
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8911
32
  } else {
8912
32
      xmlChar *content;
8913
8914
32
      content = xmlXPathCastNodeToString(ctxt->context->node);
8915
32
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8916
32
    xmlUTF8Strlen(content)));
8917
32
      xmlFree(content);
8918
32
  }
8919
32
  return;
8920
32
    }
8921
1.60k
    CHECK_ARITY(1);
8922
1.60k
    CAST_TO_STRING;
8923
1.60k
    CHECK_TYPE(XPATH_STRING);
8924
398
    cur = valuePop(ctxt);
8925
398
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8926
398
  xmlUTF8Strlen(cur->stringval)));
8927
398
    xmlXPathReleaseObject(ctxt->context, cur);
8928
398
}
8929
8930
/**
8931
 * xmlXPathConcatFunction:
8932
 * @ctxt:  the XPath Parser context
8933
 * @nargs:  the number of arguments
8934
 *
8935
 * Implement the concat() XPath function
8936
 *    string concat(string, string, string*)
8937
 * The concat function returns the concatenation of its arguments.
8938
 */
8939
void
8940
2.60k
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8941
2.60k
    xmlXPathObjectPtr cur, newobj;
8942
2.60k
    xmlChar *tmp;
8943
8944
2.60k
    if (ctxt == NULL) return;
8945
2.60k
    if (nargs < 2) {
8946
144
  CHECK_ARITY(2);
8947
144
    }
8948
8949
2.46k
    CAST_TO_STRING;
8950
2.46k
    cur = valuePop(ctxt);
8951
2.46k
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8952
0
  xmlXPathReleaseObject(ctxt->context, cur);
8953
0
  return;
8954
0
    }
8955
2.46k
    nargs--;
8956
8957
8.80k
    while (nargs > 0) {
8958
6.35k
  CAST_TO_STRING;
8959
6.35k
  newobj = valuePop(ctxt);
8960
6.35k
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8961
10
      xmlXPathReleaseObject(ctxt->context, newobj);
8962
10
      xmlXPathReleaseObject(ctxt->context, cur);
8963
10
      XP_ERROR(XPATH_INVALID_TYPE);
8964
0
  }
8965
6.34k
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8966
6.34k
  newobj->stringval = cur->stringval;
8967
6.34k
  cur->stringval = tmp;
8968
6.34k
  xmlXPathReleaseObject(ctxt->context, newobj);
8969
6.34k
  nargs--;
8970
6.34k
    }
8971
2.45k
    valuePush(ctxt, cur);
8972
2.45k
}
8973
8974
/**
8975
 * xmlXPathContainsFunction:
8976
 * @ctxt:  the XPath Parser context
8977
 * @nargs:  the number of arguments
8978
 *
8979
 * Implement the contains() XPath function
8980
 *    boolean contains(string, string)
8981
 * The contains function returns true if the first argument string
8982
 * contains the second argument string, and otherwise returns false.
8983
 */
8984
void
8985
16.5k
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8986
16.5k
    xmlXPathObjectPtr hay, needle;
8987
8988
49.7k
    CHECK_ARITY(2);
8989
49.7k
    CAST_TO_STRING;
8990
49.7k
    CHECK_TYPE(XPATH_STRING);
8991
16.5k
    needle = valuePop(ctxt);
8992
16.5k
    CAST_TO_STRING;
8993
16.5k
    hay = valuePop(ctxt);
8994
8995
16.5k
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8996
2
  xmlXPathReleaseObject(ctxt->context, hay);
8997
2
  xmlXPathReleaseObject(ctxt->context, needle);
8998
2
  XP_ERROR(XPATH_INVALID_TYPE);
8999
0
    }
9000
16.5k
    if (xmlStrstr(hay->stringval, needle->stringval))
9001
6.05k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9002
10.5k
    else
9003
10.5k
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9004
16.5k
    xmlXPathReleaseObject(ctxt->context, hay);
9005
16.5k
    xmlXPathReleaseObject(ctxt->context, needle);
9006
16.5k
}
9007
9008
/**
9009
 * xmlXPathStartsWithFunction:
9010
 * @ctxt:  the XPath Parser context
9011
 * @nargs:  the number of arguments
9012
 *
9013
 * Implement the starts-with() XPath function
9014
 *    boolean starts-with(string, string)
9015
 * The starts-with function returns true if the first argument string
9016
 * starts with the second argument string, and otherwise returns false.
9017
 */
9018
void
9019
1
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
1
    xmlXPathObjectPtr hay, needle;
9021
1
    int n;
9022
9023
1
    CHECK_ARITY(2);
9024
1
    CAST_TO_STRING;
9025
1
    CHECK_TYPE(XPATH_STRING);
9026
0
    needle = valuePop(ctxt);
9027
0
    CAST_TO_STRING;
9028
0
    hay = valuePop(ctxt);
9029
9030
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9031
0
  xmlXPathReleaseObject(ctxt->context, hay);
9032
0
  xmlXPathReleaseObject(ctxt->context, needle);
9033
0
  XP_ERROR(XPATH_INVALID_TYPE);
9034
0
    }
9035
0
    n = xmlStrlen(needle->stringval);
9036
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9037
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
0
    else
9039
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9040
0
    xmlXPathReleaseObject(ctxt->context, hay);
9041
0
    xmlXPathReleaseObject(ctxt->context, needle);
9042
0
}
9043
9044
/**
9045
 * xmlXPathSubstringFunction:
9046
 * @ctxt:  the XPath Parser context
9047
 * @nargs:  the number of arguments
9048
 *
9049
 * Implement the substring() XPath function
9050
 *    string substring(string, number, number?)
9051
 * The substring function returns the substring of the first argument
9052
 * starting at the position specified in the second argument with
9053
 * length specified in the third argument. For example,
9054
 * substring("12345",2,3) returns "234". If the third argument is not
9055
 * specified, it returns the substring starting at the position specified
9056
 * in the second argument and continuing to the end of the string. For
9057
 * example, substring("12345",2) returns "2345".  More precisely, each
9058
 * character in the string (see [3.6 Strings]) is considered to have a
9059
 * numeric position: the position of the first character is 1, the position
9060
 * of the second character is 2 and so on. The returned substring contains
9061
 * those characters for which the position of the character is greater than
9062
 * or equal to the second argument and, if the third argument is specified,
9063
 * less than the sum of the second and third arguments; the comparisons
9064
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9065
 *  - substring("12345", 1.5, 2.6) returns "234"
9066
 *  - substring("12345", 0, 3) returns "12"
9067
 *  - substring("12345", 0 div 0, 3) returns ""
9068
 *  - substring("12345", 1, 0 div 0) returns ""
9069
 *  - substring("12345", -42, 1 div 0) returns "12345"
9070
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9071
 */
9072
void
9073
19.4k
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9074
19.4k
    xmlXPathObjectPtr str, start, len;
9075
19.4k
    double le=0, in;
9076
19.4k
    int i = 1, j = INT_MAX;
9077
9078
19.4k
    if (nargs < 2) {
9079
259
  CHECK_ARITY(2);
9080
259
    }
9081
19.1k
    if (nargs > 3) {
9082
141
  CHECK_ARITY(3);
9083
141
    }
9084
    /*
9085
     * take care of possible last (position) argument
9086
    */
9087
19.0k
    if (nargs == 3) {
9088
6.16k
  CAST_TO_NUMBER;
9089
6.16k
  CHECK_TYPE(XPATH_NUMBER);
9090
6.16k
  len = valuePop(ctxt);
9091
6.16k
  le = len->floatval;
9092
6.16k
  xmlXPathReleaseObject(ctxt->context, len);
9093
6.16k
    }
9094
9095
19.0k
    CAST_TO_NUMBER;
9096
19.0k
    CHECK_TYPE(XPATH_NUMBER);
9097
19.0k
    start = valuePop(ctxt);
9098
19.0k
    in = start->floatval;
9099
19.0k
    xmlXPathReleaseObject(ctxt->context, start);
9100
19.0k
    CAST_TO_STRING;
9101
19.0k
    CHECK_TYPE(XPATH_STRING);
9102
19.0k
    str = valuePop(ctxt);
9103
9104
19.0k
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9105
1.00k
        i = INT_MAX;
9106
18.0k
    } else if (in >= 1.0) {
9107
15.8k
        i = (int)in;
9108
15.8k
        if (in - floor(in) >= 0.5)
9109
0
            i += 1;
9110
15.8k
    }
9111
9112
19.0k
    if (nargs == 3) {
9113
6.16k
        double rin, rle, end;
9114
9115
6.16k
        rin = floor(in);
9116
6.16k
        if (in - rin >= 0.5)
9117
0
            rin += 1.0;
9118
9119
6.16k
        rle = floor(le);
9120
6.16k
        if (le - rle >= 0.5)
9121
0
            rle += 1.0;
9122
9123
6.16k
        end = rin + rle;
9124
6.16k
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9125
421
            j = 1;
9126
5.74k
        } else if (end < INT_MAX) {
9127
5.61k
            j = (int)end;
9128
5.61k
        }
9129
6.16k
    }
9130
9131
19.0k
    if (i < j) {
9132
17.1k
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9133
17.1k
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9134
17.1k
  xmlFree(ret);
9135
17.1k
    } else {
9136
1.89k
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9137
1.89k
    }
9138
9139
19.0k
    xmlXPathReleaseObject(ctxt->context, str);
9140
19.0k
}
9141
9142
/**
9143
 * xmlXPathSubstringBeforeFunction:
9144
 * @ctxt:  the XPath Parser context
9145
 * @nargs:  the number of arguments
9146
 *
9147
 * Implement the substring-before() XPath function
9148
 *    string substring-before(string, string)
9149
 * The substring-before function returns the substring of the first
9150
 * argument string that precedes the first occurrence of the second
9151
 * argument string in the first argument string, or the empty string
9152
 * if the first argument string does not contain the second argument
9153
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9154
 */
9155
void
9156
3.61k
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9157
3.61k
  xmlXPathObjectPtr str;
9158
3.61k
  xmlXPathObjectPtr find;
9159
3.61k
  xmlBufPtr target;
9160
3.61k
  const xmlChar *point;
9161
3.61k
  int offset;
9162
9163
10.7k
  CHECK_ARITY(2);
9164
10.7k
  CAST_TO_STRING;
9165
10.7k
  find = valuePop(ctxt);
9166
10.7k
  CAST_TO_STRING;
9167
10.7k
  str = valuePop(ctxt);
9168
9169
10.7k
  target = xmlBufCreate();
9170
10.7k
  if (target) {
9171
3.56k
    point = xmlStrstr(str->stringval, find->stringval);
9172
3.56k
    if (point) {
9173
1.52k
      offset = point - str->stringval;
9174
1.52k
      xmlBufAdd(target, str->stringval, offset);
9175
1.52k
    }
9176
3.56k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9177
3.56k
  xmlBufContent(target)));
9178
3.56k
    xmlBufFree(target);
9179
3.56k
  }
9180
10.7k
  xmlXPathReleaseObject(ctxt->context, str);
9181
10.7k
  xmlXPathReleaseObject(ctxt->context, find);
9182
10.7k
}
9183
9184
/**
9185
 * xmlXPathSubstringAfterFunction:
9186
 * @ctxt:  the XPath Parser context
9187
 * @nargs:  the number of arguments
9188
 *
9189
 * Implement the substring-after() XPath function
9190
 *    string substring-after(string, string)
9191
 * The substring-after function returns the substring of the first
9192
 * argument string that follows the first occurrence of the second
9193
 * argument string in the first argument string, or the empty stringi
9194
 * if the first argument string does not contain the second argument
9195
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9196
 * and substring-after("1999/04/01","19") returns 99/04/01.
9197
 */
9198
void
9199
86.3k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9200
86.3k
  xmlXPathObjectPtr str;
9201
86.3k
  xmlXPathObjectPtr find;
9202
86.3k
  xmlBufPtr target;
9203
86.3k
  const xmlChar *point;
9204
86.3k
  int offset;
9205
9206
258k
  CHECK_ARITY(2);
9207
258k
  CAST_TO_STRING;
9208
258k
  find = valuePop(ctxt);
9209
258k
  CAST_TO_STRING;
9210
258k
  str = valuePop(ctxt);
9211
9212
258k
  target = xmlBufCreate();
9213
258k
  if (target) {
9214
86.1k
    point = xmlStrstr(str->stringval, find->stringval);
9215
86.1k
    if (point) {
9216
2.21k
      offset = point - str->stringval + xmlStrlen(find->stringval);
9217
2.21k
      xmlBufAdd(target, &str->stringval[offset],
9218
2.21k
       xmlStrlen(str->stringval) - offset);
9219
2.21k
    }
9220
86.1k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9221
86.1k
  xmlBufContent(target)));
9222
86.1k
    xmlBufFree(target);
9223
86.1k
  }
9224
258k
  xmlXPathReleaseObject(ctxt->context, str);
9225
258k
  xmlXPathReleaseObject(ctxt->context, find);
9226
258k
}
9227
9228
/**
9229
 * xmlXPathNormalizeFunction:
9230
 * @ctxt:  the XPath Parser context
9231
 * @nargs:  the number of arguments
9232
 *
9233
 * Implement the normalize-space() XPath function
9234
 *    string normalize-space(string?)
9235
 * The normalize-space function returns the argument string with white
9236
 * space normalized by stripping leading and trailing whitespace
9237
 * and replacing sequences of whitespace characters by a single
9238
 * space. Whitespace characters are the same allowed by the S production
9239
 * in XML. If the argument is omitted, it defaults to the context
9240
 * node converted to a string, in other words the value of the context node.
9241
 */
9242
void
9243
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9244
0
    xmlChar *source, *target;
9245
0
    int blank;
9246
9247
0
    if (ctxt == NULL) return;
9248
0
    if (nargs == 0) {
9249
        /* Use current context node */
9250
0
        valuePush(ctxt,
9251
0
            xmlXPathCacheWrapString(ctxt->context,
9252
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9253
0
        nargs = 1;
9254
0
    }
9255
9256
0
    CHECK_ARITY(1);
9257
0
    CAST_TO_STRING;
9258
0
    CHECK_TYPE(XPATH_STRING);
9259
0
    source = ctxt->value->stringval;
9260
0
    if (source == NULL)
9261
0
        return;
9262
0
    target = source;
9263
9264
    /* Skip leading whitespaces */
9265
0
    while (IS_BLANK_CH(*source))
9266
0
        source++;
9267
9268
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9269
0
    blank = 0;
9270
0
    while (*source) {
9271
0
        if (IS_BLANK_CH(*source)) {
9272
0
      blank = 1;
9273
0
        } else {
9274
0
            if (blank) {
9275
0
                *target++ = 0x20;
9276
0
                blank = 0;
9277
0
            }
9278
0
            *target++ = *source;
9279
0
        }
9280
0
        source++;
9281
0
    }
9282
0
    *target = 0;
9283
0
}
9284
9285
/**
9286
 * xmlXPathTranslateFunction:
9287
 * @ctxt:  the XPath Parser context
9288
 * @nargs:  the number of arguments
9289
 *
9290
 * Implement the translate() XPath function
9291
 *    string translate(string, string, string)
9292
 * The translate function returns the first argument string with
9293
 * occurrences of characters in the second argument string replaced
9294
 * by the character at the corresponding position in the third argument
9295
 * string. For example, translate("bar","abc","ABC") returns the string
9296
 * BAr. If there is a character in the second argument string with no
9297
 * character at a corresponding position in the third argument string
9298
 * (because the second argument string is longer than the third argument
9299
 * string), then occurrences of that character in the first argument
9300
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9301
 * returns "AAA". If a character occurs more than once in second
9302
 * argument string, then the first occurrence determines the replacement
9303
 * character. If the third argument string is longer than the second
9304
 * argument string, then excess characters are ignored.
9305
 */
9306
void
9307
1.68k
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9308
1.68k
    xmlXPathObjectPtr str;
9309
1.68k
    xmlXPathObjectPtr from;
9310
1.68k
    xmlXPathObjectPtr to;
9311
1.68k
    xmlBufPtr target;
9312
1.68k
    int offset, max;
9313
1.68k
    int ch;
9314
1.68k
    const xmlChar *point;
9315
1.68k
    xmlChar *cptr;
9316
9317
4.87k
    CHECK_ARITY(3);
9318
9319
4.87k
    CAST_TO_STRING;
9320
4.87k
    to = valuePop(ctxt);
9321
4.87k
    CAST_TO_STRING;
9322
4.87k
    from = valuePop(ctxt);
9323
4.87k
    CAST_TO_STRING;
9324
4.87k
    str = valuePop(ctxt);
9325
9326
4.87k
    target = xmlBufCreate();
9327
4.87k
    if (target) {
9328
1.59k
  max = xmlUTF8Strlen(to->stringval);
9329
605k
  for (cptr = str->stringval; (ch=*cptr); ) {
9330
603k
      offset = xmlUTF8Strloc(from->stringval, cptr);
9331
603k
      if (offset >= 0) {
9332
141k
    if (offset < max) {
9333
12.9k
        point = xmlUTF8Strpos(to->stringval, offset);
9334
12.9k
        if (point)
9335
12.9k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9336
12.9k
    }
9337
141k
      } else
9338
462k
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9339
9340
      /* Step to next character in input */
9341
603k
      cptr++;
9342
603k
      if ( ch & 0x80 ) {
9343
    /* if not simple ascii, verify proper format */
9344
95.5k
    if ( (ch & 0xc0) != 0xc0 ) {
9345
5
        xmlGenericError(xmlGenericErrorContext,
9346
5
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9347
                    /* not asserting an XPath error is probably better */
9348
5
        break;
9349
5
    }
9350
    /* then skip over remaining bytes for this char */
9351
286k
    while ( (ch <<= 1) & 0x80 )
9352
191k
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9353
4
      xmlGenericError(xmlGenericErrorContext,
9354
4
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9355
                        /* not asserting an XPath error is probably better */
9356
4
      break;
9357
4
        }
9358
95.5k
    if (ch & 0x80) /* must have had error encountered */
9359
4
        break;
9360
95.5k
      }
9361
603k
  }
9362
1.59k
    }
9363
4.87k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9364
4.87k
  xmlBufContent(target)));
9365
4.87k
    xmlBufFree(target);
9366
4.87k
    xmlXPathReleaseObject(ctxt->context, str);
9367
4.87k
    xmlXPathReleaseObject(ctxt->context, from);
9368
4.87k
    xmlXPathReleaseObject(ctxt->context, to);
9369
4.87k
}
9370
9371
/**
9372
 * xmlXPathBooleanFunction:
9373
 * @ctxt:  the XPath Parser context
9374
 * @nargs:  the number of arguments
9375
 *
9376
 * Implement the boolean() XPath function
9377
 *    boolean boolean(object)
9378
 * The boolean function converts its argument to a boolean as follows:
9379
 *    - a number is true if and only if it is neither positive or
9380
 *      negative zero nor NaN
9381
 *    - a node-set is true if and only if it is non-empty
9382
 *    - a string is true if and only if its length is non-zero
9383
 */
9384
void
9385
383k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9386
383k
    xmlXPathObjectPtr cur;
9387
9388
1.15M
    CHECK_ARITY(1);
9389
1.15M
    cur = valuePop(ctxt);
9390
1.15M
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9391
383k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9392
383k
    valuePush(ctxt, cur);
9393
383k
}
9394
9395
/**
9396
 * xmlXPathNotFunction:
9397
 * @ctxt:  the XPath Parser context
9398
 * @nargs:  the number of arguments
9399
 *
9400
 * Implement the not() XPath function
9401
 *    boolean not(boolean)
9402
 * The not function returns true if its argument is false,
9403
 * and false otherwise.
9404
 */
9405
void
9406
596
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9407
1.78k
    CHECK_ARITY(1);
9408
1.78k
    CAST_TO_BOOLEAN;
9409
1.78k
    CHECK_TYPE(XPATH_BOOLEAN);
9410
596
    ctxt->value->boolval = ! ctxt->value->boolval;
9411
596
}
9412
9413
/**
9414
 * xmlXPathTrueFunction:
9415
 * @ctxt:  the XPath Parser context
9416
 * @nargs:  the number of arguments
9417
 *
9418
 * Implement the true() XPath function
9419
 *    boolean true()
9420
 */
9421
void
9422
895
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9423
2.68k
    CHECK_ARITY(0);
9424
2.68k
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9425
2.68k
}
9426
9427
/**
9428
 * xmlXPathFalseFunction:
9429
 * @ctxt:  the XPath Parser context
9430
 * @nargs:  the number of arguments
9431
 *
9432
 * Implement the false() XPath function
9433
 *    boolean false()
9434
 */
9435
void
9436
38
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9437
114
    CHECK_ARITY(0);
9438
114
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9439
114
}
9440
9441
/**
9442
 * xmlXPathLangFunction:
9443
 * @ctxt:  the XPath Parser context
9444
 * @nargs:  the number of arguments
9445
 *
9446
 * Implement the lang() XPath function
9447
 *    boolean lang(string)
9448
 * The lang function returns true or false depending on whether the
9449
 * language of the context node as specified by xml:lang attributes
9450
 * is the same as or is a sublanguage of the language specified by
9451
 * the argument string. The language of the context node is determined
9452
 * by the value of the xml:lang attribute on the context node, or, if
9453
 * the context node has no xml:lang attribute, by the value of the
9454
 * xml:lang attribute on the nearest ancestor of the context node that
9455
 * has an xml:lang attribute. If there is no such attribute, then lang
9456
 * returns false. If there is such an attribute, then lang returns
9457
 * true if the attribute value is equal to the argument ignoring case,
9458
 * or if there is some suffix starting with - such that the attribute
9459
 * value is equal to the argument ignoring that suffix of the attribute
9460
 * value and ignoring case.
9461
 */
9462
void
9463
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9464
0
    xmlXPathObjectPtr val = NULL;
9465
0
    const xmlChar *theLang = NULL;
9466
0
    const xmlChar *lang;
9467
0
    int ret = 0;
9468
0
    int i;
9469
9470
0
    CHECK_ARITY(1);
9471
0
    CAST_TO_STRING;
9472
0
    CHECK_TYPE(XPATH_STRING);
9473
0
    val = valuePop(ctxt);
9474
0
    lang = val->stringval;
9475
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9476
0
    if ((theLang != NULL) && (lang != NULL)) {
9477
0
        for (i = 0;lang[i] != 0;i++)
9478
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9479
0
          goto not_equal;
9480
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9481
0
      ret = 1;
9482
0
    }
9483
0
not_equal:
9484
0
    if (theLang != NULL)
9485
0
  xmlFree((void *)theLang);
9486
9487
0
    xmlXPathReleaseObject(ctxt->context, val);
9488
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9489
0
}
9490
9491
/**
9492
 * xmlXPathNumberFunction:
9493
 * @ctxt:  the XPath Parser context
9494
 * @nargs:  the number of arguments
9495
 *
9496
 * Implement the number() XPath function
9497
 *    number number(object?)
9498
 */
9499
void
9500
836k
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9501
836k
    xmlXPathObjectPtr cur;
9502
836k
    double res;
9503
9504
836k
    if (ctxt == NULL) return;
9505
836k
    if (nargs == 0) {
9506
78
  if (ctxt->context->node == NULL) {
9507
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9508
78
  } else {
9509
78
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9510
9511
78
      res = xmlXPathStringEvalNumber(content);
9512
78
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9513
78
      xmlFree(content);
9514
78
  }
9515
78
  return;
9516
78
    }
9517
9518
3.34M
    CHECK_ARITY(1);
9519
3.34M
    cur = valuePop(ctxt);
9520
3.34M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9521
3.34M
}
9522
9523
/**
9524
 * xmlXPathSumFunction:
9525
 * @ctxt:  the XPath Parser context
9526
 * @nargs:  the number of arguments
9527
 *
9528
 * Implement the sum() XPath function
9529
 *    number sum(node-set)
9530
 * The sum function returns the sum of the values of the nodes in
9531
 * the argument node-set.
9532
 */
9533
void
9534
10.4k
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
10.4k
    xmlXPathObjectPtr cur;
9536
10.4k
    int i;
9537
10.4k
    double res = 0.0;
9538
9539
31.4k
    CHECK_ARITY(1);
9540
31.4k
    if ((ctxt->value == NULL) ||
9541
10.4k
  ((ctxt->value->type != XPATH_NODESET) &&
9542
10.4k
   (ctxt->value->type != XPATH_XSLT_TREE)))
9543
10.4k
  XP_ERROR(XPATH_INVALID_TYPE);
9544
10.4k
    cur = valuePop(ctxt);
9545
9546
10.4k
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9547
15.1k
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9548
10.1k
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9549
10.1k
  }
9550
4.94k
    }
9551
10.4k
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9552
10.4k
    xmlXPathReleaseObject(ctxt->context, cur);
9553
10.4k
}
9554
9555
/**
9556
 * xmlXPathFloorFunction:
9557
 * @ctxt:  the XPath Parser context
9558
 * @nargs:  the number of arguments
9559
 *
9560
 * Implement the floor() XPath function
9561
 *    number floor(number)
9562
 * The floor function returns the largest (closest to positive infinity)
9563
 * number that is not greater than the argument and that is an integer.
9564
 */
9565
void
9566
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9567
0
    CHECK_ARITY(1);
9568
0
    CAST_TO_NUMBER;
9569
0
    CHECK_TYPE(XPATH_NUMBER);
9570
9571
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9572
0
}
9573
9574
/**
9575
 * xmlXPathCeilingFunction:
9576
 * @ctxt:  the XPath Parser context
9577
 * @nargs:  the number of arguments
9578
 *
9579
 * Implement the ceiling() XPath function
9580
 *    number ceiling(number)
9581
 * The ceiling function returns the smallest (closest to negative infinity)
9582
 * number that is not less than the argument and that is an integer.
9583
 */
9584
void
9585
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9586
0
    CHECK_ARITY(1);
9587
0
    CAST_TO_NUMBER;
9588
0
    CHECK_TYPE(XPATH_NUMBER);
9589
9590
#ifdef _AIX
9591
    /* Work around buggy ceil() function on AIX */
9592
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9593
#else
9594
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9595
0
#endif
9596
0
}
9597
9598
/**
9599
 * xmlXPathRoundFunction:
9600
 * @ctxt:  the XPath Parser context
9601
 * @nargs:  the number of arguments
9602
 *
9603
 * Implement the round() XPath function
9604
 *    number round(number)
9605
 * The round function returns the number that is closest to the
9606
 * argument and that is an integer. If there are two such numbers,
9607
 * then the one that is closest to positive infinity is returned.
9608
 */
9609
void
9610
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9611
0
    double f;
9612
9613
0
    CHECK_ARITY(1);
9614
0
    CAST_TO_NUMBER;
9615
0
    CHECK_TYPE(XPATH_NUMBER);
9616
9617
0
    f = ctxt->value->floatval;
9618
9619
0
    if ((f >= -0.5) && (f < 0.5)) {
9620
        /* Handles negative zero. */
9621
0
        ctxt->value->floatval *= 0.0;
9622
0
    }
9623
0
    else {
9624
0
        double rounded = floor(f);
9625
0
        if (f - rounded >= 0.5)
9626
0
            rounded += 1.0;
9627
0
        ctxt->value->floatval = rounded;
9628
0
    }
9629
0
}
9630
9631
/************************************************************************
9632
 *                  *
9633
 *      The Parser          *
9634
 *                  *
9635
 ************************************************************************/
9636
9637
/*
9638
 * a few forward declarations since we use a recursive call based
9639
 * implementation.
9640
 */
9641
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9642
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9643
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9644
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9645
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9646
                                    int qualified);
9647
9648
/**
9649
 * xmlXPathCurrentChar:
9650
 * @ctxt:  the XPath parser context
9651
 * @cur:  pointer to the beginning of the char
9652
 * @len:  pointer to the length of the char read
9653
 *
9654
 * The current char value, if using UTF-8 this may actually span multiple
9655
 * bytes in the input buffer.
9656
 *
9657
 * Returns the current char value and its length
9658
 */
9659
9660
static int
9661
32.0M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9662
32.0M
    unsigned char c;
9663
32.0M
    unsigned int val;
9664
32.0M
    const xmlChar *cur;
9665
9666
32.0M
    if (ctxt == NULL)
9667
0
  return(0);
9668
32.0M
    cur = ctxt->cur;
9669
9670
    /*
9671
     * We are supposed to handle UTF8, check it's valid
9672
     * From rfc2044: encoding of the Unicode values on UTF-8:
9673
     *
9674
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9675
     * 0000 0000-0000 007F   0xxxxxxx
9676
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9677
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9678
     *
9679
     * Check for the 0x110000 limit too
9680
     */
9681
32.0M
    c = *cur;
9682
32.0M
    if (c & 0x80) {
9683
2.64M
  if ((cur[1] & 0xc0) != 0x80)
9684
409
      goto encoding_error;
9685
2.64M
  if ((c & 0xe0) == 0xe0) {
9686
9687
68.0k
      if ((cur[2] & 0xc0) != 0x80)
9688
0
    goto encoding_error;
9689
68.0k
      if ((c & 0xf0) == 0xf0) {
9690
10.1k
    if (((c & 0xf8) != 0xf0) ||
9691
10.1k
        ((cur[3] & 0xc0) != 0x80))
9692
0
        goto encoding_error;
9693
    /* 4-byte code */
9694
10.1k
    *len = 4;
9695
10.1k
    val = (cur[0] & 0x7) << 18;
9696
10.1k
    val |= (cur[1] & 0x3f) << 12;
9697
10.1k
    val |= (cur[2] & 0x3f) << 6;
9698
10.1k
    val |= cur[3] & 0x3f;
9699
57.9k
      } else {
9700
        /* 3-byte code */
9701
57.9k
    *len = 3;
9702
57.9k
    val = (cur[0] & 0xf) << 12;
9703
57.9k
    val |= (cur[1] & 0x3f) << 6;
9704
57.9k
    val |= cur[2] & 0x3f;
9705
57.9k
      }
9706
2.57M
  } else {
9707
    /* 2-byte code */
9708
2.57M
      *len = 2;
9709
2.57M
      val = (cur[0] & 0x1f) << 6;
9710
2.57M
      val |= cur[1] & 0x3f;
9711
2.57M
  }
9712
2.64M
  if (!IS_CHAR(val)) {
9713
4
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9714
0
  }
9715
2.64M
  return(val);
9716
29.4M
    } else {
9717
  /* 1-byte code */
9718
29.4M
  *len = 1;
9719
29.4M
  return(*cur);
9720
29.4M
    }
9721
409
encoding_error:
9722
    /*
9723
     * If we detect an UTF8 error that probably means that the
9724
     * input encoding didn't get properly advertised in the
9725
     * declaration header. Report the error and switch the encoding
9726
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9727
     * encoding !)
9728
     */
9729
409
    *len = 0;
9730
409
    XP_ERROR0(XPATH_ENCODING_ERROR);
9731
0
}
9732
9733
/**
9734
 * xmlXPathParseNCName:
9735
 * @ctxt:  the XPath Parser context
9736
 *
9737
 * parse an XML namespace non qualified name.
9738
 *
9739
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9740
 *
9741
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9742
 *                       CombiningChar | Extender
9743
 *
9744
 * Returns the namespace name or NULL
9745
 */
9746
9747
xmlChar *
9748
4.08M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9749
4.08M
    const xmlChar *in;
9750
4.08M
    xmlChar *ret;
9751
4.08M
    int count = 0;
9752
9753
4.08M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9754
    /*
9755
     * Accelerator for simple ASCII names
9756
     */
9757
4.08M
    in = ctxt->cur;
9758
4.08M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9759
4.08M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9760
4.08M
  (*in == '_')) {
9761
3.77M
  in++;
9762
21.8M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9763
21.8M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9764
21.8M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9765
21.8M
         (*in == '_') || (*in == '.') ||
9766
21.8M
         (*in == '-'))
9767
18.0M
      in++;
9768
3.77M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9769
3.77M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9770
3.77M
            (*in == '@') || (*in == '*')) {
9771
1.86M
      count = in - ctxt->cur;
9772
1.86M
      if (count == 0)
9773
0
    return(NULL);
9774
1.86M
      ret = xmlStrndup(ctxt->cur, count);
9775
1.86M
      ctxt->cur = in;
9776
1.86M
      return(ret);
9777
1.86M
  }
9778
3.77M
    }
9779
2.22M
    return(xmlXPathParseNameComplex(ctxt, 0));
9780
4.08M
}
9781
9782
9783
/**
9784
 * xmlXPathParseQName:
9785
 * @ctxt:  the XPath Parser context
9786
 * @prefix:  a xmlChar **
9787
 *
9788
 * parse an XML qualified name
9789
 *
9790
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9791
 *
9792
 * [NS 6] Prefix ::= NCName
9793
 *
9794
 * [NS 7] LocalPart ::= NCName
9795
 *
9796
 * Returns the function returns the local part, and prefix is updated
9797
 *   to get the Prefix if any.
9798
 */
9799
9800
static xmlChar *
9801
934k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9802
934k
    xmlChar *ret = NULL;
9803
9804
934k
    *prefix = NULL;
9805
934k
    ret = xmlXPathParseNCName(ctxt);
9806
934k
    if (ret && CUR == ':') {
9807
717k
        *prefix = ret;
9808
717k
  NEXT;
9809
717k
  ret = xmlXPathParseNCName(ctxt);
9810
717k
    }
9811
934k
    return(ret);
9812
934k
}
9813
9814
/**
9815
 * xmlXPathParseName:
9816
 * @ctxt:  the XPath Parser context
9817
 *
9818
 * parse an XML name
9819
 *
9820
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9821
 *                  CombiningChar | Extender
9822
 *
9823
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9824
 *
9825
 * Returns the namespace name or NULL
9826
 */
9827
9828
xmlChar *
9829
1
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9830
1
    const xmlChar *in;
9831
1
    xmlChar *ret;
9832
1
    size_t count = 0;
9833
9834
1
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9835
    /*
9836
     * Accelerator for simple ASCII names
9837
     */
9838
1
    in = ctxt->cur;
9839
1
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9840
1
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9841
1
  (*in == '_') || (*in == ':')) {
9842
1
  in++;
9843
40.7k
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9844
40.7k
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9845
40.7k
         ((*in >= 0x30) && (*in <= 0x39)) ||
9846
40.7k
         (*in == '_') || (*in == '-') ||
9847
40.7k
         (*in == ':') || (*in == '.'))
9848
40.7k
      in++;
9849
1
  if ((*in > 0) && (*in < 0x80)) {
9850
1
      count = in - ctxt->cur;
9851
1
            if (count > XML_MAX_NAME_LENGTH) {
9852
0
                ctxt->cur = in;
9853
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9854
0
            }
9855
1
      ret = xmlStrndup(ctxt->cur, count);
9856
1
      ctxt->cur = in;
9857
1
      return(ret);
9858
1
  }
9859
1
    }
9860
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9861
1
}
9862
9863
static xmlChar *
9864
2.22M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9865
2.22M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9866
2.22M
    int len = 0, l;
9867
2.22M
    int c;
9868
9869
    /*
9870
     * Handler for more complex cases
9871
     */
9872
2.22M
    c = CUR_CHAR(l);
9873
2.22M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9874
2.22M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9875
2.22M
        (c == '*') || /* accelerators */
9876
2.22M
  (!IS_LETTER(c) && (c != '_') &&
9877
2.02M
         ((!qualified) || (c != ':')))) {
9878
269k
  return(NULL);
9879
269k
    }
9880
9881
12.9M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9882
12.9M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9883
12.9M
            (c == '.') || (c == '-') ||
9884
12.9M
      (c == '_') || ((qualified) && (c == ':')) ||
9885
12.9M
      (IS_COMBINING(c)) ||
9886
12.9M
      (IS_EXTENDER(c)))) {
9887
11.0M
  COPY_BUF(l,buf,len,c);
9888
11.0M
  NEXTL(l);
9889
11.0M
  c = CUR_CHAR(l);
9890
11.0M
  if (len >= XML_MAX_NAMELEN) {
9891
      /*
9892
       * Okay someone managed to make a huge name, so he's ready to pay
9893
       * for the processing speed.
9894
       */
9895
8.65k
      xmlChar *buffer;
9896
8.65k
      int max = len * 2;
9897
9898
8.65k
            if (len > XML_MAX_NAME_LENGTH) {
9899
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9900
0
            }
9901
8.65k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9902
8.65k
      if (buffer == NULL) {
9903
3
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9904
0
      }
9905
8.64k
      memcpy(buffer, buf, len);
9906
2.45M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9907
2.45M
       (c == '.') || (c == '-') ||
9908
2.45M
       (c == '_') || ((qualified) && (c == ':')) ||
9909
2.45M
       (IS_COMBINING(c)) ||
9910
2.45M
       (IS_EXTENDER(c))) {
9911
2.44M
    if (len + 10 > max) {
9912
3.14k
                    xmlChar *tmp;
9913
3.14k
                    if (max > XML_MAX_NAME_LENGTH) {
9914
80
                        xmlFree(buffer);
9915
80
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9916
0
                    }
9917
3.06k
        max *= 2;
9918
3.06k
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9919
3.06k
        if (tmp == NULL) {
9920
1
                        xmlFree(buffer);
9921
1
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9922
0
        }
9923
3.06k
                    buffer = tmp;
9924
3.06k
    }
9925
2.44M
    COPY_BUF(l,buffer,len,c);
9926
2.44M
    NEXTL(l);
9927
2.44M
    c = CUR_CHAR(l);
9928
2.44M
      }
9929
8.56k
      buffer[len] = 0;
9930
8.56k
      return(buffer);
9931
8.64k
  }
9932
11.0M
    }
9933
1.94M
    if (len == 0)
9934
0
  return(NULL);
9935
1.94M
    return(xmlStrndup(buf, len));
9936
1.94M
}
9937
9938
36.3k
#define MAX_FRAC 20
9939
9940
/**
9941
 * xmlXPathStringEvalNumber:
9942
 * @str:  A string to scan
9943
 *
9944
 *  [30a]  Float  ::= Number ('e' Digits?)?
9945
 *
9946
 *  [30]   Number ::=   Digits ('.' Digits?)?
9947
 *                    | '.' Digits
9948
 *  [31]   Digits ::=   [0-9]+
9949
 *
9950
 * Compile a Number in the string
9951
 * In complement of the Number expression, this function also handles
9952
 * negative values : '-' Number.
9953
 *
9954
 * Returns the double value.
9955
 */
9956
double
9957
733k
xmlXPathStringEvalNumber(const xmlChar *str) {
9958
733k
    const xmlChar *cur = str;
9959
733k
    double ret;
9960
733k
    int ok = 0;
9961
733k
    int isneg = 0;
9962
733k
    int exponent = 0;
9963
733k
    int is_exponent_negative = 0;
9964
733k
#ifdef __GNUC__
9965
733k
    unsigned long tmp = 0;
9966
733k
    double temp;
9967
733k
#endif
9968
733k
    if (cur == NULL) return(0);
9969
723k
    while (IS_BLANK_CH(*cur)) cur++;
9970
723k
    if (*cur == '-') {
9971
19.5k
  isneg = 1;
9972
19.5k
  cur++;
9973
19.5k
    }
9974
723k
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9975
671k
        return(xmlXPathNAN);
9976
671k
    }
9977
9978
51.7k
#ifdef __GNUC__
9979
    /*
9980
     * tmp/temp is a workaround against a gcc compiler bug
9981
     * http://veillard.com/gcc.bug
9982
     */
9983
51.7k
    ret = 0;
9984
217k
    while ((*cur >= '0') && (*cur <= '9')) {
9985
165k
  ret = ret * 10;
9986
165k
  tmp = (*cur - '0');
9987
165k
  ok = 1;
9988
165k
  cur++;
9989
165k
  temp = (double) tmp;
9990
165k
  ret = ret + temp;
9991
165k
    }
9992
#else
9993
    ret = 0;
9994
    while ((*cur >= '0') && (*cur <= '9')) {
9995
  ret = ret * 10 + (*cur - '0');
9996
  ok = 1;
9997
  cur++;
9998
    }
9999
#endif
10000
10001
51.7k
    if (*cur == '.') {
10002
25.3k
  int v, frac = 0, max;
10003
25.3k
  double fraction = 0;
10004
10005
25.3k
        cur++;
10006
25.3k
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10007
1.94k
      return(xmlXPathNAN);
10008
1.94k
  }
10009
38.4k
        while (*cur == '0') {
10010
15.0k
      frac = frac + 1;
10011
15.0k
      cur++;
10012
15.0k
        }
10013
23.4k
        max = frac + MAX_FRAC;
10014
78.5k
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10015
55.1k
      v = (*cur - '0');
10016
55.1k
      fraction = fraction * 10 + v;
10017
55.1k
      frac = frac + 1;
10018
55.1k
      cur++;
10019
55.1k
  }
10020
23.4k
  fraction /= pow(10.0, frac);
10021
23.4k
  ret = ret + fraction;
10022
31.5k
  while ((*cur >= '0') && (*cur <= '9'))
10023
8.13k
      cur++;
10024
23.4k
    }
10025
49.8k
    if ((*cur == 'e') || (*cur == 'E')) {
10026
3.58k
      cur++;
10027
3.58k
      if (*cur == '-') {
10028
405
  is_exponent_negative = 1;
10029
405
  cur++;
10030
3.17k
      } else if (*cur == '+') {
10031
537
        cur++;
10032
537
      }
10033
35.5k
      while ((*cur >= '0') && (*cur <= '9')) {
10034
31.9k
        if (exponent < 1000000)
10035
17.2k
    exponent = exponent * 10 + (*cur - '0');
10036
31.9k
  cur++;
10037
31.9k
      }
10038
3.58k
    }
10039
49.8k
    while (IS_BLANK_CH(*cur)) cur++;
10040
49.8k
    if (*cur != 0) return(xmlXPathNAN);
10041
27.5k
    if (isneg) ret = -ret;
10042
27.5k
    if (is_exponent_negative) exponent = -exponent;
10043
27.5k
    ret *= pow(10.0, (double)exponent);
10044
27.5k
    return(ret);
10045
49.8k
}
10046
10047
/**
10048
 * xmlXPathCompNumber:
10049
 * @ctxt:  the XPath Parser context
10050
 *
10051
 *  [30]   Number ::=   Digits ('.' Digits?)?
10052
 *                    | '.' Digits
10053
 *  [31]   Digits ::=   [0-9]+
10054
 *
10055
 * Compile a Number, then push it on the stack
10056
 *
10057
 */
10058
static void
10059
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10060
312k
{
10061
312k
    double ret = 0.0;
10062
312k
    int ok = 0;
10063
312k
    int exponent = 0;
10064
312k
    int is_exponent_negative = 0;
10065
312k
    xmlXPathObjectPtr num;
10066
312k
#ifdef __GNUC__
10067
312k
    unsigned long tmp = 0;
10068
312k
    double temp;
10069
312k
#endif
10070
10071
312k
    CHECK_ERROR;
10072
311k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10073
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10074
0
    }
10075
311k
#ifdef __GNUC__
10076
    /*
10077
     * tmp/temp is a workaround against a gcc compiler bug
10078
     * http://veillard.com/gcc.bug
10079
     */
10080
311k
    ret = 0;
10081
3.56M
    while ((CUR >= '0') && (CUR <= '9')) {
10082
3.25M
  ret = ret * 10;
10083
3.25M
  tmp = (CUR - '0');
10084
3.25M
        ok = 1;
10085
3.25M
        NEXT;
10086
3.25M
  temp = (double) tmp;
10087
3.25M
  ret = ret + temp;
10088
3.25M
    }
10089
#else
10090
    ret = 0;
10091
    while ((CUR >= '0') && (CUR <= '9')) {
10092
  ret = ret * 10 + (CUR - '0');
10093
  ok = 1;
10094
  NEXT;
10095
    }
10096
#endif
10097
311k
    if (CUR == '.') {
10098
12.9k
  int v, frac = 0, max;
10099
12.9k
  double fraction = 0;
10100
10101
12.9k
        NEXT;
10102
12.9k
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10103
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10104
0
        }
10105
119k
        while (CUR == '0') {
10106
106k
            frac = frac + 1;
10107
106k
            NEXT;
10108
106k
        }
10109
12.9k
        max = frac + MAX_FRAC;
10110
43.1k
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10111
30.2k
      v = (CUR - '0');
10112
30.2k
      fraction = fraction * 10 + v;
10113
30.2k
      frac = frac + 1;
10114
30.2k
            NEXT;
10115
30.2k
        }
10116
12.9k
        fraction /= pow(10.0, frac);
10117
12.9k
        ret = ret + fraction;
10118
14.9k
        while ((CUR >= '0') && (CUR <= '9'))
10119
2.06k
            NEXT;
10120
12.9k
    }
10121
311k
    if ((CUR == 'e') || (CUR == 'E')) {
10122
3.16k
        NEXT;
10123
3.16k
        if (CUR == '-') {
10124
934
            is_exponent_negative = 1;
10125
934
            NEXT;
10126
2.22k
        } else if (CUR == '+') {
10127
908
      NEXT;
10128
908
  }
10129
17.7k
        while ((CUR >= '0') && (CUR <= '9')) {
10130
14.5k
            if (exponent < 1000000)
10131
12.6k
                exponent = exponent * 10 + (CUR - '0');
10132
14.5k
            NEXT;
10133
14.5k
        }
10134
3.16k
        if (is_exponent_negative)
10135
934
            exponent = -exponent;
10136
3.16k
        ret *= pow(10.0, (double) exponent);
10137
3.16k
    }
10138
311k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10139
311k
    if (num == NULL) {
10140
21
  ctxt->error = XPATH_MEMORY_ERROR;
10141
311k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10142
311k
                              NULL) == -1) {
10143
6
        xmlXPathReleaseObject(ctxt->context, num);
10144
6
    }
10145
311k
}
10146
10147
/**
10148
 * xmlXPathParseLiteral:
10149
 * @ctxt:  the XPath Parser context
10150
 *
10151
 * Parse a Literal
10152
 *
10153
 *  [29]   Literal ::=   '"' [^"]* '"'
10154
 *                    | "'" [^']* "'"
10155
 *
10156
 * Returns the value found or NULL in case of error
10157
 */
10158
static xmlChar *
10159
6.87k
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10160
6.87k
    const xmlChar *q;
10161
6.87k
    xmlChar *ret = NULL;
10162
10163
6.87k
    if (CUR == '"') {
10164
6.13k
        NEXT;
10165
6.13k
  q = CUR_PTR;
10166
14.6k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10167
8.54k
      NEXT;
10168
6.13k
  if (!IS_CHAR_CH(CUR)) {
10169
10
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10170
6.12k
  } else {
10171
6.12k
      ret = xmlStrndup(q, CUR_PTR - q);
10172
6.12k
      NEXT;
10173
6.12k
        }
10174
6.13k
    } else if (CUR == '\'') {
10175
665
        NEXT;
10176
665
  q = CUR_PTR;
10177
13.1k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10178
12.4k
      NEXT;
10179
665
  if (!IS_CHAR_CH(CUR)) {
10180
138
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10181
527
  } else {
10182
527
      ret = xmlStrndup(q, CUR_PTR - q);
10183
527
      NEXT;
10184
527
        }
10185
665
    } else {
10186
74
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10187
0
    }
10188
6.65k
    return(ret);
10189
6.87k
}
10190
10191
/**
10192
 * xmlXPathCompLiteral:
10193
 * @ctxt:  the XPath Parser context
10194
 *
10195
 * Parse a Literal and push it on the stack.
10196
 *
10197
 *  [29]   Literal ::=   '"' [^"]* '"'
10198
 *                    | "'" [^']* "'"
10199
 *
10200
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10201
 */
10202
static void
10203
96.0k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10204
96.0k
    const xmlChar *q;
10205
96.0k
    xmlChar *ret = NULL;
10206
96.0k
    xmlXPathObjectPtr lit;
10207
10208
96.0k
    if (CUR == '"') {
10209
41.1k
        NEXT;
10210
41.1k
  q = CUR_PTR;
10211
349k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10212
308k
      NEXT;
10213
41.1k
  if (!IS_CHAR_CH(CUR)) {
10214
2.22k
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10215
38.9k
  } else {
10216
38.9k
      ret = xmlStrndup(q, CUR_PTR - q);
10217
38.9k
      NEXT;
10218
38.9k
        }
10219
54.8k
    } else if (CUR == '\'') {
10220
54.8k
        NEXT;
10221
54.8k
  q = CUR_PTR;
10222
4.31M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10223
4.25M
      NEXT;
10224
54.8k
  if (!IS_CHAR_CH(CUR)) {
10225
742
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10226
54.1k
  } else {
10227
54.1k
      ret = xmlStrndup(q, CUR_PTR - q);
10228
54.1k
      NEXT;
10229
54.1k
        }
10230
54.8k
    } else {
10231
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10232
0
    }
10233
93.0k
    if (ret == NULL) {
10234
14
        xmlXPathPErrMemory(ctxt, NULL);
10235
14
        return;
10236
14
    }
10237
93.0k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10238
93.0k
    if (lit == NULL) {
10239
12
  ctxt->error = XPATH_MEMORY_ERROR;
10240
93.0k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10241
93.0k
                              NULL) == -1) {
10242
2
        xmlXPathReleaseObject(ctxt->context, lit);
10243
2
    }
10244
93.0k
    xmlFree(ret);
10245
93.0k
}
10246
10247
/**
10248
 * xmlXPathCompVariableReference:
10249
 * @ctxt:  the XPath Parser context
10250
 *
10251
 * Parse a VariableReference, evaluate it and push it on the stack.
10252
 *
10253
 * The variable bindings consist of a mapping from variable names
10254
 * to variable values. The value of a variable is an object, which can be
10255
 * of any of the types that are possible for the value of an expression,
10256
 * and may also be of additional types not specified here.
10257
 *
10258
 * Early evaluation is possible since:
10259
 * The variable bindings [...] used to evaluate a subexpression are
10260
 * always the same as those used to evaluate the containing expression.
10261
 *
10262
 *  [36]   VariableReference ::=   '$' QName
10263
 */
10264
static void
10265
46.0k
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10266
46.0k
    xmlChar *name;
10267
46.0k
    xmlChar *prefix;
10268
10269
46.0k
    SKIP_BLANKS;
10270
46.0k
    if (CUR != '$') {
10271
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10272
0
    }
10273
46.0k
    NEXT;
10274
46.0k
    name = xmlXPathParseQName(ctxt, &prefix);
10275
46.0k
    if (name == NULL) {
10276
2.08k
        xmlFree(prefix);
10277
2.08k
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10278
0
    }
10279
44.0k
    ctxt->comp->last = -1;
10280
44.0k
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10281
1
        xmlFree(prefix);
10282
1
        xmlFree(name);
10283
1
    }
10284
44.0k
    SKIP_BLANKS;
10285
44.0k
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10286
3.21k
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10287
0
    }
10288
44.0k
}
10289
10290
/**
10291
 * xmlXPathIsNodeType:
10292
 * @name:  a name string
10293
 *
10294
 * Is the name given a NodeType one.
10295
 *
10296
 *  [38]   NodeType ::=   'comment'
10297
 *                    | 'text'
10298
 *                    | 'processing-instruction'
10299
 *                    | 'node'
10300
 *
10301
 * Returns 1 if true 0 otherwise
10302
 */
10303
int
10304
929k
xmlXPathIsNodeType(const xmlChar *name) {
10305
929k
    if (name == NULL)
10306
0
  return(0);
10307
10308
929k
    if (xmlStrEqual(name, BAD_CAST "node"))
10309
4.81k
  return(1);
10310
924k
    if (xmlStrEqual(name, BAD_CAST "text"))
10311
5.48k
  return(1);
10312
919k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10313
1.55k
  return(1);
10314
917k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10315
3.63k
  return(1);
10316
914k
    return(0);
10317
917k
}
10318
10319
/**
10320
 * xmlXPathCompFunctionCall:
10321
 * @ctxt:  the XPath Parser context
10322
 *
10323
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10324
 *  [17]   Argument ::=   Expr
10325
 *
10326
 * Compile a function call, the evaluation of all arguments are
10327
 * pushed on the stack
10328
 */
10329
static void
10330
888k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10331
888k
    xmlChar *name;
10332
888k
    xmlChar *prefix;
10333
888k
    int nbargs = 0;
10334
888k
    int sort = 1;
10335
10336
888k
    name = xmlXPathParseQName(ctxt, &prefix);
10337
888k
    if (name == NULL) {
10338
1.37k
  xmlFree(prefix);
10339
1.37k
  XP_ERROR(XPATH_EXPR_ERROR);
10340
0
    }
10341
887k
    SKIP_BLANKS;
10342
#ifdef DEBUG_EXPR
10343
    if (prefix == NULL)
10344
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10345
      name);
10346
    else
10347
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10348
      prefix, name);
10349
#endif
10350
10351
887k
    if (CUR != '(') {
10352
755
  xmlFree(name);
10353
755
  xmlFree(prefix);
10354
755
  XP_ERROR(XPATH_EXPR_ERROR);
10355
0
    }
10356
886k
    NEXT;
10357
886k
    SKIP_BLANKS;
10358
10359
    /*
10360
    * Optimization for count(): we don't need the node-set to be sorted.
10361
    */
10362
886k
    if ((prefix == NULL) && (name[0] == 'c') &&
10363
886k
  xmlStrEqual(name, BAD_CAST "count"))
10364
5.01k
    {
10365
5.01k
  sort = 0;
10366
5.01k
    }
10367
886k
    ctxt->comp->last = -1;
10368
886k
    if (CUR != ')') {
10369
1.40M
  while (CUR != 0) {
10370
1.39M
      int op1 = ctxt->comp->last;
10371
1.39M
      ctxt->comp->last = -1;
10372
1.39M
      xmlXPathCompileExpr(ctxt, sort);
10373
1.39M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10374
99.8k
    xmlFree(name);
10375
99.8k
    xmlFree(prefix);
10376
99.8k
    return;
10377
99.8k
      }
10378
1.29M
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10379
1.29M
      nbargs++;
10380
1.29M
      if (CUR == ')') break;
10381
643k
      if (CUR != ',') {
10382
4.85k
    xmlFree(name);
10383
4.85k
    xmlFree(prefix);
10384
4.85k
    XP_ERROR(XPATH_EXPR_ERROR);
10385
0
      }
10386
638k
      NEXT;
10387
638k
      SKIP_BLANKS;
10388
638k
  }
10389
761k
    }
10390
781k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10391
5
        xmlFree(prefix);
10392
5
        xmlFree(name);
10393
5
    }
10394
781k
    NEXT;
10395
781k
    SKIP_BLANKS;
10396
781k
}
10397
10398
/**
10399
 * xmlXPathCompPrimaryExpr:
10400
 * @ctxt:  the XPath Parser context
10401
 *
10402
 *  [15]   PrimaryExpr ::=   VariableReference
10403
 *                | '(' Expr ')'
10404
 *                | Literal
10405
 *                | Number
10406
 *                | FunctionCall
10407
 *
10408
 * Compile a primary expression.
10409
 */
10410
static void
10411
1.51M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10412
1.51M
    SKIP_BLANKS;
10413
1.51M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10414
1.46M
    else if (CUR == '(') {
10415
171k
  NEXT;
10416
171k
  SKIP_BLANKS;
10417
171k
  xmlXPathCompileExpr(ctxt, 1);
10418
171k
  CHECK_ERROR;
10419
131k
  if (CUR != ')') {
10420
14.1k
      XP_ERROR(XPATH_EXPR_ERROR);
10421
0
  }
10422
117k
  NEXT;
10423
117k
  SKIP_BLANKS;
10424
1.29M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10425
312k
  xmlXPathCompNumber(ctxt);
10426
984k
    } else if ((CUR == '\'') || (CUR == '"')) {
10427
96.0k
  xmlXPathCompLiteral(ctxt);
10428
888k
    } else {
10429
888k
  xmlXPathCompFunctionCall(ctxt);
10430
888k
    }
10431
1.46M
    SKIP_BLANKS;
10432
1.46M
}
10433
10434
/**
10435
 * xmlXPathCompFilterExpr:
10436
 * @ctxt:  the XPath Parser context
10437
 *
10438
 *  [20]   FilterExpr ::=   PrimaryExpr
10439
 *               | FilterExpr Predicate
10440
 *
10441
 * Compile a filter expression.
10442
 * Square brackets are used to filter expressions in the same way that
10443
 * they are used in location paths. It is an error if the expression to
10444
 * be filtered does not evaluate to a node-set. The context node list
10445
 * used for evaluating the expression in square brackets is the node-set
10446
 * to be filtered listed in document order.
10447
 */
10448
10449
static void
10450
1.51M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10451
1.51M
    xmlXPathCompPrimaryExpr(ctxt);
10452
1.51M
    CHECK_ERROR;
10453
1.34M
    SKIP_BLANKS;
10454
10455
1.56M
    while (CUR == '[') {
10456
224k
  xmlXPathCompPredicate(ctxt, 1);
10457
224k
  SKIP_BLANKS;
10458
224k
    }
10459
10460
10461
1.34M
}
10462
10463
/**
10464
 * xmlXPathScanName:
10465
 * @ctxt:  the XPath Parser context
10466
 *
10467
 * Trickery: parse an XML name but without consuming the input flow
10468
 * Needed to avoid insanity in the parser state.
10469
 *
10470
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10471
 *                  CombiningChar | Extender
10472
 *
10473
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10474
 *
10475
 * [6] Names ::= Name (S Name)*
10476
 *
10477
 * Returns the Name parsed or NULL
10478
 */
10479
10480
static xmlChar *
10481
2.02M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10482
2.02M
    int l;
10483
2.02M
    int c;
10484
2.02M
    const xmlChar *cur;
10485
2.02M
    xmlChar *ret;
10486
10487
2.02M
    cur = ctxt->cur;
10488
10489
2.02M
    c = CUR_CHAR(l);
10490
2.02M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10491
2.02M
  (!IS_LETTER(c) && (c != '_') &&
10492
2.02M
         (c != ':'))) {
10493
137k
  return(NULL);
10494
137k
    }
10495
10496
16.2M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10497
16.2M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10498
16.0M
            (c == '.') || (c == '-') ||
10499
16.0M
      (c == '_') || (c == ':') ||
10500
16.0M
      (IS_COMBINING(c)) ||
10501
16.0M
      (IS_EXTENDER(c)))) {
10502
14.3M
  NEXTL(l);
10503
14.3M
  c = CUR_CHAR(l);
10504
14.3M
    }
10505
1.89M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10506
1.89M
    ctxt->cur = cur;
10507
1.89M
    return(ret);
10508
2.02M
}
10509
10510
/**
10511
 * xmlXPathCompPathExpr:
10512
 * @ctxt:  the XPath Parser context
10513
 *
10514
 *  [19]   PathExpr ::=   LocationPath
10515
 *               | FilterExpr
10516
 *               | FilterExpr '/' RelativeLocationPath
10517
 *               | FilterExpr '//' RelativeLocationPath
10518
 *
10519
 * Compile a path expression.
10520
 * The / operator and // operators combine an arbitrary expression
10521
 * and a relative location path. It is an error if the expression
10522
 * does not evaluate to a node-set.
10523
 * The / operator does composition in the same way as when / is
10524
 * used in a location path. As in location paths, // is short for
10525
 * /descendant-or-self::node()/.
10526
 */
10527
10528
static void
10529
8.78M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10530
8.78M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10531
8.78M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10532
10533
8.78M
    SKIP_BLANKS;
10534
8.78M
    if ((CUR == '$') || (CUR == '(') ||
10535
8.78M
  (IS_ASCII_DIGIT(CUR)) ||
10536
8.78M
        (CUR == '\'') || (CUR == '"') ||
10537
8.78M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10538
625k
  lc = 0;
10539
8.16M
    } else if (CUR == '*') {
10540
  /* relative or absolute location path */
10541
4.51M
  lc = 1;
10542
4.51M
    } else if (CUR == '/') {
10543
  /* relative or absolute location path */
10544
892k
  lc = 1;
10545
2.74M
    } else if (CUR == '@') {
10546
  /* relative abbreviated attribute location path */
10547
83.1k
  lc = 1;
10548
2.66M
    } else if (CUR == '.') {
10549
  /* relative abbreviated attribute location path */
10550
637k
  lc = 1;
10551
2.02M
    } else {
10552
  /*
10553
   * Problem is finding if we have a name here whether it's:
10554
   *   - a nodetype
10555
   *   - a function call in which case it's followed by '('
10556
   *   - an axis in which case it's followed by ':'
10557
   *   - a element name
10558
   * We do an a priori analysis here rather than having to
10559
   * maintain parsed token content through the recursive function
10560
   * calls. This looks uglier but makes the code easier to
10561
   * read/write/debug.
10562
   */
10563
2.02M
  SKIP_BLANKS;
10564
2.02M
  name = xmlXPathScanName(ctxt);
10565
2.02M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10566
#ifdef DEBUG_STEP
10567
      xmlGenericError(xmlGenericErrorContext,
10568
        "PathExpr: Axis\n");
10569
#endif
10570
8.28k
      lc = 1;
10571
8.28k
      xmlFree(name);
10572
2.02M
  } else if (name != NULL) {
10573
1.88M
      int len =xmlStrlen(name);
10574
10575
10576
3.19M
      while (NXT(len) != 0) {
10577
3.18M
    if (NXT(len) == '/') {
10578
        /* element name */
10579
#ifdef DEBUG_STEP
10580
        xmlGenericError(xmlGenericErrorContext,
10581
          "PathExpr: AbbrRelLocation\n");
10582
#endif
10583
74.9k
        lc = 1;
10584
74.9k
        break;
10585
3.11M
    } else if (IS_BLANK_CH(NXT(len))) {
10586
        /* ignore blanks */
10587
1.31M
        ;
10588
1.79M
    } else if (NXT(len) == ':') {
10589
#ifdef DEBUG_STEP
10590
        xmlGenericError(xmlGenericErrorContext,
10591
          "PathExpr: AbbrRelLocation\n");
10592
#endif
10593
2.04k
        lc = 1;
10594
2.04k
        break;
10595
1.79M
    } else if ((NXT(len) == '(')) {
10596
        /* Node Type or Function */
10597
899k
        if (xmlXPathIsNodeType(name)) {
10598
#ifdef DEBUG_STEP
10599
            xmlGenericError(xmlGenericErrorContext,
10600
        "PathExpr: Type search\n");
10601
#endif
10602
11.3k
      lc = 1;
10603
#ifdef LIBXML_XPTR_LOCS_ENABLED
10604
                    } else if (ctxt->xptr &&
10605
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10606
                        lc = 1;
10607
#endif
10608
888k
        } else {
10609
#ifdef DEBUG_STEP
10610
            xmlGenericError(xmlGenericErrorContext,
10611
        "PathExpr: function call\n");
10612
#endif
10613
888k
      lc = 0;
10614
888k
        }
10615
899k
                    break;
10616
899k
    } else if ((NXT(len) == '[')) {
10617
        /* element name */
10618
#ifdef DEBUG_STEP
10619
        xmlGenericError(xmlGenericErrorContext,
10620
          "PathExpr: AbbrRelLocation\n");
10621
#endif
10622
13.0k
        lc = 1;
10623
13.0k
        break;
10624
884k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10625
884k
         (NXT(len) == '=')) {
10626
91.5k
        lc = 1;
10627
91.5k
        break;
10628
792k
    } else {
10629
792k
        lc = 1;
10630
792k
        break;
10631
792k
    }
10632
1.31M
    len++;
10633
1.31M
      }
10634
1.88M
      if (NXT(len) == 0) {
10635
#ifdef DEBUG_STEP
10636
    xmlGenericError(xmlGenericErrorContext,
10637
      "PathExpr: AbbrRelLocation\n");
10638
#endif
10639
    /* element name */
10640
8.19k
    lc = 1;
10641
8.19k
      }
10642
1.88M
      xmlFree(name);
10643
1.88M
  } else {
10644
      /* make sure all cases are covered explicitly */
10645
137k
      XP_ERROR(XPATH_EXPR_ERROR);
10646
0
  }
10647
2.02M
    }
10648
10649
8.64M
    if (lc) {
10650
7.13M
  if (CUR == '/') {
10651
892k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10652
6.24M
  } else {
10653
6.24M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10654
6.24M
  }
10655
7.13M
  xmlXPathCompLocationPath(ctxt);
10656
7.13M
    } else {
10657
1.51M
  xmlXPathCompFilterExpr(ctxt);
10658
1.51M
  CHECK_ERROR;
10659
1.33M
  if ((CUR == '/') && (NXT(1) == '/')) {
10660
2.64k
      SKIP(2);
10661
2.64k
      SKIP_BLANKS;
10662
10663
2.64k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10664
2.64k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10665
10666
2.64k
      xmlXPathCompRelativeLocationPath(ctxt);
10667
1.32M
  } else if (CUR == '/') {
10668
537k
      xmlXPathCompRelativeLocationPath(ctxt);
10669
537k
  }
10670
1.33M
    }
10671
8.46M
    SKIP_BLANKS;
10672
8.46M
}
10673
10674
/**
10675
 * xmlXPathCompUnionExpr:
10676
 * @ctxt:  the XPath Parser context
10677
 *
10678
 *  [18]   UnionExpr ::=   PathExpr
10679
 *               | UnionExpr '|' PathExpr
10680
 *
10681
 * Compile an union expression.
10682
 */
10683
10684
static void
10685
8.06M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10686
8.06M
    xmlXPathCompPathExpr(ctxt);
10687
8.06M
    CHECK_ERROR;
10688
7.73M
    SKIP_BLANKS;
10689
8.45M
    while (CUR == '|') {
10690
724k
  int op1 = ctxt->comp->last;
10691
724k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10692
10693
724k
  NEXT;
10694
724k
  SKIP_BLANKS;
10695
724k
  xmlXPathCompPathExpr(ctxt);
10696
10697
724k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10698
10699
724k
  SKIP_BLANKS;
10700
724k
    }
10701
7.73M
}
10702
10703
/**
10704
 * xmlXPathCompUnaryExpr:
10705
 * @ctxt:  the XPath Parser context
10706
 *
10707
 *  [27]   UnaryExpr ::=   UnionExpr
10708
 *                   | '-' UnaryExpr
10709
 *
10710
 * Compile an unary expression.
10711
 */
10712
10713
static void
10714
8.06M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10715
8.06M
    int minus = 0;
10716
8.06M
    int found = 0;
10717
10718
8.06M
    SKIP_BLANKS;
10719
8.66M
    while (CUR == '-') {
10720
605k
        minus = 1 - minus;
10721
605k
  found = 1;
10722
605k
  NEXT;
10723
605k
  SKIP_BLANKS;
10724
605k
    }
10725
10726
8.06M
    xmlXPathCompUnionExpr(ctxt);
10727
8.06M
    CHECK_ERROR;
10728
7.69M
    if (found) {
10729
70.7k
  if (minus)
10730
46.0k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10731
24.6k
  else
10732
24.6k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10733
70.7k
    }
10734
7.69M
}
10735
10736
/**
10737
 * xmlXPathCompMultiplicativeExpr:
10738
 * @ctxt:  the XPath Parser context
10739
 *
10740
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10741
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10742
 *                   | MultiplicativeExpr 'div' UnaryExpr
10743
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10744
 *  [34]   MultiplyOperator ::=   '*'
10745
 *
10746
 * Compile an Additive expression.
10747
 */
10748
10749
static void
10750
3.50M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10751
3.50M
    xmlXPathCompUnaryExpr(ctxt);
10752
3.50M
    CHECK_ERROR;
10753
3.15M
    SKIP_BLANKS;
10754
7.69M
    while ((CUR == '*') ||
10755
7.69M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10756
7.69M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10757
4.56M
  int op = -1;
10758
4.56M
  int op1 = ctxt->comp->last;
10759
10760
4.56M
        if (CUR == '*') {
10761
4.49M
      op = 0;
10762
4.49M
      NEXT;
10763
4.49M
  } else if (CUR == 'd') {
10764
1.50k
      op = 1;
10765
1.50k
      SKIP(3);
10766
65.8k
  } else if (CUR == 'm') {
10767
65.8k
      op = 2;
10768
65.8k
      SKIP(3);
10769
65.8k
  }
10770
4.56M
  SKIP_BLANKS;
10771
4.56M
        xmlXPathCompUnaryExpr(ctxt);
10772
4.56M
  CHECK_ERROR;
10773
4.54M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10774
4.54M
  SKIP_BLANKS;
10775
4.54M
    }
10776
3.15M
}
10777
10778
/**
10779
 * xmlXPathCompAdditiveExpr:
10780
 * @ctxt:  the XPath Parser context
10781
 *
10782
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10783
 *                   | AdditiveExpr '+' MultiplicativeExpr
10784
 *                   | AdditiveExpr '-' MultiplicativeExpr
10785
 *
10786
 * Compile an Additive expression.
10787
 */
10788
10789
static void
10790
3.29M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10791
10792
3.29M
    xmlXPathCompMultiplicativeExpr(ctxt);
10793
3.29M
    CHECK_ERROR;
10794
2.95M
    SKIP_BLANKS;
10795
3.13M
    while ((CUR == '+') || (CUR == '-')) {
10796
206k
  int plus;
10797
206k
  int op1 = ctxt->comp->last;
10798
10799
206k
        if (CUR == '+') plus = 1;
10800
99.2k
  else plus = 0;
10801
206k
  NEXT;
10802
206k
  SKIP_BLANKS;
10803
206k
        xmlXPathCompMultiplicativeExpr(ctxt);
10804
206k
  CHECK_ERROR;
10805
181k
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10806
181k
  SKIP_BLANKS;
10807
181k
    }
10808
2.95M
}
10809
10810
/**
10811
 * xmlXPathCompRelationalExpr:
10812
 * @ctxt:  the XPath Parser context
10813
 *
10814
 *  [24]   RelationalExpr ::=   AdditiveExpr
10815
 *                 | RelationalExpr '<' AdditiveExpr
10816
 *                 | RelationalExpr '>' AdditiveExpr
10817
 *                 | RelationalExpr '<=' AdditiveExpr
10818
 *                 | RelationalExpr '>=' AdditiveExpr
10819
 *
10820
 *  A <= B > C is allowed ? Answer from James, yes with
10821
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10822
 *  which is basically what got implemented.
10823
 *
10824
 * Compile a Relational expression, then push the result
10825
 * on the stack
10826
 */
10827
10828
static void
10829
2.82M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10830
2.82M
    xmlXPathCompAdditiveExpr(ctxt);
10831
2.82M
    CHECK_ERROR;
10832
2.48M
    SKIP_BLANKS;
10833
2.92M
    while ((CUR == '<') || (CUR == '>')) {
10834
471k
  int inf, strict;
10835
471k
  int op1 = ctxt->comp->last;
10836
10837
471k
        if (CUR == '<') inf = 1;
10838
470k
  else inf = 0;
10839
471k
  if (NXT(1) == '=') strict = 0;
10840
471k
  else strict = 1;
10841
471k
  NEXT;
10842
471k
  if (!strict) NEXT;
10843
471k
  SKIP_BLANKS;
10844
471k
        xmlXPathCompAdditiveExpr(ctxt);
10845
471k
  CHECK_ERROR;
10846
449k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10847
449k
  SKIP_BLANKS;
10848
449k
    }
10849
2.48M
}
10850
10851
/**
10852
 * xmlXPathCompEqualityExpr:
10853
 * @ctxt:  the XPath Parser context
10854
 *
10855
 *  [23]   EqualityExpr ::=   RelationalExpr
10856
 *                 | EqualityExpr '=' RelationalExpr
10857
 *                 | EqualityExpr '!=' RelationalExpr
10858
 *
10859
 *  A != B != C is allowed ? Answer from James, yes with
10860
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10861
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10862
 *  which is basically what got implemented.
10863
 *
10864
 * Compile an Equality expression.
10865
 *
10866
 */
10867
static void
10868
2.53M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10869
2.53M
    xmlXPathCompRelationalExpr(ctxt);
10870
2.53M
    CHECK_ERROR;
10871
2.21M
    SKIP_BLANKS;
10872
2.45M
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10873
283k
  int eq;
10874
283k
  int op1 = ctxt->comp->last;
10875
10876
283k
        if (CUR == '=') eq = 1;
10877
18.2k
  else eq = 0;
10878
283k
  NEXT;
10879
283k
  if (!eq) NEXT;
10880
283k
  SKIP_BLANKS;
10881
283k
        xmlXPathCompRelationalExpr(ctxt);
10882
283k
  CHECK_ERROR;
10883
247k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10884
247k
  SKIP_BLANKS;
10885
247k
    }
10886
2.21M
}
10887
10888
/**
10889
 * xmlXPathCompAndExpr:
10890
 * @ctxt:  the XPath Parser context
10891
 *
10892
 *  [22]   AndExpr ::=   EqualityExpr
10893
 *                 | AndExpr 'and' EqualityExpr
10894
 *
10895
 * Compile an AND expression.
10896
 *
10897
 */
10898
static void
10899
2.51M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10900
2.51M
    xmlXPathCompEqualityExpr(ctxt);
10901
2.51M
    CHECK_ERROR;
10902
2.15M
    SKIP_BLANKS;
10903
2.17M
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10904
20.9k
  int op1 = ctxt->comp->last;
10905
20.9k
        SKIP(3);
10906
20.9k
  SKIP_BLANKS;
10907
20.9k
        xmlXPathCompEqualityExpr(ctxt);
10908
20.9k
  CHECK_ERROR;
10909
19.1k
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10910
19.1k
  SKIP_BLANKS;
10911
19.1k
    }
10912
2.15M
}
10913
10914
/**
10915
 * xmlXPathCompileExpr:
10916
 * @ctxt:  the XPath Parser context
10917
 *
10918
 *  [14]   Expr ::=   OrExpr
10919
 *  [21]   OrExpr ::=   AndExpr
10920
 *                 | OrExpr 'or' AndExpr
10921
 *
10922
 * Parse and compile an expression
10923
 */
10924
static void
10925
2.59M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10926
2.59M
    xmlXPathContextPtr xpctxt = ctxt->context;
10927
10928
2.59M
    if (xpctxt != NULL) {
10929
2.59M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10930
2.50M
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10931
        /*
10932
         * Parsing a single '(' pushes about 10 functions on the call stack
10933
         * before recursing!
10934
         */
10935
2.50M
        xpctxt->depth += 10;
10936
2.50M
    }
10937
10938
2.50M
    xmlXPathCompAndExpr(ctxt);
10939
2.50M
    CHECK_ERROR;
10940
2.14M
    SKIP_BLANKS;
10941
2.15M
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10942
12.3k
  int op1 = ctxt->comp->last;
10943
12.3k
        SKIP(2);
10944
12.3k
  SKIP_BLANKS;
10945
12.3k
        xmlXPathCompAndExpr(ctxt);
10946
12.3k
  CHECK_ERROR;
10947
9.45k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10948
9.45k
  SKIP_BLANKS;
10949
9.45k
    }
10950
2.14M
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10951
  /* more ops could be optimized too */
10952
  /*
10953
  * This is the main place to eliminate sorting for
10954
  * operations which don't require a sorted node-set.
10955
  * E.g. count().
10956
  */
10957
1.87M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10958
1.87M
    }
10959
10960
2.14M
    if (xpctxt != NULL)
10961
2.14M
        xpctxt->depth -= 10;
10962
2.14M
}
10963
10964
/**
10965
 * xmlXPathCompPredicate:
10966
 * @ctxt:  the XPath Parser context
10967
 * @filter:  act as a filter
10968
 *
10969
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10970
 *  [9]   PredicateExpr ::=   Expr
10971
 *
10972
 * Compile a predicate expression
10973
 */
10974
static void
10975
338k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10976
338k
    int op1 = ctxt->comp->last;
10977
10978
338k
    SKIP_BLANKS;
10979
338k
    if (CUR != '[') {
10980
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10981
0
    }
10982
338k
    NEXT;
10983
338k
    SKIP_BLANKS;
10984
10985
338k
    ctxt->comp->last = -1;
10986
    /*
10987
    * This call to xmlXPathCompileExpr() will deactivate sorting
10988
    * of the predicate result.
10989
    * TODO: Sorting is still activated for filters, since I'm not
10990
    *  sure if needed. Normally sorting should not be needed, since
10991
    *  a filter can only diminish the number of items in a sequence,
10992
    *  but won't change its order; so if the initial sequence is sorted,
10993
    *  subsequent sorting is not needed.
10994
    */
10995
338k
    if (! filter)
10996
114k
  xmlXPathCompileExpr(ctxt, 0);
10997
224k
    else
10998
224k
  xmlXPathCompileExpr(ctxt, 1);
10999
338k
    CHECK_ERROR;
11000
11001
295k
    if (CUR != ']') {
11002
1.75k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11003
0
    }
11004
11005
293k
    if (filter)
11006
209k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11007
83.5k
    else
11008
83.5k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11009
11010
293k
    NEXT;
11011
293k
    SKIP_BLANKS;
11012
293k
}
11013
11014
/**
11015
 * xmlXPathCompNodeTest:
11016
 * @ctxt:  the XPath Parser context
11017
 * @test:  pointer to a xmlXPathTestVal
11018
 * @type:  pointer to a xmlXPathTypeVal
11019
 * @prefix:  placeholder for a possible name prefix
11020
 *
11021
 * [7] NodeTest ::=   NameTest
11022
 *        | NodeType '(' ')'
11023
 *        | 'processing-instruction' '(' Literal ')'
11024
 *
11025
 * [37] NameTest ::=  '*'
11026
 *        | NCName ':' '*'
11027
 *        | QName
11028
 * [38] NodeType ::= 'comment'
11029
 *       | 'text'
11030
 *       | 'processing-instruction'
11031
 *       | 'node'
11032
 *
11033
 * Returns the name found and updates @test, @type and @prefix appropriately
11034
 */
11035
static xmlChar *
11036
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11037
               xmlXPathTypeVal *type, xmlChar **prefix,
11038
6.73M
         xmlChar *name) {
11039
6.73M
    int blanks;
11040
11041
6.73M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11042
0
  STRANGE;
11043
0
  return(NULL);
11044
0
    }
11045
6.73M
    *type = (xmlXPathTypeVal) 0;
11046
6.73M
    *test = (xmlXPathTestVal) 0;
11047
6.73M
    *prefix = NULL;
11048
6.73M
    SKIP_BLANKS;
11049
11050
6.73M
    if ((name == NULL) && (CUR == '*')) {
11051
  /*
11052
   * All elements
11053
   */
11054
4.73M
  NEXT;
11055
4.73M
  *test = NODE_TEST_ALL;
11056
4.73M
  return(NULL);
11057
4.73M
    }
11058
11059
1.99M
    if (name == NULL)
11060
132k
  name = xmlXPathParseNCName(ctxt);
11061
1.99M
    if (name == NULL) {
11062
35.3k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11063
0
    }
11064
11065
1.96M
    blanks = IS_BLANK_CH(CUR);
11066
1.96M
    SKIP_BLANKS;
11067
1.96M
    if (CUR == '(') {
11068
86.4k
  NEXT;
11069
  /*
11070
   * NodeType or PI search
11071
   */
11072
86.4k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11073
7.53k
      *type = NODE_TYPE_COMMENT;
11074
78.8k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11075
22.3k
      *type = NODE_TYPE_NODE;
11076
56.5k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11077
12.0k
      *type = NODE_TYPE_PI;
11078
44.4k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11079
41.6k
      *type = NODE_TYPE_TEXT;
11080
2.80k
  else {
11081
2.80k
      if (name != NULL)
11082
2.80k
    xmlFree(name);
11083
2.80k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11084
0
  }
11085
11086
83.6k
  *test = NODE_TEST_TYPE;
11087
11088
83.6k
  SKIP_BLANKS;
11089
83.6k
  if (*type == NODE_TYPE_PI) {
11090
      /*
11091
       * Specific case: search a PI by name.
11092
       */
11093
12.0k
      if (name != NULL)
11094
12.0k
    xmlFree(name);
11095
12.0k
      name = NULL;
11096
12.0k
      if (CUR != ')') {
11097
6.87k
    name = xmlXPathParseLiteral(ctxt);
11098
6.87k
                if (name == NULL) {
11099
222
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11100
0
                }
11101
6.65k
    *test = NODE_TEST_PI;
11102
6.65k
    SKIP_BLANKS;
11103
6.65k
      }
11104
12.0k
  }
11105
83.3k
  if (CUR != ')') {
11106
1.09k
      if (name != NULL)
11107
1.09k
    xmlFree(name);
11108
1.09k
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11109
0
  }
11110
82.2k
  NEXT;
11111
82.2k
  return(name);
11112
83.3k
    }
11113
1.87M
    *test = NODE_TEST_NAME;
11114
1.87M
    if ((!blanks) && (CUR == ':')) {
11115
102k
  NEXT;
11116
11117
  /*
11118
   * Since currently the parser context don't have a
11119
   * namespace list associated:
11120
   * The namespace name for this prefix can be computed
11121
   * only at evaluation time. The compilation is done
11122
   * outside of any context.
11123
   */
11124
#if 0
11125
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11126
  if (name != NULL)
11127
      xmlFree(name);
11128
  if (*prefix == NULL) {
11129
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11130
  }
11131
#else
11132
102k
  *prefix = name;
11133
102k
#endif
11134
11135
102k
  if (CUR == '*') {
11136
      /*
11137
       * All elements
11138
       */
11139
30.6k
      NEXT;
11140
30.6k
      *test = NODE_TEST_ALL;
11141
30.6k
      return(NULL);
11142
30.6k
  }
11143
11144
71.6k
  name = xmlXPathParseNCName(ctxt);
11145
71.6k
  if (name == NULL) {
11146
7.04k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11147
0
  }
11148
71.6k
    }
11149
1.83M
    return(name);
11150
1.87M
}
11151
11152
/**
11153
 * xmlXPathIsAxisName:
11154
 * @name:  a preparsed name token
11155
 *
11156
 * [6] AxisName ::=   'ancestor'
11157
 *                  | 'ancestor-or-self'
11158
 *                  | 'attribute'
11159
 *                  | 'child'
11160
 *                  | 'descendant'
11161
 *                  | 'descendant-or-self'
11162
 *                  | 'following'
11163
 *                  | 'following-sibling'
11164
 *                  | 'namespace'
11165
 *                  | 'parent'
11166
 *                  | 'preceding'
11167
 *                  | 'preceding-sibling'
11168
 *                  | 'self'
11169
 *
11170
 * Returns the axis or 0
11171
 */
11172
static xmlXPathAxisVal
11173
2.00M
xmlXPathIsAxisName(const xmlChar *name) {
11174
2.00M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11175
2.00M
    switch (name[0]) {
11176
116k
  case 'a':
11177
116k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11178
3.93k
    ret = AXIS_ANCESTOR;
11179
116k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11180
2.66k
    ret = AXIS_ANCESTOR_OR_SELF;
11181
116k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11182
3.57k
    ret = AXIS_ATTRIBUTE;
11183
116k
      break;
11184
27.6k
  case 'c':
11185
27.6k
      if (xmlStrEqual(name, BAD_CAST "child"))
11186
308
    ret = AXIS_CHILD;
11187
27.6k
      break;
11188
20.4k
  case 'd':
11189
20.4k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11190
83
    ret = AXIS_DESCENDANT;
11191
20.4k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11192
74
    ret = AXIS_DESCENDANT_OR_SELF;
11193
20.4k
      break;
11194
7.80k
  case 'f':
11195
7.80k
      if (xmlStrEqual(name, BAD_CAST "following"))
11196
130
    ret = AXIS_FOLLOWING;
11197
7.80k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11198
92
    ret = AXIS_FOLLOWING_SIBLING;
11199
7.80k
      break;
11200
589k
  case 'n':
11201
589k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11202
146k
    ret = AXIS_NAMESPACE;
11203
589k
      break;
11204
71.1k
  case 'p':
11205
71.1k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11206
274
    ret = AXIS_PARENT;
11207
71.1k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11208
356
    ret = AXIS_PRECEDING;
11209
71.1k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11210
136
    ret = AXIS_PRECEDING_SIBLING;
11211
71.1k
      break;
11212
34.2k
  case 's':
11213
34.2k
      if (xmlStrEqual(name, BAD_CAST "self"))
11214
2.57k
    ret = AXIS_SELF;
11215
34.2k
      break;
11216
2.00M
    }
11217
2.00M
    return(ret);
11218
2.00M
}
11219
11220
/**
11221
 * xmlXPathCompStep:
11222
 * @ctxt:  the XPath Parser context
11223
 *
11224
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11225
 *                  | AbbreviatedStep
11226
 *
11227
 * [12] AbbreviatedStep ::=   '.' | '..'
11228
 *
11229
 * [5] AxisSpecifier ::= AxisName '::'
11230
 *                  | AbbreviatedAxisSpecifier
11231
 *
11232
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11233
 *
11234
 * Modified for XPtr range support as:
11235
 *
11236
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11237
 *                     | AbbreviatedStep
11238
 *                     | 'range-to' '(' Expr ')' Predicate*
11239
 *
11240
 * Compile one step in a Location Path
11241
 * A location step of . is short for self::node(). This is
11242
 * particularly useful in conjunction with //. For example, the
11243
 * location path .//para is short for
11244
 * self::node()/descendant-or-self::node()/child::para
11245
 * and so will select all para descendant elements of the context
11246
 * node.
11247
 * Similarly, a location step of .. is short for parent::node().
11248
 * For example, ../title is short for parent::node()/child::title
11249
 * and so will select the title children of the parent of the context
11250
 * node.
11251
 */
11252
static void
11253
7.63M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11254
#ifdef LIBXML_XPTR_LOCS_ENABLED
11255
    int rangeto = 0;
11256
    int op2 = -1;
11257
#endif
11258
11259
7.63M
    SKIP_BLANKS;
11260
7.63M
    if ((CUR == '.') && (NXT(1) == '.')) {
11261
44.0k
  SKIP(2);
11262
44.0k
  SKIP_BLANKS;
11263
44.0k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11264
44.0k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11265
7.59M
    } else if (CUR == '.') {
11266
761k
  NEXT;
11267
761k
  SKIP_BLANKS;
11268
6.83M
    } else {
11269
6.83M
  xmlChar *name = NULL;
11270
6.83M
  xmlChar *prefix = NULL;
11271
6.83M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11272
6.83M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11273
6.83M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11274
6.83M
  int op1;
11275
11276
  /*
11277
   * The modification needed for XPointer change to the production
11278
   */
11279
#ifdef LIBXML_XPTR_LOCS_ENABLED
11280
  if (ctxt->xptr) {
11281
      name = xmlXPathParseNCName(ctxt);
11282
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11283
                op2 = ctxt->comp->last;
11284
    xmlFree(name);
11285
    SKIP_BLANKS;
11286
    if (CUR != '(') {
11287
        XP_ERROR(XPATH_EXPR_ERROR);
11288
    }
11289
    NEXT;
11290
    SKIP_BLANKS;
11291
11292
    xmlXPathCompileExpr(ctxt, 1);
11293
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11294
    CHECK_ERROR;
11295
11296
    SKIP_BLANKS;
11297
    if (CUR != ')') {
11298
        XP_ERROR(XPATH_EXPR_ERROR);
11299
    }
11300
    NEXT;
11301
    rangeto = 1;
11302
    goto eval_predicates;
11303
      }
11304
  }
11305
#endif
11306
6.83M
  if (CUR == '*') {
11307
4.59M
      axis = AXIS_CHILD;
11308
4.59M
  } else {
11309
2.23M
      if (name == NULL)
11310
2.23M
    name = xmlXPathParseNCName(ctxt);
11311
2.23M
      if (name != NULL) {
11312
2.00M
    axis = xmlXPathIsAxisName(name);
11313
2.00M
    if (axis != 0) {
11314
160k
        SKIP_BLANKS;
11315
160k
        if ((CUR == ':') && (NXT(1) == ':')) {
11316
141k
      SKIP(2);
11317
141k
      xmlFree(name);
11318
141k
      name = NULL;
11319
141k
        } else {
11320
      /* an element name can conflict with an axis one :-\ */
11321
19.6k
      axis = AXIS_CHILD;
11322
19.6k
        }
11323
1.84M
    } else {
11324
1.84M
        axis = AXIS_CHILD;
11325
1.84M
    }
11326
2.00M
      } else if (CUR == '@') {
11327
92.5k
    NEXT;
11328
92.5k
    axis = AXIS_ATTRIBUTE;
11329
131k
      } else {
11330
131k
    axis = AXIS_CHILD;
11331
131k
      }
11332
2.23M
  }
11333
11334
6.83M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11335
99.3k
            xmlFree(name);
11336
99.3k
            return;
11337
99.3k
        }
11338
11339
6.73M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11340
6.73M
  if (test == 0)
11341
38.1k
      return;
11342
11343
6.69M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11344
6.69M
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11345
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11346
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11347
0
      }
11348
0
  }
11349
#ifdef DEBUG_STEP
11350
  xmlGenericError(xmlGenericErrorContext,
11351
    "Basis : computing new set\n");
11352
#endif
11353
11354
#ifdef DEBUG_STEP
11355
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11356
  if (ctxt->value == NULL)
11357
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11358
  else if (ctxt->value->nodesetval == NULL)
11359
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11360
  else
11361
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11362
#endif
11363
11364
#ifdef LIBXML_XPTR_LOCS_ENABLED
11365
eval_predicates:
11366
#endif
11367
6.69M
  op1 = ctxt->comp->last;
11368
6.69M
  ctxt->comp->last = -1;
11369
11370
6.69M
  SKIP_BLANKS;
11371
6.80M
  while (CUR == '[') {
11372
114k
      xmlXPathCompPredicate(ctxt, 0);
11373
114k
  }
11374
11375
#ifdef LIBXML_XPTR_LOCS_ENABLED
11376
  if (rangeto) {
11377
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11378
  } else
11379
#endif
11380
6.69M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11381
6.69M
                           test, type, (void *)prefix, (void *)name) == -1) {
11382
40
            xmlFree(prefix);
11383
40
            xmlFree(name);
11384
40
        }
11385
6.69M
    }
11386
#ifdef DEBUG_STEP
11387
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11388
    if (ctxt->value == NULL)
11389
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11390
    else if (ctxt->value->nodesetval == NULL)
11391
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11392
    else
11393
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11394
    ctxt->value->nodesetval);
11395
#endif
11396
7.63M
}
11397
11398
/**
11399
 * xmlXPathCompRelativeLocationPath:
11400
 * @ctxt:  the XPath Parser context
11401
 *
11402
 *  [3]   RelativeLocationPath ::=   Step
11403
 *                     | RelativeLocationPath '/' Step
11404
 *                     | AbbreviatedRelativeLocationPath
11405
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11406
 *
11407
 * Compile a relative location path.
11408
 */
11409
static void
11410
xmlXPathCompRelativeLocationPath
11411
7.18M
(xmlXPathParserContextPtr ctxt) {
11412
7.18M
    SKIP_BLANKS;
11413
7.18M
    if ((CUR == '/') && (NXT(1) == '/')) {
11414
1.09k
  SKIP(2);
11415
1.09k
  SKIP_BLANKS;
11416
1.09k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11417
1.09k
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11418
7.18M
    } else if (CUR == '/') {
11419
539k
      NEXT;
11420
539k
  SKIP_BLANKS;
11421
539k
    }
11422
7.18M
    xmlXPathCompStep(ctxt);
11423
7.18M
    CHECK_ERROR;
11424
7.15M
    SKIP_BLANKS;
11425
7.59M
    while (CUR == '/') {
11426
447k
  if ((CUR == '/') && (NXT(1) == '/')) {
11427
132k
      SKIP(2);
11428
132k
      SKIP_BLANKS;
11429
132k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11430
132k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11431
132k
      xmlXPathCompStep(ctxt);
11432
315k
  } else if (CUR == '/') {
11433
315k
      NEXT;
11434
315k
      SKIP_BLANKS;
11435
315k
      xmlXPathCompStep(ctxt);
11436
315k
  }
11437
447k
  SKIP_BLANKS;
11438
447k
    }
11439
7.15M
}
11440
11441
/**
11442
 * xmlXPathCompLocationPath:
11443
 * @ctxt:  the XPath Parser context
11444
 *
11445
 *  [1]   LocationPath ::=   RelativeLocationPath
11446
 *                     | AbsoluteLocationPath
11447
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11448
 *                     | AbbreviatedAbsoluteLocationPath
11449
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11450
 *                           '//' RelativeLocationPath
11451
 *
11452
 * Compile a location path
11453
 *
11454
 * // is short for /descendant-or-self::node()/. For example,
11455
 * //para is short for /descendant-or-self::node()/child::para and
11456
 * so will select any para element in the document (even a para element
11457
 * that is a document element will be selected by //para since the
11458
 * document element node is a child of the root node); div//para is
11459
 * short for div/descendant-or-self::node()/child::para and so will
11460
 * select all para descendants of div children.
11461
 */
11462
static void
11463
7.13M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11464
7.13M
    SKIP_BLANKS;
11465
7.13M
    if (CUR != '/') {
11466
6.24M
        xmlXPathCompRelativeLocationPath(ctxt);
11467
6.24M
    } else {
11468
1.76M
  while (CUR == '/') {
11469
895k
      if ((CUR == '/') && (NXT(1) == '/')) {
11470
142k
    SKIP(2);
11471
142k
    SKIP_BLANKS;
11472
142k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11473
142k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11474
142k
    xmlXPathCompRelativeLocationPath(ctxt);
11475
753k
      } else if (CUR == '/') {
11476
753k
    NEXT;
11477
753k
    SKIP_BLANKS;
11478
753k
    if ((CUR != 0 ) &&
11479
753k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11480
750k
         (CUR == '@') || (CUR == '*')))
11481
264k
        xmlXPathCompRelativeLocationPath(ctxt);
11482
753k
      }
11483
895k
      CHECK_ERROR;
11484
895k
  }
11485
892k
    }
11486
7.13M
}
11487
11488
/************************************************************************
11489
 *                  *
11490
 *    XPath precompiled expression evaluation     *
11491
 *                  *
11492
 ************************************************************************/
11493
11494
static int
11495
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11496
11497
#ifdef DEBUG_STEP
11498
static void
11499
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11500
        int nbNodes)
11501
{
11502
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11503
    switch (op->value) {
11504
        case AXIS_ANCESTOR:
11505
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11506
            break;
11507
        case AXIS_ANCESTOR_OR_SELF:
11508
            xmlGenericError(xmlGenericErrorContext,
11509
                            "axis 'ancestors-or-self' ");
11510
            break;
11511
        case AXIS_ATTRIBUTE:
11512
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11513
            break;
11514
        case AXIS_CHILD:
11515
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11516
            break;
11517
        case AXIS_DESCENDANT:
11518
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11519
            break;
11520
        case AXIS_DESCENDANT_OR_SELF:
11521
            xmlGenericError(xmlGenericErrorContext,
11522
                            "axis 'descendant-or-self' ");
11523
            break;
11524
        case AXIS_FOLLOWING:
11525
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11526
            break;
11527
        case AXIS_FOLLOWING_SIBLING:
11528
            xmlGenericError(xmlGenericErrorContext,
11529
                            "axis 'following-siblings' ");
11530
            break;
11531
        case AXIS_NAMESPACE:
11532
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11533
            break;
11534
        case AXIS_PARENT:
11535
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11536
            break;
11537
        case AXIS_PRECEDING:
11538
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11539
            break;
11540
        case AXIS_PRECEDING_SIBLING:
11541
            xmlGenericError(xmlGenericErrorContext,
11542
                            "axis 'preceding-sibling' ");
11543
            break;
11544
        case AXIS_SELF:
11545
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11546
            break;
11547
    }
11548
    xmlGenericError(xmlGenericErrorContext,
11549
  " context contains %d nodes\n", nbNodes);
11550
    switch (op->value2) {
11551
        case NODE_TEST_NONE:
11552
            xmlGenericError(xmlGenericErrorContext,
11553
                            "           searching for none !!!\n");
11554
            break;
11555
        case NODE_TEST_TYPE:
11556
            xmlGenericError(xmlGenericErrorContext,
11557
                            "           searching for type %d\n", op->value3);
11558
            break;
11559
        case NODE_TEST_PI:
11560
            xmlGenericError(xmlGenericErrorContext,
11561
                            "           searching for PI !!!\n");
11562
            break;
11563
        case NODE_TEST_ALL:
11564
            xmlGenericError(xmlGenericErrorContext,
11565
                            "           searching for *\n");
11566
            break;
11567
        case NODE_TEST_NS:
11568
            xmlGenericError(xmlGenericErrorContext,
11569
                            "           searching for namespace %s\n",
11570
                            op->value5);
11571
            break;
11572
        case NODE_TEST_NAME:
11573
            xmlGenericError(xmlGenericErrorContext,
11574
                            "           searching for name %s\n", op->value5);
11575
            if (op->value4)
11576
                xmlGenericError(xmlGenericErrorContext,
11577
                                "           with namespace %s\n", op->value4);
11578
            break;
11579
    }
11580
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11581
}
11582
#endif /* DEBUG_STEP */
11583
11584
/**
11585
 * xmlXPathNodeSetFilter:
11586
 * @ctxt:  the XPath Parser context
11587
 * @set: the node set to filter
11588
 * @filterOpIndex: the index of the predicate/filter op
11589
 * @minPos: minimum position in the filtered set (1-based)
11590
 * @maxPos: maximum position in the filtered set (1-based)
11591
 * @hasNsNodes: true if the node set may contain namespace nodes
11592
 *
11593
 * Filter a node set, keeping only nodes for which the predicate expression
11594
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11595
 * filtered result.
11596
 */
11597
static void
11598
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11599
          xmlNodeSetPtr set,
11600
          int filterOpIndex,
11601
                      int minPos, int maxPos,
11602
          int hasNsNodes)
11603
230k
{
11604
230k
    xmlXPathContextPtr xpctxt;
11605
230k
    xmlNodePtr oldnode;
11606
230k
    xmlDocPtr olddoc;
11607
230k
    xmlXPathStepOpPtr filterOp;
11608
230k
    int oldcs, oldpp;
11609
230k
    int i, j, pos;
11610
11611
230k
    if ((set == NULL) || (set->nodeNr == 0))
11612
77.5k
        return;
11613
11614
    /*
11615
    * Check if the node set contains a sufficient number of nodes for
11616
    * the requested range.
11617
    */
11618
152k
    if (set->nodeNr < minPos) {
11619
7.71k
        xmlXPathNodeSetClear(set, hasNsNodes);
11620
7.71k
        return;
11621
7.71k
    }
11622
11623
145k
    xpctxt = ctxt->context;
11624
145k
    oldnode = xpctxt->node;
11625
145k
    olddoc = xpctxt->doc;
11626
145k
    oldcs = xpctxt->contextSize;
11627
145k
    oldpp = xpctxt->proximityPosition;
11628
145k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11629
11630
145k
    xpctxt->contextSize = set->nodeNr;
11631
11632
725k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11633
677k
        xmlNodePtr node = set->nodeTab[i];
11634
677k
        int res;
11635
11636
677k
        xpctxt->node = node;
11637
677k
        xpctxt->proximityPosition = i + 1;
11638
11639
        /*
11640
        * Also set the xpath document in case things like
11641
        * key() are evaluated in the predicate.
11642
        *
11643
        * TODO: Get real doc for namespace nodes.
11644
        */
11645
677k
        if ((node->type != XML_NAMESPACE_DECL) &&
11646
677k
            (node->doc != NULL))
11647
611k
            xpctxt->doc = node->doc;
11648
11649
677k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11650
11651
677k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11652
5.52k
            break;
11653
672k
        if (res < 0) {
11654
            /* Shouldn't happen */
11655
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11656
0
            break;
11657
0
        }
11658
11659
672k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11660
336k
            if (i != j) {
11661
33.2k
                set->nodeTab[j] = node;
11662
33.2k
                set->nodeTab[i] = NULL;
11663
33.2k
            }
11664
11665
336k
            j += 1;
11666
336k
        } else {
11667
            /* Remove the entry from the initial node set. */
11668
335k
            set->nodeTab[i] = NULL;
11669
335k
            if (node->type == XML_NAMESPACE_DECL)
11670
46.5k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11671
335k
        }
11672
11673
672k
        if (res != 0) {
11674
426k
            if (pos == maxPos) {
11675
92.1k
                i += 1;
11676
92.1k
                break;
11677
92.1k
            }
11678
11679
334k
            pos += 1;
11680
334k
        }
11681
672k
    }
11682
11683
    /* Free remaining nodes. */
11684
145k
    if (hasNsNodes) {
11685
54.4k
        for (; i < set->nodeNr; i++) {
11686
26.7k
            xmlNodePtr node = set->nodeTab[i];
11687
26.7k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11688
12.2k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11689
26.7k
        }
11690
27.7k
    }
11691
11692
145k
    set->nodeNr = j;
11693
11694
    /* If too many elements were removed, shrink table to preserve memory. */
11695
145k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11696
145k
        (set->nodeNr < set->nodeMax / 2)) {
11697
4.31k
        xmlNodePtr *tmp;
11698
4.31k
        int nodeMax = set->nodeNr;
11699
11700
4.31k
        if (nodeMax < XML_NODESET_DEFAULT)
11701
4.20k
            nodeMax = XML_NODESET_DEFAULT;
11702
4.31k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11703
4.31k
                nodeMax * sizeof(xmlNodePtr));
11704
4.31k
        if (tmp == NULL) {
11705
114
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11706
4.19k
        } else {
11707
4.19k
            set->nodeTab = tmp;
11708
4.19k
            set->nodeMax = nodeMax;
11709
4.19k
        }
11710
4.31k
    }
11711
11712
145k
    xpctxt->node = oldnode;
11713
145k
    xpctxt->doc = olddoc;
11714
145k
    xpctxt->contextSize = oldcs;
11715
145k
    xpctxt->proximityPosition = oldpp;
11716
145k
}
11717
11718
#ifdef LIBXML_XPTR_LOCS_ENABLED
11719
/**
11720
 * xmlXPathLocationSetFilter:
11721
 * @ctxt:  the XPath Parser context
11722
 * @locset: the location set to filter
11723
 * @filterOpIndex: the index of the predicate/filter op
11724
 * @minPos: minimum position in the filtered set (1-based)
11725
 * @maxPos: maximum position in the filtered set (1-based)
11726
 *
11727
 * Filter a location set, keeping only nodes for which the predicate
11728
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11729
 * in the filtered result.
11730
 */
11731
static void
11732
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11733
              xmlLocationSetPtr locset,
11734
              int filterOpIndex,
11735
                          int minPos, int maxPos)
11736
{
11737
    xmlXPathContextPtr xpctxt;
11738
    xmlNodePtr oldnode;
11739
    xmlDocPtr olddoc;
11740
    xmlXPathStepOpPtr filterOp;
11741
    int oldcs, oldpp;
11742
    int i, j, pos;
11743
11744
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11745
        return;
11746
11747
    xpctxt = ctxt->context;
11748
    oldnode = xpctxt->node;
11749
    olddoc = xpctxt->doc;
11750
    oldcs = xpctxt->contextSize;
11751
    oldpp = xpctxt->proximityPosition;
11752
    filterOp = &ctxt->comp->steps[filterOpIndex];
11753
11754
    xpctxt->contextSize = locset->locNr;
11755
11756
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11757
        xmlNodePtr contextNode = locset->locTab[i]->user;
11758
        int res;
11759
11760
        xpctxt->node = contextNode;
11761
        xpctxt->proximityPosition = i + 1;
11762
11763
        /*
11764
        * Also set the xpath document in case things like
11765
        * key() are evaluated in the predicate.
11766
        *
11767
        * TODO: Get real doc for namespace nodes.
11768
        */
11769
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11770
            (contextNode->doc != NULL))
11771
            xpctxt->doc = contextNode->doc;
11772
11773
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11774
11775
        if (ctxt->error != XPATH_EXPRESSION_OK)
11776
            break;
11777
        if (res < 0) {
11778
            /* Shouldn't happen */
11779
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11780
            break;
11781
        }
11782
11783
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11784
            if (i != j) {
11785
                locset->locTab[j] = locset->locTab[i];
11786
                locset->locTab[i] = NULL;
11787
            }
11788
11789
            j += 1;
11790
        } else {
11791
            /* Remove the entry from the initial location set. */
11792
            xmlXPathFreeObject(locset->locTab[i]);
11793
            locset->locTab[i] = NULL;
11794
        }
11795
11796
        if (res != 0) {
11797
            if (pos == maxPos) {
11798
                i += 1;
11799
                break;
11800
            }
11801
11802
            pos += 1;
11803
        }
11804
    }
11805
11806
    /* Free remaining nodes. */
11807
    for (; i < locset->locNr; i++)
11808
        xmlXPathFreeObject(locset->locTab[i]);
11809
11810
    locset->locNr = j;
11811
11812
    /* If too many elements were removed, shrink table to preserve memory. */
11813
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11814
        (locset->locNr < locset->locMax / 2)) {
11815
        xmlXPathObjectPtr *tmp;
11816
        int locMax = locset->locNr;
11817
11818
        if (locMax < XML_NODESET_DEFAULT)
11819
            locMax = XML_NODESET_DEFAULT;
11820
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11821
                locMax * sizeof(xmlXPathObjectPtr));
11822
        if (tmp == NULL) {
11823
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11824
        } else {
11825
            locset->locTab = tmp;
11826
            locset->locMax = locMax;
11827
        }
11828
    }
11829
11830
    xpctxt->node = oldnode;
11831
    xpctxt->doc = olddoc;
11832
    xpctxt->contextSize = oldcs;
11833
    xpctxt->proximityPosition = oldpp;
11834
}
11835
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11836
11837
/**
11838
 * xmlXPathCompOpEvalPredicate:
11839
 * @ctxt:  the XPath Parser context
11840
 * @op: the predicate op
11841
 * @set: the node set to filter
11842
 * @minPos: minimum position in the filtered set (1-based)
11843
 * @maxPos: maximum position in the filtered set (1-based)
11844
 * @hasNsNodes: true if the node set may contain namespace nodes
11845
 *
11846
 * Filter a node set, keeping only nodes for which the sequence of predicate
11847
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11848
 * in the filtered result.
11849
 */
11850
static void
11851
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11852
          xmlXPathStepOpPtr op,
11853
          xmlNodeSetPtr set,
11854
                            int minPos, int maxPos,
11855
          int hasNsNodes)
11856
140k
{
11857
140k
    if (op->ch1 != -1) {
11858
27.1k
  xmlXPathCompExprPtr comp = ctxt->comp;
11859
  /*
11860
  * Process inner predicates first.
11861
  */
11862
27.1k
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11863
0
            xmlGenericError(xmlGenericErrorContext,
11864
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11865
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11866
0
  }
11867
27.1k
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11868
27.1k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11869
27.1k
        ctxt->context->depth += 1;
11870
27.1k
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11871
27.1k
                                    1, set->nodeNr, hasNsNodes);
11872
27.1k
        ctxt->context->depth -= 1;
11873
27.1k
  CHECK_ERROR;
11874
27.1k
    }
11875
11876
138k
    if (op->ch2 != -1)
11877
138k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11878
138k
}
11879
11880
static int
11881
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11882
          xmlXPathStepOpPtr op,
11883
          int *maxPos)
11884
69.9k
{
11885
11886
69.9k
    xmlXPathStepOpPtr exprOp;
11887
11888
    /*
11889
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11890
    */
11891
11892
    /*
11893
    * If not -1, then ch1 will point to:
11894
    * 1) For predicates (XPATH_OP_PREDICATE):
11895
    *    - an inner predicate operator
11896
    * 2) For filters (XPATH_OP_FILTER):
11897
    *    - an inner filter operator OR
11898
    *    - an expression selecting the node set.
11899
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11900
    */
11901
69.9k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11902
0
  return(0);
11903
11904
69.9k
    if (op->ch2 != -1) {
11905
69.9k
  exprOp = &ctxt->comp->steps[op->ch2];
11906
69.9k
    } else
11907
0
  return(0);
11908
11909
69.9k
    if ((exprOp != NULL) &&
11910
69.9k
  (exprOp->op == XPATH_OP_VALUE) &&
11911
69.9k
  (exprOp->value4 != NULL) &&
11912
69.9k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11913
30.7k
    {
11914
30.7k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11915
11916
  /*
11917
  * We have a "[n]" predicate here.
11918
  * TODO: Unfortunately this simplistic test here is not
11919
  * able to detect a position() predicate in compound
11920
  * expressions like "[@attr = 'a" and position() = 1],
11921
  * and even not the usage of position() in
11922
  * "[position() = 1]"; thus - obviously - a position-range,
11923
  * like it "[position() < 5]", is also not detected.
11924
  * Maybe we could rewrite the AST to ease the optimization.
11925
  */
11926
11927
30.7k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11928
29.7k
      *maxPos = (int) floatval;
11929
29.7k
            if (floatval == (double) *maxPos)
11930
29.4k
                return(1);
11931
29.7k
        }
11932
30.7k
    }
11933
40.5k
    return(0);
11934
69.9k
}
11935
11936
static int
11937
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11938
                           xmlXPathStepOpPtr op,
11939
         xmlNodePtr * first, xmlNodePtr * last,
11940
         int toBool)
11941
2.26M
{
11942
11943
2.26M
#define XP_TEST_HIT \
11944
8.39M
    if (hasAxisRange != 0) { \
11945
106k
  if (++pos == maxPos) { \
11946
57.2k
      if (addNode(seq, cur) < 0) \
11947
57.2k
          ctxt->error = XPATH_MEMORY_ERROR; \
11948
57.2k
      goto axis_range_end; } \
11949
8.28M
    } else { \
11950
8.28M
  if (addNode(seq, cur) < 0) \
11951
8.28M
      ctxt->error = XPATH_MEMORY_ERROR; \
11952
8.28M
  if (breakOnFirstHit) goto first_hit; }
11953
11954
2.26M
#define XP_TEST_HIT_NS \
11955
2.26M
    if (hasAxisRange != 0) { \
11956
58.9k
  if (++pos == maxPos) { \
11957
19.6k
      hasNsNodes = 1; \
11958
19.6k
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11959
19.6k
          ctxt->error = XPATH_MEMORY_ERROR; \
11960
19.6k
  goto axis_range_end; } \
11961
391k
    } else { \
11962
391k
  hasNsNodes = 1; \
11963
391k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11964
391k
      ctxt->error = XPATH_MEMORY_ERROR; \
11965
391k
  if (breakOnFirstHit) goto first_hit; }
11966
11967
2.26M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11968
2.26M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11969
2.26M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11970
2.26M
    const xmlChar *prefix = op->value4;
11971
2.26M
    const xmlChar *name = op->value5;
11972
2.26M
    const xmlChar *URI = NULL;
11973
11974
#ifdef DEBUG_STEP
11975
    int nbMatches = 0, prevMatches = 0;
11976
#endif
11977
2.26M
    int total = 0, hasNsNodes = 0;
11978
    /* The popped object holding the context nodes */
11979
2.26M
    xmlXPathObjectPtr obj;
11980
    /* The set of context nodes for the node tests */
11981
2.26M
    xmlNodeSetPtr contextSeq;
11982
2.26M
    int contextIdx;
11983
2.26M
    xmlNodePtr contextNode;
11984
    /* The final resulting node set wrt to all context nodes */
11985
2.26M
    xmlNodeSetPtr outSeq;
11986
    /*
11987
    * The temporary resulting node set wrt 1 context node.
11988
    * Used to feed predicate evaluation.
11989
    */
11990
2.26M
    xmlNodeSetPtr seq;
11991
2.26M
    xmlNodePtr cur;
11992
    /* First predicate operator */
11993
2.26M
    xmlXPathStepOpPtr predOp;
11994
2.26M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
11995
2.26M
    int hasPredicateRange, hasAxisRange, pos;
11996
2.26M
    int breakOnFirstHit;
11997
11998
2.26M
    xmlXPathTraversalFunction next = NULL;
11999
2.26M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12000
2.26M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12001
2.26M
    xmlNodePtr oldContextNode;
12002
2.26M
    xmlXPathContextPtr xpctxt = ctxt->context;
12003
12004
12005
2.26M
    CHECK_TYPE0(XPATH_NODESET);
12006
2.25M
    obj = valuePop(ctxt);
12007
    /*
12008
    * Setup namespaces.
12009
    */
12010
2.25M
    if (prefix != NULL) {
12011
63.3k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12012
63.3k
        if (URI == NULL) {
12013
22.8k
      xmlXPathReleaseObject(xpctxt, obj);
12014
22.8k
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12015
0
  }
12016
63.3k
    }
12017
    /*
12018
    * Setup axis.
12019
    *
12020
    * MAYBE FUTURE TODO: merging optimizations:
12021
    * - If the nodes to be traversed wrt to the initial nodes and
12022
    *   the current axis cannot overlap, then we could avoid searching
12023
    *   for duplicates during the merge.
12024
    *   But the question is how/when to evaluate if they cannot overlap.
12025
    *   Example: if we know that for two initial nodes, the one is
12026
    *   not in the ancestor-or-self axis of the other, then we could safely
12027
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12028
    *   the descendant-or-self axis.
12029
    */
12030
2.23M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12031
2.23M
    switch (axis) {
12032
392
        case AXIS_ANCESTOR:
12033
392
            first = NULL;
12034
392
            next = xmlXPathNextAncestor;
12035
392
            break;
12036
232
        case AXIS_ANCESTOR_OR_SELF:
12037
232
            first = NULL;
12038
232
            next = xmlXPathNextAncestorOrSelf;
12039
232
            break;
12040
697k
        case AXIS_ATTRIBUTE:
12041
697k
            first = NULL;
12042
697k
      last = NULL;
12043
697k
            next = xmlXPathNextAttribute;
12044
697k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12045
697k
            break;
12046
1.23M
        case AXIS_CHILD:
12047
1.23M
      last = NULL;
12048
1.23M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12049
1.23M
    (type == NODE_TYPE_NODE))
12050
1.18M
      {
12051
    /*
12052
    * Optimization if an element node type is 'element'.
12053
    */
12054
1.18M
    next = xmlXPathNextChildElement;
12055
1.18M
      } else
12056
53.0k
    next = xmlXPathNextChild;
12057
1.23M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058
1.23M
            break;
12059
138k
        case AXIS_DESCENDANT:
12060
138k
      last = NULL;
12061
138k
            next = xmlXPathNextDescendant;
12062
138k
            break;
12063
36.8k
        case AXIS_DESCENDANT_OR_SELF:
12064
36.8k
      last = NULL;
12065
36.8k
            next = xmlXPathNextDescendantOrSelf;
12066
36.8k
            break;
12067
0
        case AXIS_FOLLOWING:
12068
0
      last = NULL;
12069
0
            next = xmlXPathNextFollowing;
12070
0
            break;
12071
0
        case AXIS_FOLLOWING_SIBLING:
12072
0
      last = NULL;
12073
0
            next = xmlXPathNextFollowingSibling;
12074
0
            break;
12075
95.0k
        case AXIS_NAMESPACE:
12076
95.0k
            first = NULL;
12077
95.0k
      last = NULL;
12078
95.0k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12079
95.0k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080
95.0k
            break;
12081
30.4k
        case AXIS_PARENT:
12082
30.4k
            first = NULL;
12083
30.4k
            next = xmlXPathNextParent;
12084
30.4k
            break;
12085
12
        case AXIS_PRECEDING:
12086
12
            first = NULL;
12087
12
            next = xmlXPathNextPrecedingInternal;
12088
12
            break;
12089
4
        case AXIS_PRECEDING_SIBLING:
12090
4
            first = NULL;
12091
4
            next = xmlXPathNextPrecedingSibling;
12092
4
            break;
12093
801
        case AXIS_SELF:
12094
801
            first = NULL;
12095
801
      last = NULL;
12096
801
            next = xmlXPathNextSelf;
12097
801
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12098
801
            break;
12099
2.23M
    }
12100
12101
#ifdef DEBUG_STEP
12102
    xmlXPathDebugDumpStepAxis(op,
12103
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12104
#endif
12105
12106
2.23M
    if (next == NULL) {
12107
0
  xmlXPathReleaseObject(xpctxt, obj);
12108
0
        return(0);
12109
0
    }
12110
2.23M
    contextSeq = obj->nodesetval;
12111
2.23M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12112
426k
  xmlXPathReleaseObject(xpctxt, obj);
12113
426k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12114
426k
        return(0);
12115
426k
    }
12116
    /*
12117
    * Predicate optimization ---------------------------------------------
12118
    * If this step has a last predicate, which contains a position(),
12119
    * then we'll optimize (although not exactly "position()", but only
12120
    * the  short-hand form, i.e., "[n]".
12121
    *
12122
    * Example - expression "/foo[parent::bar][1]":
12123
    *
12124
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12125
    *   ROOT                               -- op->ch1
12126
    *   PREDICATE                          -- op->ch2 (predOp)
12127
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12128
    *       SORT
12129
    *         COLLECT  'parent' 'name' 'node' bar
12130
    *           NODE
12131
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12132
    *
12133
    */
12134
1.80M
    maxPos = 0;
12135
1.80M
    predOp = NULL;
12136
1.80M
    hasPredicateRange = 0;
12137
1.80M
    hasAxisRange = 0;
12138
1.80M
    if (op->ch2 != -1) {
12139
  /*
12140
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12141
  */
12142
69.9k
  predOp = &ctxt->comp->steps[op->ch2];
12143
69.9k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12144
29.4k
      if (predOp->ch1 != -1) {
12145
    /*
12146
    * Use the next inner predicate operator.
12147
    */
12148
8.25k
    predOp = &ctxt->comp->steps[predOp->ch1];
12149
8.25k
    hasPredicateRange = 1;
12150
21.1k
      } else {
12151
    /*
12152
    * There's no other predicate than the [n] predicate.
12153
    */
12154
21.1k
    predOp = NULL;
12155
21.1k
    hasAxisRange = 1;
12156
21.1k
      }
12157
29.4k
  }
12158
69.9k
    }
12159
1.80M
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12160
    /*
12161
    * Axis traversal -----------------------------------------------------
12162
    */
12163
    /*
12164
     * 2.3 Node Tests
12165
     *  - For the attribute axis, the principal node type is attribute.
12166
     *  - For the namespace axis, the principal node type is namespace.
12167
     *  - For other axes, the principal node type is element.
12168
     *
12169
     * A node test * is true for any node of the
12170
     * principal node type. For example, child::* will
12171
     * select all element children of the context node
12172
     */
12173
1.80M
    oldContextNode = xpctxt->node;
12174
1.80M
    addNode = xmlXPathNodeSetAddUnique;
12175
1.80M
    outSeq = NULL;
12176
1.80M
    seq = NULL;
12177
1.80M
    contextNode = NULL;
12178
1.80M
    contextIdx = 0;
12179
12180
12181
5.12M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12182
5.12M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12183
3.34M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12184
12185
3.34M
  if (seq == NULL) {
12186
1.83M
      seq = xmlXPathNodeSetCreate(NULL);
12187
1.83M
      if (seq == NULL) {
12188
                /* TODO: Propagate memory error. */
12189
7.94k
    total = 0;
12190
7.94k
    goto error;
12191
7.94k
      }
12192
1.83M
  }
12193
  /*
12194
  * Traverse the axis and test the nodes.
12195
  */
12196
3.33M
  pos = 0;
12197
3.33M
  cur = NULL;
12198
3.33M
  hasNsNodes = 0;
12199
16.8M
        do {
12200
16.8M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12201
297
                goto error;
12202
12203
16.8M
            cur = next(ctxt, cur);
12204
16.8M
            if (cur == NULL)
12205
3.19M
                break;
12206
12207
      /*
12208
      * QUESTION TODO: What does the "first" and "last" stuff do?
12209
      */
12210
13.6M
            if ((first != NULL) && (*first != NULL)) {
12211
55.2k
    if (*first == cur)
12212
2
        break;
12213
55.2k
    if (((total % 256) == 0) &&
12214
55.2k
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12215
55.2k
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12216
#else
12217
        (xmlXPathCmpNodes(*first, cur) >= 0))
12218
#endif
12219
55.2k
    {
12220
55.2k
        break;
12221
55.2k
    }
12222
55.2k
      }
12223
13.6M
      if ((last != NULL) && (*last != NULL)) {
12224
0
    if (*last == cur)
12225
0
        break;
12226
0
    if (((total % 256) == 0) &&
12227
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12228
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12229
#else
12230
        (xmlXPathCmpNodes(cur, *last) >= 0))
12231
#endif
12232
0
    {
12233
0
        break;
12234
0
    }
12235
0
      }
12236
12237
13.6M
            total++;
12238
12239
#ifdef DEBUG_STEP
12240
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12241
#endif
12242
12243
13.6M
      switch (test) {
12244
0
                case NODE_TEST_NONE:
12245
0
        total = 0;
12246
0
                    STRANGE
12247
0
        goto error;
12248
7.04M
                case NODE_TEST_TYPE:
12249
7.04M
        if (type == NODE_TYPE_NODE) {
12250
4.36M
      switch (cur->type) {
12251
40.7k
          case XML_DOCUMENT_NODE:
12252
40.7k
          case XML_HTML_DOCUMENT_NODE:
12253
2.55M
          case XML_ELEMENT_NODE:
12254
2.55M
          case XML_ATTRIBUTE_NODE:
12255
2.64M
          case XML_PI_NODE:
12256
2.71M
          case XML_COMMENT_NODE:
12257
2.71M
          case XML_CDATA_SECTION_NODE:
12258
4.33M
          case XML_TEXT_NODE:
12259
4.33M
        XP_TEST_HIT
12260
4.33M
        break;
12261
4.33M
          case XML_NAMESPACE_DECL: {
12262
30.0k
        if (axis == AXIS_NAMESPACE) {
12263
3.04k
            XP_TEST_HIT_NS
12264
27.0k
        } else {
12265
27.0k
                              hasNsNodes = 1;
12266
27.0k
            XP_TEST_HIT
12267
27.0k
        }
12268
29.7k
        break;
12269
30.0k
                            }
12270
29.7k
          default:
12271
14
        break;
12272
4.36M
      }
12273
4.36M
        } else if (cur->type == (xmlElementType) type) {
12274
278k
      if (cur->type == XML_NAMESPACE_DECL)
12275
0
          XP_TEST_HIT_NS
12276
278k
      else
12277
278k
          XP_TEST_HIT
12278
2.39M
        } else if ((type == NODE_TYPE_TEXT) &&
12279
2.39M
       (cur->type == XML_CDATA_SECTION_NODE))
12280
0
        {
12281
0
      XP_TEST_HIT
12282
0
        }
12283
6.99M
        break;
12284
6.99M
                case NODE_TEST_PI:
12285
20.5k
                    if ((cur->type == XML_PI_NODE) &&
12286
20.5k
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12287
1
        {
12288
1
      XP_TEST_HIT
12289
1
                    }
12290
20.5k
                    break;
12291
3.83M
                case NODE_TEST_ALL:
12292
3.83M
                    if (axis == AXIS_ATTRIBUTE) {
12293
17.6k
                        if (cur->type == XML_ATTRIBUTE_NODE)
12294
17.6k
      {
12295
17.6k
                            if (prefix == NULL)
12296
17.6k
          {
12297
17.6k
        XP_TEST_HIT
12298
17.6k
                            } else if ((cur->ns != NULL) &&
12299
0
        (xmlStrEqual(URI, cur->ns->href)))
12300
0
          {
12301
0
        XP_TEST_HIT
12302
0
                            }
12303
17.6k
                        }
12304
3.81M
                    } else if (axis == AXIS_NAMESPACE) {
12305
446k
                        if (cur->type == XML_NAMESPACE_DECL)
12306
446k
      {
12307
446k
          XP_TEST_HIT_NS
12308
446k
                        }
12309
3.36M
                    } else {
12310
3.36M
                        if (cur->type == XML_ELEMENT_NODE) {
12311
2.97M
                            if (prefix == NULL)
12312
2.97M
          {
12313
2.97M
        XP_TEST_HIT
12314
12315
2.97M
                            } else if ((cur->ns != NULL) &&
12316
2.99k
        (xmlStrEqual(URI, cur->ns->href)))
12317
116
          {
12318
116
        XP_TEST_HIT
12319
116
                            }
12320
2.97M
                        }
12321
3.36M
                    }
12322
3.80M
                    break;
12323
3.80M
                case NODE_TEST_NS:{
12324
0
                        TODO;
12325
0
                        break;
12326
3.83M
                    }
12327
2.74M
                case NODE_TEST_NAME:
12328
2.74M
                    if (axis == AXIS_ATTRIBUTE) {
12329
785k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12330
0
          break;
12331
1.95M
        } else if (axis == AXIS_NAMESPACE) {
12332
117k
                        if (cur->type != XML_NAMESPACE_DECL)
12333
0
          break;
12334
1.83M
        } else {
12335
1.83M
            if (cur->type != XML_ELEMENT_NODE)
12336
425k
          break;
12337
1.83M
        }
12338
2.31M
                    switch (cur->type) {
12339
1.41M
                        case XML_ELEMENT_NODE:
12340
1.41M
                            if (xmlStrEqual(name, cur->name)) {
12341
168k
                                if (prefix == NULL) {
12342
85.3k
                                    if (cur->ns == NULL)
12343
85.0k
            {
12344
85.0k
          XP_TEST_HIT
12345
85.0k
                                    }
12346
85.3k
                                } else {
12347
83.5k
                                    if ((cur->ns != NULL) &&
12348
83.5k
                                        (xmlStrEqual(URI, cur->ns->href)))
12349
82.7k
            {
12350
82.7k
          XP_TEST_HIT
12351
82.7k
                                    }
12352
83.5k
                                }
12353
168k
                            }
12354
1.41M
                            break;
12355
1.41M
                        case XML_ATTRIBUTE_NODE:{
12356
785k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12357
12358
785k
                                if (xmlStrEqual(name, attr->name)) {
12359
595k
                                    if (prefix == NULL) {
12360
595k
                                        if ((attr->ns == NULL) ||
12361
595k
                                            (attr->ns->prefix == NULL))
12362
595k
          {
12363
595k
              XP_TEST_HIT
12364
595k
                                        }
12365
595k
                                    } else {
12366
236
                                        if ((attr->ns != NULL) &&
12367
236
                                            (xmlStrEqual(URI,
12368
0
                attr->ns->href)))
12369
0
          {
12370
0
              XP_TEST_HIT
12371
0
                                        }
12372
236
                                    }
12373
595k
                                }
12374
784k
                                break;
12375
785k
                            }
12376
784k
                        case XML_NAMESPACE_DECL:
12377
117k
                            if (cur->type == XML_NAMESPACE_DECL) {
12378
117k
                                xmlNsPtr ns = (xmlNsPtr) cur;
12379
12380
117k
                                if ((ns->prefix != NULL) && (name != NULL)
12381
117k
                                    && (xmlStrEqual(ns->prefix, name)))
12382
1.69k
        {
12383
1.69k
            XP_TEST_HIT_NS
12384
1.69k
                                }
12385
117k
                            }
12386
117k
                            break;
12387
117k
                        default:
12388
0
                            break;
12389
2.31M
                    }
12390
2.31M
                    break;
12391
13.6M
      } /* switch(test) */
12392
13.6M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12393
12394
3.25M
  goto apply_predicates;
12395
12396
3.25M
axis_range_end: /* ----------------------------------------------------- */
12397
  /*
12398
  * We have a "/foo[n]", and position() = n was reached.
12399
  * Note that we can have as well "/foo/::parent::foo[1]", so
12400
  * a duplicate-aware merge is still needed.
12401
  * Merge with the result.
12402
  */
12403
76.9k
  if (outSeq == NULL) {
12404
15.0k
      outSeq = seq;
12405
15.0k
      seq = NULL;
12406
15.0k
  } else
12407
            /* TODO: Check memory error. */
12408
61.9k
      outSeq = mergeAndClear(outSeq, seq);
12409
  /*
12410
  * Break if only a true/false result was requested.
12411
  */
12412
76.9k
  if (toBool)
12413
216
      break;
12414
76.6k
  continue;
12415
12416
76.6k
first_hit: /* ---------------------------------------------------------- */
12417
  /*
12418
  * Break if only a true/false result was requested and
12419
  * no predicates existed and a node test succeeded.
12420
  */
12421
4.17k
  if (outSeq == NULL) {
12422
4.17k
      outSeq = seq;
12423
4.17k
      seq = NULL;
12424
4.17k
  } else
12425
            /* TODO: Check memory error. */
12426
0
      outSeq = mergeAndClear(outSeq, seq);
12427
4.17k
  break;
12428
12429
#ifdef DEBUG_STEP
12430
  if (seq != NULL)
12431
      nbMatches += seq->nodeNr;
12432
#endif
12433
12434
3.25M
apply_predicates: /* --------------------------------------------------- */
12435
3.25M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12436
273
      goto error;
12437
12438
        /*
12439
  * Apply predicates.
12440
  */
12441
3.25M
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12442
      /*
12443
      * E.g. when we have a "/foo[some expression][n]".
12444
      */
12445
      /*
12446
      * QUESTION TODO: The old predicate evaluation took into
12447
      *  account location-sets.
12448
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12449
      *  Do we expect such a set here?
12450
      *  All what I learned now from the evaluation semantics
12451
      *  does not indicate that a location-set will be processed
12452
      *  here, so this looks OK.
12453
      */
12454
      /*
12455
      * Iterate over all predicates, starting with the outermost
12456
      * predicate.
12457
      * TODO: Problem: we cannot execute the inner predicates first
12458
      *  since we cannot go back *up* the operator tree!
12459
      *  Options we have:
12460
      *  1) Use of recursive functions (like is it currently done
12461
      *     via xmlXPathCompOpEval())
12462
      *  2) Add a predicate evaluation information stack to the
12463
      *     context struct
12464
      *  3) Change the way the operators are linked; we need a
12465
      *     "parent" field on xmlXPathStepOp
12466
      *
12467
      * For the moment, I'll try to solve this with a recursive
12468
      * function: xmlXPathCompOpEvalPredicate().
12469
      */
12470
113k
      if (hasPredicateRange != 0)
12471
15.6k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12472
15.6k
              hasNsNodes);
12473
97.9k
      else
12474
97.9k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12475
97.9k
              hasNsNodes);
12476
12477
113k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12478
5.42k
    total = 0;
12479
5.42k
    goto error;
12480
5.42k
      }
12481
113k
        }
12482
12483
3.24M
        if (seq->nodeNr > 0) {
12484
      /*
12485
      * Add to result set.
12486
      */
12487
1.22M
      if (outSeq == NULL) {
12488
914k
    outSeq = seq;
12489
914k
    seq = NULL;
12490
914k
      } else {
12491
                /* TODO: Check memory error. */
12492
305k
    outSeq = mergeAndClear(outSeq, seq);
12493
305k
      }
12494
12495
1.22M
            if (toBool)
12496
1.81k
                break;
12497
1.22M
  }
12498
3.24M
    }
12499
12500
1.80M
error:
12501
1.80M
    if ((obj->boolval) && (obj->user != NULL)) {
12502
  /*
12503
  * QUESTION TODO: What does this do and why?
12504
  * TODO: Do we have to do this also for the "error"
12505
  * cleanup further down?
12506
  */
12507
0
  ctxt->value->boolval = 1;
12508
0
  ctxt->value->user = obj->user;
12509
0
  obj->user = NULL;
12510
0
  obj->boolval = 0;
12511
0
    }
12512
1.80M
    xmlXPathReleaseObject(xpctxt, obj);
12513
12514
    /*
12515
    * Ensure we return at least an empty set.
12516
    */
12517
1.80M
    if (outSeq == NULL) {
12518
875k
  if ((seq != NULL) && (seq->nodeNr == 0))
12519
867k
      outSeq = seq;
12520
8.02k
  else
12521
            /* TODO: Check memory error. */
12522
8.02k
      outSeq = xmlXPathNodeSetCreate(NULL);
12523
875k
    }
12524
1.80M
    if ((seq != NULL) && (seq != outSeq)) {
12525
27.2k
   xmlXPathFreeNodeSet(seq);
12526
27.2k
    }
12527
    /*
12528
    * Hand over the result. Better to push the set also in
12529
    * case of errors.
12530
    */
12531
1.80M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12532
    /*
12533
    * Reset the context node.
12534
    */
12535
1.80M
    xpctxt->node = oldContextNode;
12536
    /*
12537
    * When traversing the namespace axis in "toBool" mode, it's
12538
    * possible that tmpNsList wasn't freed.
12539
    */
12540
1.80M
    if (xpctxt->tmpNsList != NULL) {
12541
8.23k
        xmlFree(xpctxt->tmpNsList);
12542
8.23k
        xpctxt->tmpNsList = NULL;
12543
8.23k
    }
12544
12545
#ifdef DEBUG_STEP
12546
    xmlGenericError(xmlGenericErrorContext,
12547
  "\nExamined %d nodes, found %d nodes at that step\n",
12548
  total, nbMatches);
12549
#endif
12550
12551
1.80M
    return(total);
12552
1.80M
}
12553
12554
static int
12555
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12556
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12557
12558
/**
12559
 * xmlXPathCompOpEvalFirst:
12560
 * @ctxt:  the XPath parser context with the compiled expression
12561
 * @op:  an XPath compiled operation
12562
 * @first:  the first elem found so far
12563
 *
12564
 * Evaluate the Precompiled XPath operation searching only the first
12565
 * element in document order
12566
 *
12567
 * Returns the number of examined objects.
12568
 */
12569
static int
12570
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12571
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12572
50.8k
{
12573
50.8k
    int total = 0, cur;
12574
50.8k
    xmlXPathCompExprPtr comp;
12575
50.8k
    xmlXPathObjectPtr arg1, arg2;
12576
12577
50.8k
    CHECK_ERROR0;
12578
50.8k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12579
1
        return(0);
12580
50.8k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12581
50.8k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12582
50.8k
    ctxt->context->depth += 1;
12583
50.8k
    comp = ctxt->comp;
12584
50.8k
    switch (op->op) {
12585
0
        case XPATH_OP_END:
12586
0
            break;
12587
7.67k
        case XPATH_OP_UNION:
12588
7.67k
            total =
12589
7.67k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12590
7.67k
                                        first);
12591
7.67k
      CHECK_ERROR0;
12592
7.21k
            if ((ctxt->value != NULL)
12593
7.21k
                && (ctxt->value->type == XPATH_NODESET)
12594
7.21k
                && (ctxt->value->nodesetval != NULL)
12595
7.21k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12596
                /*
12597
                 * limit tree traversing to first node in the result
12598
                 */
12599
    /*
12600
    * OPTIMIZE TODO: This implicitly sorts
12601
    *  the result, even if not needed. E.g. if the argument
12602
    *  of the count() function, no sorting is needed.
12603
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12604
    *  already sorted?
12605
    */
12606
146
    if (ctxt->value->nodesetval->nodeNr > 1)
12607
4
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12608
146
                *first = ctxt->value->nodesetval->nodeTab[0];
12609
146
            }
12610
7.21k
            cur =
12611
7.21k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12612
7.21k
                                        first);
12613
7.21k
      CHECK_ERROR0;
12614
12615
7.12k
            arg2 = valuePop(ctxt);
12616
7.12k
            arg1 = valuePop(ctxt);
12617
7.12k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12618
7.12k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12619
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12620
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12621
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12622
0
            }
12623
7.12k
            if ((ctxt->context->opLimit != 0) &&
12624
7.12k
                (((arg1->nodesetval != NULL) &&
12625
7.12k
                  (xmlXPathCheckOpLimit(ctxt,
12626
3.89k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12627
7.12k
                 ((arg2->nodesetval != NULL) &&
12628
7.12k
                  (xmlXPathCheckOpLimit(ctxt,
12629
6.76k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12630
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12631
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12632
0
                break;
12633
0
            }
12634
12635
            /* TODO: Check memory error. */
12636
7.12k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12637
7.12k
                                                    arg2->nodesetval);
12638
7.12k
            valuePush(ctxt, arg1);
12639
7.12k
      xmlXPathReleaseObject(ctxt->context, arg2);
12640
            /* optimizer */
12641
7.12k
      if (total > cur)
12642
249
    xmlXPathCompSwap(op);
12643
7.12k
            total += cur;
12644
7.12k
            break;
12645
4
        case XPATH_OP_ROOT:
12646
4
            xmlXPathRoot(ctxt);
12647
4
            break;
12648
285
        case XPATH_OP_NODE:
12649
285
            if (op->ch1 != -1)
12650
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12651
285
      CHECK_ERROR0;
12652
285
            if (op->ch2 != -1)
12653
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12654
285
      CHECK_ERROR0;
12655
285
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12656
285
    ctxt->context->node));
12657
285
            break;
12658
13.9k
        case XPATH_OP_COLLECT:{
12659
13.9k
                if (op->ch1 == -1)
12660
0
                    break;
12661
12662
13.9k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12663
13.9k
    CHECK_ERROR0;
12664
12665
13.8k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12666
13.8k
                break;
12667
13.9k
            }
12668
0
        case XPATH_OP_VALUE:
12669
0
            valuePush(ctxt,
12670
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12671
0
      (xmlXPathObjectPtr) op->value4));
12672
0
            break;
12673
7.58k
        case XPATH_OP_SORT:
12674
7.58k
            if (op->ch1 != -1)
12675
7.58k
                total +=
12676
7.58k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12677
7.58k
                                            first);
12678
7.58k
      CHECK_ERROR0;
12679
7.14k
            if ((ctxt->value != NULL)
12680
7.14k
                && (ctxt->value->type == XPATH_NODESET)
12681
7.14k
                && (ctxt->value->nodesetval != NULL)
12682
7.14k
    && (ctxt->value->nodesetval->nodeNr > 1))
12683
275
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12684
7.14k
            break;
12685
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12686
20.8k
  case XPATH_OP_FILTER:
12687
20.8k
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12688
20.8k
            break;
12689
0
#endif
12690
560
        default:
12691
560
            total += xmlXPathCompOpEval(ctxt, op);
12692
560
            break;
12693
50.8k
    }
12694
12695
49.7k
    ctxt->context->depth -= 1;
12696
49.7k
    return(total);
12697
50.8k
}
12698
12699
/**
12700
 * xmlXPathCompOpEvalLast:
12701
 * @ctxt:  the XPath parser context with the compiled expression
12702
 * @op:  an XPath compiled operation
12703
 * @last:  the last elem found so far
12704
 *
12705
 * Evaluate the Precompiled XPath operation searching only the last
12706
 * element in document order
12707
 *
12708
 * Returns the number of nodes traversed
12709
 */
12710
static int
12711
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12712
                       xmlNodePtr * last)
12713
170k
{
12714
170k
    int total = 0, cur;
12715
170k
    xmlXPathCompExprPtr comp;
12716
170k
    xmlXPathObjectPtr arg1, arg2;
12717
12718
170k
    CHECK_ERROR0;
12719
170k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12720
1
        return(0);
12721
170k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12722
170k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12723
170k
    ctxt->context->depth += 1;
12724
170k
    comp = ctxt->comp;
12725
170k
    switch (op->op) {
12726
0
        case XPATH_OP_END:
12727
0
            break;
12728
28.4k
        case XPATH_OP_UNION:
12729
28.4k
            total =
12730
28.4k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12731
28.4k
      CHECK_ERROR0;
12732
28.1k
            if ((ctxt->value != NULL)
12733
28.1k
                && (ctxt->value->type == XPATH_NODESET)
12734
28.1k
                && (ctxt->value->nodesetval != NULL)
12735
28.1k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12736
                /*
12737
                 * limit tree traversing to first node in the result
12738
                 */
12739
6.63k
    if (ctxt->value->nodesetval->nodeNr > 1)
12740
6.20k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741
6.63k
                *last =
12742
6.63k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12743
6.63k
                                                     nodesetval->nodeNr -
12744
6.63k
                                                     1];
12745
6.63k
            }
12746
28.1k
            cur =
12747
28.1k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12748
28.1k
      CHECK_ERROR0;
12749
27.8k
            if ((ctxt->value != NULL)
12750
27.8k
                && (ctxt->value->type == XPATH_NODESET)
12751
27.8k
                && (ctxt->value->nodesetval != NULL)
12752
27.8k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12753
6.82k
            }
12754
12755
27.8k
            arg2 = valuePop(ctxt);
12756
27.8k
            arg1 = valuePop(ctxt);
12757
27.8k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12758
27.8k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12759
2
          xmlXPathReleaseObject(ctxt->context, arg1);
12760
2
          xmlXPathReleaseObject(ctxt->context, arg2);
12761
2
                XP_ERROR0(XPATH_INVALID_TYPE);
12762
0
            }
12763
27.8k
            if ((ctxt->context->opLimit != 0) &&
12764
27.8k
                (((arg1->nodesetval != NULL) &&
12765
27.8k
                  (xmlXPathCheckOpLimit(ctxt,
12766
24.7k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12767
27.8k
                 ((arg2->nodesetval != NULL) &&
12768
27.8k
                  (xmlXPathCheckOpLimit(ctxt,
12769
27.2k
                                        arg2->nodesetval->nodeNr) < 0)))) {
12770
2
          xmlXPathReleaseObject(ctxt->context, arg1);
12771
2
          xmlXPathReleaseObject(ctxt->context, arg2);
12772
2
                break;
12773
2
            }
12774
12775
            /* TODO: Check memory error. */
12776
27.8k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12777
27.8k
                                                    arg2->nodesetval);
12778
27.8k
            valuePush(ctxt, arg1);
12779
27.8k
      xmlXPathReleaseObject(ctxt->context, arg2);
12780
            /* optimizer */
12781
27.8k
      if (total > cur)
12782
6.53k
    xmlXPathCompSwap(op);
12783
27.8k
            total += cur;
12784
27.8k
            break;
12785
254
        case XPATH_OP_ROOT:
12786
254
            xmlXPathRoot(ctxt);
12787
254
            break;
12788
223
        case XPATH_OP_NODE:
12789
223
            if (op->ch1 != -1)
12790
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12791
223
      CHECK_ERROR0;
12792
223
            if (op->ch2 != -1)
12793
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12794
223
      CHECK_ERROR0;
12795
223
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12796
223
    ctxt->context->node));
12797
223
            break;
12798
81.8k
        case XPATH_OP_COLLECT:{
12799
81.8k
                if (op->ch1 == -1)
12800
0
                    break;
12801
12802
81.8k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12803
81.8k
    CHECK_ERROR0;
12804
12805
81.6k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12806
81.6k
                break;
12807
81.8k
            }
12808
3
        case XPATH_OP_VALUE:
12809
3
            valuePush(ctxt,
12810
3
                      xmlXPathCacheObjectCopy(ctxt->context,
12811
3
      (xmlXPathObjectPtr) op->value4));
12812
3
            break;
12813
57.1k
        case XPATH_OP_SORT:
12814
57.1k
            if (op->ch1 != -1)
12815
57.1k
                total +=
12816
57.1k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12817
57.1k
                                           last);
12818
57.1k
      CHECK_ERROR0;
12819
56.4k
            if ((ctxt->value != NULL)
12820
56.4k
                && (ctxt->value->type == XPATH_NODESET)
12821
56.4k
                && (ctxt->value->nodesetval != NULL)
12822
56.4k
    && (ctxt->value->nodesetval->nodeNr > 1))
12823
6.57k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12824
56.4k
            break;
12825
2.96k
        default:
12826
2.96k
            total += xmlXPathCompOpEval(ctxt, op);
12827
2.96k
            break;
12828
170k
    }
12829
12830
169k
    ctxt->context->depth -= 1;
12831
169k
    return (total);
12832
170k
}
12833
12834
#ifdef XP_OPTIMIZED_FILTER_FIRST
12835
static int
12836
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12837
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12838
20.8k
{
12839
20.8k
    int total = 0;
12840
20.8k
    xmlXPathCompExprPtr comp;
12841
20.8k
    xmlXPathObjectPtr obj;
12842
20.8k
    xmlNodeSetPtr set;
12843
12844
20.8k
    CHECK_ERROR0;
12845
20.8k
    comp = ctxt->comp;
12846
    /*
12847
    * Optimization for ()[last()] selection i.e. the last elem
12848
    */
12849
20.8k
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12850
20.8k
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12851
20.8k
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12852
14.3k
  int f = comp->steps[op->ch2].ch1;
12853
12854
14.3k
  if ((f != -1) &&
12855
14.3k
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12856
14.3k
      (comp->steps[f].value5 == NULL) &&
12857
14.3k
      (comp->steps[f].value == 0) &&
12858
14.3k
      (comp->steps[f].value4 != NULL) &&
12859
14.3k
      (xmlStrEqual
12860
11.3k
      (comp->steps[f].value4, BAD_CAST "last"))) {
12861
8.57k
      xmlNodePtr last = NULL;
12862
12863
8.57k
      total +=
12864
8.57k
    xmlXPathCompOpEvalLast(ctxt,
12865
8.57k
        &comp->steps[op->ch1],
12866
8.57k
        &last);
12867
8.57k
      CHECK_ERROR0;
12868
      /*
12869
      * The nodeset should be in document order,
12870
      * Keep only the last value
12871
      */
12872
8.38k
      if ((ctxt->value != NULL) &&
12873
8.38k
    (ctxt->value->type == XPATH_NODESET) &&
12874
8.38k
    (ctxt->value->nodesetval != NULL) &&
12875
8.38k
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12876
8.38k
    (ctxt->value->nodesetval->nodeNr > 1)) {
12877
1.78k
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12878
1.78k
    *first = *(ctxt->value->nodesetval->nodeTab);
12879
1.78k
      }
12880
8.38k
      return (total);
12881
8.57k
  }
12882
14.3k
    }
12883
12884
12.2k
    if (op->ch1 != -1)
12885
12.2k
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12886
12.2k
    CHECK_ERROR0;
12887
11.8k
    if (op->ch2 == -1)
12888
0
  return (total);
12889
11.8k
    if (ctxt->value == NULL)
12890
0
  return (total);
12891
12892
#ifdef LIBXML_XPTR_LOCS_ENABLED
12893
    /*
12894
    * Hum are we filtering the result of an XPointer expression
12895
    */
12896
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12897
        xmlLocationSetPtr locset = ctxt->value->user;
12898
12899
        if (locset != NULL) {
12900
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12901
            if (locset->locNr > 0)
12902
                *first = (xmlNodePtr) locset->locTab[0]->user;
12903
        }
12904
12905
  return (total);
12906
    }
12907
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12908
12909
    /*
12910
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12911
     * the stack. We have to temporarily remove the nodeset object from the
12912
     * stack to avoid freeing it prematurely.
12913
     */
12914
11.8k
    CHECK_TYPE0(XPATH_NODESET);
12915
11.5k
    obj = valuePop(ctxt);
12916
11.5k
    set = obj->nodesetval;
12917
11.5k
    if (set != NULL) {
12918
10.0k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12919
10.0k
        if (set->nodeNr > 0)
12920
170
            *first = set->nodeTab[0];
12921
10.0k
    }
12922
11.5k
    valuePush(ctxt, obj);
12923
12924
11.5k
    return (total);
12925
11.8k
}
12926
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12927
12928
/**
12929
 * xmlXPathCompOpEval:
12930
 * @ctxt:  the XPath parser context with the compiled expression
12931
 * @op:  an XPath compiled operation
12932
 *
12933
 * Evaluate the Precompiled XPath operation
12934
 * Returns the number of nodes traversed
12935
 */
12936
static int
12937
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12938
15.7M
{
12939
15.7M
    int total = 0;
12940
15.7M
    int equal, ret;
12941
15.7M
    xmlXPathCompExprPtr comp;
12942
15.7M
    xmlXPathObjectPtr arg1, arg2;
12943
12944
15.7M
    CHECK_ERROR0;
12945
15.7M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12946
10.7k
        return(0);
12947
15.6M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12948
15.6M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12949
15.6M
    ctxt->context->depth += 1;
12950
15.6M
    comp = ctxt->comp;
12951
15.6M
    switch (op->op) {
12952
0
        case XPATH_OP_END:
12953
0
            break;
12954
33.3k
        case XPATH_OP_AND:
12955
33.3k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12956
33.3k
      CHECK_ERROR0;
12957
31.0k
            xmlXPathBooleanFunction(ctxt, 1);
12958
31.0k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12959
23.4k
                break;
12960
7.67k
            arg2 = valuePop(ctxt);
12961
7.67k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12962
7.67k
      if (ctxt->error) {
12963
650
    xmlXPathFreeObject(arg2);
12964
650
    break;
12965
650
      }
12966
7.02k
            xmlXPathBooleanFunction(ctxt, 1);
12967
7.02k
            if (ctxt->value != NULL)
12968
7.02k
                ctxt->value->boolval &= arg2->boolval;
12969
7.02k
      xmlXPathReleaseObject(ctxt->context, arg2);
12970
7.02k
            break;
12971
100k
        case XPATH_OP_OR:
12972
100k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12973
100k
      CHECK_ERROR0;
12974
99.5k
            xmlXPathBooleanFunction(ctxt, 1);
12975
99.5k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12976
3.69k
                break;
12977
95.8k
            arg2 = valuePop(ctxt);
12978
95.8k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12979
95.8k
      if (ctxt->error) {
12980
666
    xmlXPathFreeObject(arg2);
12981
666
    break;
12982
666
      }
12983
95.2k
            xmlXPathBooleanFunction(ctxt, 1);
12984
95.2k
            if (ctxt->value != NULL)
12985
94.9k
                ctxt->value->boolval |= arg2->boolval;
12986
95.2k
      xmlXPathReleaseObject(ctxt->context, arg2);
12987
95.2k
            break;
12988
473k
        case XPATH_OP_EQUAL:
12989
473k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12990
473k
      CHECK_ERROR0;
12991
452k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12992
452k
      CHECK_ERROR0;
12993
435k
      if (op->value)
12994
370k
    equal = xmlXPathEqualValues(ctxt);
12995
64.3k
      else
12996
64.3k
    equal = xmlXPathNotEqualValues(ctxt);
12997
435k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12998
435k
            break;
12999
486k
        case XPATH_OP_CMP:
13000
486k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13001
486k
      CHECK_ERROR0;
13002
456k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13003
456k
      CHECK_ERROR0;
13004
404k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13005
404k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13006
404k
            break;
13007
379k
        case XPATH_OP_PLUS:
13008
379k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13009
379k
      CHECK_ERROR0;
13010
367k
            if (op->ch2 != -1) {
13011
139k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13012
139k
      }
13013
367k
      CHECK_ERROR0;
13014
358k
            if (op->value == 0)
13015
75.5k
                xmlXPathSubValues(ctxt);
13016
282k
            else if (op->value == 1)
13017
54.6k
                xmlXPathAddValues(ctxt);
13018
228k
            else if (op->value == 2)
13019
205k
                xmlXPathValueFlipSign(ctxt);
13020
23.0k
            else if (op->value == 3) {
13021
23.0k
                CAST_TO_NUMBER;
13022
23.0k
                CHECK_TYPE0(XPATH_NUMBER);
13023
22.1k
            }
13024
357k
            break;
13025
357k
        case XPATH_OP_MULT:
13026
293k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13027
293k
      CHECK_ERROR0;
13028
179k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13029
179k
      CHECK_ERROR0;
13030
176k
            if (op->value == 0)
13031
119k
                xmlXPathMultValues(ctxt);
13032
57.1k
            else if (op->value == 1)
13033
1.02k
                xmlXPathDivValues(ctxt);
13034
56.0k
            else if (op->value == 2)
13035
56.0k
                xmlXPathModValues(ctxt);
13036
176k
            break;
13037
262k
        case XPATH_OP_UNION:
13038
262k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13039
262k
      CHECK_ERROR0;
13040
255k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13041
255k
      CHECK_ERROR0;
13042
13043
247k
            arg2 = valuePop(ctxt);
13044
247k
            arg1 = valuePop(ctxt);
13045
247k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13046
247k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13047
1.58k
          xmlXPathReleaseObject(ctxt->context, arg1);
13048
1.58k
          xmlXPathReleaseObject(ctxt->context, arg2);
13049
1.58k
                XP_ERROR0(XPATH_INVALID_TYPE);
13050
0
            }
13051
246k
            if ((ctxt->context->opLimit != 0) &&
13052
246k
                (((arg1->nodesetval != NULL) &&
13053
246k
                  (xmlXPathCheckOpLimit(ctxt,
13054
227k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13055
246k
                 ((arg2->nodesetval != NULL) &&
13056
246k
                  (xmlXPathCheckOpLimit(ctxt,
13057
223k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13058
9
          xmlXPathReleaseObject(ctxt->context, arg1);
13059
9
          xmlXPathReleaseObject(ctxt->context, arg2);
13060
9
                break;
13061
9
            }
13062
13063
246k
      if ((arg1->nodesetval == NULL) ||
13064
246k
    ((arg2->nodesetval != NULL) &&
13065
227k
     (arg2->nodesetval->nodeNr != 0)))
13066
136k
      {
13067
                /* TODO: Check memory error. */
13068
136k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13069
136k
              arg2->nodesetval);
13070
136k
      }
13071
13072
246k
            valuePush(ctxt, arg1);
13073
246k
      xmlXPathReleaseObject(ctxt->context, arg2);
13074
246k
            break;
13075
751k
        case XPATH_OP_ROOT:
13076
751k
            xmlXPathRoot(ctxt);
13077
751k
            break;
13078
2.20M
        case XPATH_OP_NODE:
13079
2.20M
            if (op->ch1 != -1)
13080
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13081
2.20M
      CHECK_ERROR0;
13082
2.20M
            if (op->ch2 != -1)
13083
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13084
2.20M
      CHECK_ERROR0;
13085
2.20M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13086
2.20M
    ctxt->context->node));
13087
2.20M
            break;
13088
2.18M
        case XPATH_OP_COLLECT:{
13089
2.18M
                if (op->ch1 == -1)
13090
0
                    break;
13091
13092
2.18M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13093
2.18M
    CHECK_ERROR0;
13094
13095
2.14M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13096
2.14M
                break;
13097
2.18M
            }
13098
899k
        case XPATH_OP_VALUE:
13099
899k
            valuePush(ctxt,
13100
899k
                      xmlXPathCacheObjectCopy(ctxt->context,
13101
899k
      (xmlXPathObjectPtr) op->value4));
13102
899k
            break;
13103
99.5k
        case XPATH_OP_VARIABLE:{
13104
99.5k
    xmlXPathObjectPtr val;
13105
13106
99.5k
                if (op->ch1 != -1)
13107
0
                    total +=
13108
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13109
99.5k
                if (op->value5 == NULL) {
13110
99.0k
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13111
99.0k
        if (val == NULL)
13112
96.4k
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13113
96.4k
                    valuePush(ctxt, val);
13114
96.4k
    } else {
13115
523
                    const xmlChar *URI;
13116
13117
523
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13118
523
                    if (URI == NULL) {
13119
385
                        xmlGenericError(xmlGenericErrorContext,
13120
385
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13121
385
                                    (char *) op->value4, (char *)op->value5);
13122
385
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13123
385
                        break;
13124
385
                    }
13125
138
        val = xmlXPathVariableLookupNS(ctxt->context,
13126
138
                                                       op->value4, URI);
13127
138
        if (val == NULL)
13128
138
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13129
0
                    valuePush(ctxt, val);
13130
0
                }
13131
96.4k
                break;
13132
99.5k
            }
13133
1.76M
        case XPATH_OP_FUNCTION:{
13134
1.76M
                xmlXPathFunction func;
13135
1.76M
                const xmlChar *oldFunc, *oldFuncURI;
13136
1.76M
    int i;
13137
1.76M
                int frame;
13138
13139
1.76M
                frame = ctxt->valueNr;
13140
1.76M
                if (op->ch1 != -1) {
13141
1.50M
                    total +=
13142
1.50M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13143
1.50M
                    if (ctxt->error != XPATH_EXPRESSION_OK)
13144
21.1k
                        break;
13145
1.50M
                }
13146
1.74M
    if (ctxt->valueNr < frame + op->value) {
13147
0
        xmlGenericError(xmlGenericErrorContext,
13148
0
          "xmlXPathCompOpEval: parameter error\n");
13149
0
        ctxt->error = XPATH_INVALID_OPERAND;
13150
0
        break;
13151
0
    }
13152
3.98M
    for (i = 0; i < op->value; i++) {
13153
2.23M
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13154
0
      xmlGenericError(xmlGenericErrorContext,
13155
0
        "xmlXPathCompOpEval: parameter error\n");
13156
0
      ctxt->error = XPATH_INVALID_OPERAND;
13157
0
      break;
13158
0
        }
13159
2.23M
                }
13160
1.74M
                if (op->cache != NULL)
13161
1.24M
                    func = op->cache;
13162
493k
                else {
13163
493k
                    const xmlChar *URI = NULL;
13164
13165
493k
                    if (op->value5 == NULL)
13166
33.3k
                        func =
13167
33.3k
                            xmlXPathFunctionLookup(ctxt->context,
13168
33.3k
                                                   op->value4);
13169
460k
                    else {
13170
460k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13171
460k
                        if (URI == NULL) {
13172
7.36k
                            xmlGenericError(xmlGenericErrorContext,
13173
7.36k
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13174
7.36k
                                    (char *)op->value4, (char *)op->value5);
13175
7.36k
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13176
7.36k
                            break;
13177
7.36k
                        }
13178
453k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13179
453k
                                                        op->value4, URI);
13180
453k
                    }
13181
486k
                    if (func == NULL) {
13182
11.2k
                        xmlGenericError(xmlGenericErrorContext,
13183
11.2k
                                "xmlXPathCompOpEval: function %s not found\n",
13184
11.2k
                                        (char *)op->value4);
13185
11.2k
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13186
0
                    }
13187
475k
                    op->cache = func;
13188
475k
                    op->cacheURI = (void *) URI;
13189
475k
                }
13190
1.72M
                oldFunc = ctxt->context->function;
13191
1.72M
                oldFuncURI = ctxt->context->functionURI;
13192
1.72M
                ctxt->context->function = op->value4;
13193
1.72M
                ctxt->context->functionURI = op->cacheURI;
13194
1.72M
                func(ctxt, op->value);
13195
1.72M
                ctxt->context->function = oldFunc;
13196
1.72M
                ctxt->context->functionURI = oldFuncURI;
13197
1.72M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13198
1.72M
                    (ctxt->valueNr != frame + 1))
13199
1.72M
                    XP_ERROR0(XPATH_STACK_ERROR);
13200
1.72M
                break;
13201
1.72M
            }
13202
2.27M
        case XPATH_OP_ARG:
13203
2.27M
            if (op->ch1 != -1) {
13204
774k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13205
774k
          CHECK_ERROR0;
13206
774k
            }
13207
2.27M
            if (op->ch2 != -1) {
13208
2.27M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13209
2.27M
          CHECK_ERROR0;
13210
2.27M
      }
13211
2.25M
            break;
13212
2.25M
        case XPATH_OP_PREDICATE:
13213
166k
        case XPATH_OP_FILTER:{
13214
166k
                xmlXPathObjectPtr obj;
13215
166k
                xmlNodeSetPtr set;
13216
13217
                /*
13218
                 * Optimization for ()[1] selection i.e. the first elem
13219
                 */
13220
166k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13221
166k
#ifdef XP_OPTIMIZED_FILTER_FIRST
13222
        /*
13223
        * FILTER TODO: Can we assume that the inner processing
13224
        *  will result in an ordered list if we have an
13225
        *  XPATH_OP_FILTER?
13226
        *  What about an additional field or flag on
13227
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13228
        *  to assume anything, so it would be more robust and
13229
        *  easier to optimize.
13230
        */
13231
166k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13232
166k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13233
#else
13234
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13235
#endif
13236
166k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13237
86.0k
                    xmlXPathObjectPtr val;
13238
13239
86.0k
                    val = comp->steps[op->ch2].value4;
13240
86.0k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13241
86.0k
                        (val->floatval == 1.0)) {
13242
28.3k
                        xmlNodePtr first = NULL;
13243
13244
28.3k
                        total +=
13245
28.3k
                            xmlXPathCompOpEvalFirst(ctxt,
13246
28.3k
                                                    &comp->steps[op->ch1],
13247
28.3k
                                                    &first);
13248
28.3k
      CHECK_ERROR0;
13249
                        /*
13250
                         * The nodeset should be in document order,
13251
                         * Keep only the first value
13252
                         */
13253
27.0k
                        if ((ctxt->value != NULL) &&
13254
27.0k
                            (ctxt->value->type == XPATH_NODESET) &&
13255
27.0k
                            (ctxt->value->nodesetval != NULL) &&
13256
27.0k
                            (ctxt->value->nodesetval->nodeNr > 1))
13257
275
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13258
275
                                                        1, 1);
13259
27.0k
                        break;
13260
28.3k
                    }
13261
86.0k
                }
13262
                /*
13263
                 * Optimization for ()[last()] selection i.e. the last elem
13264
                 */
13265
137k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13266
137k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13267
137k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13268
61.7k
                    int f = comp->steps[op->ch2].ch1;
13269
13270
61.7k
                    if ((f != -1) &&
13271
61.7k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13272
61.7k
                        (comp->steps[f].value5 == NULL) &&
13273
61.7k
                        (comp->steps[f].value == 0) &&
13274
61.7k
                        (comp->steps[f].value4 != NULL) &&
13275
61.7k
                        (xmlStrEqual
13276
51.8k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13277
48.5k
                        xmlNodePtr last = NULL;
13278
13279
48.5k
                        total +=
13280
48.5k
                            xmlXPathCompOpEvalLast(ctxt,
13281
48.5k
                                                   &comp->steps[op->ch1],
13282
48.5k
                                                   &last);
13283
48.5k
      CHECK_ERROR0;
13284
                        /*
13285
                         * The nodeset should be in document order,
13286
                         * Keep only the last value
13287
                         */
13288
48.1k
                        if ((ctxt->value != NULL) &&
13289
48.1k
                            (ctxt->value->type == XPATH_NODESET) &&
13290
48.1k
                            (ctxt->value->nodesetval != NULL) &&
13291
48.1k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13292
48.1k
                            (ctxt->value->nodesetval->nodeNr > 1))
13293
4.78k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13294
48.1k
                        break;
13295
48.5k
                    }
13296
61.7k
                }
13297
    /*
13298
    * Process inner predicates first.
13299
    * Example "index[parent::book][1]":
13300
    * ...
13301
    *   PREDICATE   <-- we are here "[1]"
13302
    *     PREDICATE <-- process "[parent::book]" first
13303
    *       SORT
13304
    *         COLLECT  'parent' 'name' 'node' book
13305
    *           NODE
13306
    *     ELEM Object is a number : 1
13307
    */
13308
89.0k
                if (op->ch1 != -1)
13309
89.0k
                    total +=
13310
89.0k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311
89.0k
    CHECK_ERROR0;
13312
87.1k
                if (op->ch2 == -1)
13313
0
                    break;
13314
87.1k
                if (ctxt->value == NULL)
13315
0
                    break;
13316
13317
#ifdef LIBXML_XPTR_LOCS_ENABLED
13318
                /*
13319
                 * Hum are we filtering the result of an XPointer expression
13320
                 */
13321
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13322
                    xmlLocationSetPtr locset = ctxt->value->user;
13323
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13324
                                              1, locset->locNr);
13325
                    break;
13326
                }
13327
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13328
13329
                /*
13330
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
13331
                 * nodes from the stack. We have to temporarily remove the
13332
                 * nodeset object from the stack to avoid freeing it
13333
                 * prematurely.
13334
                 */
13335
87.1k
                CHECK_TYPE0(XPATH_NODESET);
13336
86.4k
                obj = valuePop(ctxt);
13337
86.4k
                set = obj->nodesetval;
13338
86.4k
                if (set != NULL)
13339
81.9k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13340
81.9k
                                          1, set->nodeNr, 1);
13341
86.4k
                valuePush(ctxt, obj);
13342
86.4k
                break;
13343
87.1k
            }
13344
3.31M
        case XPATH_OP_SORT:
13345
3.31M
            if (op->ch1 != -1)
13346
3.31M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13347
3.31M
      CHECK_ERROR0;
13348
3.16M
            if ((ctxt->value != NULL) &&
13349
3.16M
                (ctxt->value->type == XPATH_NODESET) &&
13350
3.16M
                (ctxt->value->nodesetval != NULL) &&
13351
3.16M
    (ctxt->value->nodesetval->nodeNr > 1))
13352
94.4k
      {
13353
94.4k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13354
94.4k
      }
13355
3.16M
            break;
13356
#ifdef LIBXML_XPTR_LOCS_ENABLED
13357
        case XPATH_OP_RANGETO:{
13358
                xmlXPathObjectPtr range;
13359
                xmlXPathObjectPtr res, obj;
13360
                xmlXPathObjectPtr tmp;
13361
                xmlLocationSetPtr newlocset = NULL;
13362
        xmlLocationSetPtr oldlocset;
13363
                xmlNodeSetPtr oldset;
13364
                xmlNodePtr oldnode = ctxt->context->node;
13365
                int oldcs = ctxt->context->contextSize;
13366
                int oldpp = ctxt->context->proximityPosition;
13367
                int i, j;
13368
13369
                if (op->ch1 != -1) {
13370
                    total +=
13371
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13372
                    CHECK_ERROR0;
13373
                }
13374
                if (ctxt->value == NULL) {
13375
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13376
                }
13377
                if (op->ch2 == -1)
13378
                    break;
13379
13380
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13381
                    /*
13382
                     * Extract the old locset, and then evaluate the result of the
13383
                     * expression for all the element in the locset. use it to grow
13384
                     * up a new locset.
13385
                     */
13386
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13387
13388
                    if ((ctxt->value->user == NULL) ||
13389
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13390
                        break;
13391
13392
                    obj = valuePop(ctxt);
13393
                    oldlocset = obj->user;
13394
13395
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13396
13397
                    for (i = 0; i < oldlocset->locNr; i++) {
13398
                        /*
13399
                         * Run the evaluation with a node list made of a
13400
                         * single item in the nodelocset.
13401
                         */
13402
                        ctxt->context->node = oldlocset->locTab[i]->user;
13403
                        ctxt->context->contextSize = oldlocset->locNr;
13404
                        ctxt->context->proximityPosition = i + 1;
13405
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13406
          ctxt->context->node);
13407
                        valuePush(ctxt, tmp);
13408
13409
                        if (op->ch2 != -1)
13410
                            total +=
13411
                                xmlXPathCompOpEval(ctxt,
13412
                                                   &comp->steps[op->ch2]);
13413
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13414
                            xmlXPtrFreeLocationSet(newlocset);
13415
                            goto rangeto_error;
13416
      }
13417
13418
                        res = valuePop(ctxt);
13419
      if (res->type == XPATH_LOCATIONSET) {
13420
          xmlLocationSetPtr rloc =
13421
              (xmlLocationSetPtr)res->user;
13422
          for (j=0; j<rloc->locNr; j++) {
13423
              range = xmlXPtrNewRange(
13424
          oldlocset->locTab[i]->user,
13425
          oldlocset->locTab[i]->index,
13426
          rloc->locTab[j]->user2,
13427
          rloc->locTab[j]->index2);
13428
        if (range != NULL) {
13429
            xmlXPtrLocationSetAdd(newlocset, range);
13430
        }
13431
          }
13432
      } else {
13433
          range = xmlXPtrNewRangeNodeObject(
13434
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13435
                            if (range != NULL) {
13436
                                xmlXPtrLocationSetAdd(newlocset,range);
13437
          }
13438
                        }
13439
13440
                        /*
13441
                         * Cleanup
13442
                         */
13443
                        if (res != NULL) {
13444
          xmlXPathReleaseObject(ctxt->context, res);
13445
      }
13446
                        if (ctxt->value == tmp) {
13447
                            res = valuePop(ctxt);
13448
          xmlXPathReleaseObject(ctxt->context, res);
13449
                        }
13450
                    }
13451
    } else {  /* Not a location set */
13452
                    CHECK_TYPE0(XPATH_NODESET);
13453
                    obj = valuePop(ctxt);
13454
                    oldset = obj->nodesetval;
13455
13456
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13457
13458
                    if (oldset != NULL) {
13459
                        for (i = 0; i < oldset->nodeNr; i++) {
13460
                            /*
13461
                             * Run the evaluation with a node list made of a single item
13462
                             * in the nodeset.
13463
                             */
13464
                            ctxt->context->node = oldset->nodeTab[i];
13465
          /*
13466
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13467
          */
13468
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13469
        ctxt->context->node);
13470
                            valuePush(ctxt, tmp);
13471
13472
                            if (op->ch2 != -1)
13473
                                total +=
13474
                                    xmlXPathCompOpEval(ctxt,
13475
                                                   &comp->steps[op->ch2]);
13476
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13477
                                xmlXPtrFreeLocationSet(newlocset);
13478
                                goto rangeto_error;
13479
          }
13480
13481
                            res = valuePop(ctxt);
13482
                            range =
13483
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13484
                                                      res);
13485
                            if (range != NULL) {
13486
                                xmlXPtrLocationSetAdd(newlocset, range);
13487
                            }
13488
13489
                            /*
13490
                             * Cleanup
13491
                             */
13492
                            if (res != NULL) {
13493
        xmlXPathReleaseObject(ctxt->context, res);
13494
          }
13495
                            if (ctxt->value == tmp) {
13496
                                res = valuePop(ctxt);
13497
        xmlXPathReleaseObject(ctxt->context, res);
13498
                            }
13499
                        }
13500
                    }
13501
                }
13502
13503
                /*
13504
                 * The result is used as the new evaluation set.
13505
                 */
13506
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13507
rangeto_error:
13508
    xmlXPathReleaseObject(ctxt->context, obj);
13509
                ctxt->context->node = oldnode;
13510
                ctxt->context->contextSize = oldcs;
13511
                ctxt->context->proximityPosition = oldpp;
13512
                break;
13513
            }
13514
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13515
0
        default:
13516
0
            xmlGenericError(xmlGenericErrorContext,
13517
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13518
0
            ctxt->error = XPATH_INVALID_OPERAND;
13519
0
            break;
13520
15.6M
    }
13521
13522
15.1M
    ctxt->context->depth -= 1;
13523
15.1M
    return (total);
13524
15.6M
}
13525
13526
/**
13527
 * xmlXPathCompOpEvalToBoolean:
13528
 * @ctxt:  the XPath parser context
13529
 *
13530
 * Evaluates if the expression evaluates to true.
13531
 *
13532
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13533
 */
13534
static int
13535
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13536
          xmlXPathStepOpPtr op,
13537
          int isPredicate)
13538
705k
{
13539
705k
    xmlXPathObjectPtr resObj = NULL;
13540
13541
779k
start:
13542
779k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13543
96
        return(0);
13544
    /* comp = ctxt->comp; */
13545
779k
    switch (op->op) {
13546
0
        case XPATH_OP_END:
13547
0
            return (0);
13548
35.9k
  case XPATH_OP_VALUE:
13549
35.9k
      resObj = (xmlXPathObjectPtr) op->value4;
13550
35.9k
      if (isPredicate)
13551
35.9k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13552
19
      return(xmlXPathCastToBoolean(resObj));
13553
73.7k
  case XPATH_OP_SORT:
13554
      /*
13555
      * We don't need sorting for boolean results. Skip this one.
13556
      */
13557
73.7k
            if (op->ch1 != -1) {
13558
73.7k
    op = &ctxt->comp->steps[op->ch1];
13559
73.7k
    goto start;
13560
73.7k
      }
13561
0
      return(0);
13562
28.1k
  case XPATH_OP_COLLECT:
13563
28.1k
      if (op->ch1 == -1)
13564
0
    return(0);
13565
13566
28.1k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13567
28.1k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13568
367
    return(-1);
13569
13570
27.8k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13571
27.8k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13572
728
    return(-1);
13573
13574
27.0k
      resObj = valuePop(ctxt);
13575
27.0k
      if (resObj == NULL)
13576
0
    return(-1);
13577
27.0k
      break;
13578
641k
  default:
13579
      /*
13580
      * Fallback to call xmlXPathCompOpEval().
13581
      */
13582
641k
      xmlXPathCompOpEval(ctxt, op);
13583
641k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13584
4.43k
    return(-1);
13585
13586
636k
      resObj = valuePop(ctxt);
13587
636k
      if (resObj == NULL)
13588
0
    return(-1);
13589
636k
      break;
13590
779k
    }
13591
13592
664k
    if (resObj) {
13593
664k
  int res;
13594
13595
664k
  if (resObj->type == XPATH_BOOLEAN) {
13596
300k
      res = resObj->boolval;
13597
363k
  } else if (isPredicate) {
13598
      /*
13599
      * For predicates a result of type "number" is handled
13600
      * differently:
13601
      * SPEC XPath 1.0:
13602
      * "If the result is a number, the result will be converted
13603
      *  to true if the number is equal to the context position
13604
      *  and will be converted to false otherwise;"
13605
      */
13606
361k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13607
361k
  } else {
13608
2.47k
      res = xmlXPathCastToBoolean(resObj);
13609
2.47k
  }
13610
664k
  xmlXPathReleaseObject(ctxt->context, resObj);
13611
664k
  return(res);
13612
664k
    }
13613
13614
0
    return(0);
13615
664k
}
13616
13617
#ifdef XPATH_STREAMING
13618
/**
13619
 * xmlXPathRunStreamEval:
13620
 * @ctxt:  the XPath parser context with the compiled expression
13621
 *
13622
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13623
 */
13624
static int
13625
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13626
          xmlXPathObjectPtr *resultSeq, int toBool)
13627
1.46M
{
13628
1.46M
    int max_depth, min_depth;
13629
1.46M
    int from_root;
13630
1.46M
    int ret, depth;
13631
1.46M
    int eval_all_nodes;
13632
1.46M
    xmlNodePtr cur = NULL, limit = NULL;
13633
1.46M
    xmlStreamCtxtPtr patstream = NULL;
13634
13635
1.46M
    if ((ctxt == NULL) || (comp == NULL))
13636
0
        return(-1);
13637
1.46M
    max_depth = xmlPatternMaxDepth(comp);
13638
1.46M
    if (max_depth == -1)
13639
0
        return(-1);
13640
1.46M
    if (max_depth == -2)
13641
41.7k
        max_depth = 10000;
13642
1.46M
    min_depth = xmlPatternMinDepth(comp);
13643
1.46M
    if (min_depth == -1)
13644
0
        return(-1);
13645
1.46M
    from_root = xmlPatternFromRoot(comp);
13646
1.46M
    if (from_root < 0)
13647
0
        return(-1);
13648
#if 0
13649
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13650
#endif
13651
13652
1.46M
    if (! toBool) {
13653
1.46M
  if (resultSeq == NULL)
13654
0
      return(-1);
13655
1.46M
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13656
1.46M
  if (*resultSeq == NULL)
13657
27
      return(-1);
13658
1.46M
    }
13659
13660
    /*
13661
     * handle the special cases of "/" amd "." being matched
13662
     */
13663
1.46M
    if (min_depth == 0) {
13664
892k
  if (from_root) {
13665
      /* Select "/" */
13666
0
      if (toBool)
13667
0
    return(1);
13668
            /* TODO: Check memory error. */
13669
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13670
0
                         (xmlNodePtr) ctxt->doc);
13671
892k
  } else {
13672
      /* Select "self::node()" */
13673
892k
      if (toBool)
13674
0
    return(1);
13675
            /* TODO: Check memory error. */
13676
892k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13677
892k
  }
13678
892k
    }
13679
1.46M
    if (max_depth == 0) {
13680
889k
  return(0);
13681
889k
    }
13682
13683
579k
    if (from_root) {
13684
11.3k
        cur = (xmlNodePtr)ctxt->doc;
13685
568k
    } else if (ctxt->node != NULL) {
13686
568k
        switch (ctxt->node->type) {
13687
292k
            case XML_ELEMENT_NODE:
13688
299k
            case XML_DOCUMENT_NODE:
13689
299k
            case XML_DOCUMENT_FRAG_NODE:
13690
299k
            case XML_HTML_DOCUMENT_NODE:
13691
299k
          cur = ctxt->node;
13692
299k
    break;
13693
0
            case XML_ATTRIBUTE_NODE:
13694
224k
            case XML_TEXT_NODE:
13695
224k
            case XML_CDATA_SECTION_NODE:
13696
224k
            case XML_ENTITY_REF_NODE:
13697
224k
            case XML_ENTITY_NODE:
13698
224k
            case XML_PI_NODE:
13699
267k
            case XML_COMMENT_NODE:
13700
267k
            case XML_NOTATION_NODE:
13701
267k
            case XML_DTD_NODE:
13702
267k
            case XML_DOCUMENT_TYPE_NODE:
13703
267k
            case XML_ELEMENT_DECL:
13704
267k
            case XML_ATTRIBUTE_DECL:
13705
267k
            case XML_ENTITY_DECL:
13706
268k
            case XML_NAMESPACE_DECL:
13707
268k
            case XML_XINCLUDE_START:
13708
268k
            case XML_XINCLUDE_END:
13709
268k
    break;
13710
568k
  }
13711
568k
  limit = cur;
13712
568k
    }
13713
579k
    if (cur == NULL) {
13714
268k
        return(0);
13715
268k
    }
13716
13717
310k
    patstream = xmlPatternGetStreamCtxt(comp);
13718
310k
    if (patstream == NULL) {
13719
  /*
13720
  * QUESTION TODO: Is this an error?
13721
  */
13722
74
  return(0);
13723
74
    }
13724
13725
310k
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13726
13727
310k
    if (from_root) {
13728
11.3k
  ret = xmlStreamPush(patstream, NULL, NULL);
13729
11.3k
  if (ret < 0) {
13730
11.3k
  } else if (ret == 1) {
13731
896
      if (toBool)
13732
0
    goto return_1;
13733
            /* TODO: Check memory error. */
13734
896
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13735
896
  }
13736
11.3k
    }
13737
310k
    depth = 0;
13738
310k
    goto scan_children;
13739
1.29M
next_node:
13740
1.97M
    do {
13741
1.97M
        if (ctxt->opLimit != 0) {
13742
1.97M
            if (ctxt->opCount >= ctxt->opLimit) {
13743
22
                xmlGenericError(xmlGenericErrorContext,
13744
22
                        "XPath operation limit exceeded\n");
13745
22
                xmlFreeStreamCtxt(patstream);
13746
22
                return(-1);
13747
22
            }
13748
1.97M
            ctxt->opCount++;
13749
1.97M
        }
13750
13751
1.97M
  switch (cur->type) {
13752
953k
      case XML_ELEMENT_NODE:
13753
1.93M
      case XML_TEXT_NODE:
13754
1.93M
      case XML_CDATA_SECTION_NODE:
13755
1.96M
      case XML_COMMENT_NODE:
13756
1.97M
      case XML_PI_NODE:
13757
1.97M
    if (cur->type == XML_ELEMENT_NODE) {
13758
953k
        ret = xmlStreamPush(patstream, cur->name,
13759
953k
        (cur->ns ? cur->ns->href : NULL));
13760
1.01M
    } else if (eval_all_nodes)
13761
118k
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13762
899k
    else
13763
899k
        break;
13764
13765
1.07M
    if (ret < 0) {
13766
        /* NOP. */
13767
1.07M
    } else if (ret == 1) {
13768
547k
        if (toBool)
13769
0
      goto return_1;
13770
547k
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13771
547k
            < 0) {
13772
1.03k
      ctxt->lastError.domain = XML_FROM_XPATH;
13773
1.03k
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13774
1.03k
        }
13775
547k
    }
13776
1.07M
    if ((cur->children == NULL) || (depth >= max_depth)) {
13777
852k
        ret = xmlStreamPop(patstream);
13778
852k
        while (cur->next != NULL) {
13779
786k
      cur = cur->next;
13780
786k
      if ((cur->type != XML_ENTITY_DECL) &&
13781
786k
          (cur->type != XML_DTD_NODE))
13782
786k
          goto next_node;
13783
786k
        }
13784
852k
    }
13785
285k
      default:
13786
285k
    break;
13787
1.97M
  }
13788
13789
1.49M
scan_children:
13790
1.49M
  if (cur->type == XML_NAMESPACE_DECL) break;
13791
1.49M
  if ((cur->children != NULL) && (depth < max_depth)) {
13792
      /*
13793
       * Do not descend on entities declarations
13794
       */
13795
480k
      if (cur->children->type != XML_ENTITY_DECL) {
13796
480k
    cur = cur->children;
13797
480k
    depth++;
13798
    /*
13799
     * Skip DTDs
13800
     */
13801
480k
    if (cur->type != XML_DTD_NODE)
13802
480k
        continue;
13803
480k
      }
13804
480k
  }
13805
13806
1.01M
  if (cur == limit)
13807
49.6k
      break;
13808
13809
965k
  while (cur->next != NULL) {
13810
512k
      cur = cur->next;
13811
512k
      if ((cur->type != XML_ENTITY_DECL) &&
13812
512k
    (cur->type != XML_DTD_NODE))
13813
512k
    goto next_node;
13814
512k
  }
13815
13816
480k
  do {
13817
480k
      cur = cur->parent;
13818
480k
      depth--;
13819
480k
      if ((cur == NULL) || (cur == limit) ||
13820
480k
                (cur->type == XML_DOCUMENT_NODE))
13821
261k
          goto done;
13822
219k
      if (cur->type == XML_ELEMENT_NODE) {
13823
219k
    ret = xmlStreamPop(patstream);
13824
219k
      } else if ((eval_all_nodes) &&
13825
0
    ((cur->type == XML_TEXT_NODE) ||
13826
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13827
0
     (cur->type == XML_COMMENT_NODE) ||
13828
0
     (cur->type == XML_PI_NODE)))
13829
0
      {
13830
0
    ret = xmlStreamPop(patstream);
13831
0
      }
13832
219k
      if (cur->next != NULL) {
13833
191k
    cur = cur->next;
13834
191k
    break;
13835
191k
      }
13836
219k
  } while (cur != NULL);
13837
13838
671k
    } while ((cur != NULL) && (depth >= 0));
13839
13840
310k
done:
13841
13842
310k
    if (patstream)
13843
310k
  xmlFreeStreamCtxt(patstream);
13844
310k
    return(0);
13845
13846
0
return_1:
13847
0
    if (patstream)
13848
0
  xmlFreeStreamCtxt(patstream);
13849
0
    return(1);
13850
1.29M
}
13851
#endif /* XPATH_STREAMING */
13852
13853
/**
13854
 * xmlXPathRunEval:
13855
 * @ctxt:  the XPath parser context with the compiled expression
13856
 * @toBool:  evaluate to a boolean result
13857
 *
13858
 * Evaluate the Precompiled XPath expression in the given context.
13859
 */
13860
static int
13861
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13862
2.66M
{
13863
2.66M
    xmlXPathCompExprPtr comp;
13864
2.66M
    int oldDepth;
13865
13866
2.66M
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13867
0
  return(-1);
13868
13869
2.66M
    if (ctxt->valueTab == NULL) {
13870
  /* Allocate the value stack */
13871
83.0k
  ctxt->valueTab = (xmlXPathObjectPtr *)
13872
83.0k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13873
83.0k
  if (ctxt->valueTab == NULL) {
13874
21
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13875
21
      return(-1);
13876
21
  }
13877
83.0k
  ctxt->valueNr = 0;
13878
83.0k
  ctxt->valueMax = 10;
13879
83.0k
  ctxt->value = NULL;
13880
83.0k
    }
13881
2.66M
#ifdef XPATH_STREAMING
13882
2.66M
    if (ctxt->comp->stream) {
13883
1.46M
  int res;
13884
13885
1.46M
  if (toBool) {
13886
      /*
13887
      * Evaluation to boolean result.
13888
      */
13889
163
      res = xmlXPathRunStreamEval(ctxt->context,
13890
163
    ctxt->comp->stream, NULL, 1);
13891
163
      if (res != -1)
13892
163
    return(res);
13893
1.46M
  } else {
13894
1.46M
      xmlXPathObjectPtr resObj = NULL;
13895
13896
      /*
13897
      * Evaluation to a sequence.
13898
      */
13899
1.46M
      res = xmlXPathRunStreamEval(ctxt->context,
13900
1.46M
    ctxt->comp->stream, &resObj, 0);
13901
13902
1.46M
      if ((res != -1) && (resObj != NULL)) {
13903
1.46M
    valuePush(ctxt, resObj);
13904
1.46M
    return(0);
13905
1.46M
      }
13906
49
      if (resObj != NULL)
13907
22
    xmlXPathReleaseObject(ctxt->context, resObj);
13908
49
  }
13909
  /*
13910
  * QUESTION TODO: This falls back to normal XPath evaluation
13911
  * if res == -1. Is this intended?
13912
  */
13913
1.46M
    }
13914
1.19M
#endif
13915
1.19M
    comp = ctxt->comp;
13916
1.19M
    if (comp->last < 0) {
13917
49
  xmlGenericError(xmlGenericErrorContext,
13918
49
      "xmlXPathRunEval: last is less than zero\n");
13919
49
  return(-1);
13920
49
    }
13921
1.19M
    oldDepth = ctxt->context->depth;
13922
1.19M
    if (toBool)
13923
27.8k
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13924
27.8k
      &comp->steps[comp->last], 0));
13925
1.17M
    else
13926
1.17M
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13927
1.17M
    ctxt->context->depth = oldDepth;
13928
13929
1.17M
    return(0);
13930
1.19M
}
13931
13932
/************************************************************************
13933
 *                  *
13934
 *      Public interfaces       *
13935
 *                  *
13936
 ************************************************************************/
13937
13938
/**
13939
 * xmlXPathEvalPredicate:
13940
 * @ctxt:  the XPath context
13941
 * @res:  the Predicate Expression evaluation result
13942
 *
13943
 * Evaluate a predicate result for the current node.
13944
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13945
 * the result to a boolean. If the result is a number, the result will
13946
 * be converted to true if the number is equal to the position of the
13947
 * context node in the context node list (as returned by the position
13948
 * function) and will be converted to false otherwise; if the result
13949
 * is not a number, then the result will be converted as if by a call
13950
 * to the boolean function.
13951
 *
13952
 * Returns 1 if predicate is true, 0 otherwise
13953
 */
13954
int
13955
15.1k
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13956
15.1k
    if ((ctxt == NULL) || (res == NULL)) return(0);
13957
15.1k
    switch (res->type) {
13958
10.4k
        case XPATH_BOOLEAN:
13959
10.4k
      return(res->boolval);
13960
2.87k
        case XPATH_NUMBER:
13961
2.87k
      return(res->floatval == ctxt->proximityPosition);
13962
1.34k
        case XPATH_NODESET:
13963
1.34k
        case XPATH_XSLT_TREE:
13964
1.34k
      if (res->nodesetval == NULL)
13965
256
    return(0);
13966
1.09k
      return(res->nodesetval->nodeNr != 0);
13967
425
        case XPATH_STRING:
13968
425
      return((res->stringval != NULL) &&
13969
425
             (xmlStrlen(res->stringval) != 0));
13970
0
        default:
13971
0
      STRANGE
13972
15.1k
    }
13973
0
    return(0);
13974
15.1k
}
13975
13976
/**
13977
 * xmlXPathEvaluatePredicateResult:
13978
 * @ctxt:  the XPath Parser context
13979
 * @res:  the Predicate Expression evaluation result
13980
 *
13981
 * Evaluate a predicate result for the current node.
13982
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13983
 * the result to a boolean. If the result is a number, the result will
13984
 * be converted to true if the number is equal to the position of the
13985
 * context node in the context node list (as returned by the position
13986
 * function) and will be converted to false otherwise; if the result
13987
 * is not a number, then the result will be converted as if by a call
13988
 * to the boolean function.
13989
 *
13990
 * Returns 1 if predicate is true, 0 otherwise
13991
 */
13992
int
13993
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13994
397k
                                xmlXPathObjectPtr res) {
13995
397k
    if ((ctxt == NULL) || (res == NULL)) return(0);
13996
397k
    switch (res->type) {
13997
0
        case XPATH_BOOLEAN:
13998
0
      return(res->boolval);
13999
238k
        case XPATH_NUMBER:
14000
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14001
      return((res->floatval == ctxt->context->proximityPosition) &&
14002
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14003
#else
14004
238k
      return(res->floatval == ctxt->context->proximityPosition);
14005
0
#endif
14006
70.5k
        case XPATH_NODESET:
14007
70.5k
        case XPATH_XSLT_TREE:
14008
70.5k
      if (res->nodesetval == NULL)
14009
6.00k
    return(0);
14010
64.5k
      return(res->nodesetval->nodeNr != 0);
14011
87.9k
        case XPATH_STRING:
14012
87.9k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14013
#ifdef LIBXML_XPTR_LOCS_ENABLED
14014
  case XPATH_LOCATIONSET:{
14015
      xmlLocationSetPtr ptr = res->user;
14016
      if (ptr == NULL)
14017
          return(0);
14018
      return (ptr->locNr != 0);
14019
      }
14020
#endif
14021
0
        default:
14022
0
      STRANGE
14023
397k
    }
14024
0
    return(0);
14025
397k
}
14026
14027
#ifdef XPATH_STREAMING
14028
/**
14029
 * xmlXPathTryStreamCompile:
14030
 * @ctxt: an XPath context
14031
 * @str:  the XPath expression
14032
 *
14033
 * Try to compile the XPath expression as a streamable subset.
14034
 *
14035
 * Returns the compiled expression or NULL if failed to compile.
14036
 */
14037
static xmlXPathCompExprPtr
14038
906k
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14039
    /*
14040
     * Optimization: use streaming patterns when the XPath expression can
14041
     * be compiled to a stream lookup
14042
     */
14043
906k
    xmlPatternPtr stream;
14044
906k
    xmlXPathCompExprPtr comp;
14045
906k
    xmlDictPtr dict = NULL;
14046
906k
    const xmlChar **namespaces = NULL;
14047
906k
    xmlNsPtr ns;
14048
906k
    int i, j;
14049
14050
906k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14051
906k
        (!xmlStrchr(str, '@'))) {
14052
454k
  const xmlChar *tmp;
14053
14054
  /*
14055
   * We don't try to handle expressions using the verbose axis
14056
   * specifiers ("::"), just the simplified form at this point.
14057
   * Additionally, if there is no list of namespaces available and
14058
   *  there's a ":" in the expression, indicating a prefixed QName,
14059
   *  then we won't try to compile either. xmlPatterncompile() needs
14060
   *  to have a list of namespaces at compilation time in order to
14061
   *  compile prefixed name tests.
14062
   */
14063
454k
  tmp = xmlStrchr(str, ':');
14064
454k
  if ((tmp != NULL) &&
14065
454k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14066
10.1k
      return(NULL);
14067
14068
444k
  if (ctxt != NULL) {
14069
444k
      dict = ctxt->dict;
14070
444k
      if (ctxt->nsNr > 0) {
14071
309k
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14072
309k
    if (namespaces == NULL) {
14073
52
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14074
52
        return(NULL);
14075
52
    }
14076
3.74M
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14077
3.43M
        ns = ctxt->namespaces[j];
14078
3.43M
        namespaces[i++] = ns->href;
14079
3.43M
        namespaces[i++] = ns->prefix;
14080
3.43M
    }
14081
309k
    namespaces[i++] = NULL;
14082
309k
    namespaces[i] = NULL;
14083
309k
      }
14084
444k
  }
14085
14086
444k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14087
444k
  if (namespaces != NULL) {
14088
309k
      xmlFree((xmlChar **)namespaces);
14089
309k
  }
14090
444k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14091
214k
      comp = xmlXPathNewCompExpr();
14092
214k
      if (comp == NULL) {
14093
17
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14094
17
          xmlFreePattern(stream);
14095
17
    return(NULL);
14096
17
      }
14097
214k
      comp->stream = stream;
14098
214k
      comp->dict = dict;
14099
214k
      if (comp->dict)
14100
25.3k
    xmlDictReference(comp->dict);
14101
214k
      return(comp);
14102
214k
  }
14103
230k
  xmlFreePattern(stream);
14104
230k
    }
14105
682k
    return(NULL);
14106
906k
}
14107
#endif /* XPATH_STREAMING */
14108
14109
static void
14110
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14111
                           xmlXPathStepOpPtr op)
14112
9.90M
{
14113
9.90M
    xmlXPathCompExprPtr comp = pctxt->comp;
14114
9.90M
    xmlXPathContextPtr ctxt;
14115
14116
    /*
14117
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14118
    * internal representation.
14119
    */
14120
14121
9.90M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14122
9.90M
        (op->ch1 != -1) &&
14123
9.90M
        (op->ch2 == -1 /* no predicate */))
14124
1.78M
    {
14125
1.78M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14126
14127
1.78M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14128
1.78M
            ((xmlXPathAxisVal) prevop->value ==
14129
201k
                AXIS_DESCENDANT_OR_SELF) &&
14130
1.78M
            (prevop->ch2 == -1) &&
14131
1.78M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14132
1.78M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14133
89.2k
        {
14134
            /*
14135
            * This is a "descendant-or-self::node()" without predicates.
14136
            * Try to eliminate it.
14137
            */
14138
14139
89.2k
            switch ((xmlXPathAxisVal) op->value) {
14140
85.1k
                case AXIS_CHILD:
14141
85.1k
                case AXIS_DESCENDANT:
14142
                    /*
14143
                    * Convert "descendant-or-self::node()/child::" or
14144
                    * "descendant-or-self::node()/descendant::" to
14145
                    * "descendant::"
14146
                    */
14147
85.1k
                    op->ch1   = prevop->ch1;
14148
85.1k
                    op->value = AXIS_DESCENDANT;
14149
85.1k
                    break;
14150
0
                case AXIS_SELF:
14151
208
                case AXIS_DESCENDANT_OR_SELF:
14152
                    /*
14153
                    * Convert "descendant-or-self::node()/self::" or
14154
                    * "descendant-or-self::node()/descendant-or-self::" to
14155
                    * to "descendant-or-self::"
14156
                    */
14157
208
                    op->ch1   = prevop->ch1;
14158
208
                    op->value = AXIS_DESCENDANT_OR_SELF;
14159
208
                    break;
14160
3.85k
                default:
14161
3.85k
                    break;
14162
89.2k
            }
14163
89.2k
  }
14164
1.78M
    }
14165
14166
    /* OP_VALUE has invalid ch1. */
14167
9.90M
    if (op->op == XPATH_OP_VALUE)
14168
366k
        return;
14169
14170
    /* Recurse */
14171
9.53M
    ctxt = pctxt->context;
14172
9.53M
    if (ctxt != NULL) {
14173
9.53M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14174
22.7k
            return;
14175
9.51M
        ctxt->depth += 1;
14176
9.51M
    }
14177
9.51M
    if (op->ch1 != -1)
14178
6.52M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14179
9.51M
    if (op->ch2 != -1)
14180
3.04M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14181
9.51M
    if (ctxt != NULL)
14182
9.51M
        ctxt->depth -= 1;
14183
9.51M
}
14184
14185
/**
14186
 * xmlXPathCtxtCompile:
14187
 * @ctxt: an XPath context
14188
 * @str:  the XPath expression
14189
 *
14190
 * Compile an XPath expression
14191
 *
14192
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14193
 *         the caller has to free the object.
14194
 */
14195
xmlXPathCompExprPtr
14196
724k
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14197
724k
    xmlXPathParserContextPtr pctxt;
14198
724k
    xmlXPathCompExprPtr comp;
14199
724k
    int oldDepth = 0;
14200
14201
724k
#ifdef XPATH_STREAMING
14202
724k
    comp = xmlXPathTryStreamCompile(ctxt, str);
14203
724k
    if (comp != NULL)
14204
186k
        return(comp);
14205
538k
#endif
14206
14207
538k
    xmlInitParser();
14208
14209
538k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14210
538k
    if (pctxt == NULL)
14211
882
        return NULL;
14212
537k
    if (ctxt != NULL)
14213
537k
        oldDepth = ctxt->depth;
14214
537k
    xmlXPathCompileExpr(pctxt, 1);
14215
537k
    if (ctxt != NULL)
14216
537k
        ctxt->depth = oldDepth;
14217
14218
537k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14219
209k
    {
14220
209k
        xmlXPathFreeParserContext(pctxt);
14221
209k
        return(NULL);
14222
209k
    }
14223
14224
328k
    if (*pctxt->cur != 0) {
14225
  /*
14226
   * aleksey: in some cases this line prints *second* error message
14227
   * (see bug #78858) and probably this should be fixed.
14228
   * However, we are not sure that all error messages are printed
14229
   * out in other places. It's not critical so we leave it as-is for now
14230
   */
14231
34.8k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14232
34.8k
  comp = NULL;
14233
293k
    } else {
14234
293k
  comp = pctxt->comp;
14235
293k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14236
288k
            if (ctxt != NULL)
14237
288k
                oldDepth = ctxt->depth;
14238
288k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14239
288k
            if (ctxt != NULL)
14240
288k
                ctxt->depth = oldDepth;
14241
288k
  }
14242
293k
  pctxt->comp = NULL;
14243
293k
    }
14244
328k
    xmlXPathFreeParserContext(pctxt);
14245
14246
328k
    if (comp != NULL) {
14247
293k
  comp->expr = xmlStrdup(str);
14248
#ifdef DEBUG_EVAL_COUNTS
14249
  comp->string = xmlStrdup(str);
14250
  comp->nb = 0;
14251
#endif
14252
293k
    }
14253
328k
    return(comp);
14254
537k
}
14255
14256
/**
14257
 * xmlXPathCompile:
14258
 * @str:  the XPath expression
14259
 *
14260
 * Compile an XPath expression
14261
 *
14262
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14263
 *         the caller has to free the object.
14264
 */
14265
xmlXPathCompExprPtr
14266
0
xmlXPathCompile(const xmlChar *str) {
14267
0
    return(xmlXPathCtxtCompile(NULL, str));
14268
0
}
14269
14270
/**
14271
 * xmlXPathCompiledEvalInternal:
14272
 * @comp:  the compiled XPath expression
14273
 * @ctxt:  the XPath context
14274
 * @resObj: the resulting XPath object or NULL
14275
 * @toBool: 1 if only a boolean result is requested
14276
 *
14277
 * Evaluate the Precompiled XPath expression in the given context.
14278
 * The caller has to free @resObj.
14279
 *
14280
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14281
 *         the caller has to free the object.
14282
 */
14283
static int
14284
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14285
           xmlXPathContextPtr ctxt,
14286
           xmlXPathObjectPtr *resObjPtr,
14287
           int toBool)
14288
2.60M
{
14289
2.60M
    xmlXPathParserContextPtr pctxt;
14290
2.60M
    xmlXPathObjectPtr resObj;
14291
#ifndef LIBXML_THREAD_ENABLED
14292
    static int reentance = 0;
14293
#endif
14294
2.60M
    int res;
14295
14296
2.60M
    CHECK_CTXT_NEG(ctxt)
14297
14298
2.60M
    if (comp == NULL)
14299
308
  return(-1);
14300
2.60M
    xmlInitParser();
14301
14302
#ifndef LIBXML_THREAD_ENABLED
14303
    reentance++;
14304
    if (reentance > 1)
14305
  xmlXPathDisableOptimizer = 1;
14306
#endif
14307
14308
#ifdef DEBUG_EVAL_COUNTS
14309
    comp->nb++;
14310
    if ((comp->string != NULL) && (comp->nb > 100)) {
14311
  fprintf(stderr, "100 x %s\n", comp->string);
14312
  comp->nb = 0;
14313
    }
14314
#endif
14315
2.60M
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14316
2.60M
    if (pctxt == NULL)
14317
18.2k
        return(-1);
14318
2.58M
    res = xmlXPathRunEval(pctxt, toBool);
14319
14320
2.58M
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14321
122k
        resObj = NULL;
14322
2.46M
    } else {
14323
2.46M
        resObj = valuePop(pctxt);
14324
2.46M
        if (resObj == NULL) {
14325
27.9k
            if (!toBool)
14326
48
                xmlGenericError(xmlGenericErrorContext,
14327
48
                    "xmlXPathCompiledEval: No result on the stack.\n");
14328
2.43M
        } else if (pctxt->valueNr > 0) {
14329
0
            xmlGenericError(xmlGenericErrorContext,
14330
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14331
0
                pctxt->valueNr);
14332
0
        }
14333
2.46M
    }
14334
14335
2.58M
    if (resObjPtr)
14336
2.55M
        *resObjPtr = resObj;
14337
27.9k
    else
14338
27.9k
        xmlXPathReleaseObject(ctxt, resObj);
14339
14340
2.58M
    pctxt->comp = NULL;
14341
2.58M
    xmlXPathFreeParserContext(pctxt);
14342
#ifndef LIBXML_THREAD_ENABLED
14343
    reentance--;
14344
#endif
14345
14346
2.58M
    return(res);
14347
2.60M
}
14348
14349
/**
14350
 * xmlXPathCompiledEval:
14351
 * @comp:  the compiled XPath expression
14352
 * @ctx:  the XPath context
14353
 *
14354
 * Evaluate the Precompiled XPath expression in the given context.
14355
 *
14356
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14357
 *         the caller has to free the object.
14358
 */
14359
xmlXPathObjectPtr
14360
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14361
2.57M
{
14362
2.57M
    xmlXPathObjectPtr res = NULL;
14363
14364
2.57M
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14365
2.57M
    return(res);
14366
2.57M
}
14367
14368
/**
14369
 * xmlXPathCompiledEvalToBoolean:
14370
 * @comp:  the compiled XPath expression
14371
 * @ctxt:  the XPath context
14372
 *
14373
 * Applies the XPath boolean() function on the result of the given
14374
 * compiled expression.
14375
 *
14376
 * Returns 1 if the expression evaluated to true, 0 if to false and
14377
 *         -1 in API and internal errors.
14378
 */
14379
int
14380
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14381
            xmlXPathContextPtr ctxt)
14382
28.0k
{
14383
28.0k
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14384
28.0k
}
14385
14386
/**
14387
 * xmlXPathEvalExpr:
14388
 * @ctxt:  the XPath Parser context
14389
 *
14390
 * Parse and evaluate an XPath expression in the given context,
14391
 * then push the result on the context stack
14392
 */
14393
void
14394
182k
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14395
182k
#ifdef XPATH_STREAMING
14396
182k
    xmlXPathCompExprPtr comp;
14397
182k
#endif
14398
182k
    int oldDepth = 0;
14399
14400
182k
    if (ctxt == NULL) return;
14401
14402
182k
#ifdef XPATH_STREAMING
14403
182k
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14404
182k
    if (comp != NULL) {
14405
28.1k
        if (ctxt->comp != NULL)
14406
28.1k
      xmlXPathFreeCompExpr(ctxt->comp);
14407
28.1k
        ctxt->comp = comp;
14408
28.1k
    } else
14409
153k
#endif
14410
153k
    {
14411
153k
        if (ctxt->context != NULL)
14412
153k
            oldDepth = ctxt->context->depth;
14413
153k
  xmlXPathCompileExpr(ctxt, 1);
14414
153k
        if (ctxt->context != NULL)
14415
153k
            ctxt->context->depth = oldDepth;
14416
153k
        CHECK_ERROR;
14417
14418
        /* Check for trailing characters. */
14419
86.6k
        if (*ctxt->cur != 0)
14420
54.8k
            XP_ERROR(XPATH_EXPR_ERROR);
14421
14422
54.8k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14423
48.6k
            if (ctxt->context != NULL)
14424
48.6k
                oldDepth = ctxt->context->depth;
14425
48.6k
      xmlXPathOptimizeExpression(ctxt,
14426
48.6k
    &ctxt->comp->steps[ctxt->comp->last]);
14427
48.6k
            if (ctxt->context != NULL)
14428
48.6k
                ctxt->context->depth = oldDepth;
14429
48.6k
        }
14430
54.8k
    }
14431
14432
83.0k
    xmlXPathRunEval(ctxt, 0);
14433
83.0k
}
14434
14435
/**
14436
 * xmlXPathEval:
14437
 * @str:  the XPath expression
14438
 * @ctx:  the XPath context
14439
 *
14440
 * Evaluate the XPath Location Path in the given context.
14441
 *
14442
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14443
 *         the caller has to free the object.
14444
 */
14445
xmlXPathObjectPtr
14446
186k
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14447
186k
    xmlXPathParserContextPtr ctxt;
14448
186k
    xmlXPathObjectPtr res;
14449
14450
186k
    CHECK_CTXT(ctx)
14451
14452
186k
    xmlInitParser();
14453
14454
186k
    ctxt = xmlXPathNewParserContext(str, ctx);
14455
186k
    if (ctxt == NULL)
14456
4.82k
        return NULL;
14457
182k
    xmlXPathEvalExpr(ctxt);
14458
14459
182k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14460
116k
  res = NULL;
14461
116k
    } else {
14462
65.5k
  res = valuePop(ctxt);
14463
65.5k
        if (res == NULL) {
14464
1
            xmlGenericError(xmlGenericErrorContext,
14465
1
                "xmlXPathCompiledEval: No result on the stack.\n");
14466
65.5k
        } else if (ctxt->valueNr > 0) {
14467
0
            xmlGenericError(xmlGenericErrorContext,
14468
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14469
0
                ctxt->valueNr);
14470
0
        }
14471
65.5k
    }
14472
14473
182k
    xmlXPathFreeParserContext(ctxt);
14474
182k
    return(res);
14475
186k
}
14476
14477
/**
14478
 * xmlXPathSetContextNode:
14479
 * @node: the node to to use as the context node
14480
 * @ctx:  the XPath context
14481
 *
14482
 * Sets 'node' as the context node. The node must be in the same
14483
 * document as that associated with the context.
14484
 *
14485
 * Returns -1 in case of error or 0 if successful
14486
 */
14487
int
14488
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14489
0
    if ((node == NULL) || (ctx == NULL))
14490
0
        return(-1);
14491
14492
0
    if (node->doc == ctx->doc) {
14493
0
        ctx->node = node;
14494
0
  return(0);
14495
0
    }
14496
0
    return(-1);
14497
0
}
14498
14499
/**
14500
 * xmlXPathNodeEval:
14501
 * @node: the node to to use as the context node
14502
 * @str:  the XPath expression
14503
 * @ctx:  the XPath context
14504
 *
14505
 * Evaluate the XPath Location Path in the given context. The node 'node'
14506
 * is set as the context node. The context node is not restored.
14507
 *
14508
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14509
 *         the caller has to free the object.
14510
 */
14511
xmlXPathObjectPtr
14512
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14513
0
    if (str == NULL)
14514
0
        return(NULL);
14515
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14516
0
        return(NULL);
14517
0
    return(xmlXPathEval(str, ctx));
14518
0
}
14519
14520
/**
14521
 * xmlXPathEvalExpression:
14522
 * @str:  the XPath expression
14523
 * @ctxt:  the XPath context
14524
 *
14525
 * Alias for xmlXPathEval().
14526
 *
14527
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14528
 *         the caller has to free the object.
14529
 */
14530
xmlXPathObjectPtr
14531
17.0k
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14532
17.0k
    return(xmlXPathEval(str, ctxt));
14533
17.0k
}
14534
14535
/************************************************************************
14536
 *                  *
14537
 *  Extra functions not pertaining to the XPath spec    *
14538
 *                  *
14539
 ************************************************************************/
14540
/**
14541
 * xmlXPathEscapeUriFunction:
14542
 * @ctxt:  the XPath Parser context
14543
 * @nargs:  the number of arguments
14544
 *
14545
 * Implement the escape-uri() XPath function
14546
 *    string escape-uri(string $str, bool $escape-reserved)
14547
 *
14548
 * This function applies the URI escaping rules defined in section 2 of [RFC
14549
 * 2396] to the string supplied as $uri-part, which typically represents all
14550
 * or part of a URI. The effect of the function is to replace any special
14551
 * character in the string by an escape sequence of the form %xx%yy...,
14552
 * where xxyy... is the hexadecimal representation of the octets used to
14553
 * represent the character in UTF-8.
14554
 *
14555
 * The set of characters that are escaped depends on the setting of the
14556
 * boolean argument $escape-reserved.
14557
 *
14558
 * If $escape-reserved is true, all characters are escaped other than lower
14559
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14560
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14561
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14562
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14563
 * A-F).
14564
 *
14565
 * If $escape-reserved is false, the behavior differs in that characters
14566
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14567
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14568
 *
14569
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14570
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14571
 * compared using string comparison functions, this function must always use
14572
 * the upper-case letters A-F.
14573
 *
14574
 * Generally, $escape-reserved should be set to true when escaping a string
14575
 * that is to form a single part of a URI, and to false when escaping an
14576
 * entire URI or URI reference.
14577
 *
14578
 * In the case of non-ascii characters, the string is encoded according to
14579
 * utf-8 and then converted according to RFC 2396.
14580
 *
14581
 * Examples
14582
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14583
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14584
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14585
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14586
 *
14587
 */
14588
static void
14589
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14590
0
    xmlXPathObjectPtr str;
14591
0
    int escape_reserved;
14592
0
    xmlBufPtr target;
14593
0
    xmlChar *cptr;
14594
0
    xmlChar escape[4];
14595
14596
0
    CHECK_ARITY(2);
14597
14598
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14599
14600
0
    CAST_TO_STRING;
14601
0
    str = valuePop(ctxt);
14602
14603
0
    target = xmlBufCreate();
14604
14605
0
    escape[0] = '%';
14606
0
    escape[3] = 0;
14607
14608
0
    if (target) {
14609
0
  for (cptr = str->stringval; *cptr; cptr++) {
14610
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14611
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14612
0
    (*cptr >= '0' && *cptr <= '9') ||
14613
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14614
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14615
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14616
0
    (*cptr == '%' &&
14617
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14618
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14619
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14620
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14621
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14622
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14623
0
    (!escape_reserved &&
14624
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14625
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14626
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14627
0
      *cptr == ','))) {
14628
0
    xmlBufAdd(target, cptr, 1);
14629
0
      } else {
14630
0
    if ((*cptr >> 4) < 10)
14631
0
        escape[1] = '0' + (*cptr >> 4);
14632
0
    else
14633
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14634
0
    if ((*cptr & 0xF) < 10)
14635
0
        escape[2] = '0' + (*cptr & 0xF);
14636
0
    else
14637
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14638
14639
0
    xmlBufAdd(target, &escape[0], 3);
14640
0
      }
14641
0
  }
14642
0
    }
14643
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14644
0
  xmlBufContent(target)));
14645
0
    xmlBufFree(target);
14646
0
    xmlXPathReleaseObject(ctxt->context, str);
14647
0
}
14648
14649
/**
14650
 * xmlXPathRegisterAllFunctions:
14651
 * @ctxt:  the XPath context
14652
 *
14653
 * Registers all default XPath functions in this context
14654
 */
14655
void
14656
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14657
33.2k
{
14658
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14659
33.2k
                         xmlXPathBooleanFunction);
14660
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14661
33.2k
                         xmlXPathCeilingFunction);
14662
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14663
33.2k
                         xmlXPathCountFunction);
14664
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14665
33.2k
                         xmlXPathConcatFunction);
14666
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14667
33.2k
                         xmlXPathContainsFunction);
14668
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14669
33.2k
                         xmlXPathIdFunction);
14670
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14671
33.2k
                         xmlXPathFalseFunction);
14672
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14673
33.2k
                         xmlXPathFloorFunction);
14674
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14675
33.2k
                         xmlXPathLastFunction);
14676
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14677
33.2k
                         xmlXPathLangFunction);
14678
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14679
33.2k
                         xmlXPathLocalNameFunction);
14680
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14681
33.2k
                         xmlXPathNotFunction);
14682
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14683
33.2k
                         xmlXPathNameFunction);
14684
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14685
33.2k
                         xmlXPathNamespaceURIFunction);
14686
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14687
33.2k
                         xmlXPathNormalizeFunction);
14688
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14689
33.2k
                         xmlXPathNumberFunction);
14690
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14691
33.2k
                         xmlXPathPositionFunction);
14692
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14693
33.2k
                         xmlXPathRoundFunction);
14694
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14695
33.2k
                         xmlXPathStringFunction);
14696
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14697
33.2k
                         xmlXPathStringLengthFunction);
14698
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14699
33.2k
                         xmlXPathStartsWithFunction);
14700
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14701
33.2k
                         xmlXPathSubstringFunction);
14702
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14703
33.2k
                         xmlXPathSubstringBeforeFunction);
14704
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14705
33.2k
                         xmlXPathSubstringAfterFunction);
14706
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14707
33.2k
                         xmlXPathSumFunction);
14708
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14709
33.2k
                         xmlXPathTrueFunction);
14710
33.2k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14711
33.2k
                         xmlXPathTranslateFunction);
14712
14713
33.2k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14714
33.2k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14715
33.2k
                         xmlXPathEscapeUriFunction);
14716
33.2k
}
14717
14718
#endif /* LIBXML_XPATH_ENABLED */