Coverage Report

Created: 2023-03-26 06:13

/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
1
    xmlGenericError(xmlGenericErrorContext,       \
62
1
      "Unimplemented block at %s:%d\n",       \
63
1
            __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
464k
#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
220k
#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
25.3M
#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
4.93M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
165
4.93M
    int depth1, depth2;
166
4.93M
    int misc = 0, precedence1 = 0, precedence2 = 0;
167
4.93M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
168
4.93M
    xmlNodePtr cur, root;
169
4.93M
    ptrdiff_t l1, l2;
170
171
4.93M
    if ((node1 == NULL) || (node2 == NULL))
172
0
  return(-2);
173
174
4.93M
    if (node1 == node2)
175
0
  return(0);
176
177
    /*
178
     * a couple of optimizations which will avoid computations in most cases
179
     */
180
4.93M
    switch (node1->type) {
181
2.55M
  case XML_ELEMENT_NODE:
182
2.55M
      if (node2->type == XML_ELEMENT_NODE) {
183
1.58M
    if ((0 > (ptrdiff_t) node1->content) &&
184
1.58M
        (0 > (ptrdiff_t) node2->content) &&
185
1.58M
        (node1->doc == node2->doc))
186
1.13M
    {
187
1.13M
        l1 = -((ptrdiff_t) node1->content);
188
1.13M
        l2 = -((ptrdiff_t) node2->content);
189
1.13M
        if (l1 < l2)
190
793k
      return(1);
191
337k
        if (l1 > l2)
192
337k
      return(-1);
193
337k
    } else
194
456k
        goto turtle_comparison;
195
1.58M
      }
196
965k
      break;
197
965k
  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.78M
  case XML_TEXT_NODE:
204
1.78M
  case XML_CDATA_SECTION_NODE:
205
1.91M
  case XML_COMMENT_NODE:
206
1.93M
  case XML_PI_NODE: {
207
1.93M
      miscNode1 = node1;
208
      /*
209
      * Find nearest element node.
210
      */
211
1.93M
      if (node1->prev != NULL) {
212
1.62M
    do {
213
1.62M
        node1 = node1->prev;
214
1.62M
        if (node1->type == XML_ELEMENT_NODE) {
215
964k
      precedence1 = 3; /* element in prev-sibl axis */
216
964k
      break;
217
964k
        }
218
655k
        if (node1->prev == NULL) {
219
32.5k
      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
32.5k
      node1 = node1->parent;
225
32.5k
      break;
226
32.5k
        }
227
655k
    } while (1);
228
997k
      } else {
229
936k
    precedence1 = 2; /* element is parent */
230
936k
    node1 = node1->parent;
231
936k
      }
232
1.93M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
233
1.93M
    (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.42M
    misc = 1;
241
1.93M
  }
242
0
      break;
243
198k
  case XML_NAMESPACE_DECL:
244
      /*
245
      * TODO: why do we return 1 for namespace nodes?
246
      */
247
198k
      return(1);
248
52.3k
  default:
249
52.3k
      break;
250
4.93M
    }
251
3.14M
    switch (node2->type) {
252
941k
  case XML_ELEMENT_NODE:
253
941k
      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.88M
  case XML_TEXT_NODE:
261
1.88M
  case XML_CDATA_SECTION_NODE:
262
1.99M
  case XML_COMMENT_NODE:
263
2.04M
  case XML_PI_NODE: {
264
2.04M
      miscNode2 = node2;
265
2.04M
      if (node2->prev != NULL) {
266
1.72M
    do {
267
1.72M
        node2 = node2->prev;
268
1.72M
        if (node2->type == XML_ELEMENT_NODE) {
269
1.06M
      precedence2 = 3; /* element in prev-sibl axis */
270
1.06M
      break;
271
1.06M
        }
272
661k
        if (node2->prev == NULL) {
273
29.4k
      precedence2 = 2; /* element is parent */
274
29.4k
      node2 = node2->parent;
275
29.4k
      break;
276
29.4k
        }
277
661k
    } while (1);
278
1.09M
      } else {
279
949k
    precedence2 = 2; /* element is parent */
280
949k
    node2 = node2->parent;
281
949k
      }
282
2.04M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
283
2.04M
    (0 <= (ptrdiff_t) node2->content))
284
571k
      {
285
571k
    node2 = miscNode2;
286
571k
    precedence2 = 0;
287
571k
      } else
288
1.47M
    misc = 1;
289
2.04M
  }
290
0
      break;
291
16.6k
  case XML_NAMESPACE_DECL:
292
16.6k
      return(1);
293
34.9k
  default:
294
34.9k
      break;
295
3.14M
    }
296
3.12M
    if (misc) {
297
2.37M
  if (node1 == node2) {
298
590k
      if (precedence1 == precedence2) {
299
    /*
300
    * The ugly case; but normally there aren't many
301
    * adjacent non-element nodes around.
302
    */
303
67.2k
    cur = miscNode2->prev;
304
76.0k
    while (cur != NULL) {
305
71.2k
        if (cur == miscNode1)
306
56.0k
      return(1);
307
15.1k
        if (cur->type == XML_ELEMENT_NODE)
308
6.34k
      return(-1);
309
8.79k
        cur = cur->prev;
310
8.79k
    }
311
4.83k
    return (-1);
312
523k
      } 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
523k
    if (precedence1 < precedence2)
319
388k
        return(1);
320
135k
    else
321
135k
        return(-1);
322
523k
      }
323
590k
  }
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.78M
  if ((precedence2 == 3) && (precedence1 > 1)) {
334
315k
      cur = node1->parent;
335
1.15M
      while (cur) {
336
930k
    if (cur == node2)
337
94.2k
        return(1);
338
836k
    cur = cur->parent;
339
836k
      }
340
315k
  }
341
1.68M
  if ((precedence1 == 3) && (precedence2 > 1)) {
342
263k
      cur = node2->parent;
343
1.15M
      while (cur) {
344
934k
    if (cur == node1)
345
44.7k
        return(-1);
346
890k
    cur = cur->parent;
347
890k
      }
348
263k
  }
349
1.68M
    }
350
351
    /*
352
     * Speedup using document order if available.
353
     */
354
2.40M
    if ((node1->type == XML_ELEMENT_NODE) &&
355
2.40M
  (node2->type == XML_ELEMENT_NODE) &&
356
2.40M
  (0 > (ptrdiff_t) node1->content) &&
357
2.40M
  (0 > (ptrdiff_t) node2->content) &&
358
2.40M
  (node1->doc == node2->doc)) {
359
360
1.57M
  l1 = -((ptrdiff_t) node1->content);
361
1.57M
  l2 = -((ptrdiff_t) node2->content);
362
1.57M
  if (l1 < l2)
363
881k
      return(1);
364
694k
  if (l1 > l2)
365
694k
      return(-1);
366
694k
    }
367
368
1.27M
turtle_comparison:
369
370
1.27M
    if (node1 == node2->prev)
371
293k
  return(1);
372
986k
    if (node1 == node2->next)
373
25.9k
  return(-1);
374
    /*
375
     * compute depth to root
376
     */
377
3.11M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
378
2.27M
  if (cur->parent == node1)
379
123k
      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.52M
#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
4.93M
    {
464
4.93M
        int res = xmlXPathCmpNodesExt(x, y);
465
4.93M
        return res == -2 ? res : -res;
466
4.93M
    }
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
4.93M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
475
#include "timsort.h"
476
#endif /* WITH_TIM_SORT */
477
478
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
479
480
/************************************************************************
481
 *                  *
482
 *      Floating point stuff        *
483
 *                  *
484
 ************************************************************************/
485
486
double xmlXPathNAN = 0.0;
487
double xmlXPathPINF = 0.0;
488
double xmlXPathNINF = 0.0;
489
490
/**
491
 * xmlXPathInit:
492
 *
493
 * DEPRECATED: Alias for xmlInitParser.
494
 */
495
void
496
0
xmlXPathInit(void) {
497
0
    xmlInitParser();
498
0
}
499
500
/**
501
 * xmlInitXPathInternal:
502
 *
503
 * Initialize the XPath environment
504
 */
505
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
506
void
507
2
xmlInitXPathInternal(void) {
508
2
#if defined(NAN) && defined(INFINITY)
509
2
    xmlXPathNAN = NAN;
510
2
    xmlXPathPINF = INFINITY;
511
2
    xmlXPathNINF = -INFINITY;
512
#else
513
    /* MSVC doesn't allow division by zero in constant expressions. */
514
    double zero = 0.0;
515
    xmlXPathNAN = 0.0 / zero;
516
    xmlXPathPINF = 1.0 / zero;
517
    xmlXPathNINF = -xmlXPathPINF;
518
#endif
519
2
}
520
521
/**
522
 * xmlXPathIsNaN:
523
 * @val:  a double value
524
 *
525
 * Returns 1 if the value is a NaN, 0 otherwise
526
 */
527
int
528
1.25M
xmlXPathIsNaN(double val) {
529
1.25M
#ifdef isnan
530
1.25M
    return isnan(val);
531
#else
532
    return !(val == val);
533
#endif
534
1.25M
}
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
886k
xmlXPathIsInf(double val) {
544
886k
#ifdef isinf
545
886k
    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
886k
}
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.7k
    { 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
481k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
635
481k
       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
103k
{
646
103k
    if (ctxt != NULL) {
647
25.7k
        xmlResetError(&ctxt->lastError);
648
25.7k
        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.14k
            ctxt->lastError.message = (char *)
657
1.14k
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
658
1.14k
        }
659
25.7k
        ctxt->lastError.domain = XML_FROM_XPATH;
660
25.7k
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
661
25.7k
  if (ctxt->error != NULL)
662
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
663
78.1k
    } else {
664
78.1k
        if (extra)
665
78.1k
            __xmlRaiseError(NULL, NULL, NULL,
666
78.1k
                            NULL, NULL, XML_FROM_XPATH,
667
78.1k
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668
78.1k
                            extra, NULL, NULL, 0, 0,
669
78.1k
                            "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.1k
    }
677
103k
}
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
736
{
689
736
    if (ctxt == NULL)
690
0
  xmlXPathErrMemory(NULL, extra);
691
736
    else {
692
736
  ctxt->error = XPATH_MEMORY_ERROR;
693
736
  xmlXPathErrMemory(ctxt->context, extra);
694
736
    }
695
736
}
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
481k
{
707
481k
    if ((error < 0) || (error > MAXERRNO))
708
0
  error = MAXERRNO;
709
481k
    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
481k
    if (ctxt->error != 0)
720
39.8k
        return;
721
441k
    ctxt->error = error;
722
441k
    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
441k
    xmlResetError(&ctxt->context->lastError);
735
736
441k
    ctxt->context->lastError.domain = XML_FROM_XPATH;
737
441k
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
738
441k
                           XPATH_EXPRESSION_OK;
739
441k
    ctxt->context->lastError.level = XML_ERR_ERROR;
740
441k
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
741
441k
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
742
441k
    ctxt->context->lastError.node = ctxt->context->debugNode;
743
441k
    if (ctxt->context->error != NULL) {
744
0
  ctxt->context->error(ctxt->context->userData,
745
0
                       &ctxt->context->lastError);
746
441k
    } else {
747
441k
  __xmlRaiseError(NULL, NULL, NULL,
748
441k
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
749
441k
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
750
441k
      XML_ERR_ERROR, NULL, 0,
751
441k
      (const char *) ctxt->base, NULL, NULL,
752
441k
      ctxt->cur - ctxt->base, 0,
753
441k
      "%s", xmlXPathErrorMessages[error]);
754
441k
    }
755
756
441k
}
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.2k
              int line ATTRIBUTE_UNUSED, int no) {
770
81.2k
    xmlXPathErr(ctxt, no);
771
81.2k
}
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
26.2M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
783
26.2M
    xmlXPathContextPtr xpctxt = ctxt->context;
784
785
26.2M
    if ((opCount > xpctxt->opLimit) ||
786
26.2M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
787
11.0k
        xpctxt->opCount = xpctxt->opLimit;
788
11.0k
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
789
11.0k
        return(-1);
790
11.0k
    }
791
792
26.2M
    xpctxt->opCount += opCount;
793
26.2M
    return(0);
794
26.2M
}
795
796
#define OP_LIMIT_EXCEEDED(ctxt, n) \
797
25.8M
    ((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
7.16M
{
826
7.16M
    if (list->size <= list->number) {
827
50.1k
        void **tmp;
828
50.1k
        size_t newSize;
829
830
50.1k
        if (list->size == 0) {
831
22.7k
            if (initialSize <= 0)
832
252
                initialSize = 1;
833
22.7k
            newSize = initialSize;
834
27.3k
        } else {
835
27.3k
            if (list->size > 50000000) {
836
0
                xmlXPathErrMemory(NULL,
837
0
                    "xmlPointerListAddSize: re-allocating item\n");
838
0
                return(-1);
839
0
            }
840
27.3k
      newSize = list->size * 2;
841
27.3k
        }
842
50.1k
  tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
843
50.1k
  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
35.4k
        list->items = tmp;
849
35.4k
        list->size = newSize;
850
35.4k
    }
851
7.14M
    list->items[list->number++] = item;
852
7.14M
    return(0);
853
7.16M
}
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.3k
{
865
26.3k
    xmlPointerListPtr ret;
866
867
26.3k
    ret = xmlMalloc(sizeof(xmlPointerList));
868
26.3k
    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.5k
    memset(ret, 0, sizeof(xmlPointerList));
874
22.5k
    if (initialSize > 0) {
875
22.5k
  xmlPointerListAddSize(ret, NULL, initialSize);
876
22.5k
  ret->number = 0;
877
22.5k
    }
878
22.5k
    return (ret);
879
26.3k
}
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.5k
{
890
22.5k
    if (list == NULL)
891
0
  return;
892
22.5k
    if (list->items != NULL)
893
22.5k
  xmlFree(list->items);
894
22.5k
    xmlFree(list);
895
22.5k
}
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
929k
xmlXPathNewCompExpr(void) {
1028
929k
    xmlXPathCompExprPtr cur;
1029
1030
929k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1031
929k
    if (cur == NULL) {
1032
78
        xmlXPathErrMemory(NULL, "allocating component\n");
1033
78
  return(NULL);
1034
78
    }
1035
929k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1036
929k
    cur->maxStep = 10;
1037
929k
    cur->nbStep = 0;
1038
929k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1039
929k
                                     sizeof(xmlXPathStepOp));
1040
929k
    if (cur->steps == NULL) {
1041
90
        xmlXPathErrMemory(NULL, "allocating steps\n");
1042
90
  xmlFree(cur);
1043
90
  return(NULL);
1044
90
    }
1045
929k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1046
929k
    cur->last = -1;
1047
#ifdef DEBUG_EVAL_COUNTS
1048
    cur->nb = 0;
1049
#endif
1050
929k
    return(cur);
1051
929k
}
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
929k
{
1062
929k
    xmlXPathStepOpPtr op;
1063
929k
    int i;
1064
1065
929k
    if (comp == NULL)
1066
308
        return;
1067
929k
    if (comp->dict == NULL) {
1068
11.3M
  for (i = 0; i < comp->nbStep; i++) {
1069
10.7M
      op = &comp->steps[i];
1070
10.7M
      if (op->value4 != NULL) {
1071
1.13M
    if (op->op == XPATH_OP_VALUE)
1072
348k
        xmlXPathFreeObject(op->value4);
1073
785k
    else
1074
785k
        xmlFree(op->value4);
1075
1.13M
      }
1076
10.7M
      if (op->value5 != NULL)
1077
1.75M
    xmlFree(op->value5);
1078
10.7M
  }
1079
675k
    } 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
929k
    if (comp->steps != NULL) {
1090
929k
        xmlFree(comp->steps);
1091
929k
    }
1092
#ifdef DEBUG_EVAL_COUNTS
1093
    if (comp->string != NULL) {
1094
        xmlFree(comp->string);
1095
    }
1096
#endif
1097
929k
#ifdef XPATH_STREAMING
1098
929k
    if (comp->stream != NULL) {
1099
185k
        xmlFreePatternList(comp->stream);
1100
185k
    }
1101
929k
#endif
1102
929k
    if (comp->expr != NULL) {
1103
286k
        xmlFree(comp->expr);
1104
286k
    }
1105
1106
929k
    xmlFree(comp);
1107
929k
}
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
23.6M
   int value2, int value3, void *value4, void *value5) {
1129
23.6M
    xmlXPathCompExprPtr comp = ctxt->comp;
1130
23.6M
    if (comp->nbStep >= comp->maxStep) {
1131
464k
  xmlXPathStepOp *real;
1132
1133
464k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1134
3
      xmlXPathPErrMemory(ctxt, "adding step\n");
1135
3
      return(-1);
1136
3
        }
1137
464k
  comp->maxStep *= 2;
1138
464k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1139
464k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1140
464k
  if (real == NULL) {
1141
584
      comp->maxStep /= 2;
1142
584
      xmlXPathPErrMemory(ctxt, "adding step\n");
1143
584
      return(-1);
1144
584
  }
1145
464k
  comp->steps = real;
1146
464k
    }
1147
23.6M
    comp->last = comp->nbStep;
1148
23.6M
    comp->steps[comp->nbStep].ch1 = ch1;
1149
23.6M
    comp->steps[comp->nbStep].ch2 = ch2;
1150
23.6M
    comp->steps[comp->nbStep].op = op;
1151
23.6M
    comp->steps[comp->nbStep].value = value;
1152
23.6M
    comp->steps[comp->nbStep].value2 = value2;
1153
23.6M
    comp->steps[comp->nbStep].value3 = value3;
1154
23.6M
    if ((comp->dict != NULL) &&
1155
23.6M
        ((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
19.3M
    } else {
1170
19.3M
  comp->steps[comp->nbStep].value4 = value4;
1171
19.3M
  comp->steps[comp->nbStep].value5 = value5;
1172
19.3M
    }
1173
23.6M
    comp->steps[comp->nbStep].cache = NULL;
1174
23.6M
    return(comp->nbStep++);
1175
23.6M
}
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.24k
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1186
6.24k
    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.24k
    tmp = op->ch1;
1199
6.24k
    op->ch1 = op->ch2;
1200
6.24k
    op->ch2 = tmp;
1201
6.24k
}
1202
1203
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1204
6.12M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1205
6.12M
                  (op), (val), (val2), (val3), (val4), (val5))
1206
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1207
1.43M
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1208
1.43M
                  (op), (val), (val2), (val3), (val4), (val5))
1209
1210
6.90M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1211
6.90M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1212
1213
1.88M
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1214
1.88M
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1215
1216
7.26M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1217
7.26M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1218
7.26M
      (val), (val2), 0 ,NULL ,NULL)
1219
1220
/************************************************************************
1221
 *                  *
1222
 *    XPath object cache structures       *
1223
 *                  *
1224
 ************************************************************************/
1225
1226
/* #define XP_DEFAULT_CACHE_ON */
1227
1228
417k
#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.1k
{
2216
33.1k
    xmlXPathContextCachePtr ret;
2217
2218
33.1k
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2219
33.1k
    if (ret == NULL) {
2220
23
        xmlXPathErrMemory(NULL, "creating object cache\n");
2221
23
  return(NULL);
2222
23
    }
2223
33.0k
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2224
33.0k
    ret->maxNodeset = 100;
2225
33.0k
    ret->maxString = 100;
2226
33.0k
    ret->maxBoolean = 100;
2227
33.0k
    ret->maxNumber = 100;
2228
33.0k
    ret->maxMisc = 100;
2229
33.0k
    return(ret);
2230
33.1k
}
2231
2232
static void
2233
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2234
22.5k
{
2235
22.5k
    int i;
2236
22.5k
    xmlXPathObjectPtr obj;
2237
2238
22.5k
    if (list == NULL)
2239
0
  return;
2240
2241
332k
    for (i = 0; i < list->number; i++) {
2242
310k
  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
310k
  if (obj->nodesetval != NULL) {
2248
256k
      if (obj->nodesetval->nodeTab != NULL)
2249
230k
    xmlFree(obj->nodesetval->nodeTab);
2250
256k
      xmlFree(obj->nodesetval);
2251
256k
  }
2252
310k
  xmlFree(obj);
2253
#ifdef XP_DEBUG_OBJ_USAGE
2254
  xmlXPathDebugObjCounterAll--;
2255
#endif
2256
310k
    }
2257
22.5k
    xmlPointerListFree(list);
2258
22.5k
}
2259
2260
static void
2261
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2262
33.0k
{
2263
33.0k
    if (cache == NULL)
2264
0
  return;
2265
33.0k
    if (cache->nodesetObjs)
2266
9.28k
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2267
33.0k
    if (cache->stringObjs)
2268
2.35k
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2269
33.0k
    if (cache->booleanObjs)
2270
2.84k
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2271
33.0k
    if (cache->numberObjs)
2272
3.26k
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2273
33.0k
    if (cache->miscObjs)
2274
4.80k
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2275
33.0k
    xmlFree(cache);
2276
33.0k
}
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.1k
{
2306
33.1k
    if (ctxt == NULL)
2307
0
  return(-1);
2308
33.1k
    if (active) {
2309
33.1k
  xmlXPathContextCachePtr cache;
2310
2311
33.1k
  if (ctxt->cache == NULL) {
2312
33.1k
      ctxt->cache = xmlXPathNewCache();
2313
33.1k
      if (ctxt->cache == NULL)
2314
23
    return(-1);
2315
33.1k
  }
2316
33.0k
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2317
33.0k
  if (options == 0) {
2318
33.0k
      if (value < 0)
2319
33.0k
    value = 100;
2320
33.0k
      cache->maxNodeset = value;
2321
33.0k
      cache->maxString = value;
2322
33.0k
      cache->maxNumber = value;
2323
33.0k
      cache->maxBoolean = value;
2324
33.0k
      cache->maxMisc = value;
2325
33.0k
  }
2326
33.0k
    } else if (ctxt->cache != NULL) {
2327
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2328
0
  ctxt->cache = NULL;
2329
0
    }
2330
33.0k
    return(0);
2331
33.1k
}
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.14M
{
2348
2.14M
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2349
2.14M
  xmlXPathContextCachePtr cache =
2350
2.14M
      (xmlXPathContextCachePtr) ctxt->cache;
2351
2352
2.14M
  if ((cache->miscObjs != NULL) &&
2353
2.14M
      (cache->miscObjs->number != 0))
2354
1.51M
  {
2355
1.51M
      xmlXPathObjectPtr ret;
2356
2357
1.51M
      ret = (xmlXPathObjectPtr)
2358
1.51M
    cache->miscObjs->items[--cache->miscObjs->number];
2359
1.51M
      ret->type = XPATH_NODESET;
2360
1.51M
      ret->nodesetval = val;
2361
#ifdef XP_DEBUG_OBJ_USAGE
2362
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2363
#endif
2364
1.51M
      return(ret);
2365
1.51M
  }
2366
2.14M
    }
2367
2368
631k
    return(xmlXPathWrapNodeSet(val));
2369
2370
2.14M
}
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
70.5k
{
2385
70.5k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2386
70.5k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2387
2388
70.5k
  if ((cache->stringObjs != NULL) &&
2389
70.5k
      (cache->stringObjs->number != 0))
2390
35.4k
  {
2391
2392
35.4k
      xmlXPathObjectPtr ret;
2393
2394
35.4k
      ret = (xmlXPathObjectPtr)
2395
35.4k
    cache->stringObjs->items[--cache->stringObjs->number];
2396
35.4k
      ret->type = XPATH_STRING;
2397
35.4k
      ret->stringval = val;
2398
#ifdef XP_DEBUG_OBJ_USAGE
2399
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2400
#endif
2401
35.4k
      return(ret);
2402
35.4k
  } else if ((cache->miscObjs != NULL) &&
2403
35.1k
      (cache->miscObjs->number != 0))
2404
30.3k
  {
2405
30.3k
      xmlXPathObjectPtr ret;
2406
      /*
2407
      * Fallback to misc-cache.
2408
      */
2409
30.3k
      ret = (xmlXPathObjectPtr)
2410
30.3k
    cache->miscObjs->items[--cache->miscObjs->number];
2411
2412
30.3k
      ret->type = XPATH_STRING;
2413
30.3k
      ret->stringval = val;
2414
#ifdef XP_DEBUG_OBJ_USAGE
2415
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2416
#endif
2417
30.3k
      return(ret);
2418
30.3k
  }
2419
70.5k
    }
2420
4.80k
    return(xmlXPathWrapString(val));
2421
70.5k
}
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.23M
{
2437
4.23M
    if ((ctxt != NULL) && (ctxt->cache)) {
2438
4.23M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2439
2440
4.23M
  if ((cache->nodesetObjs != NULL) &&
2441
4.23M
      (cache->nodesetObjs->number != 0))
2442
2.87M
  {
2443
2.87M
      xmlXPathObjectPtr ret;
2444
      /*
2445
      * Use the nodeset-cache.
2446
      */
2447
2.87M
      ret = (xmlXPathObjectPtr)
2448
2.87M
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2449
2.87M
      ret->type = XPATH_NODESET;
2450
2.87M
      ret->boolval = 0;
2451
2.87M
      if (val) {
2452
2.63M
    if ((ret->nodesetval->nodeMax == 0) ||
2453
2.63M
        (val->type == XML_NAMESPACE_DECL))
2454
510k
    {
2455
                    /* TODO: Check memory error. */
2456
510k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2457
2.12M
    } else {
2458
2.12M
        ret->nodesetval->nodeTab[0] = val;
2459
2.12M
        ret->nodesetval->nodeNr = 1;
2460
2.12M
    }
2461
2.63M
      }
2462
#ifdef XP_DEBUG_OBJ_USAGE
2463
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2464
#endif
2465
2.87M
      return(ret);
2466
2.87M
  } else if ((cache->miscObjs != NULL) &&
2467
1.36M
      (cache->miscObjs->number != 0))
2468
34.3k
  {
2469
34.3k
      xmlXPathObjectPtr ret;
2470
34.3k
            xmlNodeSetPtr set;
2471
      /*
2472
      * Fallback to misc-cache.
2473
      */
2474
2475
34.3k
      set = xmlXPathNodeSetCreate(val);
2476
34.3k
      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.2k
      ret = (xmlXPathObjectPtr)
2483
34.2k
    cache->miscObjs->items[--cache->miscObjs->number];
2484
2485
34.2k
      ret->type = XPATH_NODESET;
2486
34.2k
      ret->boolval = 0;
2487
34.2k
      ret->nodesetval = set;
2488
#ifdef XP_DEBUG_OBJ_USAGE
2489
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2490
#endif
2491
34.2k
      return(ret);
2492
34.3k
  }
2493
4.23M
    }
2494
1.33M
    return(xmlXPathNewNodeSet(val));
2495
4.23M
}
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
391k
{
2510
391k
    if ((ctxt != NULL) && (ctxt->cache)) {
2511
391k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2512
2513
391k
  if ((cache->stringObjs != NULL) &&
2514
391k
      (cache->stringObjs->number != 0))
2515
276k
  {
2516
276k
      xmlXPathObjectPtr ret;
2517
276k
            xmlChar *copy;
2518
2519
276k
            if (val == NULL)
2520
3.86k
                val = BAD_CAST "";
2521
276k
            copy = xmlStrdup(val);
2522
276k
            if (copy == NULL) {
2523
1.01k
                xmlXPathErrMemory(ctxt, NULL);
2524
1.01k
                return(NULL);
2525
1.01k
            }
2526
2527
275k
      ret = (xmlXPathObjectPtr)
2528
275k
    cache->stringObjs->items[--cache->stringObjs->number];
2529
275k
      ret->type = XPATH_STRING;
2530
275k
            ret->stringval = copy;
2531
#ifdef XP_DEBUG_OBJ_USAGE
2532
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533
#endif
2534
275k
      return(ret);
2535
276k
  } 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.2k
      ret = (xmlXPathObjectPtr)
2550
45.2k
    cache->miscObjs->items[--cache->miscObjs->number];
2551
2552
45.2k
      ret->type = XPATH_STRING;
2553
45.2k
            ret->stringval = copy;
2554
#ifdef XP_DEBUG_OBJ_USAGE
2555
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556
#endif
2557
45.2k
      return(ret);
2558
45.4k
  }
2559
391k
    }
2560
70.0k
    return(xmlXPathNewString(val));
2561
391k
}
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
868k
{
2592
868k
    if ((ctxt != NULL) && (ctxt->cache)) {
2593
868k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595
868k
  if ((cache->booleanObjs != NULL) &&
2596
868k
      (cache->booleanObjs->number != 0))
2597
756k
  {
2598
756k
      xmlXPathObjectPtr ret;
2599
2600
756k
      ret = (xmlXPathObjectPtr)
2601
756k
    cache->booleanObjs->items[--cache->booleanObjs->number];
2602
756k
      ret->type = XPATH_BOOLEAN;
2603
756k
      ret->boolval = (val != 0);
2604
#ifdef XP_DEBUG_OBJ_USAGE
2605
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606
#endif
2607
756k
      return(ret);
2608
756k
  } else if ((cache->miscObjs != NULL) &&
2609
112k
      (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
868k
    }
2624
41.2k
    return(xmlXPathNewBoolean(val));
2625
868k
}
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
1.39M
{
2640
1.39M
     if ((ctxt != NULL) && (ctxt->cache)) {
2641
1.39M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643
1.39M
  if ((cache->numberObjs != NULL) &&
2644
1.39M
      (cache->numberObjs->number != 0))
2645
1.03M
  {
2646
1.03M
      xmlXPathObjectPtr ret;
2647
2648
1.03M
      ret = (xmlXPathObjectPtr)
2649
1.03M
    cache->numberObjs->items[--cache->numberObjs->number];
2650
1.03M
      ret->type = XPATH_NUMBER;
2651
1.03M
      ret->floatval = val;
2652
#ifdef XP_DEBUG_OBJ_USAGE
2653
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654
#endif
2655
1.03M
      return(ret);
2656
1.03M
  } else if ((cache->miscObjs != NULL) &&
2657
358k
      (cache->miscObjs->number != 0))
2658
147k
  {
2659
147k
      xmlXPathObjectPtr ret;
2660
2661
147k
      ret = (xmlXPathObjectPtr)
2662
147k
    cache->miscObjs->items[--cache->miscObjs->number];
2663
2664
147k
      ret->type = XPATH_NUMBER;
2665
147k
      ret->floatval = val;
2666
#ifdef XP_DEBUG_OBJ_USAGE
2667
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668
#endif
2669
147k
      return(ret);
2670
147k
  }
2671
1.39M
    }
2672
210k
    return(xmlXPathNewFloat(val));
2673
1.39M
}
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
112k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689
112k
    xmlChar *res = NULL;
2690
2691
112k
    if (val == NULL)
2692
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694
112k
    switch (val->type) {
2695
0
    case XPATH_UNDEFINED:
2696
#ifdef DEBUG_EXPR
2697
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698
#endif
2699
0
  break;
2700
44.8k
    case XPATH_NODESET:
2701
44.9k
    case XPATH_XSLT_TREE:
2702
44.9k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2703
44.9k
  break;
2704
59.9k
    case XPATH_STRING:
2705
59.9k
  return(val);
2706
3.02k
    case XPATH_BOOLEAN:
2707
3.02k
  res = xmlXPathCastBooleanToString(val->boolval);
2708
3.02k
  break;
2709
4.44k
    case XPATH_NUMBER:
2710
4.44k
  res = xmlXPathCastNumberToString(val->floatval);
2711
4.44k
  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
112k
    }
2721
52.3k
    xmlXPathReleaseObject(ctxt, val);
2722
52.3k
    if (res == NULL)
2723
52
  return(xmlXPathCacheNewCString(ctxt, ""));
2724
52.3k
    return(xmlXPathCacheWrapString(ctxt, res));
2725
52.3k
}
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
417k
{
2740
417k
    if (val == NULL)
2741
0
  return(NULL);
2742
2743
417k
    if (XP_HAS_CACHE(ctxt)) {
2744
417k
  switch (val->type) {
2745
0
      case XPATH_NODESET:
2746
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2747
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748
160k
      case XPATH_STRING:
2749
160k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2750
0
      case XPATH_BOOLEAN:
2751
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752
257k
      case XPATH_NUMBER:
2753
257k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754
0
      default:
2755
0
    break;
2756
417k
  }
2757
417k
    }
2758
0
    return(xmlXPathObjectCopy(val));
2759
417k
}
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
218k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774
218k
    xmlXPathObjectPtr ret;
2775
2776
218k
    if (val == NULL)
2777
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2778
218k
    if (val->type == XPATH_BOOLEAN)
2779
39.3k
  return(val);
2780
179k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781
179k
    xmlXPathReleaseObject(ctxt, val);
2782
179k
    return(ret);
2783
218k
}
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
638k
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798
638k
    xmlXPathObjectPtr ret;
2799
2800
638k
    if (val == NULL)
2801
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802
638k
    if (val->type == XPATH_NUMBER)
2803
9.85k
  return(val);
2804
628k
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805
628k
    xmlXPathReleaseObject(ctxt, val);
2806
628k
    return(ret);
2807
638k
}
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
11.0M
{
2826
11.0M
    xmlXPathObjectPtr ret;
2827
2828
11.0M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2829
29.0k
        return (NULL);
2830
2831
11.0M
    ctxt->valueNr--;
2832
11.0M
    if (ctxt->valueNr > 0)
2833
4.96M
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834
6.09M
    else
2835
6.09M
        ctxt->value = NULL;
2836
11.0M
    ret = ctxt->valueTab[ctxt->valueNr];
2837
11.0M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2838
11.0M
    return (ret);
2839
11.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
11.2M
{
2855
11.2M
    if (ctxt == NULL) return(-1);
2856
11.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.0k
  ctxt->error = XPATH_MEMORY_ERROR;
2862
22.0k
        return(-1);
2863
22.0k
    }
2864
11.2M
    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
11.2M
    ctxt->valueTab[ctxt->valueNr] = value;
2884
11.2M
    ctxt->value = value;
2885
11.2M
    return (ctxt->valueNr++);
2886
11.2M
}
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
978
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2899
978
    xmlXPathObjectPtr obj;
2900
978
    int ret;
2901
2902
978
    obj = valuePop(ctxt);
2903
978
    if (obj == NULL) {
2904
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905
0
  return(0);
2906
0
    }
2907
978
    if (obj->type != XPATH_BOOLEAN)
2908
79
  ret = xmlXPathCastToBoolean(obj);
2909
899
    else
2910
899
        ret = obj->boolval;
2911
978
    xmlXPathReleaseObject(ctxt->context, obj);
2912
978
    return(ret);
2913
978
}
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.17M
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2953
1.17M
    xmlXPathObjectPtr obj;
2954
1.17M
    xmlChar * ret;
2955
2956
1.17M
    obj = valuePop(ctxt);
2957
1.17M
    if (obj == NULL) {
2958
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959
0
  return(NULL);
2960
0
    }
2961
1.17M
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2962
    /* TODO: needs refactoring somewhere else */
2963
1.17M
    if (obj->stringval == ret)
2964
2.65k
  obj->stringval = NULL;
2965
1.17M
    xmlXPathReleaseObject(ctxt->context, obj);
2966
1.17M
    return(ret);
2967
1.17M
}
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
473k
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2980
473k
    xmlXPathObjectPtr obj;
2981
473k
    xmlNodeSetPtr ret;
2982
2983
473k
    if (ctxt == NULL) return(NULL);
2984
473k
    if (ctxt->value == NULL) {
2985
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986
0
  return(NULL);
2987
0
    }
2988
473k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2989
3.09k
  xmlXPathSetTypeError(ctxt);
2990
3.09k
  return(NULL);
2991
3.09k
    }
2992
470k
    obj = valuePop(ctxt);
2993
470k
    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
470k
    obj->nodesetval = NULL;
3000
470k
    xmlXPathReleaseObject(ctxt->context, obj);
3001
470k
    return(ret);
3002
473k
}
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
215M
#define CUR (*ctxt->cur)
3057
452k
#define SKIP(val) ctxt->cur += (val)
3058
15.1M
#define NXT(val) ctxt->cur[(val)]
3059
202k
#define CUR_PTR ctxt->cur
3060
29.9M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3061
3062
#define COPY_BUF(l,b,i,v)                                              \
3063
12.9M
    if (l == 1) b[i++] = v;                                            \
3064
12.9M
    else i += xmlCopyChar(l,&b[i],v)
3065
3066
26.7M
#define NEXTL(l)  ctxt->cur += l
3067
3068
#define SKIP_BLANKS             \
3069
112M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3070
3071
#define CURRENT (*ctxt->cur)
3072
116M
#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.51k
#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
130k
      char work[30];
3120
130k
      char *ptr, *cur;
3121
130k
      int value = (int) number;
3122
3123
130k
            ptr = &buffer[0];
3124
130k
      if (value == 0) {
3125
0
    *ptr++ = '0';
3126
130k
      } else {
3127
130k
    snprintf(work, 29, "%d", value);
3128
130k
    cur = &work[0];
3129
385k
    while ((*cur) && (ptr - buffer < buffersize)) {
3130
254k
        *ptr++ = *cur++;
3131
254k
    }
3132
130k
      }
3133
130k
      if (ptr - buffer < buffersize) {
3134
130k
    *ptr = 0;
3135
130k
      } else if (buffersize > 0) {
3136
0
    ptr--;
3137
0
    *ptr = 0;
3138
0
      }
3139
130k
  } 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.35k
      else {
3175
    /* Use regular notation */
3176
2.35k
    if (absolute_value > 0.0) {
3177
2.35k
        integer_place = (int)log10(absolute_value);
3178
2.35k
        if (integer_place > 0)
3179
1.28k
            fraction_place = DBL_DIG - integer_place - 1;
3180
1.06k
        else
3181
1.06k
            fraction_place = DBL_DIG - integer_place;
3182
2.35k
    } else {
3183
0
        fraction_place = 1;
3184
0
    }
3185
2.35k
    size = snprintf(work, sizeof(work), "%0.*f",
3186
2.35k
        fraction_place, number);
3187
2.35k
      }
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.1k
      while (*(--ptr) == '0')
3199
84.8k
    ;
3200
10.3k
      if (*ptr != '.')
3201
6.71k
          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.1k
xmlXPathOrderDocElems(xmlDocPtr doc) {
3238
12.1k
    ptrdiff_t count = 0;
3239
12.1k
    xmlNodePtr cur;
3240
3241
12.1k
    if (doc == NULL)
3242
0
  return(-1);
3243
12.1k
    cur = doc->children;
3244
535k
    while (cur != NULL) {
3245
523k
  if (cur->type == XML_ELEMENT_NODE) {
3246
261k
      cur->content = (void *) (-(++count));
3247
261k
      if (cur->children != NULL) {
3248
110k
    cur = cur->children;
3249
110k
    continue;
3250
110k
      }
3251
261k
  }
3252
413k
  if (cur->next != NULL) {
3253
318k
      cur = cur->next;
3254
318k
      continue;
3255
318k
  }
3256
122k
  do {
3257
122k
      cur = cur->parent;
3258
122k
      if (cur == NULL)
3259
0
    break;
3260
122k
      if (cur == (xmlNodePtr) doc) {
3261
12.1k
    cur = NULL;
3262
12.1k
    break;
3263
12.1k
      }
3264
110k
      if (cur->next != NULL) {
3265
81.9k
    cur = cur->next;
3266
81.9k
    break;
3267
81.9k
      }
3268
110k
  } while (cur != NULL);
3269
94.1k
    }
3270
12.1k
    return(count);
3271
12.1k
}
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
12.2k
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3285
12.2k
    int depth1, depth2;
3286
12.2k
    int attr1 = 0, attr2 = 0;
3287
12.2k
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3288
12.2k
    xmlNodePtr cur, root;
3289
3290
12.2k
    if ((node1 == NULL) || (node2 == NULL))
3291
0
  return(-2);
3292
    /*
3293
     * a couple of optimizations which will avoid computations in most cases
3294
     */
3295
12.2k
    if (node1 == node2)    /* trivial case */
3296
0
  return(0);
3297
12.2k
    if (node1->type == XML_ATTRIBUTE_NODE) {
3298
0
  attr1 = 1;
3299
0
  attrNode1 = node1;
3300
0
  node1 = node1->parent;
3301
0
    }
3302
12.2k
    if (node2->type == XML_ATTRIBUTE_NODE) {
3303
0
  attr2 = 1;
3304
0
  attrNode2 = node2;
3305
0
  node2 = node2->parent;
3306
0
    }
3307
12.2k
    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
12.2k
    if ((node1->type == XML_NAMESPACE_DECL) ||
3326
12.2k
        (node2->type == XML_NAMESPACE_DECL))
3327
2.14k
  return(1);
3328
10.0k
    if (node1 == node2->prev)
3329
58
  return(1);
3330
10.0k
    if (node1 == node2->next)
3331
0
  return(-1);
3332
3333
    /*
3334
     * Speedup using document order if available.
3335
     */
3336
10.0k
    if ((node1->type == XML_ELEMENT_NODE) &&
3337
10.0k
  (node2->type == XML_ELEMENT_NODE) &&
3338
10.0k
  (0 > (ptrdiff_t) node1->content) &&
3339
10.0k
  (0 > (ptrdiff_t) node2->content) &&
3340
10.0k
  (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
57.6k
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3355
48.9k
  if (cur->parent == node1)
3356
811
      return(1);
3357
48.1k
  depth2++;
3358
48.1k
    }
3359
8.67k
    root = cur;
3360
36.1k
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3361
27.4k
  if (cur->parent == node2)
3362
0
      return(-1);
3363
27.4k
  depth1++;
3364
27.4k
    }
3365
    /*
3366
     * Distinct document (or distinct entities :-( ) case.
3367
     */
3368
8.67k
    if (root != cur) {
3369
75
  return(-2);
3370
75
    }
3371
    /*
3372
     * get the nearest common ancestor.
3373
     */
3374
8.74k
    while (depth1 > depth2) {
3375
150
  depth1--;
3376
150
  node1 = node1->parent;
3377
150
    }
3378
17.1k
    while (depth2 > depth1) {
3379
8.52k
  depth2--;
3380
8.52k
  node2 = node2->parent;
3381
8.52k
    }
3382
11.6k
    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
8.59k
    if (node1 == node2->prev)
3393
36
  return(1);
3394
8.56k
    if (node1 == node2->next)
3395
0
  return(-1);
3396
    /*
3397
     * Speedup using document order if available.
3398
     */
3399
8.56k
    if ((node1->type == XML_ELEMENT_NODE) &&
3400
8.56k
  (node2->type == XML_ELEMENT_NODE) &&
3401
8.56k
  (0 > (ptrdiff_t) node1->content) &&
3402
8.56k
  (0 > (ptrdiff_t) node2->content) &&
3403
8.56k
  (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
44.3k
    for (cur = node1->next;cur != NULL;cur = cur->next)
3415
44.3k
  if (cur == node2)
3416
7.92k
      return(1);
3417
0
    return(-1); /* assume there is no sibling list corruption */
3418
7.92k
}
3419
3420
/**
3421
 * xmlXPathNodeSetSort:
3422
 * @set:  the node set
3423
 *
3424
 * Sort the node set in document order
3425
 */
3426
void
3427
457k
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3428
#ifndef WITH_TIM_SORT
3429
    int i, j, incr, len;
3430
    xmlNodePtr tmp;
3431
#endif
3432
3433
457k
    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
457k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3465
457k
#endif /* WITH_TIM_SORT */
3466
457k
}
3467
3468
8.58M
#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
478k
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3482
478k
    xmlNsPtr cur;
3483
3484
478k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3485
0
  return(NULL);
3486
478k
    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
478k
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3493
478k
    if (cur == NULL) {
3494
638
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3495
638
  return(NULL);
3496
638
    }
3497
477k
    memset(cur, 0, sizeof(xmlNs));
3498
477k
    cur->type = XML_NAMESPACE_DECL;
3499
477k
    if (ns->href != NULL)
3500
477k
  cur->href = xmlStrdup(ns->href);
3501
477k
    if (ns->prefix != NULL)
3502
473k
  cur->prefix = xmlStrdup(ns->prefix);
3503
477k
    cur->next = (xmlNsPtr) node;
3504
477k
    return((xmlNodePtr) cur);
3505
478k
}
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
477k
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3517
477k
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3518
0
  return;
3519
3520
477k
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3521
477k
  if (ns->href != NULL)
3522
477k
      xmlFree((xmlChar *)ns->href);
3523
477k
  if (ns->prefix != NULL)
3524
473k
      xmlFree((xmlChar *)ns->prefix);
3525
477k
  xmlFree(ns);
3526
477k
    }
3527
477k
}
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.00M
xmlXPathNodeSetCreate(xmlNodePtr val) {
3539
4.00M
    xmlNodeSetPtr ret;
3540
3541
4.00M
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3542
4.00M
    if (ret == NULL) {
3543
16.8k
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3544
16.8k
  return(NULL);
3545
16.8k
    }
3546
3.98M
    memset(ret, 0 , sizeof(xmlNodeSet));
3547
3.98M
    if (val != NULL) {
3548
217k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3549
217k
               sizeof(xmlNodePtr));
3550
217k
  if (ret->nodeTab == NULL) {
3551
75
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3552
75
      xmlFree(ret);
3553
75
      return(NULL);
3554
75
  }
3555
217k
  memset(ret->nodeTab, 0 ,
3556
217k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3557
217k
        ret->nodeMax = XML_NODESET_DEFAULT;
3558
217k
  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
216k
      ret->nodeTab[ret->nodeNr++] = val;
3569
217k
    }
3570
3.98M
    return(ret);
3571
3.98M
}
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
302k
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3622
302k
    int i;
3623
302k
    xmlNodePtr nsNode;
3624
3625
302k
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3626
302k
        (ns->type != XML_NAMESPACE_DECL) ||
3627
302k
  (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
697k
    for (i = 0;i < cur->nodeNr;i++) {
3635
395k
        if ((cur->nodeTab[i] != NULL) &&
3636
395k
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3637
395k
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3638
395k
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3639
3
      return(0);
3640
395k
    }
3641
3642
    /*
3643
     * grow the nodeTab if needed
3644
     */
3645
302k
    if (cur->nodeMax == 0) {
3646
57.2k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3647
57.2k
               sizeof(xmlNodePtr));
3648
57.2k
  if (cur->nodeTab == NULL) {
3649
12
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3650
12
      return(-1);
3651
12
  }
3652
57.2k
  memset(cur->nodeTab, 0 ,
3653
57.2k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3654
57.2k
        cur->nodeMax = XML_NODESET_DEFAULT;
3655
244k
    } else if (cur->nodeNr == cur->nodeMax) {
3656
167
        xmlNodePtr *temp;
3657
3658
167
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3659
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3660
0
            return(-1);
3661
0
        }
3662
167
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3663
167
              sizeof(xmlNodePtr));
3664
167
  if (temp == NULL) {
3665
1
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3666
1
      return(-1);
3667
1
  }
3668
166
        cur->nodeMax *= 2;
3669
166
  cur->nodeTab = temp;
3670
166
    }
3671
301k
    nsNode = xmlXPathNodeSetDupNs(node, ns);
3672
301k
    if(nsNode == NULL)
3673
86
        return(-1);
3674
301k
    cur->nodeTab[cur->nodeNr++] = nsNode;
3675
301k
    return(0);
3676
301k
}
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
55.9k
    if (cur->nodeMax == 0) {
3704
3.10k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3705
3.10k
               sizeof(xmlNodePtr));
3706
3.10k
  if (cur->nodeTab == NULL) {
3707
349
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3708
349
      return(-1);
3709
349
  }
3710
2.75k
  memset(cur->nodeTab, 0 ,
3711
2.75k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3712
2.75k
        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.2k
    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.0k
  cur->nodeTab[cur->nodeNr++] = val;
3738
54.9k
    return(0);
3739
55.2k
}
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
8.19M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3753
8.19M
    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
8.18M
    if (cur->nodeMax == 0) {
3760
2.44M
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3761
2.44M
               sizeof(xmlNodePtr));
3762
2.44M
  if (cur->nodeTab == NULL) {
3763
18.3k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3764
18.3k
      return(-1);
3765
18.3k
  }
3766
2.42M
  memset(cur->nodeTab, 0 ,
3767
2.42M
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3768
2.42M
        cur->nodeMax = XML_NODESET_DEFAULT;
3769
5.74M
    } else if (cur->nodeNr == cur->nodeMax) {
3770
155k
        xmlNodePtr *temp;
3771
3772
155k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3773
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3774
0
            return(-1);
3775
0
        }
3776
155k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3777
155k
              sizeof(xmlNodePtr));
3778
155k
  if (temp == NULL) {
3779
1.24k
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3780
1.24k
      return(-1);
3781
1.24k
  }
3782
153k
  cur->nodeTab = temp;
3783
153k
        cur->nodeMax *= 2;
3784
153k
    }
3785
8.17M
    if (val->type == XML_NAMESPACE_DECL) {
3786
34.1k
  xmlNsPtr ns = (xmlNsPtr) val;
3787
34.1k
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3788
3789
34.1k
        if (nsNode == NULL)
3790
269
            return(-1);
3791
33.9k
  cur->nodeTab[cur->nodeNr++] = nsNode;
3792
33.9k
    } else
3793
8.13M
  cur->nodeTab[cur->nodeNr++] = val;
3794
8.16M
    return(0);
3795
8.17M
}
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
260k
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3811
260k
    int i, j, initNr, skip;
3812
260k
    xmlNodePtr n1, n2;
3813
3814
260k
    if (val2 == NULL) return(val1);
3815
220k
    if (val1 == NULL) {
3816
84.8k
  val1 = xmlXPathNodeSetCreate(NULL);
3817
84.8k
        if (val1 == NULL)
3818
317
            return (NULL);
3819
84.8k
    }
3820
3821
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822
219k
    initNr = val1->nodeNr;
3823
3824
2.00M
    for (i = 0;i < val2->nodeNr;i++) {
3825
1.78M
  n2 = val2->nodeTab[i];
3826
  /*
3827
   * check against duplicates
3828
   */
3829
1.78M
  skip = 0;
3830
21.0M
  for (j = 0; j < initNr; j++) {
3831
19.3M
      n1 = val1->nodeTab[j];
3832
19.3M
      if (n1 == n2) {
3833
50.8k
    skip = 1;
3834
50.8k
    break;
3835
19.2M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3836
19.2M
           (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
19.3M
  }
3846
1.78M
  if (skip)
3847
57.0k
      continue;
3848
3849
  /*
3850
   * grow the nodeTab if needed
3851
   */
3852
1.72M
  if (val1->nodeMax == 0) {
3853
105k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3854
105k
                sizeof(xmlNodePtr));
3855
105k
      if (val1->nodeTab == NULL) {
3856
209
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3857
209
    goto error;
3858
209
      }
3859
105k
      memset(val1->nodeTab, 0 ,
3860
105k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3861
105k
      val1->nodeMax = XML_NODESET_DEFAULT;
3862
1.61M
  } else if (val1->nodeNr == val1->nodeMax) {
3863
43.1k
      xmlNodePtr *temp;
3864
3865
43.1k
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3866
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3867
0
                goto error;
3868
0
            }
3869
43.1k
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3870
43.1k
               sizeof(xmlNodePtr));
3871
43.1k
      if (temp == NULL) {
3872
26
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3873
26
    goto error;
3874
26
      }
3875
43.0k
      val1->nodeTab = temp;
3876
43.0k
      val1->nodeMax *= 2;
3877
43.0k
  }
3878
1.72M
  if (n2->type == XML_NAMESPACE_DECL) {
3879
137k
      xmlNsPtr ns = (xmlNsPtr) n2;
3880
137k
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3881
3882
137k
            if (nsNode == NULL)
3883
22
                goto error;
3884
137k
      val1->nodeTab[val1->nodeNr++] = nsNode;
3885
137k
  } else
3886
1.58M
      val1->nodeTab[val1->nodeNr++] = n2;
3887
1.72M
    }
3888
3889
219k
    return(val1);
3890
3891
257
error:
3892
257
    xmlXPathFreeNodeSet(val1);
3893
257
    return(NULL);
3894
219k
}
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
132k
{
3912
132k
    {
3913
132k
  int i, j, initNbSet1;
3914
132k
  xmlNodePtr n1, n2;
3915
3916
132k
  initNbSet1 = set1->nodeNr;
3917
496k
  for (i = 0;i < set2->nodeNr;i++) {
3918
364k
      n2 = set2->nodeTab[i];
3919
      /*
3920
      * Skip duplicates.
3921
      */
3922
29.4M
      for (j = 0; j < initNbSet1; j++) {
3923
29.4M
    n1 = set1->nodeTab[j];
3924
29.4M
    if (n1 == n2) {
3925
329k
        goto skip_node;
3926
29.0M
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3927
29.0M
        (n2->type == XML_NAMESPACE_DECL))
3928
569k
    {
3929
569k
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3930
569k
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3931
7.95k
      ((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
569k
    }
3940
29.4M
      }
3941
      /*
3942
      * grow the nodeTab if needed
3943
      */
3944
34.8k
      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
34.8k
      } else if (set1->nodeNr >= set1->nodeMax) {
3955
1.29k
    xmlNodePtr *temp;
3956
3957
1.29k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3958
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3959
0
                    goto error;
3960
0
                }
3961
1.29k
    temp = (xmlNodePtr *) xmlRealloc(
3962
1.29k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3963
1.29k
    if (temp == NULL) {
3964
8
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3965
8
        goto error;
3966
8
    }
3967
1.28k
    set1->nodeTab = temp;
3968
1.28k
    set1->nodeMax *= 2;
3969
1.28k
      }
3970
34.8k
      set1->nodeTab[set1->nodeNr++] = n2;
3971
364k
skip_node:
3972
364k
            set2->nodeTab[i] = NULL;
3973
364k
  }
3974
132k
    }
3975
132k
    set2->nodeNr = 0;
3976
132k
    return(set1);
3977
3978
8
error:
3979
8
    xmlXPathFreeNodeSet(set1);
3980
8
    xmlXPathNodeSetClear(set2, 1);
3981
8
    return(NULL);
3982
132k
}
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
192k
{
3999
192k
    {
4000
192k
  int i;
4001
192k
  xmlNodePtr n2;
4002
4003
615k
  for (i = 0;i < set2->nodeNr;i++) {
4004
422k
      n2 = set2->nodeTab[i];
4005
422k
      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
422k
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
18.1k
    xmlNodePtr *temp;
4017
4018
18.1k
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    goto error;
4021
0
                }
4022
18.1k
    temp = (xmlNodePtr *) xmlRealloc(
4023
18.1k
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
18.1k
    if (temp == NULL) {
4025
45
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
45
        goto error;
4027
45
    }
4028
18.0k
    set1->nodeTab = temp;
4029
18.0k
    set1->nodeMax *= 2;
4030
18.0k
      }
4031
422k
      set1->nodeTab[set1->nodeNr++] = n2;
4032
422k
            set2->nodeTab[i] = NULL;
4033
422k
  }
4034
192k
    }
4035
192k
    set2->nodeNr = 0;
4036
192k
    return(set1);
4037
4038
45
error:
4039
45
    xmlXPathFreeNodeSet(set1);
4040
45
    xmlXPathNodeSetClear(set2, 1);
4041
45
    return(NULL);
4042
192k
}
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.74M
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4109
3.74M
    if (obj == NULL) return;
4110
3.72M
    if (obj->nodeTab != NULL) {
4111
2.57M
  int i;
4112
4113
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114
11.2M
  for (i = 0;i < obj->nodeNr;i++)
4115
8.70M
      if ((obj->nodeTab[i] != NULL) &&
4116
8.70M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4117
248k
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4118
2.57M
  xmlFree(obj->nodeTab);
4119
2.57M
    }
4120
3.72M
    xmlFree(obj);
4121
3.72M
}
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
7.80k
{
4135
7.80k
    if ((set == NULL) || (pos >= set->nodeNr))
4136
0
  return;
4137
7.80k
    else if ((hasNsNodes)) {
4138
7.28k
  int i;
4139
7.28k
  xmlNodePtr node;
4140
4141
36.8k
  for (i = pos; i < set->nodeNr; i++) {
4142
29.5k
      node = set->nodeTab[i];
4143
29.5k
      if ((node != NULL) &&
4144
29.5k
    (node->type == XML_NAMESPACE_DECL))
4145
28.8k
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4146
29.5k
  }
4147
7.28k
    }
4148
7.80k
    set->nodeNr = pos;
4149
7.80k
}
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.01k
{
4176
6.01k
    int i;
4177
6.01k
    xmlNodePtr node;
4178
4179
6.01k
    if ((set == NULL) || (set->nodeNr <= 1))
4180
0
  return;
4181
40.3k
    for (i = 0; i < set->nodeNr - 1; i++) {
4182
34.2k
        node = set->nodeTab[i];
4183
34.2k
        if ((node != NULL) &&
4184
34.2k
            (node->type == XML_NAMESPACE_DECL))
4185
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
34.2k
    }
4187
6.01k
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4188
6.01k
    set->nodeNr = 1;
4189
6.01k
}
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
1.98M
xmlXPathNewNodeSet(xmlNodePtr val) {
4271
1.98M
    xmlXPathObjectPtr ret;
4272
4273
1.98M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4274
1.98M
    if (ret == NULL) {
4275
4.24k
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4276
4.24k
  return(NULL);
4277
4.24k
    }
4278
1.97M
    memset(ret, 0 , sizeof(xmlXPathObject));
4279
1.97M
    ret->type = XPATH_NODESET;
4280
1.97M
    ret->boolval = 0;
4281
    /* TODO: Check memory error. */
4282
1.97M
    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
1.97M
    return(ret);
4288
1.98M
}
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
656k
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4364
656k
    xmlXPathObjectPtr ret;
4365
4366
656k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4367
656k
    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
649k
    memset(ret, 0 , sizeof(xmlXPathObject));
4373
649k
    ret->type = XPATH_NODESET;
4374
649k
    ret->nodesetval = val;
4375
#ifdef XP_DEBUG_OBJ_USAGE
4376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4377
#endif
4378
649k
    return(ret);
4379
656k
}
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.03M
           const xmlChar *ns_uri, xmlXPathFunction f) {
4820
1.03M
    if (ctxt == NULL)
4821
0
  return(-1);
4822
1.03M
    if (name == NULL)
4823
0
  return(-1);
4824
4825
1.03M
    if (ctxt->funcHash == NULL)
4826
56
  ctxt->funcHash = xmlHashCreate(0);
4827
1.03M
    if (ctxt->funcHash == NULL)
4828
56
  return(-1);
4829
1.03M
    if (f == NULL)
4830
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4831
1.03M
XML_IGNORE_FPTR_CAST_WARNINGS
4832
1.03M
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4833
1.03M
XML_POP_WARNINGS
4834
1.03M
}
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.1k
          void *funcCtxt) {
4848
12.1k
    if (ctxt == NULL)
4849
0
  return;
4850
12.1k
    ctxt->funcLookupFunc = f;
4851
12.1k
    ctxt->funcLookupData = funcCtxt;
4852
12.1k
}
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
479k
       const xmlChar *ns_uri) {
4895
479k
    xmlXPathFunction ret;
4896
4897
479k
    if (ctxt == NULL)
4898
0
  return(NULL);
4899
479k
    if (name == NULL)
4900
1
  return(NULL);
4901
4902
479k
    if (ctxt->funcLookupFunc != NULL) {
4903
479k
  xmlXPathFuncLookupFunc f;
4904
4905
479k
  f = ctxt->funcLookupFunc;
4906
479k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4907
479k
  if (ret != NULL)
4908
439k
      return(ret);
4909
479k
    }
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.1k
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4928
33.1k
    if (ctxt == NULL)
4929
0
  return;
4930
4931
33.1k
    xmlHashFree(ctxt->funcHash, NULL);
4932
33.1k
    ctxt->funcHash = NULL;
4933
33.1k
}
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
0
       xmlXPathObjectPtr value) {
4955
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4956
0
}
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
0
         xmlXPathObjectPtr value) {
4974
0
    if (ctxt == NULL)
4975
0
  return(-1);
4976
0
    if (name == NULL)
4977
0
  return(-1);
4978
4979
0
    if (ctxt->varHash == NULL)
4980
0
  ctxt->varHash = xmlHashCreate(0);
4981
0
    if (ctxt->varHash == NULL)
4982
0
  return(-1);
4983
0
    if (value == NULL)
4984
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4985
0
                             xmlXPathFreeObjectEntry));
4986
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4987
0
             (void *) value, xmlXPathFreeObjectEntry));
4988
0
}
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.1k
   xmlXPathVariableLookupFunc f, void *data) {
5001
12.1k
    if (ctxt == NULL)
5002
0
  return;
5003
12.1k
    ctxt->varLookupFunc = f;
5004
12.1k
    ctxt->varLookupData = data;
5005
12.1k
}
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.1k
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5074
33.1k
    if (ctxt == NULL)
5075
0
  return;
5076
5077
33.1k
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5078
33.1k
    ctxt->varHash = NULL;
5079
33.1k
}
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
0
         const xmlChar *ns_uri) {
5095
0
    xmlChar *copy;
5096
5097
0
    if (ctxt == NULL)
5098
0
  return(-1);
5099
0
    if (prefix == NULL)
5100
0
  return(-1);
5101
0
    if (prefix[0] == 0)
5102
0
  return(-1);
5103
5104
0
    if (ctxt->nsHash == NULL)
5105
0
  ctxt->nsHash = xmlHashCreate(10);
5106
0
    if (ctxt->nsHash == NULL)
5107
0
  return(-1);
5108
0
    if (ns_uri == NULL)
5109
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5110
0
                            xmlHashDefaultDeallocator));
5111
5112
0
    copy = xmlStrdup(ns_uri);
5113
0
    if (copy == NULL)
5114
0
        return(-1);
5115
0
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
5116
0
                           xmlHashDefaultDeallocator) < 0) {
5117
0
        xmlFree(copy);
5118
0
        return(-1);
5119
0
    }
5120
5121
0
    return(0);
5122
0
}
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
518k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136
518k
    if (ctxt == NULL)
5137
0
  return(NULL);
5138
518k
    if (prefix == NULL)
5139
0
  return(NULL);
5140
5141
518k
#ifdef XML_XML_NAMESPACE
5142
518k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143
5.02k
  return(XML_XML_NAMESPACE);
5144
513k
#endif
5145
5146
513k
    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
31.2k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157
513k
}
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.1k
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167
33.1k
    if (ctxt == NULL)
5168
0
  return;
5169
5170
33.1k
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5171
33.1k
    ctxt->nsHash = NULL;
5172
33.1k
}
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
498k
xmlXPathNewFloat(double val) {
5192
498k
    xmlXPathObjectPtr ret;
5193
5194
498k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195
498k
    if (ret == NULL) {
5196
4.03k
        xmlXPathErrMemory(NULL, "creating float object\n");
5197
4.03k
  return(NULL);
5198
4.03k
    }
5199
494k
    memset(ret, 0 , sizeof(xmlXPathObject));
5200
494k
    ret->type = XPATH_NUMBER;
5201
494k
    ret->floatval = val;
5202
#ifdef XP_DEBUG_OBJ_USAGE
5203
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204
#endif
5205
494k
    return(ret);
5206
498k
}
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
57.0k
xmlXPathNewBoolean(int val) {
5218
57.0k
    xmlXPathObjectPtr ret;
5219
5220
57.0k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221
57.0k
    if (ret == NULL) {
5222
1.39k
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5223
1.39k
  return(NULL);
5224
1.39k
    }
5225
55.6k
    memset(ret, 0 , sizeof(xmlXPathObject));
5226
55.6k
    ret->type = XPATH_BOOLEAN;
5227
55.6k
    ret->boolval = (val != 0);
5228
#ifdef XP_DEBUG_OBJ_USAGE
5229
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230
#endif
5231
55.6k
    return(ret);
5232
57.0k
}
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
124k
xmlXPathNewString(const xmlChar *val) {
5244
124k
    xmlXPathObjectPtr ret;
5245
5246
124k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247
124k
    if (ret == NULL) {
5248
3.67k
        xmlXPathErrMemory(NULL, "creating string object\n");
5249
3.67k
  return(NULL);
5250
3.67k
    }
5251
120k
    memset(ret, 0 , sizeof(xmlXPathObject));
5252
120k
    ret->type = XPATH_STRING;
5253
120k
    if (val == NULL)
5254
177
        val = BAD_CAST "";
5255
120k
    ret->stringval = xmlStrdup(val);
5256
120k
    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
120k
    return(ret);
5264
120k
}
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.38M
xmlXPathWrapString (xmlChar *val) {
5278
1.38M
    xmlXPathObjectPtr ret;
5279
5280
1.38M
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281
1.38M
    if (ret == NULL) {
5282
57
        xmlXPathErrMemory(NULL, "creating string object\n");
5283
57
        xmlFree(val);
5284
57
  return(NULL);
5285
57
    }
5286
1.38M
    memset(ret, 0 , sizeof(xmlXPathObject));
5287
1.38M
    ret->type = XPATH_STRING;
5288
1.38M
    ret->stringval = val;
5289
#ifdef XP_DEBUG_OBJ_USAGE
5290
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5291
#endif
5292
1.38M
    return(ret);
5293
1.38M
}
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
40.4k
xmlXPathWrapExternal (void *val) {
5331
40.4k
    xmlXPathObjectPtr ret;
5332
5333
40.4k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5334
40.4k
    if (ret == NULL) {
5335
4
        xmlXPathErrMemory(NULL, "creating user object\n");
5336
4
  return(NULL);
5337
4
    }
5338
40.4k
    memset(ret, 0 , sizeof(xmlXPathObject));
5339
40.4k
    ret->type = XPATH_USERS;
5340
40.4k
    ret->user = val;
5341
#ifdef XP_DEBUG_OBJ_USAGE
5342
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5343
#endif
5344
40.4k
    return(ret);
5345
40.4k
}
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.44M
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453
4.44M
    if (obj == NULL) return;
5454
4.44M
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5455
2.09M
  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.09M
  } else {
5466
2.09M
      if (obj->nodesetval != NULL)
5467
1.84M
    xmlXPathFreeNodeSet(obj->nodesetval);
5468
2.09M
  }
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.34M
    } else if (obj->type == XPATH_STRING) {
5475
1.59M
  if (obj->stringval != NULL)
5476
1.56M
      xmlFree(obj->stringval);
5477
1.59M
    }
5478
#ifdef XP_DEBUG_OBJ_USAGE
5479
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480
#endif
5481
4.44M
    xmlFree(obj);
5482
4.44M
}
5483
5484
static void
5485
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5486
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5487
0
}
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
7.24M
{
5499
7.24M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500
26.3k
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501
7.14M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5502
5503
8.35M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5504
5505
7.24M
    if (obj == NULL)
5506
28.1k
  return;
5507
7.21M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5508
0
   xmlXPathFreeObject(obj);
5509
7.21M
    } else {
5510
7.21M
  xmlXPathContextCachePtr cache =
5511
7.21M
      (xmlXPathContextCachePtr) ctxt->cache;
5512
5513
7.21M
  switch (obj->type) {
5514
5.00M
      case XPATH_NODESET:
5515
5.03M
      case XPATH_XSLT_TREE:
5516
5.03M
    if (obj->nodesetval != NULL) {
5517
4.32M
        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.32M
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5527
4.32M
      (XP_CACHE_WANTS(cache->nodesetObjs,
5528
4.30M
          cache->maxNodeset)))
5529
3.13M
        {
5530
3.13M
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5531
3.12M
      goto obj_cached;
5532
3.13M
        } else {
5533
1.18M
      xmlXPathFreeNodeSet(obj->nodesetval);
5534
1.18M
      obj->nodesetval = NULL;
5535
1.18M
        }
5536
4.32M
    }
5537
1.89M
    break;
5538
1.89M
      case XPATH_STRING:
5539
333k
    if (obj->stringval != NULL)
5540
333k
        xmlFree(obj->stringval);
5541
5542
333k
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5543
327k
        XP_CACHE_ADD(cache->stringObjs, obj);
5544
326k
        goto obj_cached;
5545
327k
    }
5546
6.16k
    break;
5547
767k
      case XPATH_BOOLEAN:
5548
767k
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5549
766k
        XP_CACHE_ADD(cache->booleanObjs, obj);
5550
764k
        goto obj_cached;
5551
765k
    }
5552
762
    break;
5553
1.04M
      case XPATH_NUMBER:
5554
1.04M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5555
1.04M
        XP_CACHE_ADD(cache->numberObjs, obj);
5556
1.04M
        goto obj_cached;
5557
1.04M
    }
5558
152
    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
40.4k
      default:
5567
40.4k
    goto free_obj;
5568
7.21M
  }
5569
5570
  /*
5571
  * Fallback to adding to the misc-objects slot.
5572
  */
5573
1.90M
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5574
1.86M
      XP_CACHE_ADD(cache->miscObjs, obj);
5575
1.86M
  } else
5576
35.5k
      goto free_obj;
5577
5578
7.12M
obj_cached:
5579
5580
#ifdef XP_DEBUG_OBJ_USAGE
5581
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5582
#endif
5583
5584
7.12M
  if (obj->nodesetval != NULL) {
5585
3.12M
      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.12M
      if (tmpset->nodeNr > 1) {
5594
108k
    int i;
5595
108k
    xmlNodePtr node;
5596
5597
989k
    for (i = 0; i < tmpset->nodeNr; i++) {
5598
881k
        node = tmpset->nodeTab[i];
5599
881k
        if ((node != NULL) &&
5600
881k
      (node->type == XML_NAMESPACE_DECL))
5601
115k
        {
5602
115k
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5603
115k
        }
5604
881k
    }
5605
3.01M
      } else if (tmpset->nodeNr == 1) {
5606
2.38M
    if ((tmpset->nodeTab[0] != NULL) &&
5607
2.38M
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5608
26.1k
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5609
2.38M
      }
5610
3.12M
      tmpset->nodeNr = 0;
5611
3.12M
      memset(obj, 0, sizeof(xmlXPathObject));
5612
3.12M
      obj->nodesetval = tmpset;
5613
3.12M
  } else
5614
3.99M
      memset(obj, 0, sizeof(xmlXPathObject));
5615
5616
7.12M
  return;
5617
5618
94.5k
free_obj:
5619
  /*
5620
  * Cache is full; free the object.
5621
  */
5622
94.5k
  if (obj->nodesetval != NULL)
5623
8.87k
      xmlXPathFreeNodeSet(obj->nodesetval);
5624
#ifdef XP_DEBUG_OBJ_USAGE
5625
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5626
#endif
5627
94.5k
  xmlFree(obj);
5628
94.5k
    }
5629
94.5k
    return;
5630
7.21M
}
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
157k
xmlXPathCastBooleanToString (int val) {
5649
157k
    xmlChar *ret;
5650
157k
    if (val)
5651
14.1k
  ret = xmlStrdup((const xmlChar *) "true");
5652
143k
    else
5653
143k
  ret = xmlStrdup((const xmlChar *) "false");
5654
157k
    return(ret);
5655
157k
}
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
340k
xmlXPathCastNumberToString (double val) {
5667
340k
    xmlChar *ret;
5668
340k
    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
340k
    default:
5676
340k
  if (xmlXPathIsNaN(val)) {
5677
194k
      ret = xmlStrdup((const xmlChar *) "NaN");
5678
194k
  } 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
340k
    }
5689
340k
    return(ret);
5690
340k
}
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.35M
xmlXPathCastNodeToString (xmlNodePtr node) {
5702
2.35M
xmlChar *ret;
5703
2.35M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5704
10.0k
  ret = xmlStrdup((const xmlChar *) "");
5705
2.35M
    return(ret);
5706
2.35M
}
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.85M
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5718
2.85M
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5719
761k
  return(xmlStrdup((const xmlChar *) ""));
5720
5721
2.09M
    if (ns->nodeNr > 1)
5722
68.1k
  xmlXPathNodeSetSort(ns);
5723
2.09M
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5724
2.85M
}
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.95M
xmlXPathCastToString(xmlXPathObjectPtr val) {
5737
1.95M
    xmlChar *ret = NULL;
5738
5739
1.95M
    if (val == NULL)
5740
0
  return(xmlStrdup((const xmlChar *) ""));
5741
1.95M
    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.26M
        case XPATH_NODESET:
5749
1.26M
        case XPATH_XSLT_TREE:
5750
1.26M
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5751
1.26M
      break;
5752
208k
  case XPATH_STRING:
5753
208k
      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.26M
  }
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.95M
    }
5771
1.75M
    return(ret);
5772
1.95M
}
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
506k
xmlXPathCastStringToNumber(const xmlChar * val) {
5848
506k
    return(xmlXPathStringEvalNumber(val));
5849
506k
}
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
28.2k
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861
28.2k
    xmlChar *strval;
5862
28.2k
    double ret;
5863
5864
28.2k
    if (node == NULL)
5865
0
  return(xmlXPathNAN);
5866
28.2k
    strval = xmlXPathCastNodeToString(node);
5867
28.2k
    if (strval == NULL)
5868
994
  return(xmlXPathNAN);
5869
27.2k
    ret = xmlXPathCastStringToNumber(strval);
5870
27.2k
    xmlFree(strval);
5871
5872
27.2k
    return(ret);
5873
28.2k
}
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
358k
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885
358k
    xmlChar *str;
5886
358k
    double ret;
5887
5888
358k
    if (ns == NULL)
5889
26.6k
  return(xmlXPathNAN);
5890
332k
    str = xmlXPathCastNodeSetToString(ns);
5891
332k
    ret = xmlXPathCastStringToNumber(str);
5892
332k
    xmlFree(str);
5893
332k
    return(ret);
5894
358k
}
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
917k
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906
917k
    double ret = 0.0;
5907
5908
917k
    if (val == NULL)
5909
0
  return(xmlXPathNAN);
5910
917k
    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
358k
    case XPATH_NODESET:
5918
358k
    case XPATH_XSLT_TREE:
5919
358k
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920
358k
  break;
5921
140k
    case XPATH_STRING:
5922
140k
  ret = xmlXPathCastStringToNumber(val->stringval);
5923
140k
  break;
5924
102k
    case XPATH_NUMBER:
5925
102k
  ret = val->floatval;
5926
102k
  break;
5927
315k
    case XPATH_BOOLEAN:
5928
315k
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5929
315k
  break;
5930
0
    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
0
  TODO;
5937
0
  ret = xmlXPathNAN;
5938
0
  break;
5939
917k
    }
5940
917k
    return(ret);
5941
917k
}
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
68.3k
xmlXPathCastNumberToBoolean (double val) {
5975
68.3k
     if (xmlXPathIsNaN(val) || (val == 0.0))
5976
26.1k
   return(0);
5977
42.1k
     return(1);
5978
68.3k
}
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
892
xmlXPathCastStringToBoolean (const xmlChar *val) {
5990
892
    if ((val == NULL) || (xmlStrlen(val) == 0))
5991
247
  return(0);
5992
645
    return(1);
5993
892
}
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
181k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020
181k
    int ret = 0;
6021
6022
181k
    if (val == NULL)
6023
0
  return(0);
6024
181k
    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
892
    case XPATH_STRING:
6036
892
  ret = xmlXPathCastStringToBoolean(val->stringval);
6037
892
  break;
6038
17.8k
    case XPATH_NUMBER:
6039
17.8k
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6040
17.8k
  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
181k
    }
6054
181k
    return(ret);
6055
181k
}
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.1k
xmlXPathNewContext(xmlDocPtr doc) {
6096
33.1k
    xmlXPathContextPtr ret;
6097
6098
33.1k
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6099
33.1k
    if (ret == NULL) {
6100
8
        xmlXPathErrMemory(NULL, "creating context\n");
6101
8
  return(NULL);
6102
8
    }
6103
33.1k
    memset(ret, 0 , sizeof(xmlXPathContext));
6104
33.1k
    ret->doc = doc;
6105
33.1k
    ret->node = NULL;
6106
6107
33.1k
    ret->varHash = NULL;
6108
6109
33.1k
    ret->nb_types = 0;
6110
33.1k
    ret->max_types = 0;
6111
33.1k
    ret->types = NULL;
6112
6113
33.1k
    ret->funcHash = xmlHashCreate(0);
6114
6115
33.1k
    ret->nb_axis = 0;
6116
33.1k
    ret->max_axis = 0;
6117
33.1k
    ret->axis = NULL;
6118
6119
33.1k
    ret->nsHash = NULL;
6120
33.1k
    ret->user = NULL;
6121
6122
33.1k
    ret->contextSize = -1;
6123
33.1k
    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.1k
    xmlXPathRegisterAllFunctions(ret);
6133
6134
33.1k
    return(ret);
6135
33.1k
}
6136
6137
/**
6138
 * xmlXPathFreeContext:
6139
 * @ctxt:  the context to free
6140
 *
6141
 * Free up an xmlXPathContext
6142
 */
6143
void
6144
33.1k
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6145
33.1k
    if (ctxt == NULL) return;
6146
6147
33.1k
    if (ctxt->cache != NULL)
6148
33.0k
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6149
33.1k
    xmlXPathRegisteredNsCleanup(ctxt);
6150
33.1k
    xmlXPathRegisteredFuncsCleanup(ctxt);
6151
33.1k
    xmlXPathRegisteredVariablesCleanup(ctxt);
6152
33.1k
    xmlResetError(&ctxt->lastError);
6153
33.1k
    xmlFree(ctxt);
6154
33.1k
}
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.59M
    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
721k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6204
721k
    xmlXPathParserContextPtr ret;
6205
6206
721k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6207
721k
    if (ret == NULL) {
6208
5.57k
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6209
5.57k
  return(NULL);
6210
5.57k
    }
6211
716k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6212
716k
    ret->cur = ret->base = str;
6213
716k
    ret->context = ctxt;
6214
6215
716k
    ret->comp = xmlXPathNewCompExpr();
6216
716k
    if (ret->comp == NULL) {
6217
151
  xmlFree(ret->valueTab);
6218
151
  xmlFree(ret);
6219
151
  return(NULL);
6220
151
    }
6221
716k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6222
229k
        ret->comp->dict = ctxt->dict;
6223
229k
  xmlDictReference(ret->comp->dict);
6224
229k
    }
6225
6226
716k
    return(ret);
6227
716k
}
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.59M
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6240
2.59M
    xmlXPathParserContextPtr ret;
6241
6242
2.59M
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6243
2.59M
    if (ret == NULL) {
6244
18.0k
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6245
18.0k
  return(NULL);
6246
18.0k
    }
6247
2.57M
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6248
6249
    /* Allocate the value stack */
6250
2.57M
    ret->valueTab = (xmlXPathObjectPtr *)
6251
2.57M
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6252
2.57M
    if (ret->valueTab == NULL) {
6253
221
  xmlFree(ret);
6254
221
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6255
221
  return(NULL);
6256
221
    }
6257
2.57M
    ret->valueNr = 0;
6258
2.57M
    ret->valueMax = 10;
6259
2.57M
    ret->value = NULL;
6260
6261
2.57M
    ret->context = ctxt;
6262
2.57M
    ret->comp = comp;
6263
6264
2.57M
    return(ret);
6265
2.57M
}
6266
6267
/**
6268
 * xmlXPathFreeParserContext:
6269
 * @ctxt:  the context to free
6270
 *
6271
 * Free up an xmlXPathParserContext
6272
 */
6273
void
6274
3.28M
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6275
3.28M
    int i;
6276
6277
3.28M
    if (ctxt->valueTab != NULL) {
6278
2.81M
        for (i = 0; i < ctxt->valueNr; i++) {
6279
158k
            if (ctxt->context)
6280
158k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281
0
            else
6282
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6283
158k
        }
6284
2.65M
        xmlFree(ctxt->valueTab);
6285
2.65M
    }
6286
3.28M
    if (ctxt->comp != NULL) {
6287
429k
#ifdef XPATH_STREAMING
6288
429k
  if (ctxt->comp->stream != NULL) {
6289
28.1k
      xmlFreePatternList(ctxt->comp->stream);
6290
28.1k
      ctxt->comp->stream = NULL;
6291
28.1k
  }
6292
429k
#endif
6293
429k
  xmlXPathFreeCompExpr(ctxt->comp);
6294
429k
    }
6295
3.28M
    xmlFree(ctxt);
6296
3.28M
}
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
85.3k
xmlXPathNodeValHash(xmlNodePtr node) {
6315
85.3k
    int len = 2;
6316
85.3k
    const xmlChar * string = NULL;
6317
85.3k
    xmlNodePtr tmp = NULL;
6318
85.3k
    unsigned int ret = 0;
6319
6320
85.3k
    if (node == NULL)
6321
0
  return(0);
6322
6323
85.3k
    if (node->type == XML_DOCUMENT_NODE) {
6324
33.1k
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325
33.1k
  if (tmp == NULL)
6326
26.2k
      node = node->children;
6327
6.92k
  else
6328
6.92k
      node = tmp;
6329
6330
33.1k
  if (node == NULL)
6331
721
      return(0);
6332
33.1k
    }
6333
6334
84.6k
    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
31.1k
  case XML_TEXT_NODE:
6339
31.1k
      string = node->content;
6340
31.1k
      if (string == NULL)
6341
339
    return(0);
6342
30.8k
      if (string[0] == 0)
6343
291
    return(0);
6344
30.5k
      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
19.1k
  case XML_ELEMENT_NODE:
6356
19.1k
      tmp = node->children;
6357
19.1k
      break;
6358
0
  default:
6359
0
      return(0);
6360
84.6k
    }
6361
658k
    while (tmp != NULL) {
6362
645k
  switch (tmp->type) {
6363
0
      case XML_CDATA_SECTION_NODE:
6364
49.8k
      case XML_TEXT_NODE:
6365
49.8k
    string = tmp->content;
6366
49.8k
    break;
6367
595k
      default:
6368
595k
                string = NULL;
6369
595k
    break;
6370
645k
  }
6371
645k
  if ((string != NULL) && (string[0] != 0)) {
6372
49.2k
      if (len == 1) {
6373
2.84k
    return(ret + (string[0] << 8));
6374
2.84k
      }
6375
46.4k
      if (string[1] == 0) {
6376
9.02k
    len = 1;
6377
9.02k
    ret = string[0];
6378
37.4k
      } else {
6379
37.4k
    return(string[0] + (string[1] << 8));
6380
37.4k
      }
6381
46.4k
  }
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
12.2k
    return(ret);
6414
52.5k
}
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
15.8k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6459
15.8k
    int i, ret = 0;
6460
15.8k
    xmlNodeSetPtr ns;
6461
15.8k
    xmlChar *str2;
6462
6463
15.8k
    if ((f == NULL) || (arg == NULL) ||
6464
15.8k
  ((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
15.8k
    ns = arg->nodesetval;
6470
15.8k
    if (ns != NULL) {
6471
42.8k
  for (i = 0;i < ns->nodeNr;i++) {
6472
34.0k
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6473
34.0k
       if (str2 != NULL) {
6474
33.1k
     valuePush(ctxt,
6475
33.1k
         xmlXPathCacheNewString(ctxt->context, str2));
6476
33.1k
     xmlFree(str2);
6477
33.1k
     xmlXPathNumberFunction(ctxt, 1);
6478
33.1k
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6479
33.1k
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6480
33.1k
     if (ret)
6481
510
         break;
6482
33.1k
       }
6483
34.0k
  }
6484
9.30k
    }
6485
15.8k
    xmlXPathReleaseObject(ctxt->context, arg);
6486
15.8k
    xmlXPathReleaseObject(ctxt->context, f);
6487
15.8k
    return(ret);
6488
15.8k
}
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.88k
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6603
4.01k
  xmlXPathFreeObject(arg1);
6604
4.01k
  xmlXPathFreeObject(arg2);
6605
4.01k
  return(0);
6606
4.01k
    }
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
186k
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6671
186k
    if ((val == NULL) || (arg == NULL) ||
6672
186k
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6673
0
        return(0);
6674
6675
186k
    switch(val->type) {
6676
15.8k
        case XPATH_NUMBER:
6677
15.8k
      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
186k
    }
6697
0
    return(0);
6698
186k
}
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.08k
        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.2k
    val = valuePop(ctxt);
6796
39.2k
    v = val->floatval;
6797
39.2k
    xmlXPathReleaseObject(ctxt->context, val);
6798
39.2k
    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.2k
      }
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
144k
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6837
144k
    int i, j;
6838
144k
    unsigned int *hashs1;
6839
144k
    unsigned int *hashs2;
6840
144k
    xmlChar **values1;
6841
144k
    xmlChar **values2;
6842
144k
    int ret = 0;
6843
144k
    xmlNodeSetPtr ns1;
6844
144k
    xmlNodeSetPtr ns2;
6845
6846
144k
    if ((arg1 == NULL) ||
6847
144k
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6848
0
        return(0);
6849
144k
    if ((arg2 == NULL) ||
6850
144k
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6851
0
        return(0);
6852
6853
144k
    ns1 = arg1->nodesetval;
6854
144k
    ns2 = arg2->nodesetval;
6855
6856
144k
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6857
28.0k
  return(0);
6858
116k
    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
35.1k
    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
34.2k
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6871
34.2k
    if (values1 == NULL) {
6872
        /* TODO: Propagate memory error. */
6873
91
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6874
91
  return(0);
6875
91
    }
6876
34.1k
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6877
34.1k
    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
34.1k
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6884
34.1k
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6885
34.1k
    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
34.1k
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6893
34.1k
    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
34.1k
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902
58.9k
    for (i = 0;i < ns1->nodeNr;i++) {
6903
37.3k
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6904
70.7k
  for (j = 0;j < ns2->nodeNr;j++) {
6905
45.9k
      if (i == 0)
6906
37.9k
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6907
45.9k
      if (hashs1[i] != hashs2[j]) {
6908
33.2k
    if (neq) {
6909
2.46k
        ret = 1;
6910
2.46k
        break;
6911
2.46k
    }
6912
33.2k
      }
6913
12.7k
      else {
6914
12.7k
    if (values1[i] == NULL)
6915
11.7k
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916
12.7k
    if (values2[j] == NULL)
6917
11.6k
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6918
12.7k
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6919
12.7k
    if (ret)
6920
10.1k
        break;
6921
12.7k
      }
6922
45.9k
  }
6923
37.3k
  if (ret)
6924
12.6k
      break;
6925
37.3k
    }
6926
77.2k
    for (i = 0;i < ns1->nodeNr;i++)
6927
43.0k
  if (values1[i] != NULL)
6928
11.0k
      xmlFree(values1[i]);
6929
87.1k
    for (j = 0;j < ns2->nodeNr;j++)
6930
52.9k
  if (values2[j] != NULL)
6931
11.6k
      xmlFree(values2[j]);
6932
34.1k
    xmlFree(values1);
6933
34.1k
    xmlFree(values2);
6934
34.1k
    xmlFree(hashs1);
6935
34.1k
    xmlFree(hashs2);
6936
34.1k
    return(ret);
6937
34.1k
}
6938
6939
static int
6940
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941
116k
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6942
116k
    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
116k
    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
62.4k
        case XPATH_NUMBER:
6995
36.9k
      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
31.3k
    case XPATH_NUMBER:
7014
        /* Hand check NaN and Infinity equalities */
7015
31.3k
        if (xmlXPathIsNaN(arg1->floatval) ||
7016
31.3k
          xmlXPathIsNaN(arg2->floatval)) {
7017
20.3k
            ret = 0;
7018
20.3k
        } 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
10.7k
        } 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
10.4k
        } 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
10.1k
        } 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
10.1k
        } else {
7039
10.1k
            ret = (arg1->floatval == arg2->floatval);
7040
10.1k
        }
7041
31.3k
        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
36.9k
      }
7054
36.9k
      break;
7055
36.9k
        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
116k
    }
7132
116k
    xmlXPathReleaseObject(ctxt->context, arg1);
7133
116k
    xmlXPathReleaseObject(ctxt->context, arg2);
7134
116k
    return(ret);
7135
116k
}
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
291k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7147
291k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7148
291k
    int ret = 0;
7149
7150
291k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7151
291k
    arg2 = valuePop(ctxt);
7152
291k
    arg1 = valuePop(ctxt);
7153
291k
    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
291k
    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
291k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7174
291k
      (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.5k
      case XPATH_NUMBER:
7202
20.5k
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7203
20.5k
    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
104k
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7222
291k
}
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
59.0k
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7234
59.0k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7235
59.0k
    int ret = 0;
7236
7237
59.0k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7238
59.0k
    arg2 = valuePop(ctxt);
7239
59.0k
    arg1 = valuePop(ctxt);
7240
59.0k
    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
59.0k
    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
59.0k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7261
59.0k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7262
  /*
7263
   *Hack it to assure arg1 is the nodeset
7264
   */
7265
47.2k
  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
47.2k
  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
21.6k
      case XPATH_NODESET:
7278
22.6k
      case XPATH_XSLT_TREE:
7279
22.6k
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7280
22.6k
    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
47.2k
  }
7303
47.2k
  xmlXPathReleaseObject(ctxt->context, arg1);
7304
47.2k
  xmlXPathReleaseObject(ctxt->context, arg2);
7305
47.2k
  return(ret);
7306
47.2k
    }
7307
7308
11.7k
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7309
59.0k
}
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
527k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7337
527k
    int ret = 0, arg1i = 0, arg2i = 0;
7338
527k
    xmlXPathObjectPtr arg1, arg2;
7339
7340
527k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7341
527k
    arg2 = valuePop(ctxt);
7342
527k
    arg1 = valuePop(ctxt);
7343
527k
    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
527k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7352
527k
      (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
300k
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7359
300k
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7360
113k
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7361
186k
  } else {
7362
186k
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7363
9.09k
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7364
9.09k
                                arg1, arg2);
7365
177k
      } else {
7366
177k
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7367
177k
                                arg2, arg1);
7368
177k
      }
7369
186k
  }
7370
300k
  return(ret);
7371
300k
    }
7372
7373
227k
    if (arg1->type != XPATH_NUMBER) {
7374
188k
  valuePush(ctxt, arg1);
7375
188k
  xmlXPathNumberFunction(ctxt, 1);
7376
188k
  arg1 = valuePop(ctxt);
7377
188k
    }
7378
227k
    if (arg2->type != XPATH_NUMBER) {
7379
172k
  valuePush(ctxt, arg2);
7380
172k
  xmlXPathNumberFunction(ctxt, 1);
7381
172k
  arg2 = valuePop(ctxt);
7382
172k
    }
7383
227k
    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
227k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7391
70.9k
  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
227k
error:
7435
227k
    xmlXPathReleaseObject(ctxt->context, arg1);
7436
227k
    xmlXPathReleaseObject(ctxt->context, arg2);
7437
227k
    return(ret);
7438
227k
}
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
32.5k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7450
32.5k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7451
32.5k
    CAST_TO_NUMBER;
7452
32.5k
    CHECK_TYPE(XPATH_NUMBER);
7453
31.9k
    ctxt->value->floatval = -ctxt->value->floatval;
7454
31.9k
}
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.5k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7466
54.5k
    xmlXPathObjectPtr arg;
7467
54.5k
    double val;
7468
7469
54.5k
    arg = valuePop(ctxt);
7470
54.5k
    if (arg == NULL)
7471
54.5k
  XP_ERROR(XPATH_INVALID_OPERAND);
7472
54.5k
    val = xmlXPathCastToNumber(arg);
7473
54.5k
    xmlXPathReleaseObject(ctxt->context, arg);
7474
54.5k
    CAST_TO_NUMBER;
7475
54.5k
    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.3k
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7489
75.3k
    xmlXPathObjectPtr arg;
7490
75.3k
    double val;
7491
7492
75.3k
    arg = valuePop(ctxt);
7493
75.3k
    if (arg == NULL)
7494
75.3k
  XP_ERROR(XPATH_INVALID_OPERAND);
7495
75.3k
    val = xmlXPathCastToNumber(arg);
7496
75.3k
    xmlXPathReleaseObject(ctxt->context, arg);
7497
75.3k
    CAST_TO_NUMBER;
7498
75.3k
    CHECK_TYPE(XPATH_NUMBER);
7499
74.3k
    ctxt->value->floatval -= val;
7500
74.3k
}
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
93.6k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7512
93.6k
    xmlXPathObjectPtr arg;
7513
93.6k
    double val;
7514
7515
93.6k
    arg = valuePop(ctxt);
7516
93.6k
    if (arg == NULL)
7517
93.6k
  XP_ERROR(XPATH_INVALID_OPERAND);
7518
93.6k
    val = xmlXPathCastToNumber(arg);
7519
93.6k
    xmlXPathReleaseObject(ctxt->context, arg);
7520
93.6k
    CAST_TO_NUMBER;
7521
93.6k
    CHECK_TYPE(XPATH_NUMBER);
7522
93.2k
    ctxt->value->floatval *= val;
7523
93.2k
}
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.00M
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7639
1.00M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7640
1.00M
    if (cur == NULL) {
7641
522k
  if (ctxt->context->node == NULL) return(NULL);
7642
522k
  switch (ctxt->context->node->type) {
7643
271k
            case XML_ELEMENT_NODE:
7644
466k
            case XML_TEXT_NODE:
7645
466k
            case XML_CDATA_SECTION_NODE:
7646
466k
            case XML_ENTITY_REF_NODE:
7647
466k
            case XML_ENTITY_NODE:
7648
469k
            case XML_PI_NODE:
7649
477k
            case XML_COMMENT_NODE:
7650
477k
            case XML_NOTATION_NODE:
7651
477k
            case XML_DTD_NODE:
7652
477k
    return(ctxt->context->node->children);
7653
12.0k
            case XML_DOCUMENT_NODE:
7654
12.0k
            case XML_DOCUMENT_TYPE_NODE:
7655
12.0k
            case XML_DOCUMENT_FRAG_NODE:
7656
12.0k
            case XML_HTML_DOCUMENT_NODE:
7657
12.0k
    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
522k
  }
7667
0
  return(NULL);
7668
522k
    }
7669
485k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7670
485k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7671
0
  return(NULL);
7672
485k
    return(cur->next);
7673
485k
}
7674
7675
/**
7676
 * xmlXPathNextChildElement:
7677
 * @ctxt:  the XPath Parser context
7678
 * @cur:  the current node in the traversal
7679
 *
7680
 * Traversal function for the "child" direction and nodes of type element.
7681
 * The child axis contains the children of the context node in document order.
7682
 *
7683
 * Returns the next element following that axis
7684
 */
7685
static xmlNodePtr
7686
2.30M
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687
2.30M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688
2.30M
    if (cur == NULL) {
7689
1.13M
  cur = ctxt->context->node;
7690
1.13M
  if (cur == NULL) return(NULL);
7691
  /*
7692
  * Get the first element child.
7693
  */
7694
1.13M
  switch (cur->type) {
7695
826k
            case XML_ELEMENT_NODE:
7696
826k
      case XML_DOCUMENT_FRAG_NODE:
7697
826k
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698
826k
            case XML_ENTITY_NODE:
7699
826k
    cur = cur->children;
7700
826k
    if (cur != NULL) {
7701
490k
        if (cur->type == XML_ELEMENT_NODE)
7702
73.4k
      return(cur);
7703
483k
        do {
7704
483k
      cur = cur->next;
7705
483k
        } while ((cur != NULL) &&
7706
483k
      (cur->type != XML_ELEMENT_NODE));
7707
417k
        return(cur);
7708
490k
    }
7709
335k
    return(NULL);
7710
164k
            case XML_DOCUMENT_NODE:
7711
164k
            case XML_HTML_DOCUMENT_NODE:
7712
164k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7713
146k
      default:
7714
146k
    return(NULL);
7715
1.13M
  }
7716
0
  return(NULL);
7717
1.13M
    }
7718
    /*
7719
    * Get the next sibling element node.
7720
    */
7721
1.16M
    switch (cur->type) {
7722
1.16M
  case XML_ELEMENT_NODE:
7723
1.16M
  case XML_TEXT_NODE:
7724
1.16M
  case XML_ENTITY_REF_NODE:
7725
1.16M
  case XML_ENTITY_NODE:
7726
1.16M
  case XML_CDATA_SECTION_NODE:
7727
1.16M
  case XML_PI_NODE:
7728
1.16M
  case XML_COMMENT_NODE:
7729
1.16M
  case XML_XINCLUDE_END:
7730
1.16M
      break;
7731
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7732
0
  default:
7733
0
      return(NULL);
7734
1.16M
    }
7735
1.16M
    if (cur->next != NULL) {
7736
952k
  if (cur->next->type == XML_ELEMENT_NODE)
7737
422k
      return(cur->next);
7738
530k
  cur = cur->next;
7739
761k
  do {
7740
761k
      cur = cur->next;
7741
761k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7742
530k
  return(cur);
7743
952k
    }
7744
213k
    return(NULL);
7745
1.16M
}
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
5.92M
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7832
5.92M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7833
5.92M
    if (cur == NULL) {
7834
166k
  if (ctxt->context->node == NULL)
7835
0
      return(NULL);
7836
166k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7837
166k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7838
601
      return(NULL);
7839
7840
165k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7841
120k
      return(ctxt->context->doc->children);
7842
45.1k
        return(ctxt->context->node->children);
7843
165k
    }
7844
7845
5.75M
    if (cur->type == XML_NAMESPACE_DECL)
7846
0
        return(NULL);
7847
5.75M
    if (cur->children != NULL) {
7848
  /*
7849
   * Do not descend on entities declarations
7850
   */
7851
1.33M
  if (cur->children->type != XML_ENTITY_DECL) {
7852
1.33M
      cur = cur->children;
7853
      /*
7854
       * Skip DTDs
7855
       */
7856
1.33M
      if (cur->type != XML_DTD_NODE)
7857
1.33M
    return(cur);
7858
1.33M
  }
7859
1.33M
    }
7860
7861
4.41M
    if (cur == ctxt->context->node) return(NULL);
7862
7863
4.41M
    while (cur->next != NULL) {
7864
3.30M
  cur = cur->next;
7865
3.30M
  if ((cur->type != XML_ENTITY_DECL) &&
7866
3.30M
      (cur->type != XML_DTD_NODE))
7867
3.30M
      return(cur);
7868
3.30M
    }
7869
7870
1.46M
    do {
7871
1.46M
        cur = cur->parent;
7872
1.46M
  if (cur == NULL) break;
7873
1.46M
  if (cur == ctxt->context->node) return(NULL);
7874
1.31M
  if (cur->next != NULL) {
7875
956k
      cur = cur->next;
7876
956k
      return(cur);
7877
956k
  }
7878
1.31M
    } while (cur != NULL);
7879
0
    return(cur);
7880
1.11M
}
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
1.56M
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7897
1.56M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7898
1.56M
    if (cur == NULL)
7899
39.5k
        return(ctxt->context->node);
7900
7901
1.52M
    if (ctxt->context->node == NULL)
7902
0
        return(NULL);
7903
1.52M
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7904
1.52M
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7905
11.9k
        return(NULL);
7906
7907
1.51M
    return(xmlXPathNextDescendant(ctxt, cur));
7908
1.52M
}
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
213
            case XML_ATTRIBUTE_NODE: {
7954
213
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7955
7956
213
    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
132k
    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
360k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154
360k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155
360k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156
360k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8157
416
  return(NULL);
8158
360k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8159
0
        return(NULL);
8160
360k
    if (cur == NULL)
8161
0
        return(ctxt->context->node->prev);
8162
360k
    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
360k
    return(cur->prev);
8168
360k
}
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
0
{
8311
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8312
0
    if (cur == NULL) {
8313
0
        cur = ctxt->context->node;
8314
0
        if (cur == NULL)
8315
0
            return (NULL);
8316
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8317
0
            cur = cur->parent;
8318
0
        } 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
0
        ctxt->ancestor = cur->parent;
8327
0
    }
8328
0
    if (cur->type == XML_NAMESPACE_DECL)
8329
0
        return(NULL);
8330
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8331
0
  cur = cur->prev;
8332
0
    while (cur->prev == NULL) {
8333
0
        cur = cur->parent;
8334
0
        if (cur == NULL)
8335
0
            return (NULL);
8336
0
        if (cur == ctxt->context->doc->children)
8337
0
            return (NULL);
8338
0
        if (cur != ctxt->ancestor)
8339
0
            return (cur);
8340
0
        ctxt->ancestor = cur->parent;
8341
0
    }
8342
0
    cur = cur->prev;
8343
0
    while (cur->last != NULL)
8344
0
        cur = cur->last;
8345
0
    return (cur);
8346
0
}
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
585k
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8364
585k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8365
585k
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8366
568k
    if (cur == NULL) {
8367
130k
        if (ctxt->context->tmpNsList != NULL)
8368
11.7k
      xmlFree(ctxt->context->tmpNsList);
8369
130k
  ctxt->context->tmpNsList =
8370
130k
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8371
130k
  ctxt->context->tmpNsNr = 0;
8372
130k
  if (ctxt->context->tmpNsList != NULL) {
8373
479k
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8374
350k
    ctxt->context->tmpNsNr++;
8375
350k
      }
8376
129k
  }
8377
130k
  return((xmlNodePtr) xmlXPathXMLNamespace);
8378
130k
    }
8379
437k
    if (ctxt->context->tmpNsNr > 0) {
8380
327k
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8381
327k
    } else {
8382
110k
  if (ctxt->context->tmpNsList != NULL)
8383
109k
      xmlFree(ctxt->context->tmpNsList);
8384
110k
  ctxt->context->tmpNsList = NULL;
8385
110k
  return(NULL);
8386
110k
    }
8387
437k
}
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
38.2k
  return(NULL);
8406
1.51M
    if (cur == NULL) {
8407
715k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8408
0
      return(NULL);
8409
715k
        return((xmlNodePtr)ctxt->context->node->properties);
8410
715k
    }
8411
803k
    return((xmlNodePtr)cur->next);
8412
1.51M
}
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
680k
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8437
680k
    if ((ctxt == NULL) || (ctxt->context == NULL))
8438
0
  return;
8439
680k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8440
680k
  (xmlNodePtr) ctxt->context->doc));
8441
680k
}
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
969
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8541
969
    xmlNodeSetPtr ret;
8542
969
    const xmlChar *cur = ids;
8543
969
    xmlChar *ID;
8544
969
    xmlAttrPtr attr;
8545
969
    xmlNodePtr elem = NULL;
8546
8547
969
    if (ids == NULL) return(NULL);
8548
8549
910
    ret = xmlXPathNodeSetCreate(NULL);
8550
910
    if (ret == NULL)
8551
6
        return(ret);
8552
8553
919
    while (IS_BLANK_CH(*cur)) cur++;
8554
2.97k
    while (*cur != 0) {
8555
23.1k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8556
21.0k
      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
904
    return(ret);
8586
910
}
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.31k
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8608
1.31k
    xmlChar *tokens;
8609
1.31k
    xmlNodeSetPtr ret;
8610
1.31k
    xmlXPathObjectPtr obj;
8611
8612
3.94k
    CHECK_ARITY(1);
8613
3.94k
    obj = valuePop(ctxt);
8614
3.94k
    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
336
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8639
336
    if (obj == NULL) return;
8640
333
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8641
333
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8642
333
    xmlXPathReleaseObject(ctxt->context, obj);
8643
333
    return;
8644
336
}
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
112k
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8874
112k
    xmlXPathObjectPtr cur;
8875
8876
112k
    if (ctxt == NULL) return;
8877
112k
    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
450k
    CHECK_ARITY(1);
8885
450k
    cur = valuePop(ctxt);
8886
450k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8887
111k
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8888
111k
}
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.55k
    point = xmlStrstr(str->stringval, find->stringval);
9172
3.55k
    if (point) {
9173
1.51k
      offset = point - str->stringval;
9174
1.51k
      xmlBufAdd(target, str->stringval, offset);
9175
1.51k
    }
9176
3.55k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9177
3.55k
  xmlBufContent(target)));
9178
3.55k
    xmlBufFree(target);
9179
3.55k
  }
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
3.62k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9200
3.62k
  xmlXPathObjectPtr str;
9201
3.62k
  xmlXPathObjectPtr find;
9202
3.62k
  xmlBufPtr target;
9203
3.62k
  const xmlChar *point;
9204
3.62k
  int offset;
9205
9206
10.5k
  CHECK_ARITY(2);
9207
10.5k
  CAST_TO_STRING;
9208
10.5k
  find = valuePop(ctxt);
9209
10.5k
  CAST_TO_STRING;
9210
10.5k
  str = valuePop(ctxt);
9211
9212
10.5k
  target = xmlBufCreate();
9213
10.5k
  if (target) {
9214
3.43k
    point = xmlStrstr(str->stringval, find->stringval);
9215
3.43k
    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
3.43k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9221
3.43k
  xmlBufContent(target)));
9222
3.43k
    xmlBufFree(target);
9223
3.43k
  }
9224
10.5k
  xmlXPathReleaseObject(ctxt->context, str);
9225
10.5k
  xmlXPathReleaseObject(ctxt->context, find);
9226
10.5k
}
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.66k
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9308
1.66k
    xmlXPathObjectPtr str;
9309
1.66k
    xmlXPathObjectPtr from;
9310
1.66k
    xmlXPathObjectPtr to;
9311
1.66k
    xmlBufPtr target;
9312
1.66k
    int offset, max;
9313
1.66k
    int ch;
9314
1.66k
    const xmlChar *point;
9315
1.66k
    xmlChar *cptr;
9316
9317
4.83k
    CHECK_ARITY(3);
9318
9319
4.83k
    CAST_TO_STRING;
9320
4.83k
    to = valuePop(ctxt);
9321
4.83k
    CAST_TO_STRING;
9322
4.83k
    from = valuePop(ctxt);
9323
4.83k
    CAST_TO_STRING;
9324
4.83k
    str = valuePop(ctxt);
9325
9326
4.83k
    target = xmlBufCreate();
9327
4.83k
    if (target) {
9328
1.57k
  max = xmlUTF8Strlen(to->stringval);
9329
374k
  for (cptr = str->stringval; (ch=*cptr); ) {
9330
373k
      offset = xmlUTF8Strloc(from->stringval, cptr);
9331
373k
      if (offset >= 0) {
9332
5.66k
    if (offset < max) {
9333
5.10k
        point = xmlUTF8Strpos(to->stringval, offset);
9334
5.10k
        if (point)
9335
5.10k
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9336
5.10k
    }
9337
5.66k
      } else
9338
367k
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9339
9340
      /* Step to next character in input */
9341
373k
      cptr++;
9342
373k
      if ( ch & 0x80 ) {
9343
    /* if not simple ascii, verify proper format */
9344
483
    if ( (ch & 0xc0) != 0xc0 ) {
9345
0
        xmlGenericError(xmlGenericErrorContext,
9346
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9347
                    /* not asserting an XPath error is probably better */
9348
0
        break;
9349
0
    }
9350
    /* then skip over remaining bytes for this char */
9351
1.45k
    while ( (ch <<= 1) & 0x80 )
9352
970
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9353
0
      xmlGenericError(xmlGenericErrorContext,
9354
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9355
                        /* not asserting an XPath error is probably better */
9356
0
      break;
9357
0
        }
9358
483
    if (ch & 0x80) /* must have had error encountered */
9359
0
        break;
9360
483
      }
9361
373k
  }
9362
1.57k
    }
9363
4.83k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9364
4.83k
  xmlBufContent(target)));
9365
4.83k
    xmlBufFree(target);
9366
4.83k
    xmlXPathReleaseObject(ctxt->context, str);
9367
4.83k
    xmlXPathReleaseObject(ctxt->context, from);
9368
4.83k
    xmlXPathReleaseObject(ctxt->context, to);
9369
4.83k
}
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
218k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9386
218k
    xmlXPathObjectPtr cur;
9387
9388
655k
    CHECK_ARITY(1);
9389
655k
    cur = valuePop(ctxt);
9390
655k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9391
218k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9392
218k
    valuePush(ctxt, cur);
9393
218k
}
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
638k
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9501
638k
    xmlXPathObjectPtr cur;
9502
638k
    double res;
9503
9504
638k
    if (ctxt == NULL) return;
9505
638k
    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
2.55M
    CHECK_ARITY(1);
9519
2.55M
    cur = valuePop(ctxt);
9520
2.55M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9521
2.55M
}
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
637
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
637
    xmlXPathObjectPtr cur;
9536
637
    int i;
9537
637
    double res = 0.0;
9538
9539
1.90k
    CHECK_ARITY(1);
9540
1.90k
    if ((ctxt->value == NULL) ||
9541
636
  ((ctxt->value->type != XPATH_NODESET) &&
9542
636
   (ctxt->value->type != XPATH_XSLT_TREE)))
9543
634
  XP_ERROR(XPATH_INVALID_TYPE);
9544
634
    cur = valuePop(ctxt);
9545
9546
634
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9547
803
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9548
529
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9549
529
  }
9550
274
    }
9551
634
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9552
634
    xmlXPathReleaseObject(ctxt->context, cur);
9553
634
}
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
29.9M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9662
29.9M
    unsigned char c;
9663
29.9M
    unsigned int val;
9664
29.9M
    const xmlChar *cur;
9665
9666
29.9M
    if (ctxt == NULL)
9667
0
  return(0);
9668
29.9M
    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
29.9M
    c = *cur;
9682
29.9M
    if (c & 0x80) {
9683
2.56M
  if ((cur[1] & 0xc0) != 0x80)
9684
0
      goto encoding_error;
9685
2.56M
  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.49M
  } else {
9707
    /* 2-byte code */
9708
2.49M
      *len = 2;
9709
2.49M
      val = (cur[0] & 0x1f) << 6;
9710
2.49M
      val |= cur[1] & 0x3f;
9711
2.49M
  }
9712
2.56M
  if (!IS_CHAR(val)) {
9713
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9714
0
  }
9715
2.56M
  return(val);
9716
27.3M
    } else {
9717
  /* 1-byte code */
9718
27.3M
  *len = 1;
9719
27.3M
  return(*cur);
9720
27.3M
    }
9721
0
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
0
    *len = 0;
9730
0
    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
3.46M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9749
3.46M
    const xmlChar *in;
9750
3.46M
    xmlChar *ret;
9751
3.46M
    int count = 0;
9752
9753
3.46M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9754
    /*
9755
     * Accelerator for simple ASCII names
9756
     */
9757
3.46M
    in = ctxt->cur;
9758
3.46M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9759
3.46M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9760
3.46M
  (*in == '_')) {
9761
3.26M
  in++;
9762
21.2M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9763
21.2M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9764
21.2M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9765
21.2M
         (*in == '_') || (*in == '.') ||
9766
21.2M
         (*in == '-'))
9767
17.9M
      in++;
9768
3.26M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9769
3.26M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9770
3.26M
            (*in == '@') || (*in == '*')) {
9771
1.79M
      count = in - ctxt->cur;
9772
1.79M
      if (count == 0)
9773
0
    return(NULL);
9774
1.79M
      ret = xmlStrndup(ctxt->cur, count);
9775
1.79M
      ctxt->cur = in;
9776
1.79M
      return(ret);
9777
1.79M
  }
9778
3.26M
    }
9779
1.66M
    return(xmlXPathParseNameComplex(ctxt, 0));
9780
3.46M
}
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
915k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9802
915k
    xmlChar *ret = NULL;
9803
9804
915k
    *prefix = NULL;
9805
915k
    ret = xmlXPathParseNCName(ctxt);
9806
915k
    if (ret && CUR == ':') {
9807
698k
        *prefix = ret;
9808
698k
  NEXT;
9809
698k
  ret = xmlXPathParseNCName(ctxt);
9810
698k
    }
9811
915k
    return(ret);
9812
915k
}
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
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9830
0
    const xmlChar *in;
9831
0
    xmlChar *ret;
9832
0
    size_t count = 0;
9833
9834
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9835
    /*
9836
     * Accelerator for simple ASCII names
9837
     */
9838
0
    in = ctxt->cur;
9839
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9840
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9841
0
  (*in == '_') || (*in == ':')) {
9842
0
  in++;
9843
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9844
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9845
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9846
0
         (*in == '_') || (*in == '-') ||
9847
0
         (*in == ':') || (*in == '.'))
9848
0
      in++;
9849
0
  if ((*in > 0) && (*in < 0x80)) {
9850
0
      count = in - ctxt->cur;
9851
0
            if (count > XML_MAX_NAME_LENGTH) {
9852
0
                ctxt->cur = in;
9853
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9854
0
            }
9855
0
      ret = xmlStrndup(ctxt->cur, count);
9856
0
      ctxt->cur = in;
9857
0
      return(ret);
9858
0
  }
9859
0
    }
9860
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9861
0
}
9862
9863
static xmlChar *
9864
1.66M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9865
1.66M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9866
1.66M
    int len = 0, l;
9867
1.66M
    int c;
9868
9869
    /*
9870
     * Handler for more complex cases
9871
     */
9872
1.66M
    c = CUR_CHAR(l);
9873
1.66M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9874
1.66M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9875
1.66M
        (c == '*') || /* accelerators */
9876
1.66M
  (!IS_LETTER(c) && (c != '_') &&
9877
1.55M
         ((!qualified) || (c != ':')))) {
9878
176k
  return(NULL);
9879
176k
    }
9880
9881
11.9M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9882
11.9M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9883
11.9M
            (c == '.') || (c == '-') ||
9884
11.9M
      (c == '_') || ((qualified) && (c == ':')) ||
9885
11.9M
      (IS_COMBINING(c)) ||
9886
11.9M
      (IS_EXTENDER(c)))) {
9887
10.4M
  COPY_BUF(l,buf,len,c);
9888
10.4M
  NEXTL(l);
9889
10.4M
  c = CUR_CHAR(l);
9890
10.4M
  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.64k
      xmlChar *buffer;
9896
8.64k
      int max = len * 2;
9897
9898
8.64k
            if (len > XML_MAX_NAME_LENGTH) {
9899
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9900
0
            }
9901
8.64k
      buffer = (xmlChar *) xmlMallocAtomic(max);
9902
8.64k
      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.05k
                    buffer = tmp;
9924
3.05k
    }
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
10.4M
    }
9933
1.48M
    if (len == 0)
9934
0
  return(NULL);
9935
1.48M
    return(xmlStrndup(buf, len));
9936
1.48M
}
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
511k
xmlXPathStringEvalNumber(const xmlChar *str) {
9958
511k
    const xmlChar *cur = str;
9959
511k
    double ret;
9960
511k
    int ok = 0;
9961
511k
    int isneg = 0;
9962
511k
    int exponent = 0;
9963
511k
    int is_exponent_negative = 0;
9964
511k
#ifdef __GNUC__
9965
511k
    unsigned long tmp = 0;
9966
511k
    double temp;
9967
511k
#endif
9968
511k
    if (cur == NULL) return(0);
9969
501k
    while (IS_BLANK_CH(*cur)) cur++;
9970
501k
    if (*cur == '-') {
9971
19.3k
  isneg = 1;
9972
19.3k
  cur++;
9973
19.3k
    }
9974
501k
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9975
449k
        return(xmlXPathNAN);
9976
449k
    }
9977
9978
51.5k
#ifdef __GNUC__
9979
    /*
9980
     * tmp/temp is a workaround against a gcc compiler bug
9981
     * http://veillard.com/gcc.bug
9982
     */
9983
51.5k
    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.5k
    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.93k
      return(xmlXPathNAN);
10008
1.93k
  }
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.6k
    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.6k
    while (IS_BLANK_CH(*cur)) cur++;
10040
49.6k
    if (*cur != 0) return(xmlXPathNAN);
10041
27.3k
    if (isneg) ret = -ret;
10042
27.3k
    if (is_exponent_negative) exponent = -exponent;
10043
27.3k
    ret *= pow(10.0, (double)exponent);
10044
27.3k
    return(ret);
10045
49.6k
}
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
311k
{
10061
311k
    double ret = 0.0;
10062
311k
    int ok = 0;
10063
311k
    int exponent = 0;
10064
311k
    int is_exponent_negative = 0;
10065
311k
    xmlXPathObjectPtr num;
10066
311k
#ifdef __GNUC__
10067
311k
    unsigned long tmp = 0;
10068
311k
    double temp;
10069
311k
#endif
10070
10071
311k
    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.8k
  int v, frac = 0, max;
10099
12.8k
  double fraction = 0;
10100
10101
12.8k
        NEXT;
10102
12.8k
        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.8k
        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.8k
        fraction /= pow(10.0, frac);
10117
12.8k
        ret = ret + fraction;
10118
14.9k
        while ((CUR >= '0') && (CUR <= '9'))
10119
2.06k
            NEXT;
10120
12.8k
    }
10121
311k
    if ((CUR == 'e') || (CUR == 'E')) {
10122
3.15k
        NEXT;
10123
3.15k
        if (CUR == '-') {
10124
934
            is_exponent_negative = 1;
10125
934
            NEXT;
10126
2.21k
        } 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.15k
        if (is_exponent_negative)
10135
934
            exponent = -exponent;
10136
3.15k
        ret *= pow(10.0, (double) exponent);
10137
3.15k
    }
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
95.9k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10204
95.9k
    const xmlChar *q;
10205
95.9k
    xmlChar *ret = NULL;
10206
95.9k
    xmlXPathObjectPtr lit;
10207
10208
95.9k
    if (CUR == '"') {
10209
41.1k
        NEXT;
10210
41.1k
  q = CUR_PTR;
10211
289k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10212
248k
      NEXT;
10213
41.1k
  if (!IS_CHAR_CH(CUR)) {
10214
2.20k
      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.7k
    } else if (CUR == '\'') {
10220
54.7k
        NEXT;
10221
54.7k
  q = CUR_PTR;
10222
781k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10223
727k
      NEXT;
10224
54.7k
  if (!IS_CHAR_CH(CUR)) {
10225
742
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10226
54.0k
  } else {
10227
54.0k
      ret = xmlStrndup(q, CUR_PTR - q);
10228
54.0k
      NEXT;
10229
54.0k
        }
10230
54.7k
    } else {
10231
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10232
0
    }
10233
92.9k
    if (ret == NULL) {
10234
14
        xmlXPathPErrMemory(ctxt, NULL);
10235
14
        return;
10236
14
    }
10237
92.9k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10238
92.9k
    if (lit == NULL) {
10239
12
  ctxt->error = XPATH_MEMORY_ERROR;
10240
92.9k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10241
92.9k
                              NULL) == -1) {
10242
2
        xmlXPathReleaseObject(ctxt->context, lit);
10243
2
    }
10244
92.9k
    xmlFree(ret);
10245
92.9k
}
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
910k
xmlXPathIsNodeType(const xmlChar *name) {
10305
910k
    if (name == NULL)
10306
0
  return(0);
10307
10308
910k
    if (xmlStrEqual(name, BAD_CAST "node"))
10309
4.81k
  return(1);
10310
905k
    if (xmlStrEqual(name, BAD_CAST "text"))
10311
5.48k
  return(1);
10312
899k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10313
1.55k
  return(1);
10314
898k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10315
3.63k
  return(1);
10316
894k
    return(0);
10317
898k
}
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
869k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10331
869k
    xmlChar *name;
10332
869k
    xmlChar *prefix;
10333
869k
    int nbargs = 0;
10334
869k
    int sort = 1;
10335
10336
869k
    name = xmlXPathParseQName(ctxt, &prefix);
10337
869k
    if (name == NULL) {
10338
1.37k
  xmlFree(prefix);
10339
1.37k
  XP_ERROR(XPATH_EXPR_ERROR);
10340
0
    }
10341
867k
    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
867k
    if (CUR != '(') {
10352
755
  xmlFree(name);
10353
755
  xmlFree(prefix);
10354
755
  XP_ERROR(XPATH_EXPR_ERROR);
10355
0
    }
10356
866k
    NEXT;
10357
866k
    SKIP_BLANKS;
10358
10359
    /*
10360
    * Optimization for count(): we don't need the node-set to be sorted.
10361
    */
10362
866k
    if ((prefix == NULL) && (name[0] == 'c') &&
10363
866k
  xmlStrEqual(name, BAD_CAST "count"))
10364
5.01k
    {
10365
5.01k
  sort = 0;
10366
5.01k
    }
10367
866k
    ctxt->comp->last = -1;
10368
866k
    if (CUR != ')') {
10369
1.37M
  while (CUR != 0) {
10370
1.37M
      int op1 = ctxt->comp->last;
10371
1.37M
      ctxt->comp->last = -1;
10372
1.37M
      xmlXPathCompileExpr(ctxt, sort);
10373
1.37M
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10374
87.0k
    xmlFree(name);
10375
87.0k
    xmlFree(prefix);
10376
87.0k
    return;
10377
87.0k
      }
10378
1.28M
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10379
1.28M
      nbargs++;
10380
1.28M
      if (CUR == ')') break;
10381
636k
      if (CUR != ',') {
10382
4.82k
    xmlFree(name);
10383
4.82k
    xmlFree(prefix);
10384
4.82k
    XP_ERROR(XPATH_EXPR_ERROR);
10385
0
      }
10386
631k
      NEXT;
10387
631k
      SKIP_BLANKS;
10388
631k
  }
10389
742k
    }
10390
775k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10391
5
        xmlFree(prefix);
10392
5
        xmlFree(name);
10393
5
    }
10394
775k
    NEXT;
10395
775k
    SKIP_BLANKS;
10396
775k
}
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.47M
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10412
1.47M
    SKIP_BLANKS;
10413
1.47M
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10414
1.42M
    else if (CUR == '(') {
10415
151k
  NEXT;
10416
151k
  SKIP_BLANKS;
10417
151k
  xmlXPathCompileExpr(ctxt, 1);
10418
151k
  CHECK_ERROR;
10419
112k
  if (CUR != ')') {
10420
14.1k
      XP_ERROR(XPATH_EXPR_ERROR);
10421
0
  }
10422
98.3k
  NEXT;
10423
98.3k
  SKIP_BLANKS;
10424
1.27M
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10425
311k
  xmlXPathCompNumber(ctxt);
10426
964k
    } else if ((CUR == '\'') || (CUR == '"')) {
10427
95.9k
  xmlXPathCompLiteral(ctxt);
10428
869k
    } else {
10429
869k
  xmlXPathCompFunctionCall(ctxt);
10430
869k
    }
10431
1.42M
    SKIP_BLANKS;
10432
1.42M
}
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.47M
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10451
1.47M
    xmlXPathCompPrimaryExpr(ctxt);
10452
1.47M
    CHECK_ERROR;
10453
1.31M
    SKIP_BLANKS;
10454
10455
1.52M
    while (CUR == '[') {
10456
204k
  xmlXPathCompPredicate(ctxt, 1);
10457
204k
  SKIP_BLANKS;
10458
204k
    }
10459
10460
10461
1.31M
}
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
1.57M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10482
1.57M
    int l;
10483
1.57M
    int c;
10484
1.57M
    const xmlChar *cur;
10485
1.57M
    xmlChar *ret;
10486
10487
1.57M
    cur = ctxt->cur;
10488
10489
1.57M
    c = CUR_CHAR(l);
10490
1.57M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10491
1.57M
  (!IS_LETTER(c) && (c != '_') &&
10492
1.57M
         (c != ':'))) {
10493
136k
  return(NULL);
10494
136k
    }
10495
10496
15.1M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10497
15.1M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10498
14.9M
            (c == '.') || (c == '-') ||
10499
14.9M
      (c == '_') || (c == ':') ||
10500
14.9M
      (IS_COMBINING(c)) ||
10501
14.9M
      (IS_EXTENDER(c)))) {
10502
13.7M
  NEXTL(l);
10503
13.7M
  c = CUR_CHAR(l);
10504
13.7M
    }
10505
1.43M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10506
1.43M
    ctxt->cur = cur;
10507
1.43M
    return(ret);
10508
1.57M
}
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.21M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10530
8.21M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10531
8.21M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10532
10533
8.21M
    SKIP_BLANKS;
10534
8.21M
    if ((CUR == '$') || (CUR == '(') ||
10535
8.21M
  (IS_ASCII_DIGIT(CUR)) ||
10536
8.21M
        (CUR == '\'') || (CUR == '"') ||
10537
8.21M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10538
605k
  lc = 0;
10539
7.60M
    } else if (CUR == '*') {
10540
  /* relative or absolute location path */
10541
4.46M
  lc = 1;
10542
4.46M
    } else if (CUR == '/') {
10543
  /* relative or absolute location path */
10544
859k
  lc = 1;
10545
2.28M
    } else if (CUR == '@') {
10546
  /* relative abbreviated attribute location path */
10547
83.1k
  lc = 1;
10548
2.20M
    } else if (CUR == '.') {
10549
  /* relative abbreviated attribute location path */
10550
631k
  lc = 1;
10551
1.57M
    } 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
1.57M
  SKIP_BLANKS;
10564
1.57M
  name = xmlXPathScanName(ctxt);
10565
1.57M
  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
1.56M
  } else if (name != NULL) {
10573
1.42M
      int len =xmlStrlen(name);
10574
10575
10576
2.74M
      while (NXT(len) != 0) {
10577
2.73M
    if (NXT(len) == '/') {
10578
        /* element name */
10579
#ifdef DEBUG_STEP
10580
        xmlGenericError(xmlGenericErrorContext,
10581
          "PathExpr: AbbrRelLocation\n");
10582
#endif
10583
74.8k
        lc = 1;
10584
74.8k
        break;
10585
2.65M
    } else if (IS_BLANK_CH(NXT(len))) {
10586
        /* ignore blanks */
10587
1.31M
        ;
10588
1.34M
    } else if (NXT(len) == ':') {
10589
#ifdef DEBUG_STEP
10590
        xmlGenericError(xmlGenericErrorContext,
10591
          "PathExpr: AbbrRelLocation\n");
10592
#endif
10593
2.03k
        lc = 1;
10594
2.03k
        break;
10595
1.34M
    } else if ((NXT(len) == '(')) {
10596
        /* Node Type or Function */
10597
880k
        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
869k
        } else {
10609
#ifdef DEBUG_STEP
10610
            xmlGenericError(xmlGenericErrorContext,
10611
        "PathExpr: function call\n");
10612
#endif
10613
869k
      lc = 0;
10614
869k
        }
10615
880k
                    break;
10616
880k
    } 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
450k
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10625
450k
         (NXT(len) == '=')) {
10626
90.9k
        lc = 1;
10627
90.9k
        break;
10628
359k
    } else {
10629
359k
        lc = 1;
10630
359k
        break;
10631
359k
    }
10632
1.31M
    len++;
10633
1.31M
      }
10634
1.42M
      if (NXT(len) == 0) {
10635
#ifdef DEBUG_STEP
10636
    xmlGenericError(xmlGenericErrorContext,
10637
      "PathExpr: AbbrRelLocation\n");
10638
#endif
10639
    /* element name */
10640
8.12k
    lc = 1;
10641
8.12k
      }
10642
1.42M
      xmlFree(name);
10643
1.42M
  } else {
10644
      /* make sure all cases are covered explicitly */
10645
136k
      XP_ERROR(XPATH_EXPR_ERROR);
10646
0
  }
10647
1.57M
    }
10648
10649
8.07M
    if (lc) {
10650
6.60M
  if (CUR == '/') {
10651
859k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10652
5.74M
  } else {
10653
5.74M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10654
5.74M
  }
10655
6.60M
  xmlXPathCompLocationPath(ctxt);
10656
6.60M
    } else {
10657
1.47M
  xmlXPathCompFilterExpr(ctxt);
10658
1.47M
  CHECK_ERROR;
10659
1.31M
  if ((CUR == '/') && (NXT(1) == '/')) {
10660
2.62k
      SKIP(2);
10661
2.62k
      SKIP_BLANKS;
10662
10663
2.62k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10664
2.62k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10665
10666
2.62k
      xmlXPathCompRelativeLocationPath(ctxt);
10667
1.31M
  } else if (CUR == '/') {
10668
530k
      xmlXPathCompRelativeLocationPath(ctxt);
10669
530k
  }
10670
1.31M
    }
10671
7.91M
    SKIP_BLANKS;
10672
7.91M
}
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
7.91M
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10686
7.91M
    xmlXPathCompPathExpr(ctxt);
10687
7.91M
    CHECK_ERROR;
10688
7.60M
    SKIP_BLANKS;
10689
7.91M
    while (CUR == '|') {
10690
302k
  int op1 = ctxt->comp->last;
10691
302k
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10692
10693
302k
  NEXT;
10694
302k
  SKIP_BLANKS;
10695
302k
  xmlXPathCompPathExpr(ctxt);
10696
10697
302k
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10698
10699
302k
  SKIP_BLANKS;
10700
302k
    }
10701
7.60M
}
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
7.91M
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10715
7.91M
    int minus = 0;
10716
7.91M
    int found = 0;
10717
10718
7.91M
    SKIP_BLANKS;
10719
8.49M
    while (CUR == '-') {
10720
586k
        minus = 1 - minus;
10721
586k
  found = 1;
10722
586k
  NEXT;
10723
586k
  SKIP_BLANKS;
10724
586k
    }
10725
10726
7.91M
    xmlXPathCompUnionExpr(ctxt);
10727
7.91M
    CHECK_ERROR;
10728
7.57M
    if (found) {
10729
51.3k
  if (minus)
10730
26.6k
      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
51.3k
    }
10734
7.57M
}
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.42M
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10751
3.42M
    xmlXPathCompUnaryExpr(ctxt);
10752
3.42M
    CHECK_ERROR;
10753
3.09M
    SKIP_BLANKS;
10754
7.57M
    while ((CUR == '*') ||
10755
7.57M
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10756
7.57M
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10757
4.48M
  int op = -1;
10758
4.48M
  int op1 = ctxt->comp->last;
10759
10760
4.48M
        if (CUR == '*') {
10761
4.41M
      op = 0;
10762
4.41M
      NEXT;
10763
4.41M
  } 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.48M
  SKIP_BLANKS;
10771
4.48M
        xmlXPathCompUnaryExpr(ctxt);
10772
4.48M
  CHECK_ERROR;
10773
4.47M
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10774
4.47M
  SKIP_BLANKS;
10775
4.47M
    }
10776
3.09M
}
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.21M
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10791
10792
3.21M
    xmlXPathCompMultiplicativeExpr(ctxt);
10793
3.21M
    CHECK_ERROR;
10794
2.90M
    SKIP_BLANKS;
10795
3.08M
    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.90M
}
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.74M
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10830
2.74M
    xmlXPathCompAdditiveExpr(ctxt);
10831
2.74M
    CHECK_ERROR;
10832
2.43M
    SKIP_BLANKS;
10833
2.88M
    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
470k
  else strict = 1;
10841
471k
  NEXT;
10842
471k
  if (!strict) NEXT;
10843
471k
  SKIP_BLANKS;
10844
471k
        xmlXPathCompAdditiveExpr(ctxt);
10845
471k
  CHECK_ERROR;
10846
448k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10847
448k
  SKIP_BLANKS;
10848
448k
    }
10849
2.43M
}
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.46M
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10869
2.46M
    xmlXPathCompRelationalExpr(ctxt);
10870
2.46M
    CHECK_ERROR;
10871
2.16M
    SKIP_BLANKS;
10872
2.41M
    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.16M
}
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.44M
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10900
2.44M
    xmlXPathCompEqualityExpr(ctxt);
10901
2.44M
    CHECK_ERROR;
10902
2.10M
    SKIP_BLANKS;
10903
2.12M
    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.10M
}
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.51M
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10926
2.51M
    xmlXPathContextPtr xpctxt = ctxt->context;
10927
10928
2.51M
    if (xpctxt != NULL) {
10929
2.51M
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10930
2.43M
            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.43M
        xpctxt->depth += 10;
10936
2.43M
    }
10937
10938
2.43M
    xmlXPathCompAndExpr(ctxt);
10939
2.43M
    CHECK_ERROR;
10940
2.09M
    SKIP_BLANKS;
10941
2.10M
    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.43k
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10948
9.43k
  SKIP_BLANKS;
10949
9.43k
    }
10950
2.09M
    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.83M
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10958
1.83M
    }
10959
10960
2.09M
    if (xpctxt != NULL)
10961
2.09M
        xpctxt->depth -= 10;
10962
2.09M
}
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
319k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10976
319k
    int op1 = ctxt->comp->last;
10977
10978
319k
    SKIP_BLANKS;
10979
319k
    if (CUR != '[') {
10980
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10981
0
    }
10982
319k
    NEXT;
10983
319k
    SKIP_BLANKS;
10984
10985
319k
    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
319k
    if (! filter)
10996
114k
  xmlXPathCompileExpr(ctxt, 0);
10997
204k
    else
10998
204k
  xmlXPathCompileExpr(ctxt, 1);
10999
319k
    CHECK_ERROR;
11000
11001
288k
    if (CUR != ']') {
11002
1.75k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11003
0
    }
11004
11005
286k
    if (filter)
11006
203k
  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
286k
    NEXT;
11011
286k
    SKIP_BLANKS;
11012
286k
}
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.16M
         xmlChar *name) {
11039
6.16M
    int blanks;
11040
11041
6.16M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11042
0
  STRANGE;
11043
0
  return(NULL);
11044
0
    }
11045
6.16M
    *type = (xmlXPathTypeVal) 0;
11046
6.16M
    *test = (xmlXPathTestVal) 0;
11047
6.16M
    *prefix = NULL;
11048
6.16M
    SKIP_BLANKS;
11049
11050
6.16M
    if ((name == NULL) && (CUR == '*')) {
11051
  /*
11052
   * All elements
11053
   */
11054
4.65M
  NEXT;
11055
4.65M
  *test = NODE_TEST_ALL;
11056
4.65M
  return(NULL);
11057
4.65M
    }
11058
11059
1.50M
    if (name == NULL)
11060
132k
  name = xmlXPathParseNCName(ctxt);
11061
1.50M
    if (name == NULL) {
11062
35.3k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11063
0
    }
11064
11065
1.47M
    blanks = IS_BLANK_CH(CUR);
11066
1.47M
    SKIP_BLANKS;
11067
1.47M
    if (CUR == '(') {
11068
86.1k
  NEXT;
11069
  /*
11070
   * NodeType or PI search
11071
   */
11072
86.1k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11073
7.52k
      *type = NODE_TYPE_COMMENT;
11074
78.6k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11075
22.0k
      *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.3k
  *test = NODE_TEST_TYPE;
11087
11088
83.3k
  SKIP_BLANKS;
11089
83.3k
  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.1k
  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.0k
  NEXT;
11111
82.0k
  return(name);
11112
83.1k
    }
11113
1.38M
    *test = NODE_TEST_NAME;
11114
1.38M
    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.5k
  name = xmlXPathParseNCName(ctxt);
11145
71.5k
  if (name == NULL) {
11146
7.02k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11147
0
  }
11148
71.5k
    }
11149
1.34M
    return(name);
11150
1.38M
}
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
1.51M
xmlXPathIsAxisName(const xmlChar *name) {
11174
1.51M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11175
1.51M
    switch (name[0]) {
11176
94.6k
  case 'a':
11177
94.6k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11178
3.93k
    ret = AXIS_ANCESTOR;
11179
94.6k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11180
2.66k
    ret = AXIS_ANCESTOR_OR_SELF;
11181
94.6k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11182
3.57k
    ret = AXIS_ATTRIBUTE;
11183
94.6k
      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.0k
  case 'd':
11189
20.0k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11190
79
    ret = AXIS_DESCENDANT;
11191
20.0k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11192
74
    ret = AXIS_DESCENDANT_OR_SELF;
11193
20.0k
      break;
11194
7.79k
  case 'f':
11195
7.79k
      if (xmlStrEqual(name, BAD_CAST "following"))
11196
130
    ret = AXIS_FOLLOWING;
11197
7.79k
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11198
92
    ret = AXIS_FOLLOWING_SIBLING;
11199
7.79k
      break;
11200
589k
  case 'n':
11201
589k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11202
146k
    ret = AXIS_NAMESPACE;
11203
589k
      break;
11204
71.0k
  case 'p':
11205
71.0k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11206
274
    ret = AXIS_PARENT;
11207
71.0k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11208
344
    ret = AXIS_PRECEDING;
11209
71.0k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11210
132
    ret = AXIS_PRECEDING_SIBLING;
11211
71.0k
      break;
11212
34.1k
  case 's':
11213
34.1k
      if (xmlStrEqual(name, BAD_CAST "self"))
11214
2.57k
    ret = AXIS_SELF;
11215
34.1k
      break;
11216
1.51M
    }
11217
1.51M
    return(ret);
11218
1.51M
}
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
6.94M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11254
#ifdef LIBXML_XPTR_LOCS_ENABLED
11255
    int rangeto = 0;
11256
    int op2 = -1;
11257
#endif
11258
11259
6.94M
    SKIP_BLANKS;
11260
6.94M
    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
6.90M
    } else if (CUR == '.') {
11266
735k
  NEXT;
11267
735k
  SKIP_BLANKS;
11268
6.16M
    } else {
11269
6.16M
  xmlChar *name = NULL;
11270
6.16M
  xmlChar *prefix = NULL;
11271
6.16M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11272
6.16M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11273
6.16M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11274
6.16M
  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.16M
  if (CUR == '*') {
11307
4.51M
      axis = AXIS_CHILD;
11308
4.51M
  } else {
11309
1.64M
      if (name == NULL)
11310
1.64M
    name = xmlXPathParseNCName(ctxt);
11311
1.64M
      if (name != NULL) {
11312
1.51M
    axis = xmlXPathIsAxisName(name);
11313
1.51M
    if (axis != 0) {
11314
160k
        SKIP_BLANKS;
11315
160k
        if ((CUR == ':') && (NXT(1) == ':')) {
11316
140k
      SKIP(2);
11317
140k
      xmlFree(name);
11318
140k
      name = NULL;
11319
140k
        } else {
11320
      /* an element name can conflict with an axis one :-\ */
11321
19.6k
      axis = AXIS_CHILD;
11322
19.6k
        }
11323
1.35M
    } else {
11324
1.35M
        axis = AXIS_CHILD;
11325
1.35M
    }
11326
1.51M
      } else if (CUR == '@') {
11327
92.5k
    NEXT;
11328
92.5k
    axis = AXIS_ATTRIBUTE;
11329
92.5k
      } else {
11330
38.9k
    axis = AXIS_CHILD;
11331
38.9k
      }
11332
1.64M
  }
11333
11334
6.16M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11335
6.64k
            xmlFree(name);
11336
6.64k
            return;
11337
6.64k
        }
11338
11339
6.16M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11340
6.16M
  if (test == 0)
11341
38.1k
      return;
11342
11343
6.12M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11344
6.12M
      (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.12M
  op1 = ctxt->comp->last;
11368
6.12M
  ctxt->comp->last = -1;
11369
11370
6.12M
  SKIP_BLANKS;
11371
6.23M
  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.12M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11381
6.12M
                           test, type, (void *)prefix, (void *)name) == -1) {
11382
40
            xmlFree(prefix);
11383
40
            xmlFree(name);
11384
40
        }
11385
6.12M
    }
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
6.94M
}
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
6.65M
(xmlXPathParserContextPtr ctxt) {
11412
6.65M
    SKIP_BLANKS;
11413
6.65M
    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
6.65M
    } else if (CUR == '/') {
11419
532k
      NEXT;
11420
532k
  SKIP_BLANKS;
11421
532k
    }
11422
6.65M
    xmlXPathCompStep(ctxt);
11423
6.65M
    CHECK_ERROR;
11424
6.62M
    SKIP_BLANKS;
11425
6.91M
    while (CUR == '/') {
11426
289k
  if ((CUR == '/') && (NXT(1) == '/')) {
11427
40.2k
      SKIP(2);
11428
40.2k
      SKIP_BLANKS;
11429
40.2k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11430
40.2k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11431
40.2k
      xmlXPathCompStep(ctxt);
11432
249k
  } else if (CUR == '/') {
11433
249k
      NEXT;
11434
249k
      SKIP_BLANKS;
11435
249k
      xmlXPathCompStep(ctxt);
11436
249k
  }
11437
289k
  SKIP_BLANKS;
11438
289k
    }
11439
6.62M
}
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
6.60M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11464
6.60M
    SKIP_BLANKS;
11465
6.60M
    if (CUR != '/') {
11466
5.74M
        xmlXPathCompRelativeLocationPath(ctxt);
11467
5.74M
    } else {
11468
1.69M
  while (CUR == '/') {
11469
862k
      if ((CUR == '/') && (NXT(1) == '/')) {
11470
123k
    SKIP(2);
11471
123k
    SKIP_BLANKS;
11472
123k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11473
123k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11474
123k
    xmlXPathCompRelativeLocationPath(ctxt);
11475
739k
      } else if (CUR == '/') {
11476
739k
    NEXT;
11477
739k
    SKIP_BLANKS;
11478
739k
    if ((CUR != 0 ) &&
11479
739k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11480
736k
         (CUR == '@') || (CUR == '*')))
11481
257k
        xmlXPathCompRelativeLocationPath(ctxt);
11482
739k
      }
11483
862k
      CHECK_ERROR;
11484
862k
  }
11485
859k
    }
11486
6.60M
}
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
216k
{
11604
216k
    xmlXPathContextPtr xpctxt;
11605
216k
    xmlNodePtr oldnode;
11606
216k
    xmlDocPtr olddoc;
11607
216k
    xmlXPathStepOpPtr filterOp;
11608
216k
    int oldcs, oldpp;
11609
216k
    int i, j, pos;
11610
11611
216k
    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
138k
    if (set->nodeNr < minPos) {
11619
7.71k
        xmlXPathNodeSetClear(set, hasNsNodes);
11620
7.71k
        return;
11621
7.71k
    }
11622
11623
131k
    xpctxt = ctxt->context;
11624
131k
    oldnode = xpctxt->node;
11625
131k
    olddoc = xpctxt->doc;
11626
131k
    oldcs = xpctxt->contextSize;
11627
131k
    oldpp = xpctxt->proximityPosition;
11628
131k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11629
11630
131k
    xpctxt->contextSize = set->nodeNr;
11631
11632
421k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11633
385k
        xmlNodePtr node = set->nodeTab[i];
11634
385k
        int res;
11635
11636
385k
        xpctxt->node = node;
11637
385k
        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
385k
        if ((node->type != XML_NAMESPACE_DECL) &&
11646
385k
            (node->doc != NULL))
11647
319k
            xpctxt->doc = node->doc;
11648
11649
385k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11650
11651
385k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11652
5.39k
            break;
11653
379k
        if (res < 0) {
11654
            /* Shouldn't happen */
11655
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11656
0
            break;
11657
0
        }
11658
11659
379k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11660
181k
            if (i != j) {
11661
32.5k
                set->nodeTab[j] = node;
11662
32.5k
                set->nodeTab[i] = NULL;
11663
32.5k
            }
11664
11665
181k
            j += 1;
11666
198k
        } else {
11667
            /* Remove the entry from the initial node set. */
11668
198k
            set->nodeTab[i] = NULL;
11669
198k
            if (node->type == XML_NAMESPACE_DECL)
11670
46.3k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11671
198k
        }
11672
11673
379k
        if (res != 0) {
11674
191k
            if (pos == maxPos) {
11675
89.0k
                i += 1;
11676
89.0k
                break;
11677
89.0k
            }
11678
11679
102k
            pos += 1;
11680
102k
        }
11681
379k
    }
11682
11683
    /* Free remaining nodes. */
11684
131k
    if (hasNsNodes) {
11685
33.5k
        for (; i < set->nodeNr; i++) {
11686
12.4k
            xmlNodePtr node = set->nodeTab[i];
11687
12.4k
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11688
12.2k
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11689
12.4k
        }
11690
21.0k
    }
11691
11692
131k
    set->nodeNr = j;
11693
11694
    /* If too many elements were removed, shrink table to preserve memory. */
11695
131k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11696
131k
        (set->nodeNr < set->nodeMax / 2)) {
11697
3.56k
        xmlNodePtr *tmp;
11698
3.56k
        int nodeMax = set->nodeNr;
11699
11700
3.56k
        if (nodeMax < XML_NODESET_DEFAULT)
11701
3.46k
            nodeMax = XML_NODESET_DEFAULT;
11702
3.56k
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11703
3.56k
                nodeMax * sizeof(xmlNodePtr));
11704
3.56k
        if (tmp == NULL) {
11705
101
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11706
3.46k
        } else {
11707
3.46k
            set->nodeTab = tmp;
11708
3.46k
            set->nodeMax = nodeMax;
11709
3.46k
        }
11710
3.56k
    }
11711
11712
131k
    xpctxt->node = oldnode;
11713
131k
    xpctxt->doc = olddoc;
11714
131k
    xpctxt->contextSize = oldcs;
11715
131k
    xpctxt->proximityPosition = oldpp;
11716
131k
}
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
133k
{
11857
133k
    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
130k
    if (op->ch2 != -1)
11877
130k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11878
130k
}
11879
11880
static int
11881
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11882
          xmlXPathStepOpPtr op,
11883
          int *maxPos)
11884
69.2k
{
11885
11886
69.2k
    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.2k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11902
0
  return(0);
11903
11904
69.2k
    if (op->ch2 != -1) {
11905
69.2k
  exprOp = &ctxt->comp->steps[op->ch2];
11906
69.2k
    } else
11907
0
  return(0);
11908
11909
69.2k
    if ((exprOp != NULL) &&
11910
69.2k
  (exprOp->op == XPATH_OP_VALUE) &&
11911
69.2k
  (exprOp->value4 != NULL) &&
11912
69.2k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11913
30.4k
    {
11914
30.4k
        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.4k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11928
29.4k
      *maxPos = (int) floatval;
11929
29.4k
            if (floatval == (double) *maxPos)
11930
29.2k
                return(1);
11931
29.4k
        }
11932
30.4k
    }
11933
39.9k
    return(0);
11934
69.2k
}
11935
11936
static int
11937
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11938
                           xmlXPathStepOpPtr op,
11939
         xmlNodePtr * first, xmlNodePtr * last,
11940
         int toBool)
11941
2.16M
{
11942
11943
2.16M
#define XP_TEST_HIT \
11944
5.34M
    if (hasAxisRange != 0) { \
11945
92.0k
  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
5.25M
    } else { \
11950
5.25M
  if (addNode(seq, cur) < 0) \
11951
5.25M
      ctxt->error = XPATH_MEMORY_ERROR; \
11952
5.25M
  if (breakOnFirstHit) goto first_hit; }
11953
11954
2.16M
#define XP_TEST_HIT_NS \
11955
2.16M
    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
282k
    } else { \
11962
282k
  hasNsNodes = 1; \
11963
282k
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11964
282k
      ctxt->error = XPATH_MEMORY_ERROR; \
11965
282k
  if (breakOnFirstHit) goto first_hit; }
11966
11967
2.16M
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11968
2.16M
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11969
2.16M
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11970
2.16M
    const xmlChar *prefix = op->value4;
11971
2.16M
    const xmlChar *name = op->value5;
11972
2.16M
    const xmlChar *URI = NULL;
11973
11974
#ifdef DEBUG_STEP
11975
    int nbMatches = 0, prevMatches = 0;
11976
#endif
11977
2.16M
    int total = 0, hasNsNodes = 0;
11978
    /* The popped object holding the context nodes */
11979
2.16M
    xmlXPathObjectPtr obj;
11980
    /* The set of context nodes for the node tests */
11981
2.16M
    xmlNodeSetPtr contextSeq;
11982
2.16M
    int contextIdx;
11983
2.16M
    xmlNodePtr contextNode;
11984
    /* The final resulting node set wrt to all context nodes */
11985
2.16M
    xmlNodeSetPtr outSeq;
11986
    /*
11987
    * The temporary resulting node set wrt 1 context node.
11988
    * Used to feed predicate evaluation.
11989
    */
11990
2.16M
    xmlNodeSetPtr seq;
11991
2.16M
    xmlNodePtr cur;
11992
    /* First predicate operator */
11993
2.16M
    xmlXPathStepOpPtr predOp;
11994
2.16M
    int maxPos; /* The requested position() (when a "[n]" predicate) */
11995
2.16M
    int hasPredicateRange, hasAxisRange, pos;
11996
2.16M
    int breakOnFirstHit;
11997
11998
2.16M
    xmlXPathTraversalFunction next = NULL;
11999
2.16M
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12000
2.16M
    xmlXPathNodeSetMergeFunction mergeAndClear;
12001
2.16M
    xmlNodePtr oldContextNode;
12002
2.16M
    xmlXPathContextPtr xpctxt = ctxt->context;
12003
12004
12005
2.16M
    CHECK_TYPE0(XPATH_NODESET);
12006
2.16M
    obj = valuePop(ctxt);
12007
    /*
12008
    * Setup namespaces.
12009
    */
12010
2.16M
    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.14M
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12031
2.14M
    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.16M
        case AXIS_CHILD:
12047
1.16M
      last = NULL;
12048
1.16M
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12049
1.16M
    (type == NODE_TYPE_NODE))
12050
1.10M
      {
12051
    /*
12052
    * Optimization if an element node type is 'element'.
12053
    */
12054
1.10M
    next = xmlXPathNextChildElement;
12055
1.10M
      } else
12056
52.8k
    next = xmlXPathNextChild;
12057
1.16M
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058
1.16M
            break;
12059
128k
        case AXIS_DESCENDANT:
12060
128k
      last = NULL;
12061
128k
            next = xmlXPathNextDescendant;
12062
128k
            break;
12063
29.1k
        case AXIS_DESCENDANT_OR_SELF:
12064
29.1k
      last = NULL;
12065
29.1k
            next = xmlXPathNextDescendantOrSelf;
12066
29.1k
            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
94.7k
        case AXIS_NAMESPACE:
12076
94.7k
            first = NULL;
12077
94.7k
      last = NULL;
12078
94.7k
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12079
94.7k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080
94.7k
            break;
12081
30.4k
        case AXIS_PARENT:
12082
30.4k
            first = NULL;
12083
30.4k
            next = xmlXPathNextParent;
12084
30.4k
            break;
12085
0
        case AXIS_PRECEDING:
12086
0
            first = NULL;
12087
0
            next = xmlXPathNextPrecedingInternal;
12088
0
            break;
12089
0
        case AXIS_PRECEDING_SIBLING:
12090
0
            first = NULL;
12091
0
            next = xmlXPathNextPrecedingSibling;
12092
0
            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.14M
    }
12100
12101
#ifdef DEBUG_STEP
12102
    xmlXPathDebugDumpStepAxis(op,
12103
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12104
#endif
12105
12106
2.14M
    if (next == NULL) {
12107
0
  xmlXPathReleaseObject(xpctxt, obj);
12108
0
        return(0);
12109
0
    }
12110
2.14M
    contextSeq = obj->nodesetval;
12111
2.14M
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12112
421k
  xmlXPathReleaseObject(xpctxt, obj);
12113
421k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12114
421k
        return(0);
12115
421k
    }
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.72M
    maxPos = 0;
12135
1.72M
    predOp = NULL;
12136
1.72M
    hasPredicateRange = 0;
12137
1.72M
    hasAxisRange = 0;
12138
1.72M
    if (op->ch2 != -1) {
12139
  /*
12140
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12141
  */
12142
69.2k
  predOp = &ctxt->comp->steps[op->ch2];
12143
69.2k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12144
29.2k
      if (predOp->ch1 != -1) {
12145
    /*
12146
    * Use the next inner predicate operator.
12147
    */
12148
8.01k
    predOp = &ctxt->comp->steps[predOp->ch1];
12149
8.01k
    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.2k
  }
12158
69.2k
    }
12159
1.72M
    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.72M
    oldContextNode = xpctxt->node;
12174
1.72M
    addNode = xmlXPathNodeSetAddUnique;
12175
1.72M
    outSeq = NULL;
12176
1.72M
    seq = NULL;
12177
1.72M
    contextNode = NULL;
12178
1.72M
    contextIdx = 0;
12179
12180
12181
4.62M
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12182
4.62M
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12183
2.92M
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12184
12185
2.92M
  if (seq == NULL) {
12186
1.74M
      seq = xmlXPathNodeSetCreate(NULL);
12187
1.74M
      if (seq == NULL) {
12188
                /* TODO: Propagate memory error. */
12189
7.88k
    total = 0;
12190
7.88k
    goto error;
12191
7.88k
      }
12192
1.74M
  }
12193
  /*
12194
  * Traverse the axis and test the nodes.
12195
  */
12196
2.91M
  pos = 0;
12197
2.91M
  cur = NULL;
12198
2.91M
  hasNsNodes = 0;
12199
11.7M
        do {
12200
11.7M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12201
290
                goto error;
12202
12203
11.7M
            cur = next(ctxt, cur);
12204
11.7M
            if (cur == NULL)
12205
2.83M
                break;
12206
12207
      /*
12208
      * QUESTION TODO: What does the "first" and "last" stuff do?
12209
      */
12210
8.88M
            if ((first != NULL) && (*first != NULL)) {
12211
0
    if (*first == cur)
12212
0
        break;
12213
0
    if (((total % 256) == 0) &&
12214
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12215
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12216
#else
12217
        (xmlXPathCmpNodes(*first, cur) >= 0))
12218
#endif
12219
0
    {
12220
0
        break;
12221
0
    }
12222
0
      }
12223
8.88M
      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
8.88M
            total++;
12238
12239
#ifdef DEBUG_STEP
12240
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12241
#endif
12242
12243
8.88M
      switch (test) {
12244
0
                case NODE_TEST_NONE:
12245
0
        total = 0;
12246
0
                    STRANGE
12247
0
        goto error;
12248
4.69M
                case NODE_TEST_TYPE:
12249
4.69M
        if (type == NODE_TYPE_NODE) {
12250
3.49M
      switch (cur->type) {
12251
33.3k
          case XML_DOCUMENT_NODE:
12252
33.3k
          case XML_HTML_DOCUMENT_NODE:
12253
2.06M
          case XML_ELEMENT_NODE:
12254
2.06M
          case XML_ATTRIBUTE_NODE:
12255
2.15M
          case XML_PI_NODE:
12256
2.22M
          case XML_COMMENT_NODE:
12257
2.22M
          case XML_CDATA_SECTION_NODE:
12258
3.48M
          case XML_TEXT_NODE:
12259
3.48M
        XP_TEST_HIT
12260
3.47M
        break;
12261
3.47M
          case XML_NAMESPACE_DECL: {
12262
12.7k
        if (axis == AXIS_NAMESPACE) {
12263
3.04k
            XP_TEST_HIT_NS
12264
9.68k
        } else {
12265
9.68k
                              hasNsNodes = 1;
12266
9.68k
            XP_TEST_HIT
12267
9.68k
        }
12268
12.3k
        break;
12269
12.7k
                            }
12270
12.3k
          default:
12271
0
        break;
12272
3.49M
      }
12273
3.49M
        } else if (cur->type == (xmlElementType) type) {
12274
272k
      if (cur->type == XML_NAMESPACE_DECL)
12275
0
          XP_TEST_HIT_NS
12276
272k
      else
12277
272k
          XP_TEST_HIT
12278
930k
        } else if ((type == NODE_TYPE_TEXT) &&
12279
930k
       (cur->type == XML_CDATA_SECTION_NODE))
12280
0
        {
12281
0
      XP_TEST_HIT
12282
0
        }
12283
4.64M
        break;
12284
4.64M
                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
1.46M
                case NODE_TEST_ALL:
12292
1.46M
                    if (axis == AXIS_ATTRIBUTE) {
12293
17.4k
                        if (cur->type == XML_ATTRIBUTE_NODE)
12294
17.4k
      {
12295
17.4k
                            if (prefix == NULL)
12296
17.4k
          {
12297
17.4k
        XP_TEST_HIT
12298
17.4k
                            } else if ((cur->ns != NULL) &&
12299
0
        (xmlStrEqual(URI, cur->ns->href)))
12300
0
          {
12301
0
        XP_TEST_HIT
12302
0
                            }
12303
17.4k
                        }
12304
1.44M
                    } else if (axis == AXIS_NAMESPACE) {
12305
336k
                        if (cur->type == XML_NAMESPACE_DECL)
12306
336k
      {
12307
336k
          XP_TEST_HIT_NS
12308
336k
                        }
12309
1.10M
                    } else {
12310
1.10M
                        if (cur->type == XML_ELEMENT_NODE) {
12311
801k
                            if (prefix == NULL)
12312
798k
          {
12313
798k
        XP_TEST_HIT
12314
12315
798k
                            } else if ((cur->ns != NULL) &&
12316
2.99k
        (xmlStrEqual(URI, cur->ns->href)))
12317
116
          {
12318
116
        XP_TEST_HIT
12319
116
                            }
12320
801k
                        }
12321
1.10M
                    }
12322
1.43M
                    break;
12323
1.43M
                case NODE_TEST_NS:{
12324
0
                        TODO;
12325
0
                        break;
12326
1.46M
                    }
12327
2.70M
                case NODE_TEST_NAME:
12328
2.70M
                    if (axis == AXIS_ATTRIBUTE) {
12329
785k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12330
0
          break;
12331
1.91M
        } else if (axis == AXIS_NAMESPACE) {
12332
117k
                        if (cur->type != XML_NAMESPACE_DECL)
12333
0
          break;
12334
1.79M
        } else {
12335
1.79M
            if (cur->type != XML_ELEMENT_NODE)
12336
425k
          break;
12337
1.79M
        }
12338
2.27M
                    switch (cur->type) {
12339
1.37M
                        case XML_ELEMENT_NODE:
12340
1.37M
                            if (xmlStrEqual(name, cur->name)) {
12341
168k
                                if (prefix == NULL) {
12342
85.1k
                                    if (cur->ns == NULL)
12343
84.8k
            {
12344
84.8k
          XP_TEST_HIT
12345
84.8k
                                    }
12346
85.1k
                                } 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.37M
                            break;
12355
1.37M
                        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.27M
                    }
12390
2.27M
                    break;
12391
8.88M
      } /* switch(test) */
12392
8.88M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12393
12394
2.83M
  goto apply_predicates;
12395
12396
2.83M
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
2.83M
apply_predicates: /* --------------------------------------------------- */
12435
2.83M
        if (ctxt->error != XPATH_EXPRESSION_OK)
12436
271
      goto error;
12437
12438
        /*
12439
  * Apply predicates.
12440
  */
12441
2.83M
        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
106k
      if (hasPredicateRange != 0)
12471
15.0k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12472
15.0k
              hasNsNodes);
12473
91.1k
      else
12474
91.1k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12475
91.1k
              hasNsNodes);
12476
12477
106k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12478
5.39k
    total = 0;
12479
5.39k
    goto error;
12480
5.39k
      }
12481
106k
        }
12482
12483
2.82M
        if (seq->nodeNr > 0) {
12484
      /*
12485
      * Add to result set.
12486
      */
12487
1.13M
      if (outSeq == NULL) {
12488
876k
    outSeq = seq;
12489
876k
    seq = NULL;
12490
876k
      } else {
12491
                /* TODO: Check memory error. */
12492
263k
    outSeq = mergeAndClear(outSeq, seq);
12493
263k
      }
12494
12495
1.13M
            if (toBool)
12496
1.81k
                break;
12497
1.13M
  }
12498
2.82M
    }
12499
12500
1.72M
error:
12501
1.72M
    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.72M
    xmlXPathReleaseObject(xpctxt, obj);
12513
12514
    /*
12515
    * Ensure we return at least an empty set.
12516
    */
12517
1.72M
    if (outSeq == NULL) {
12518
824k
  if ((seq != NULL) && (seq->nodeNr == 0))
12519
816k
      outSeq = seq;
12520
7.95k
  else
12521
            /* TODO: Check memory error. */
12522
7.95k
      outSeq = xmlXPathNodeSetCreate(NULL);
12523
824k
    }
12524
1.72M
    if ((seq != NULL) && (seq != outSeq)) {
12525
26.7k
   xmlXPathFreeNodeSet(seq);
12526
26.7k
    }
12527
    /*
12528
    * Hand over the result. Better to push the set also in
12529
    * case of errors.
12530
    */
12531
1.72M
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12532
    /*
12533
    * Reset the context node.
12534
    */
12535
1.72M
    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.72M
    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.72M
    return(total);
12552
1.72M
}
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
48.5k
{
12573
48.5k
    int total = 0, cur;
12574
48.5k
    xmlXPathCompExprPtr comp;
12575
48.5k
    xmlXPathObjectPtr arg1, arg2;
12576
12577
48.5k
    CHECK_ERROR0;
12578
48.5k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12579
1
        return(0);
12580
48.5k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12581
48.5k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12582
48.5k
    ctxt->context->depth += 1;
12583
48.5k
    comp = ctxt->comp;
12584
48.5k
    switch (op->op) {
12585
0
        case XPATH_OP_END:
12586
0
            break;
12587
6.91k
        case XPATH_OP_UNION:
12588
6.91k
            total =
12589
6.91k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12590
6.91k
                                        first);
12591
6.91k
      CHECK_ERROR0;
12592
6.44k
            if ((ctxt->value != NULL)
12593
6.44k
                && (ctxt->value->type == XPATH_NODESET)
12594
6.44k
                && (ctxt->value->nodesetval != NULL)
12595
6.44k
                && (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
4
    if (ctxt->value->nodesetval->nodeNr > 1)
12607
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12608
4
                *first = ctxt->value->nodesetval->nodeTab[0];
12609
4
            }
12610
6.44k
            cur =
12611
6.44k
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12612
6.44k
                                        first);
12613
6.44k
      CHECK_ERROR0;
12614
12615
6.37k
            arg2 = valuePop(ctxt);
12616
6.37k
            arg1 = valuePop(ctxt);
12617
6.37k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12618
6.37k
                (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
6.37k
            if ((ctxt->context->opLimit != 0) &&
12624
6.37k
                (((arg1->nodesetval != NULL) &&
12625
6.37k
                  (xmlXPathCheckOpLimit(ctxt,
12626
3.38k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12627
6.37k
                 ((arg2->nodesetval != NULL) &&
12628
6.37k
                  (xmlXPathCheckOpLimit(ctxt,
12629
6.00k
                                        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
6.37k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12637
6.37k
                                                    arg2->nodesetval);
12638
6.37k
            valuePush(ctxt, arg1);
12639
6.37k
      xmlXPathReleaseObject(ctxt->context, arg2);
12640
            /* optimizer */
12641
6.37k
      if (total > cur)
12642
245
    xmlXPathCompSwap(op);
12643
6.37k
            total += cur;
12644
6.37k
            break;
12645
4
        case XPATH_OP_ROOT:
12646
4
            xmlXPathRoot(ctxt);
12647
4
            break;
12648
145
        case XPATH_OP_NODE:
12649
145
            if (op->ch1 != -1)
12650
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12651
145
      CHECK_ERROR0;
12652
145
            if (op->ch2 != -1)
12653
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12654
145
      CHECK_ERROR0;
12655
145
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12656
145
    ctxt->context->node));
12657
145
            break;
12658
12.9k
        case XPATH_OP_COLLECT:{
12659
12.9k
                if (op->ch1 == -1)
12660
0
                    break;
12661
12662
12.9k
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12663
12.9k
    CHECK_ERROR0;
12664
12665
12.8k
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12666
12.8k
                break;
12667
12.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.20k
        case XPATH_OP_SORT:
12674
7.20k
            if (op->ch1 != -1)
12675
7.20k
                total +=
12676
7.20k
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12677
7.20k
                                            first);
12678
7.20k
      CHECK_ERROR0;
12679
6.76k
            if ((ctxt->value != NULL)
12680
6.76k
                && (ctxt->value->type == XPATH_NODESET)
12681
6.76k
                && (ctxt->value->nodesetval != NULL)
12682
6.76k
    && (ctxt->value->nodesetval->nodeNr > 1))
12683
33
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12684
6.76k
            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
48.5k
    }
12694
12695
47.5k
    ctxt->context->depth -= 1;
12696
47.5k
    return(total);
12697
48.5k
}
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
146k
{
12714
146k
    int total = 0, cur;
12715
146k
    xmlXPathCompExprPtr comp;
12716
146k
    xmlXPathObjectPtr arg1, arg2;
12717
12718
146k
    CHECK_ERROR0;
12719
146k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12720
1
        return(0);
12721
146k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12722
146k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12723
146k
    ctxt->context->depth += 1;
12724
146k
    comp = ctxt->comp;
12725
146k
    switch (op->op) {
12726
0
        case XPATH_OP_END:
12727
0
            break;
12728
22.2k
        case XPATH_OP_UNION:
12729
22.2k
            total =
12730
22.2k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12731
22.2k
      CHECK_ERROR0;
12732
21.9k
            if ((ctxt->value != NULL)
12733
21.9k
                && (ctxt->value->type == XPATH_NODESET)
12734
21.9k
                && (ctxt->value->nodesetval != NULL)
12735
21.9k
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12736
                /*
12737
                 * limit tree traversing to first node in the result
12738
                 */
12739
6.34k
    if (ctxt->value->nodesetval->nodeNr > 1)
12740
5.93k
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741
6.34k
                *last =
12742
6.34k
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12743
6.34k
                                                     nodesetval->nodeNr -
12744
6.34k
                                                     1];
12745
6.34k
            }
12746
21.9k
            cur =
12747
21.9k
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12748
21.9k
      CHECK_ERROR0;
12749
21.7k
            if ((ctxt->value != NULL)
12750
21.7k
                && (ctxt->value->type == XPATH_NODESET)
12751
21.7k
                && (ctxt->value->nodesetval != NULL)
12752
21.7k
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12753
6.36k
            }
12754
12755
21.7k
            arg2 = valuePop(ctxt);
12756
21.7k
            arg1 = valuePop(ctxt);
12757
21.7k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12758
21.7k
                (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
21.7k
            if ((ctxt->context->opLimit != 0) &&
12764
21.7k
                (((arg1->nodesetval != NULL) &&
12765
21.7k
                  (xmlXPathCheckOpLimit(ctxt,
12766
18.6k
                                        arg1->nodesetval->nodeNr) < 0)) ||
12767
21.7k
                 ((arg2->nodesetval != NULL) &&
12768
21.6k
                  (xmlXPathCheckOpLimit(ctxt,
12769
21.0k
                                        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
21.6k
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12777
21.6k
                                                    arg2->nodesetval);
12778
21.6k
            valuePush(ctxt, arg1);
12779
21.6k
      xmlXPathReleaseObject(ctxt->context, arg2);
12780
            /* optimizer */
12781
21.6k
      if (total > cur)
12782
5.99k
    xmlXPathCompSwap(op);
12783
21.6k
            total += cur;
12784
21.6k
            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
69.4k
        case XPATH_OP_COLLECT:{
12799
69.4k
                if (op->ch1 == -1)
12800
0
                    break;
12801
12802
69.4k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12803
69.4k
    CHECK_ERROR0;
12804
12805
69.3k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12806
69.3k
                break;
12807
69.4k
            }
12808
3
        case XPATH_OP_VALUE:
12809
3
            valuePush(ctxt,
12810
3
                      xmlXPathCacheObjectCopy(ctxt->context,
12811
3
      (xmlXPathObjectPtr) op->value4));
12812
3
            break;
12813
50.9k
        case XPATH_OP_SORT:
12814
50.9k
            if (op->ch1 != -1)
12815
50.9k
                total +=
12816
50.9k
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12817
50.9k
                                           last);
12818
50.9k
      CHECK_ERROR0;
12819
50.3k
            if ((ctxt->value != NULL)
12820
50.3k
                && (ctxt->value->type == XPATH_NODESET)
12821
50.3k
                && (ctxt->value->nodesetval != NULL)
12822
50.3k
    && (ctxt->value->nodesetval->nodeNr > 1))
12823
6.01k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12824
50.3k
            break;
12825
2.96k
        default:
12826
2.96k
            total += xmlXPathCompOpEval(ctxt, op);
12827
2.96k
            break;
12828
146k
    }
12829
12830
144k
    ctxt->context->depth -= 1;
12831
144k
    return (total);
12832
146k
}
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
13.4M
{
12939
13.4M
    int total = 0;
12940
13.4M
    int equal, ret;
12941
13.4M
    xmlXPathCompExprPtr comp;
12942
13.4M
    xmlXPathObjectPtr arg1, arg2;
12943
12944
13.4M
    CHECK_ERROR0;
12945
13.4M
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12946
10.7k
        return(0);
12947
13.4M
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12948
13.4M
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12949
13.4M
    ctxt->context->depth += 1;
12950
13.4M
    comp = ctxt->comp;
12951
13.4M
    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
17.7k
        case XPATH_OP_OR:
12972
17.7k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12973
17.7k
      CHECK_ERROR0;
12974
16.8k
            xmlXPathBooleanFunction(ctxt, 1);
12975
16.8k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12976
3.69k
                break;
12977
13.1k
            arg2 = valuePop(ctxt);
12978
13.1k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12979
13.1k
      if (ctxt->error) {
12980
665
    xmlXPathFreeObject(arg2);
12981
665
    break;
12982
665
      }
12983
12.4k
            xmlXPathBooleanFunction(ctxt, 1);
12984
12.4k
            if (ctxt->value != NULL)
12985
12.1k
                ctxt->value->boolval |= arg2->boolval;
12986
12.4k
      xmlXPathReleaseObject(ctxt->context, arg2);
12987
12.4k
            break;
12988
388k
        case XPATH_OP_EQUAL:
12989
388k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12990
388k
      CHECK_ERROR0;
12991
367k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12992
367k
      CHECK_ERROR0;
12993
350k
      if (op->value)
12994
291k
    equal = xmlXPathEqualValues(ctxt);
12995
59.0k
      else
12996
59.0k
    equal = xmlXPathNotEqualValues(ctxt);
12997
350k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12998
350k
            break;
12999
403k
        case XPATH_OP_CMP:
13000
403k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13001
403k
      CHECK_ERROR0;
13002
374k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13003
374k
      CHECK_ERROR0;
13004
322k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13005
322k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13006
322k
            break;
13007
207k
        case XPATH_OP_PLUS:
13008
207k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13009
207k
      CHECK_ERROR0;
13010
194k
            if (op->ch2 != -1) {
13011
138k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13012
138k
      }
13013
194k
      CHECK_ERROR0;
13014
185k
            if (op->value == 0)
13015
75.3k
                xmlXPathSubValues(ctxt);
13016
110k
            else if (op->value == 1)
13017
54.5k
                xmlXPathAddValues(ctxt);
13018
55.6k
            else if (op->value == 2)
13019
32.5k
                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
184k
            break;
13025
267k
        case XPATH_OP_MULT:
13026
267k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13027
267k
      CHECK_ERROR0;
13028
153k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13029
153k
      CHECK_ERROR0;
13030
150k
            if (op->value == 0)
13031
93.6k
                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
150k
            break;
13037
237k
        case XPATH_OP_UNION:
13038
237k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13039
237k
      CHECK_ERROR0;
13040
231k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13041
231k
      CHECK_ERROR0;
13042
13043
223k
            arg2 = valuePop(ctxt);
13044
223k
            arg1 = valuePop(ctxt);
13045
223k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13046
223k
                (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
222k
            if ((ctxt->context->opLimit != 0) &&
13052
222k
                (((arg1->nodesetval != NULL) &&
13053
222k
                  (xmlXPathCheckOpLimit(ctxt,
13054
203k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13055
222k
                 ((arg2->nodesetval != NULL) &&
13056
222k
                  (xmlXPathCheckOpLimit(ctxt,
13057
199k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13058
9
          xmlXPathReleaseObject(ctxt->context, arg1);
13059
9
          xmlXPathReleaseObject(ctxt->context, arg2);
13060
9
                break;
13061
9
            }
13062
13063
222k
      if ((arg1->nodesetval == NULL) ||
13064
222k
    ((arg2->nodesetval != NULL) &&
13065
203k
     (arg2->nodesetval->nodeNr != 0)))
13066
112k
      {
13067
                /* TODO: Check memory error. */
13068
112k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13069
112k
              arg2->nodesetval);
13070
112k
      }
13071
13072
222k
            valuePush(ctxt, arg1);
13073
222k
      xmlXPathReleaseObject(ctxt->context, arg2);
13074
222k
            break;
13075
680k
        case XPATH_OP_ROOT:
13076
680k
            xmlXPathRoot(ctxt);
13077
680k
            break;
13078
2.04M
        case XPATH_OP_NODE:
13079
2.04M
            if (op->ch1 != -1)
13080
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13081
2.04M
      CHECK_ERROR0;
13082
2.04M
            if (op->ch2 != -1)
13083
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13084
2.04M
      CHECK_ERROR0;
13085
2.04M
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13086
2.04M
    ctxt->context->node));
13087
2.04M
            break;
13088
2.10M
        case XPATH_OP_COLLECT:{
13089
2.10M
                if (op->ch1 == -1)
13090
0
                    break;
13091
13092
2.10M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13093
2.10M
    CHECK_ERROR0;
13094
13095
2.06M
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13096
2.06M
                break;
13097
2.10M
            }
13098
362k
        case XPATH_OP_VALUE:
13099
362k
            valuePush(ctxt,
13100
362k
                      xmlXPathCacheObjectCopy(ctxt->context,
13101
362k
      (xmlXPathObjectPtr) op->value4));
13102
362k
            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.55M
        case XPATH_OP_FUNCTION:{
13134
1.55M
                xmlXPathFunction func;
13135
1.55M
                const xmlChar *oldFunc, *oldFuncURI;
13136
1.55M
    int i;
13137
1.55M
                int frame;
13138
13139
1.55M
                frame = ctxt->valueNr;
13140
1.55M
                if (op->ch1 != -1) {
13141
1.31M
                    total +=
13142
1.31M
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13143
1.31M
                    if (ctxt->error != XPATH_EXPRESSION_OK)
13144
21.1k
                        break;
13145
1.31M
                }
13146
1.53M
    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.41M
    for (i = 0; i < op->value; i++) {
13153
1.88M
        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
1.88M
                }
13160
1.53M
                if (op->cache != NULL)
13161
1.04M
                    func = op->cache;
13162
487k
                else {
13163
487k
                    const xmlChar *URI = NULL;
13164
13165
487k
                    if (op->value5 == NULL)
13166
33.3k
                        func =
13167
33.3k
                            xmlXPathFunctionLookup(ctxt->context,
13168
33.3k
                                                   op->value4);
13169
453k
                    else {
13170
453k
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13171
453k
                        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
446k
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13179
446k
                                                        op->value4, URI);
13180
446k
                    }
13181
479k
                    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
468k
                    op->cache = func;
13188
468k
                    op->cacheURI = (void *) URI;
13189
468k
                }
13190
1.51M
                oldFunc = ctxt->context->function;
13191
1.51M
                oldFuncURI = ctxt->context->functionURI;
13192
1.51M
                ctxt->context->function = op->value4;
13193
1.51M
                ctxt->context->functionURI = op->cacheURI;
13194
1.51M
                func(ctxt, op->value);
13195
1.51M
                ctxt->context->function = oldFunc;
13196
1.51M
                ctxt->context->functionURI = oldFuncURI;
13197
1.51M
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13198
1.51M
                    (ctxt->valueNr != frame + 1))
13199
1.51M
                    XP_ERROR0(XPATH_STACK_ERROR);
13200
1.51M
                break;
13201
1.51M
            }
13202
1.91M
        case XPATH_OP_ARG:
13203
1.91M
            if (op->ch1 != -1) {
13204
603k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13205
603k
          CHECK_ERROR0;
13206
603k
            }
13207
1.91M
            if (op->ch2 != -1) {
13208
1.91M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13209
1.91M
          CHECK_ERROR0;
13210
1.91M
      }
13211
1.89M
            break;
13212
1.89M
        case XPATH_OP_PREDICATE:
13213
152k
        case XPATH_OP_FILTER:{
13214
152k
                xmlXPathObjectPtr obj;
13215
152k
                xmlNodeSetPtr set;
13216
13217
                /*
13218
                 * Optimization for ()[1] selection i.e. the first elem
13219
                 */
13220
152k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13221
152k
#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
152k
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13232
152k
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13233
#else
13234
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13235
#endif
13236
152k
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13237
85.6k
                    xmlXPathObjectPtr val;
13238
13239
85.6k
                    val = comp->steps[op->ch2].value4;
13240
85.6k
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13241
85.6k
                        (val->floatval == 1.0)) {
13242
28.0k
                        xmlNodePtr first = NULL;
13243
13244
28.0k
                        total +=
13245
28.0k
                            xmlXPathCompOpEvalFirst(ctxt,
13246
28.0k
                                                    &comp->steps[op->ch1],
13247
28.0k
                                                    &first);
13248
28.0k
      CHECK_ERROR0;
13249
                        /*
13250
                         * The nodeset should be in document order,
13251
                         * Keep only the first value
13252
                         */
13253
26.7k
                        if ((ctxt->value != NULL) &&
13254
26.7k
                            (ctxt->value->type == XPATH_NODESET) &&
13255
26.7k
                            (ctxt->value->nodesetval != NULL) &&
13256
26.7k
                            (ctxt->value->nodesetval->nodeNr > 1))
13257
33
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13258
33
                                                        1, 1);
13259
26.7k
                        break;
13260
28.0k
                    }
13261
85.6k
                }
13262
                /*
13263
                 * Optimization for ()[last()] selection i.e. the last elem
13264
                 */
13265
124k
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13266
124k
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13267
124k
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13268
49.0k
                    int f = comp->steps[op->ch2].ch1;
13269
13270
49.0k
                    if ((f != -1) &&
13271
49.0k
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13272
49.0k
                        (comp->steps[f].value5 == NULL) &&
13273
49.0k
                        (comp->steps[f].value == 0) &&
13274
49.0k
                        (comp->steps[f].value4 != NULL) &&
13275
49.0k
                        (xmlStrEqual
13276
45.7k
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13277
42.4k
                        xmlNodePtr last = NULL;
13278
13279
42.4k
                        total +=
13280
42.4k
                            xmlXPathCompOpEvalLast(ctxt,
13281
42.4k
                                                   &comp->steps[op->ch1],
13282
42.4k
                                                   &last);
13283
42.4k
      CHECK_ERROR0;
13284
                        /*
13285
                         * The nodeset should be in document order,
13286
                         * Keep only the last value
13287
                         */
13288
41.9k
                        if ((ctxt->value != NULL) &&
13289
41.9k
                            (ctxt->value->type == XPATH_NODESET) &&
13290
41.9k
                            (ctxt->value->nodesetval != NULL) &&
13291
41.9k
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13292
41.9k
                            (ctxt->value->nodesetval->nodeNr > 1))
13293
4.22k
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13294
41.9k
                        break;
13295
42.4k
                    }
13296
49.0k
                }
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
82.4k
                if (op->ch1 != -1)
13309
82.4k
                    total +=
13310
82.4k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311
82.4k
    CHECK_ERROR0;
13312
80.5k
                if (op->ch2 == -1)
13313
0
                    break;
13314
80.5k
                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
80.5k
                CHECK_TYPE0(XPATH_NODESET);
13336
79.8k
                obj = valuePop(ctxt);
13337
79.8k
                set = obj->nodesetval;
13338
79.8k
                if (set != NULL)
13339
75.3k
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13340
75.3k
                                          1, set->nodeNr, 1);
13341
79.8k
                valuePush(ctxt, obj);
13342
79.8k
                break;
13343
80.5k
            }
13344
2.98M
        case XPATH_OP_SORT:
13345
2.98M
            if (op->ch1 != -1)
13346
2.98M
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13347
2.98M
      CHECK_ERROR0;
13348
2.83M
            if ((ctxt->value != NULL) &&
13349
2.83M
                (ctxt->value->type == XPATH_NODESET) &&
13350
2.83M
                (ctxt->value->nodesetval != NULL) &&
13351
2.83M
    (ctxt->value->nodesetval->nodeNr > 1))
13352
84.2k
      {
13353
84.2k
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13354
84.2k
      }
13355
2.83M
            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
13.4M
    }
13521
13522
12.9M
    ctxt->context->depth -= 1;
13523
12.9M
    return (total);
13524
13.4M
}
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
413k
{
13539
413k
    xmlXPathObjectPtr resObj = NULL;
13540
13541
443k
start:
13542
443k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13543
4
        return(0);
13544
    /* comp = ctxt->comp; */
13545
443k
    switch (op->op) {
13546
0
        case XPATH_OP_END:
13547
0
            return (0);
13548
35.2k
  case XPATH_OP_VALUE:
13549
35.2k
      resObj = (xmlXPathObjectPtr) op->value4;
13550
35.2k
      if (isPredicate)
13551
35.2k
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13552
19
      return(xmlXPathCastToBoolean(resObj));
13553
30.4k
  case XPATH_OP_SORT:
13554
      /*
13555
      * We don't need sorting for boolean results. Skip this one.
13556
      */
13557
30.4k
            if (op->ch1 != -1) {
13558
30.4k
    op = &ctxt->comp->steps[op->ch1];
13559
30.4k
    goto start;
13560
30.4k
      }
13561
0
      return(0);
13562
27.9k
  case XPATH_OP_COLLECT:
13563
27.9k
      if (op->ch1 == -1)
13564
0
    return(0);
13565
13566
27.9k
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13567
27.9k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13568
364
    return(-1);
13569
13570
27.6k
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13571
27.6k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13572
728
    return(-1);
13573
13574
26.8k
      resObj = valuePop(ctxt);
13575
26.8k
      if (resObj == NULL)
13576
0
    return(-1);
13577
26.8k
      break;
13578
349k
  default:
13579
      /*
13580
      * Fallback to call xmlXPathCompOpEval().
13581
      */
13582
349k
      xmlXPathCompOpEval(ctxt, op);
13583
349k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13584
4.39k
    return(-1);
13585
13586
345k
      resObj = valuePop(ctxt);
13587
345k
      if (resObj == NULL)
13588
0
    return(-1);
13589
345k
      break;
13590
443k
    }
13591
13592
372k
    if (resObj) {
13593
372k
  int res;
13594
13595
372k
  if (resObj->type == XPATH_BOOLEAN) {
13596
137k
      res = resObj->boolval;
13597
234k
  } 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
232k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13607
232k
  } else {
13608
2.47k
      res = xmlXPathCastToBoolean(resObj);
13609
2.47k
  }
13610
372k
  xmlXPathReleaseObject(ctxt->context, resObj);
13611
372k
  return(res);
13612
372k
    }
13613
13614
0
    return(0);
13615
372k
}
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
578k
    if (from_root) {
13684
11.3k
        cur = (xmlNodePtr)ctxt->doc;
13685
567k
    } else if (ctxt->node != NULL) {
13686
567k
        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
567k
  }
13711
567k
  limit = cur;
13712
567k
    }
13713
578k
    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
284k
      default:
13786
284k
    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
964k
  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
260k
          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.65M
{
13863
2.65M
    xmlXPathCompExprPtr comp;
13864
2.65M
    int oldDepth;
13865
13866
2.65M
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13867
0
  return(-1);
13868
13869
2.65M
    if (ctxt->valueTab == NULL) {
13870
  /* Allocate the value stack */
13871
82.9k
  ctxt->valueTab = (xmlXPathObjectPtr *)
13872
82.9k
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13873
82.9k
  if (ctxt->valueTab == NULL) {
13874
21
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13875
21
      return(-1);
13876
21
  }
13877
82.8k
  ctxt->valueNr = 0;
13878
82.8k
  ctxt->valueMax = 10;
13879
82.8k
  ctxt->value = NULL;
13880
82.8k
    }
13881
2.65M
#ifdef XPATH_STREAMING
13882
2.65M
    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.18M
#endif
13915
1.18M
    comp = ctxt->comp;
13916
1.18M
    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.18M
    oldDepth = ctxt->context->depth;
13922
1.18M
    if (toBool)
13923
27.8k
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13924
27.8k
      &comp->steps[comp->last], 0));
13925
1.15M
    else
13926
1.15M
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13927
1.15M
    ctxt->context->depth = oldDepth;
13928
13929
1.15M
    return(0);
13930
1.18M
}
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
267k
                                xmlXPathObjectPtr res) {
13995
267k
    if ((ctxt == NULL) || (res == NULL)) return(0);
13996
267k
    switch (res->type) {
13997
0
        case XPATH_BOOLEAN:
13998
0
      return(res->boolval);
13999
203k
        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
203k
      return(res->floatval == ctxt->context->proximityPosition);
14005
0
#endif
14006
39.6k
        case XPATH_NODESET:
14007
39.6k
        case XPATH_XSLT_TREE:
14008
39.6k
      if (res->nodesetval == NULL)
14009
5.97k
    return(0);
14010
33.6k
      return(res->nodesetval->nodeNr != 0);
14011
23.8k
        case XPATH_STRING:
14012
23.8k
      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
267k
    }
14024
0
    return(0);
14025
267k
}
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
884k
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
884k
    xmlPatternPtr stream;
14044
884k
    xmlXPathCompExprPtr comp;
14045
884k
    xmlDictPtr dict = NULL;
14046
884k
    const xmlChar **namespaces = NULL;
14047
884k
    xmlNsPtr ns;
14048
884k
    int i, j;
14049
14050
884k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14051
884k
        (!xmlStrchr(str, '@'))) {
14052
452k
  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
452k
  tmp = xmlStrchr(str, ':');
14064
452k
  if ((tmp != NULL) &&
14065
452k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14066
9.96k
      return(NULL);
14067
14068
442k
  if (ctxt != NULL) {
14069
442k
      dict = ctxt->dict;
14070
442k
      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
442k
  }
14085
14086
442k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14087
442k
  if (namespaces != NULL) {
14088
309k
      xmlFree((xmlChar **)namespaces);
14089
309k
  }
14090
442k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14091
213k
      comp = xmlXPathNewCompExpr();
14092
213k
      if (comp == NULL) {
14093
17
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14094
17
          xmlFreePattern(stream);
14095
17
    return(NULL);
14096
17
      }
14097
213k
      comp->stream = stream;
14098
213k
      comp->dict = dict;
14099
213k
      if (comp->dict)
14100
25.3k
    xmlDictReference(comp->dict);
14101
213k
      return(comp);
14102
213k
  }
14103
229k
  xmlFreePattern(stream);
14104
229k
    }
14105
660k
    return(NULL);
14106
884k
}
14107
#endif /* XPATH_STREAMING */
14108
14109
static void
14110
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14111
                           xmlXPathStepOpPtr op)
14112
9.52M
{
14113
9.52M
    xmlXPathCompExprPtr comp = pctxt->comp;
14114
9.52M
    xmlXPathContextPtr ctxt;
14115
14116
    /*
14117
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14118
    * internal representation.
14119
    */
14120
14121
9.52M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14122
9.52M
        (op->ch1 != -1) &&
14123
9.52M
        (op->ch2 == -1 /* no predicate */))
14124
1.68M
    {
14125
1.68M
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14126
14127
1.68M
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14128
1.68M
            ((xmlXPathAxisVal) prevop->value ==
14129
201k
                AXIS_DESCENDANT_OR_SELF) &&
14130
1.68M
            (prevop->ch2 == -1) &&
14131
1.68M
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14132
1.68M
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14133
89.0k
        {
14134
            /*
14135
            * This is a "descendant-or-self::node()" without predicates.
14136
            * Try to eliminate it.
14137
            */
14138
14139
89.0k
            switch ((xmlXPathAxisVal) op->value) {
14140
84.9k
                case AXIS_CHILD:
14141
84.9k
                case AXIS_DESCENDANT:
14142
                    /*
14143
                    * Convert "descendant-or-self::node()/child::" or
14144
                    * "descendant-or-self::node()/descendant::" to
14145
                    * "descendant::"
14146
                    */
14147
84.9k
                    op->ch1   = prevop->ch1;
14148
84.9k
                    op->value = AXIS_DESCENDANT;
14149
84.9k
                    break;
14150
0
                case AXIS_SELF:
14151
207
                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
207
                    op->ch1   = prevop->ch1;
14158
207
                    op->value = AXIS_DESCENDANT_OR_SELF;
14159
207
                    break;
14160
3.84k
                default:
14161
3.84k
                    break;
14162
89.0k
            }
14163
89.0k
  }
14164
1.68M
    }
14165
14166
    /* OP_VALUE has invalid ch1. */
14167
9.52M
    if (op->op == XPATH_OP_VALUE)
14168
366k
        return;
14169
14170
    /* Recurse */
14171
9.16M
    ctxt = pctxt->context;
14172
9.16M
    if (ctxt != NULL) {
14173
9.16M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14174
22.4k
            return;
14175
9.13M
        ctxt->depth += 1;
14176
9.13M
    }
14177
9.13M
    if (op->ch1 != -1)
14178
6.26M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14179
9.13M
    if (op->ch2 != -1)
14180
2.93M
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14181
9.13M
    if (ctxt != NULL)
14182
9.13M
        ctxt->depth -= 1;
14183
9.13M
}
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
702k
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14197
702k
    xmlXPathParserContextPtr pctxt;
14198
702k
    xmlXPathCompExprPtr comp;
14199
702k
    int oldDepth = 0;
14200
14201
702k
#ifdef XPATH_STREAMING
14202
702k
    comp = xmlXPathTryStreamCompile(ctxt, str);
14203
702k
    if (comp != NULL)
14204
185k
        return(comp);
14205
517k
#endif
14206
14207
517k
    xmlInitParser();
14208
14209
517k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14210
517k
    if (pctxt == NULL)
14211
882
        return NULL;
14212
516k
    if (ctxt != NULL)
14213
516k
        oldDepth = ctxt->depth;
14214
516k
    xmlXPathCompileExpr(pctxt, 1);
14215
516k
    if (ctxt != NULL)
14216
516k
        ctxt->depth = oldDepth;
14217
14218
516k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14219
195k
    {
14220
195k
        xmlXPathFreeParserContext(pctxt);
14221
195k
        return(NULL);
14222
195k
    }
14223
14224
321k
    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.3k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14232
34.3k
  comp = NULL;
14233
286k
    } else {
14234
286k
  comp = pctxt->comp;
14235
286k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14236
282k
            if (ctxt != NULL)
14237
282k
                oldDepth = ctxt->depth;
14238
282k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14239
282k
            if (ctxt != NULL)
14240
282k
                ctxt->depth = oldDepth;
14241
282k
  }
14242
286k
  pctxt->comp = NULL;
14243
286k
    }
14244
321k
    xmlXPathFreeParserContext(pctxt);
14245
14246
321k
    if (comp != NULL) {
14247
286k
  comp->expr = xmlStrdup(str);
14248
#ifdef DEBUG_EVAL_COUNTS
14249
  comp->string = xmlStrdup(str);
14250
  comp->nb = 0;
14251
#endif
14252
286k
    }
14253
321k
    return(comp);
14254
516k
}
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.59M
{
14289
2.59M
    xmlXPathParserContextPtr pctxt;
14290
2.59M
    xmlXPathObjectPtr resObj;
14291
#ifndef LIBXML_THREAD_ENABLED
14292
    static int reentance = 0;
14293
#endif
14294
2.59M
    int res;
14295
14296
2.59M
    CHECK_CTXT_NEG(ctxt)
14297
14298
2.59M
    if (comp == NULL)
14299
308
  return(-1);
14300
2.59M
    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.59M
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14316
2.59M
    if (pctxt == NULL)
14317
18.2k
        return(-1);
14318
2.57M
    res = xmlXPathRunEval(pctxt, toBool);
14319
14320
2.57M
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14321
122k
        resObj = NULL;
14322
2.45M
    } else {
14323
2.45M
        resObj = valuePop(pctxt);
14324
2.45M
        if (resObj == NULL) {
14325
27.9k
            if (!toBool)
14326
48
                xmlGenericError(xmlGenericErrorContext,
14327
48
                    "xmlXPathCompiledEval: No result on the stack.\n");
14328
2.42M
        } 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.45M
    }
14334
14335
2.57M
    if (resObjPtr)
14336
2.54M
        *resObjPtr = resObj;
14337
27.9k
    else
14338
27.9k
        xmlXPathReleaseObject(ctxt, resObj);
14339
14340
2.57M
    pctxt->comp = NULL;
14341
2.57M
    xmlXPathFreeParserContext(pctxt);
14342
#ifndef LIBXML_THREAD_ENABLED
14343
    reentance--;
14344
#endif
14345
14346
2.57M
    return(res);
14347
2.59M
}
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.56M
{
14362
2.56M
    xmlXPathObjectPtr res = NULL;
14363
14364
2.56M
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14365
2.56M
    return(res);
14366
2.56M
}
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
181k
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14395
181k
#ifdef XPATH_STREAMING
14396
181k
    xmlXPathCompExprPtr comp;
14397
181k
#endif
14398
181k
    int oldDepth = 0;
14399
14400
181k
    if (ctxt == NULL) return;
14401
14402
181k
#ifdef XPATH_STREAMING
14403
181k
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14404
181k
    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.5k
        if (*ctxt->cur != 0)
14420
54.7k
            XP_ERROR(XPATH_EXPR_ERROR);
14421
14422
54.7k
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14423
48.5k
            if (ctxt->context != NULL)
14424
48.5k
                oldDepth = ctxt->context->depth;
14425
48.5k
      xmlXPathOptimizeExpression(ctxt,
14426
48.5k
    &ctxt->comp->steps[ctxt->comp->last]);
14427
48.5k
            if (ctxt->context != NULL)
14428
48.5k
                ctxt->context->depth = oldDepth;
14429
48.5k
        }
14430
54.7k
    }
14431
14432
82.9k
    xmlXPathRunEval(ctxt, 0);
14433
82.9k
}
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
181k
    xmlXPathEvalExpr(ctxt);
14458
14459
181k
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14460
116k
  res = NULL;
14461
116k
    } else {
14462
65.3k
  res = valuePop(ctxt);
14463
65.3k
        if (res == NULL) {
14464
1
            xmlGenericError(xmlGenericErrorContext,
14465
1
                "xmlXPathCompiledEval: No result on the stack.\n");
14466
65.3k
        } 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.3k
    }
14472
14473
181k
    xmlXPathFreeParserContext(ctxt);
14474
181k
    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.1k
{
14658
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14659
33.1k
                         xmlXPathBooleanFunction);
14660
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14661
33.1k
                         xmlXPathCeilingFunction);
14662
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14663
33.1k
                         xmlXPathCountFunction);
14664
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14665
33.1k
                         xmlXPathConcatFunction);
14666
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14667
33.1k
                         xmlXPathContainsFunction);
14668
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14669
33.1k
                         xmlXPathIdFunction);
14670
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14671
33.1k
                         xmlXPathFalseFunction);
14672
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14673
33.1k
                         xmlXPathFloorFunction);
14674
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14675
33.1k
                         xmlXPathLastFunction);
14676
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14677
33.1k
                         xmlXPathLangFunction);
14678
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14679
33.1k
                         xmlXPathLocalNameFunction);
14680
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14681
33.1k
                         xmlXPathNotFunction);
14682
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14683
33.1k
                         xmlXPathNameFunction);
14684
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14685
33.1k
                         xmlXPathNamespaceURIFunction);
14686
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14687
33.1k
                         xmlXPathNormalizeFunction);
14688
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14689
33.1k
                         xmlXPathNumberFunction);
14690
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14691
33.1k
                         xmlXPathPositionFunction);
14692
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14693
33.1k
                         xmlXPathRoundFunction);
14694
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14695
33.1k
                         xmlXPathStringFunction);
14696
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14697
33.1k
                         xmlXPathStringLengthFunction);
14698
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14699
33.1k
                         xmlXPathStartsWithFunction);
14700
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14701
33.1k
                         xmlXPathSubstringFunction);
14702
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14703
33.1k
                         xmlXPathSubstringBeforeFunction);
14704
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14705
33.1k
                         xmlXPathSubstringAfterFunction);
14706
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14707
33.1k
                         xmlXPathSumFunction);
14708
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14709
33.1k
                         xmlXPathTrueFunction);
14710
33.1k
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14711
33.1k
                         xmlXPathTranslateFunction);
14712
14713
33.1k
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14714
33.1k
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14715
33.1k
                         xmlXPathEscapeUriFunction);
14716
33.1k
}
14717
14718
#endif /* LIBXML_XPATH_ENABLED */