Coverage Report

Created: 2022-11-15 06:34

/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
55
#ifdef LIBXML_PATTERN_ENABLED
56
#define XPATH_STREAMING
57
#endif
58
59
#define TODO                \
60
0
    xmlGenericError(xmlGenericErrorContext,       \
61
0
      "Unimplemented block at %s:%d\n",       \
62
0
            __FILE__, __LINE__);
63
64
/**
65
 * WITH_TIM_SORT:
66
 *
67
 * Use the Timsort algorithm provided in timsort.h to sort
68
 * nodeset as this is a great improvement over the old Shell sort
69
 * used in xmlXPathNodeSetSort()
70
 */
71
#define WITH_TIM_SORT
72
73
/*
74
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
75
* If defined, this will use xmlXPathCmpNodesExt() instead of
76
* xmlXPathCmpNodes(). The new function is optimized comparison of
77
* non-element nodes; actually it will speed up comparison only if
78
* xmlXPathOrderDocElems() was called in order to index the elements of
79
* a tree in document order; Libxslt does such an indexing, thus it will
80
* benefit from this optimization.
81
*/
82
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
83
84
/*
85
* XP_OPTIMIZED_FILTER_FIRST:
86
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
87
* in a way, that it stop evaluation at the first node.
88
*/
89
#define XP_OPTIMIZED_FILTER_FIRST
90
91
/*
92
* XP_DEBUG_OBJ_USAGE:
93
* Internal flag to enable tracking of how much XPath objects have been
94
* created.
95
*/
96
/* #define XP_DEBUG_OBJ_USAGE */
97
98
/*
99
 * XPATH_MAX_STEPS:
100
 * when compiling an XPath expression we arbitrary limit the maximum
101
 * number of step operation in the compiled expression. 1000000 is
102
 * an insanely large value which should never be reached under normal
103
 * circumstances
104
 */
105
7.69k
#define XPATH_MAX_STEPS 1000000
106
107
/*
108
 * XPATH_MAX_STACK_DEPTH:
109
 * when evaluating an XPath expression we arbitrary limit the maximum
110
 * number of object allowed to be pushed on the stack. 1000000 is
111
 * an insanely large value which should never be reached under normal
112
 * circumstances
113
 */
114
0
#define XPATH_MAX_STACK_DEPTH 1000000
115
116
/*
117
 * XPATH_MAX_NODESET_LENGTH:
118
 * when evaluating an XPath expression nodesets are created and we
119
 * arbitrary limit the maximum length of those node set. 10000000 is
120
 * an insanely large value which should never be reached under normal
121
 * circumstances, one would first need to construct an in memory tree
122
 * with more than 10 millions nodes.
123
 */
124
11.1k
#define XPATH_MAX_NODESET_LENGTH 10000000
125
126
/*
127
 * XPATH_MAX_RECRUSION_DEPTH:
128
 * Maximum amount of nested functions calls when parsing or evaluating
129
 * expressions
130
 */
131
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
132
3.32M
#define XPATH_MAX_RECURSION_DEPTH 500
133
#elif defined(_WIN32)
134
/* Windows typically limits stack size to 1MB. */
135
#define XPATH_MAX_RECURSION_DEPTH 1000
136
#else
137
#define XPATH_MAX_RECURSION_DEPTH 5000
138
#endif
139
140
/*
141
 * TODO:
142
 * There are a few spots where some tests are done which depend upon ascii
143
 * data.  These should be enhanced for full UTF8 support (see particularly
144
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
145
 */
146
147
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
148
/**
149
 * xmlXPathCmpNodesExt:
150
 * @node1:  the first node
151
 * @node2:  the second node
152
 *
153
 * Compare two nodes w.r.t document order.
154
 * This one is optimized for handling of non-element nodes.
155
 *
156
 * Returns -2 in case of error 1 if first point < second point, 0 if
157
 *         it's the same node, -1 otherwise
158
 */
159
static int
160
16.1M
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
161
16.1M
    int depth1, depth2;
162
16.1M
    int misc = 0, precedence1 = 0, precedence2 = 0;
163
16.1M
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
164
16.1M
    xmlNodePtr cur, root;
165
16.1M
    ptrdiff_t l1, l2;
166
167
16.1M
    if ((node1 == NULL) || (node2 == NULL))
168
0
  return(-2);
169
170
16.1M
    if (node1 == node2)
171
0
  return(0);
172
173
    /*
174
     * a couple of optimizations which will avoid computations in most cases
175
     */
176
16.1M
    switch (node1->type) {
177
14.8M
  case XML_ELEMENT_NODE:
178
14.8M
      if (node2->type == XML_ELEMENT_NODE) {
179
13.2M
    if ((0 > (ptrdiff_t) node1->content) &&
180
13.2M
        (0 > (ptrdiff_t) node2->content) &&
181
13.2M
        (node1->doc == node2->doc))
182
4.04k
    {
183
4.04k
        l1 = -((ptrdiff_t) node1->content);
184
4.04k
        l2 = -((ptrdiff_t) node2->content);
185
4.04k
        if (l1 < l2)
186
3.99k
      return(1);
187
49
        if (l1 > l2)
188
49
      return(-1);
189
49
    } else
190
13.2M
        goto turtle_comparison;
191
13.2M
      }
192
1.64M
      break;
193
1.64M
  case XML_ATTRIBUTE_NODE:
194
234
      precedence1 = 1; /* element is owner */
195
234
      miscNode1 = node1;
196
234
      node1 = node1->parent;
197
234
      misc = 1;
198
234
      break;
199
1.23M
  case XML_TEXT_NODE:
200
1.24M
  case XML_CDATA_SECTION_NODE:
201
1.24M
  case XML_COMMENT_NODE:
202
1.24M
  case XML_PI_NODE: {
203
1.24M
      miscNode1 = node1;
204
      /*
205
      * Find nearest element node.
206
      */
207
1.24M
      if (node1->prev != NULL) {
208
37.5k
    do {
209
37.5k
        node1 = node1->prev;
210
37.5k
        if (node1->type == XML_ELEMENT_NODE) {
211
27.0k
      precedence1 = 3; /* element in prev-sibl axis */
212
27.0k
      break;
213
27.0k
        }
214
10.5k
        if (node1->prev == NULL) {
215
0
      precedence1 = 2; /* element is parent */
216
      /*
217
      * URGENT TODO: Are there any cases, where the
218
      * parent of such a node is not an element node?
219
      */
220
0
      node1 = node1->parent;
221
0
      break;
222
0
        }
223
10.5k
    } while (1);
224
1.21M
      } else {
225
1.21M
    precedence1 = 2; /* element is parent */
226
1.21M
    node1 = node1->parent;
227
1.21M
      }
228
1.24M
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
229
1.24M
    (0 <= (ptrdiff_t) node1->content)) {
230
    /*
231
    * Fallback for whatever case.
232
    */
233
1.20M
    node1 = miscNode1;
234
1.20M
    precedence1 = 0;
235
1.20M
      } else
236
40.0k
    misc = 1;
237
1.24M
  }
238
0
      break;
239
84
  case XML_NAMESPACE_DECL:
240
      /*
241
      * TODO: why do we return 1 for namespace nodes?
242
      */
243
84
      return(1);
244
74.2k
  default:
245
74.2k
      break;
246
16.1M
    }
247
2.96M
    switch (node2->type) {
248
1.01M
  case XML_ELEMENT_NODE:
249
1.01M
      break;
250
312
  case XML_ATTRIBUTE_NODE:
251
312
      precedence2 = 1; /* element is owner */
252
312
      miscNode2 = node2;
253
312
      node2 = node2->parent;
254
312
      misc = 1;
255
312
      break;
256
1.75M
  case XML_TEXT_NODE:
257
1.75M
  case XML_CDATA_SECTION_NODE:
258
1.75M
  case XML_COMMENT_NODE:
259
1.75M
  case XML_PI_NODE: {
260
1.75M
      miscNode2 = node2;
261
1.75M
      if (node2->prev != NULL) {
262
19.2k
    do {
263
19.2k
        node2 = node2->prev;
264
19.2k
        if (node2->type == XML_ELEMENT_NODE) {
265
12.8k
      precedence2 = 3; /* element in prev-sibl axis */
266
12.8k
      break;
267
12.8k
        }
268
6.35k
        if (node2->prev == NULL) {
269
0
      precedence2 = 2; /* element is parent */
270
0
      node2 = node2->parent;
271
0
      break;
272
0
        }
273
6.35k
    } while (1);
274
1.74M
      } else {
275
1.74M
    precedence2 = 2; /* element is parent */
276
1.74M
    node2 = node2->parent;
277
1.74M
      }
278
1.75M
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
279
1.75M
    (0 <= (ptrdiff_t) node2->content))
280
1.73M
      {
281
1.73M
    node2 = miscNode2;
282
1.73M
    precedence2 = 0;
283
1.73M
      } else
284
21.8k
    misc = 1;
285
1.75M
  }
286
0
      break;
287
2
  case XML_NAMESPACE_DECL:
288
2
      return(1);
289
189k
  default:
290
189k
      break;
291
2.96M
    }
292
2.96M
    if (misc) {
293
48.9k
  if (node1 == node2) {
294
9.92k
      if (precedence1 == precedence2) {
295
    /*
296
    * The ugly case; but normally there aren't many
297
    * adjacent non-element nodes around.
298
    */
299
2.24k
    cur = miscNode2->prev;
300
2.87k
    while (cur != NULL) {
301
2.87k
        if (cur == miscNode1)
302
1.42k
      return(1);
303
1.45k
        if (cur->type == XML_ELEMENT_NODE)
304
815
      return(-1);
305
637
        cur = cur->prev;
306
637
    }
307
0
    return (-1);
308
7.68k
      } else {
309
    /*
310
    * Evaluate based on higher precedence wrt to the element.
311
    * TODO: This assumes attributes are sorted before content.
312
    *   Is this 100% correct?
313
    */
314
7.68k
    if (precedence1 < precedence2)
315
3.04k
        return(1);
316
4.64k
    else
317
4.64k
        return(-1);
318
7.68k
      }
319
9.92k
  }
320
  /*
321
  * Special case: One of the helper-elements is contained by the other.
322
  * <foo>
323
  *   <node2>
324
  *     <node1>Text-1(precedence1 == 2)</node1>
325
  *   </node2>
326
  *   Text-6(precedence2 == 3)
327
  * </foo>
328
  */
329
38.9k
  if ((precedence2 == 3) && (precedence1 > 1)) {
330
4.49k
      cur = node1->parent;
331
15.0k
      while (cur) {
332
10.9k
    if (cur == node2)
333
336
        return(1);
334
10.5k
    cur = cur->parent;
335
10.5k
      }
336
4.49k
  }
337
38.6k
  if ((precedence1 == 3) && (precedence2 > 1)) {
338
5.76k
      cur = node2->parent;
339
16.2k
      while (cur) {
340
11.3k
    if (cur == node1)
341
855
        return(-1);
342
10.4k
    cur = cur->parent;
343
10.4k
      }
344
5.76k
  }
345
38.6k
    }
346
347
    /*
348
     * Speedup using document order if available.
349
     */
350
2.95M
    if ((node1->type == XML_ELEMENT_NODE) &&
351
2.95M
  (node2->type == XML_ELEMENT_NODE) &&
352
2.95M
  (0 > (ptrdiff_t) node1->content) &&
353
2.95M
  (0 > (ptrdiff_t) node2->content) &&
354
2.95M
  (node1->doc == node2->doc)) {
355
356
37.6k
  l1 = -((ptrdiff_t) node1->content);
357
37.6k
  l2 = -((ptrdiff_t) node2->content);
358
37.6k
  if (l1 < l2)
359
17.3k
      return(1);
360
20.2k
  if (l1 > l2)
361
20.2k
      return(-1);
362
20.2k
    }
363
364
16.1M
turtle_comparison:
365
366
16.1M
    if (node1 == node2->prev)
367
12.2M
  return(1);
368
3.86M
    if (node1 == node2->next)
369
3.23k
  return(-1);
370
    /*
371
     * compute depth to root
372
     */
373
9.64M
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
374
5.86M
  if (cur->parent == node1)
375
71.4k
      return(1);
376
5.78M
  depth2++;
377
5.78M
    }
378
3.78M
    root = cur;
379
7.41M
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
380
4.51M
  if (cur->parent == node2)
381
882k
      return(-1);
382
3.63M
  depth1++;
383
3.63M
    }
384
    /*
385
     * Distinct document (or distinct entities :-( ) case.
386
     */
387
2.90M
    if (root != cur) {
388
368k
  return(-2);
389
368k
    }
390
    /*
391
     * get the nearest common ancestor.
392
     */
393
2.56M
    while (depth1 > depth2) {
394
23.8k
  depth1--;
395
23.8k
  node1 = node1->parent;
396
23.8k
    }
397
4.19M
    while (depth2 > depth1) {
398
1.65M
  depth2--;
399
1.65M
  node2 = node2->parent;
400
1.65M
    }
401
2.62M
    while (node1->parent != node2->parent) {
402
87.8k
  node1 = node1->parent;
403
87.8k
  node2 = node2->parent;
404
  /* should not happen but just in case ... */
405
87.8k
  if ((node1 == NULL) || (node2 == NULL))
406
0
      return(-2);
407
87.8k
    }
408
    /*
409
     * Find who's first.
410
     */
411
2.53M
    if (node1 == node2->prev)
412
11.2k
  return(1);
413
2.52M
    if (node1 == node2->next)
414
799k
  return(-1);
415
    /*
416
     * Speedup using document order if available.
417
     */
418
1.72M
    if ((node1->type == XML_ELEMENT_NODE) &&
419
1.72M
  (node2->type == XML_ELEMENT_NODE) &&
420
1.72M
  (0 > (ptrdiff_t) node1->content) &&
421
1.72M
  (0 > (ptrdiff_t) node2->content) &&
422
1.72M
  (node1->doc == node2->doc)) {
423
424
0
  l1 = -((ptrdiff_t) node1->content);
425
0
  l2 = -((ptrdiff_t) node2->content);
426
0
  if (l1 < l2)
427
0
      return(1);
428
0
  if (l1 > l2)
429
0
      return(-1);
430
0
    }
431
432
105M
    for (cur = node1->next;cur != NULL;cur = cur->next)
433
103M
  if (cur == node2)
434
94.8k
      return(1);
435
1.63M
    return(-1); /* assume there is no sibling list corruption */
436
1.72M
}
437
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
438
439
/*
440
 * Wrapper for the Timsort algorithm from timsort.h
441
 */
442
#ifdef WITH_TIM_SORT
443
#define SORT_NAME libxml_domnode
444
1.09M
#define SORT_TYPE xmlNodePtr
445
/**
446
 * wrap_cmp:
447
 * @x: a node
448
 * @y: another node
449
 *
450
 * Comparison function for the Timsort implementation
451
 *
452
 * Returns -2 in case of error -1 if first point < second point, 0 if
453
 *         it's the same node, +1 otherwise
454
 */
455
static
456
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
457
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
458
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
459
16.1M
    {
460
16.1M
        int res = xmlXPathCmpNodesExt(x, y);
461
16.1M
        return res == -2 ? res : -res;
462
16.1M
    }
463
#else
464
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
465
    {
466
        int res = xmlXPathCmpNodes(x, y);
467
        return res == -2 ? res : -res;
468
    }
469
#endif
470
16.1M
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
471
#include "timsort.h"
472
#endif /* WITH_TIM_SORT */
473
474
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
475
476
/************************************************************************
477
 *                  *
478
 *      Floating point stuff        *
479
 *                  *
480
 ************************************************************************/
481
482
double xmlXPathNAN = 0.0;
483
double xmlXPathPINF = 0.0;
484
double xmlXPathNINF = 0.0;
485
486
/**
487
 * xmlXPathInit:
488
 *
489
 * DEPRECATED: This function will be made private. Call xmlInitParser to
490
 * initialize the library.
491
 *
492
 * Initialize the XPath environment
493
 */
494
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
495
void
496
4
xmlXPathInit(void) {
497
4
#if defined(NAN) && defined(INFINITY)
498
4
    xmlXPathNAN = NAN;
499
4
    xmlXPathPINF = INFINITY;
500
4
    xmlXPathNINF = -INFINITY;
501
#else
502
    /* MSVC doesn't allow division by zero in constant expressions. */
503
    double zero = 0.0;
504
    xmlXPathNAN = 0.0 / zero;
505
    xmlXPathPINF = 1.0 / zero;
506
    xmlXPathNINF = -xmlXPathPINF;
507
#endif
508
4
}
509
510
/**
511
 * xmlXPathIsNaN:
512
 * @val:  a double value
513
 *
514
 * Returns 1 if the value is a NaN, 0 otherwise
515
 */
516
int
517
2.14M
xmlXPathIsNaN(double val) {
518
2.14M
#ifdef isnan
519
2.14M
    return isnan(val);
520
#else
521
    return !(val == val);
522
#endif
523
2.14M
}
524
525
/**
526
 * xmlXPathIsInf:
527
 * @val:  a double value
528
 *
529
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
530
 */
531
int
532
13.4k
xmlXPathIsInf(double val) {
533
13.4k
#ifdef isinf
534
13.4k
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
535
#else
536
    if (val >= xmlXPathPINF)
537
        return 1;
538
    if (val <= -xmlXPathPINF)
539
        return -1;
540
    return 0;
541
#endif
542
13.4k
}
543
544
#endif /* SCHEMAS or XPATH */
545
546
#ifdef LIBXML_XPATH_ENABLED
547
548
/*
549
 * TODO: when compatibility allows remove all "fake node libxslt" strings
550
 *       the test should just be name[0] = ' '
551
 */
552
#ifdef DEBUG_XPATH_EXPRESSION
553
#define DEBUG_STEP
554
#define DEBUG_EXPR
555
#define DEBUG_EVAL_COUNTS
556
#endif
557
558
static xmlNs xmlXPathXMLNamespaceStruct = {
559
    NULL,
560
    XML_NAMESPACE_DECL,
561
    XML_XML_NAMESPACE,
562
    BAD_CAST "xml",
563
    NULL,
564
    NULL
565
};
566
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
567
#ifndef LIBXML_THREAD_ENABLED
568
/*
569
 * Optimizer is disabled only when threaded apps are detected while
570
 * the library ain't compiled for thread safety.
571
 */
572
static int xmlXPathDisableOptimizer = 0;
573
#endif
574
575
/************************************************************************
576
 *                  *
577
 *      Error handling routines       *
578
 *                  *
579
 ************************************************************************/
580
581
/**
582
 * XP_ERRORNULL:
583
 * @X:  the error code
584
 *
585
 * Macro to raise an XPath error and return NULL.
586
 */
587
#define XP_ERRORNULL(X)             \
588
5.30k
    { xmlXPathErr(ctxt, X); return(NULL); }
589
590
/*
591
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
592
 */
593
static const char* const xmlXPathErrorMessages[] = {
594
    "Ok\n",
595
    "Number encoding\n",
596
    "Unfinished literal\n",
597
    "Start of literal\n",
598
    "Expected $ for variable reference\n",
599
    "Undefined variable\n",
600
    "Invalid predicate\n",
601
    "Invalid expression\n",
602
    "Missing closing curly brace\n",
603
    "Unregistered function\n",
604
    "Invalid operand\n",
605
    "Invalid type\n",
606
    "Invalid number of arguments\n",
607
    "Invalid context size\n",
608
    "Invalid context position\n",
609
    "Memory allocation error\n",
610
    "Syntax error\n",
611
    "Resource error\n",
612
    "Sub resource error\n",
613
    "Undefined namespace prefix\n",
614
    "Encoding error\n",
615
    "Char out of XML range\n",
616
    "Invalid or incomplete context\n",
617
    "Stack usage error\n",
618
    "Forbidden variable\n",
619
    "Operation limit exceeded\n",
620
    "Recursion limit exceeded\n",
621
    "?? Unknown error ??\n" /* Must be last in the list! */
622
};
623
25.9k
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
624
25.9k
       sizeof(xmlXPathErrorMessages[0])) - 1)
625
/**
626
 * xmlXPathErrMemory:
627
 * @ctxt:  an XPath context
628
 * @extra:  extra information
629
 *
630
 * Handle a redefinition of attribute error
631
 */
632
static void
633
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
634
765
{
635
765
    if (ctxt != NULL) {
636
765
        xmlResetError(&ctxt->lastError);
637
765
        if (extra) {
638
765
            xmlChar buf[200];
639
640
765
            xmlStrPrintf(buf, 200,
641
765
                         "Memory allocation failed : %s\n",
642
765
                         extra);
643
765
            ctxt->lastError.message = (char *) xmlStrdup(buf);
644
765
        } else {
645
0
            ctxt->lastError.message = (char *)
646
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
647
0
        }
648
765
        ctxt->lastError.domain = XML_FROM_XPATH;
649
765
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
650
765
  if (ctxt->error != NULL)
651
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
652
765
    } else {
653
0
        if (extra)
654
0
            __xmlRaiseError(NULL, NULL, NULL,
655
0
                            NULL, NULL, XML_FROM_XPATH,
656
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
657
0
                            extra, NULL, NULL, 0, 0,
658
0
                            "Memory allocation failed : %s\n", extra);
659
0
        else
660
0
            __xmlRaiseError(NULL, NULL, NULL,
661
0
                            NULL, NULL, XML_FROM_XPATH,
662
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
663
0
                            NULL, NULL, NULL, 0, 0,
664
0
                            "Memory allocation failed\n");
665
0
    }
666
765
}
667
668
/**
669
 * xmlXPathPErrMemory:
670
 * @ctxt:  an XPath parser context
671
 * @extra:  extra information
672
 *
673
 * Handle a redefinition of attribute error
674
 */
675
static void
676
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
677
765
{
678
765
    if (ctxt == NULL)
679
0
  xmlXPathErrMemory(NULL, extra);
680
765
    else {
681
765
  ctxt->error = XPATH_MEMORY_ERROR;
682
765
  xmlXPathErrMemory(ctxt->context, extra);
683
765
    }
684
765
}
685
686
/**
687
 * xmlXPathErr:
688
 * @ctxt:  a XPath parser context
689
 * @error:  the error code
690
 *
691
 * Handle an XPath error
692
 */
693
void
694
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
695
25.9k
{
696
25.9k
    if ((error < 0) || (error > MAXERRNO))
697
0
  error = MAXERRNO;
698
25.9k
    if (ctxt == NULL) {
699
0
  __xmlRaiseError(NULL, NULL, NULL,
700
0
      NULL, NULL, XML_FROM_XPATH,
701
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702
0
      XML_ERR_ERROR, NULL, 0,
703
0
      NULL, NULL, NULL, 0, 0,
704
0
      "%s", xmlXPathErrorMessages[error]);
705
0
  return;
706
0
    }
707
25.9k
    ctxt->error = error;
708
25.9k
    if (ctxt->context == NULL) {
709
0
  __xmlRaiseError(NULL, NULL, NULL,
710
0
      NULL, NULL, XML_FROM_XPATH,
711
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
712
0
      XML_ERR_ERROR, NULL, 0,
713
0
      (const char *) ctxt->base, NULL, NULL,
714
0
      ctxt->cur - ctxt->base, 0,
715
0
      "%s", xmlXPathErrorMessages[error]);
716
0
  return;
717
0
    }
718
719
    /* cleanup current last error */
720
25.9k
    xmlResetError(&ctxt->context->lastError);
721
722
25.9k
    ctxt->context->lastError.domain = XML_FROM_XPATH;
723
25.9k
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
724
25.9k
                           XPATH_EXPRESSION_OK;
725
25.9k
    ctxt->context->lastError.level = XML_ERR_ERROR;
726
25.9k
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
727
25.9k
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
728
25.9k
    ctxt->context->lastError.node = ctxt->context->debugNode;
729
25.9k
    if (ctxt->context->error != NULL) {
730
0
  ctxt->context->error(ctxt->context->userData,
731
0
                       &ctxt->context->lastError);
732
25.9k
    } else {
733
25.9k
  __xmlRaiseError(NULL, NULL, NULL,
734
25.9k
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
735
25.9k
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
736
25.9k
      XML_ERR_ERROR, NULL, 0,
737
25.9k
      (const char *) ctxt->base, NULL, NULL,
738
25.9k
      ctxt->cur - ctxt->base, 0,
739
25.9k
      "%s", xmlXPathErrorMessages[error]);
740
25.9k
    }
741
742
25.9k
}
743
744
/**
745
 * xmlXPatherror:
746
 * @ctxt:  the XPath Parser context
747
 * @file:  the file name
748
 * @line:  the line number
749
 * @no:  the error number
750
 *
751
 * Formats an error message.
752
 */
753
void
754
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
755
10.1k
              int line ATTRIBUTE_UNUSED, int no) {
756
10.1k
    xmlXPathErr(ctxt, no);
757
10.1k
}
758
759
/**
760
 * xmlXPathCheckOpLimit:
761
 * @ctxt:  the XPath Parser context
762
 * @opCount:  the number of operations to be added
763
 *
764
 * Adds opCount to the running total of operations and returns -1 if the
765
 * operation limit is exceeded. Returns 0 otherwise.
766
 */
767
static int
768
5.91M
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
769
5.91M
    xmlXPathContextPtr xpctxt = ctxt->context;
770
771
5.91M
    if ((opCount > xpctxt->opLimit) ||
772
5.91M
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
773
728
        xpctxt->opCount = xpctxt->opLimit;
774
728
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
775
728
        return(-1);
776
728
    }
777
778
5.90M
    xpctxt->opCount += opCount;
779
5.90M
    return(0);
780
5.91M
}
781
782
#define OP_LIMIT_EXCEEDED(ctxt, n) \
783
5.89M
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
784
785
/************************************************************************
786
 *                  *
787
 *      Utilities         *
788
 *                  *
789
 ************************************************************************/
790
791
/**
792
 * xsltPointerList:
793
 *
794
 * Pointer-list for various purposes.
795
 */
796
typedef struct _xmlPointerList xmlPointerList;
797
typedef xmlPointerList *xmlPointerListPtr;
798
struct _xmlPointerList {
799
    void **items;
800
    int number;
801
    int size;
802
};
803
/*
804
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
805
* and here, we should make the functions public.
806
*/
807
static int
808
xmlPointerListAddSize(xmlPointerListPtr list,
809
           void *item,
810
           int initialSize)
811
4.47M
{
812
4.47M
    if (list->items == NULL) {
813
355
  if (initialSize <= 0)
814
0
      initialSize = 1;
815
355
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
816
355
  if (list->items == NULL) {
817
0
      xmlXPathErrMemory(NULL,
818
0
    "xmlPointerListCreate: allocating item\n");
819
0
      return(-1);
820
0
  }
821
355
  list->number = 0;
822
355
  list->size = initialSize;
823
4.47M
    } else if (list->size <= list->number) {
824
201
        if (list->size > 50000000) {
825
0
      xmlXPathErrMemory(NULL,
826
0
    "xmlPointerListAddSize: re-allocating item\n");
827
0
            return(-1);
828
0
        }
829
201
  list->size *= 2;
830
201
  list->items = (void **) xmlRealloc(list->items,
831
201
      list->size * sizeof(void *));
832
201
  if (list->items == NULL) {
833
0
      xmlXPathErrMemory(NULL,
834
0
    "xmlPointerListAddSize: re-allocating item\n");
835
0
      list->size = 0;
836
0
      return(-1);
837
0
  }
838
201
    }
839
4.47M
    list->items[list->number++] = item;
840
4.47M
    return(0);
841
4.47M
}
842
843
/**
844
 * xsltPointerListCreate:
845
 *
846
 * Creates an xsltPointerList structure.
847
 *
848
 * Returns a xsltPointerList structure or NULL in case of an error.
849
 */
850
static xmlPointerListPtr
851
xmlPointerListCreate(int initialSize)
852
355
{
853
355
    xmlPointerListPtr ret;
854
855
355
    ret = xmlMalloc(sizeof(xmlPointerList));
856
355
    if (ret == NULL) {
857
0
  xmlXPathErrMemory(NULL,
858
0
      "xmlPointerListCreate: allocating item\n");
859
0
  return (NULL);
860
0
    }
861
355
    memset(ret, 0, sizeof(xmlPointerList));
862
355
    if (initialSize > 0) {
863
355
  xmlPointerListAddSize(ret, NULL, initialSize);
864
355
  ret->number = 0;
865
355
    }
866
355
    return (ret);
867
355
}
868
869
/**
870
 * xsltPointerListFree:
871
 *
872
 * Frees the xsltPointerList structure. This does not free
873
 * the content of the list.
874
 */
875
static void
876
xmlPointerListFree(xmlPointerListPtr list)
877
354
{
878
354
    if (list == NULL)
879
0
  return;
880
354
    if (list->items != NULL)
881
354
  xmlFree(list->items);
882
354
    xmlFree(list);
883
354
}
884
885
/************************************************************************
886
 *                  *
887
 *      Parser Types          *
888
 *                  *
889
 ************************************************************************/
890
891
/*
892
 * Types are private:
893
 */
894
895
typedef enum {
896
    XPATH_OP_END=0,
897
    XPATH_OP_AND,
898
    XPATH_OP_OR,
899
    XPATH_OP_EQUAL,
900
    XPATH_OP_CMP,
901
    XPATH_OP_PLUS,
902
    XPATH_OP_MULT,
903
    XPATH_OP_UNION,
904
    XPATH_OP_ROOT,
905
    XPATH_OP_NODE,
906
    XPATH_OP_COLLECT,
907
    XPATH_OP_VALUE, /* 11 */
908
    XPATH_OP_VARIABLE,
909
    XPATH_OP_FUNCTION,
910
    XPATH_OP_ARG,
911
    XPATH_OP_PREDICATE,
912
    XPATH_OP_FILTER, /* 16 */
913
    XPATH_OP_SORT /* 17 */
914
#ifdef LIBXML_XPTR_LOCS_ENABLED
915
    ,XPATH_OP_RANGETO
916
#endif
917
} xmlXPathOp;
918
919
typedef enum {
920
    AXIS_ANCESTOR = 1,
921
    AXIS_ANCESTOR_OR_SELF,
922
    AXIS_ATTRIBUTE,
923
    AXIS_CHILD,
924
    AXIS_DESCENDANT,
925
    AXIS_DESCENDANT_OR_SELF,
926
    AXIS_FOLLOWING,
927
    AXIS_FOLLOWING_SIBLING,
928
    AXIS_NAMESPACE,
929
    AXIS_PARENT,
930
    AXIS_PRECEDING,
931
    AXIS_PRECEDING_SIBLING,
932
    AXIS_SELF
933
} xmlXPathAxisVal;
934
935
typedef enum {
936
    NODE_TEST_NONE = 0,
937
    NODE_TEST_TYPE = 1,
938
    NODE_TEST_PI = 2,
939
    NODE_TEST_ALL = 3,
940
    NODE_TEST_NS = 4,
941
    NODE_TEST_NAME = 5
942
} xmlXPathTestVal;
943
944
typedef enum {
945
    NODE_TYPE_NODE = 0,
946
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
947
    NODE_TYPE_TEXT = XML_TEXT_NODE,
948
    NODE_TYPE_PI = XML_PI_NODE
949
} xmlXPathTypeVal;
950
951
typedef struct _xmlXPathStepOp xmlXPathStepOp;
952
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
953
struct _xmlXPathStepOp {
954
    xmlXPathOp op;    /* The identifier of the operation */
955
    int ch1;      /* First child */
956
    int ch2;      /* Second child */
957
    int value;
958
    int value2;
959
    int value3;
960
    void *value4;
961
    void *value5;
962
    xmlXPathFunction cache;
963
    void *cacheURI;
964
};
965
966
struct _xmlXPathCompExpr {
967
    int nbStep;     /* Number of steps in this expression */
968
    int maxStep;    /* Maximum number of steps allocated */
969
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
970
    int last;     /* index of last step in expression */
971
    xmlChar *expr;    /* the expression being computed */
972
    xmlDictPtr dict;    /* the dictionary to use if any */
973
#ifdef DEBUG_EVAL_COUNTS
974
    int nb;
975
    xmlChar *string;
976
#endif
977
#ifdef XPATH_STREAMING
978
    xmlPatternPtr stream;
979
#endif
980
};
981
982
/************************************************************************
983
 *                  *
984
 *      Forward declarations        *
985
 *                  *
986
 ************************************************************************/
987
static void
988
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
989
static void
990
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
991
static int
992
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
993
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
994
static int
995
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
996
          xmlXPathStepOpPtr op,
997
          int isPredicate);
998
static void
999
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1000
1001
/************************************************************************
1002
 *                  *
1003
 *      Parser Type functions       *
1004
 *                  *
1005
 ************************************************************************/
1006
1007
/**
1008
 * xmlXPathNewCompExpr:
1009
 *
1010
 * Create a new Xpath component
1011
 *
1012
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1013
 */
1014
static xmlXPathCompExprPtr
1015
47.7k
xmlXPathNewCompExpr(void) {
1016
47.7k
    xmlXPathCompExprPtr cur;
1017
1018
47.7k
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1019
47.7k
    if (cur == NULL) {
1020
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1021
0
  return(NULL);
1022
0
    }
1023
47.7k
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1024
47.7k
    cur->maxStep = 10;
1025
47.7k
    cur->nbStep = 0;
1026
47.7k
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1027
47.7k
                                     sizeof(xmlXPathStepOp));
1028
47.7k
    if (cur->steps == NULL) {
1029
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1030
0
  xmlFree(cur);
1031
0
  return(NULL);
1032
0
    }
1033
47.7k
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1034
47.7k
    cur->last = -1;
1035
#ifdef DEBUG_EVAL_COUNTS
1036
    cur->nb = 0;
1037
#endif
1038
47.7k
    return(cur);
1039
47.7k
}
1040
1041
/**
1042
 * xmlXPathFreeCompExpr:
1043
 * @comp:  an XPATH comp
1044
 *
1045
 * Free up the memory allocated by @comp
1046
 */
1047
void
1048
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1049
66.4k
{
1050
66.4k
    xmlXPathStepOpPtr op;
1051
66.4k
    int i;
1052
1053
66.4k
    if (comp == NULL)
1054
18.7k
        return;
1055
47.7k
    if (comp->dict == NULL) {
1056
27.2M
  for (i = 0; i < comp->nbStep; i++) {
1057
27.1M
      op = &comp->steps[i];
1058
27.1M
      if (op->value4 != NULL) {
1059
32.7k
    if (op->op == XPATH_OP_VALUE)
1060
18.0k
        xmlXPathFreeObject(op->value4);
1061
14.7k
    else
1062
14.7k
        xmlFree(op->value4);
1063
32.7k
      }
1064
27.1M
      if (op->value5 != NULL)
1065
7.31M
    xmlFree(op->value5);
1066
27.1M
  }
1067
28.8k
    } else {
1068
43.2k
  for (i = 0; i < comp->nbStep; i++) {
1069
24.3k
      op = &comp->steps[i];
1070
24.3k
      if (op->value4 != NULL) {
1071
9.29k
    if (op->op == XPATH_OP_VALUE)
1072
8.25k
        xmlXPathFreeObject(op->value4);
1073
9.29k
      }
1074
24.3k
  }
1075
18.8k
        xmlDictFree(comp->dict);
1076
18.8k
    }
1077
47.7k
    if (comp->steps != NULL) {
1078
47.7k
        xmlFree(comp->steps);
1079
47.7k
    }
1080
#ifdef DEBUG_EVAL_COUNTS
1081
    if (comp->string != NULL) {
1082
        xmlFree(comp->string);
1083
    }
1084
#endif
1085
47.7k
#ifdef XPATH_STREAMING
1086
47.7k
    if (comp->stream != NULL) {
1087
11.6k
        xmlFreePatternList(comp->stream);
1088
11.6k
    }
1089
47.7k
#endif
1090
47.7k
    if (comp->expr != NULL) {
1091
13.0k
        xmlFree(comp->expr);
1092
13.0k
    }
1093
1094
47.7k
    xmlFree(comp);
1095
47.7k
}
1096
1097
/**
1098
 * xmlXPathCompExprAdd:
1099
 * @comp:  the compiled expression
1100
 * @ch1: first child index
1101
 * @ch2: second child index
1102
 * @op:  an op
1103
 * @value:  the first int value
1104
 * @value2:  the second int value
1105
 * @value3:  the third int value
1106
 * @value4:  the first string value
1107
 * @value5:  the second string value
1108
 *
1109
 * Add a step to an XPath Compiled Expression
1110
 *
1111
 * Returns -1 in case of failure, the index otherwise
1112
 */
1113
static int
1114
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1115
   xmlXPathOp op, int value,
1116
27.2M
   int value2, int value3, void *value4, void *value5) {
1117
27.2M
    xmlXPathCompExprPtr comp = ctxt->comp;
1118
27.2M
    if (comp->nbStep >= comp->maxStep) {
1119
7.69k
  xmlXPathStepOp *real;
1120
1121
7.69k
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1122
765
      xmlXPathPErrMemory(ctxt, "adding step\n");
1123
765
      return(-1);
1124
765
        }
1125
6.92k
  comp->maxStep *= 2;
1126
6.92k
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1127
6.92k
                          comp->maxStep * sizeof(xmlXPathStepOp));
1128
6.92k
  if (real == NULL) {
1129
0
      comp->maxStep /= 2;
1130
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1131
0
      return(-1);
1132
0
  }
1133
6.92k
  comp->steps = real;
1134
6.92k
    }
1135
27.2M
    comp->last = comp->nbStep;
1136
27.2M
    comp->steps[comp->nbStep].ch1 = ch1;
1137
27.2M
    comp->steps[comp->nbStep].ch2 = ch2;
1138
27.2M
    comp->steps[comp->nbStep].op = op;
1139
27.2M
    comp->steps[comp->nbStep].value = value;
1140
27.2M
    comp->steps[comp->nbStep].value2 = value2;
1141
27.2M
    comp->steps[comp->nbStep].value3 = value3;
1142
27.2M
    if ((comp->dict != NULL) &&
1143
27.2M
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1144
24.3k
   (op == XPATH_OP_COLLECT))) {
1145
6.06k
        if (value4 != NULL) {
1146
1.04k
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1147
1.04k
          (void *)xmlDictLookup(comp->dict, value4, -1);
1148
1.04k
      xmlFree(value4);
1149
1.04k
  } else
1150
5.02k
      comp->steps[comp->nbStep].value4 = NULL;
1151
6.06k
        if (value5 != NULL) {
1152
2.24k
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1153
2.24k
          (void *)xmlDictLookup(comp->dict, value5, -1);
1154
2.24k
      xmlFree(value5);
1155
2.24k
  } else
1156
3.81k
      comp->steps[comp->nbStep].value5 = NULL;
1157
27.2M
    } else {
1158
27.2M
  comp->steps[comp->nbStep].value4 = value4;
1159
27.2M
  comp->steps[comp->nbStep].value5 = value5;
1160
27.2M
    }
1161
27.2M
    comp->steps[comp->nbStep].cache = NULL;
1162
27.2M
    return(comp->nbStep++);
1163
27.2M
}
1164
1165
/**
1166
 * xmlXPathCompSwap:
1167
 * @comp:  the compiled expression
1168
 * @op: operation index
1169
 *
1170
 * Swaps 2 operations in the compiled expression
1171
 */
1172
static void
1173
0
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1174
0
    int tmp;
1175
1176
#ifndef LIBXML_THREAD_ENABLED
1177
    /*
1178
     * Since this manipulates possibly shared variables, this is
1179
     * disabled if one detects that the library is used in a multithreaded
1180
     * application
1181
     */
1182
    if (xmlXPathDisableOptimizer)
1183
  return;
1184
#endif
1185
1186
0
    tmp = op->ch1;
1187
0
    op->ch1 = op->ch2;
1188
0
    op->ch2 = tmp;
1189
0
}
1190
1191
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1192
7.67M
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1193
7.67M
                  (op), (val), (val2), (val3), (val4), (val5))
1194
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1195
61.0k
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1196
61.0k
                  (op), (val), (val2), (val3), (val4), (val5))
1197
1198
12.9M
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1199
12.9M
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1200
1201
26.0k
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1202
26.0k
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1203
1204
6.49M
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1205
6.49M
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1206
6.49M
      (val), (val2), 0 ,NULL ,NULL)
1207
1208
/************************************************************************
1209
 *                  *
1210
 *    XPath object cache structures       *
1211
 *                  *
1212
 ************************************************************************/
1213
1214
/* #define XP_DEFAULT_CACHE_ON */
1215
1216
14.8k
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1217
1218
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1219
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1220
struct _xmlXPathContextCache {
1221
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1222
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1223
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1224
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1225
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1226
    int maxNodeset;
1227
    int maxString;
1228
    int maxBoolean;
1229
    int maxNumber;
1230
    int maxMisc;
1231
#ifdef XP_DEBUG_OBJ_USAGE
1232
    int dbgCachedAll;
1233
    int dbgCachedNodeset;
1234
    int dbgCachedString;
1235
    int dbgCachedBool;
1236
    int dbgCachedNumber;
1237
    int dbgCachedPoint;
1238
    int dbgCachedRange;
1239
    int dbgCachedLocset;
1240
    int dbgCachedUsers;
1241
    int dbgCachedXSLTTree;
1242
    int dbgCachedUndefined;
1243
1244
1245
    int dbgReusedAll;
1246
    int dbgReusedNodeset;
1247
    int dbgReusedString;
1248
    int dbgReusedBool;
1249
    int dbgReusedNumber;
1250
    int dbgReusedPoint;
1251
    int dbgReusedRange;
1252
    int dbgReusedLocset;
1253
    int dbgReusedUsers;
1254
    int dbgReusedXSLTTree;
1255
    int dbgReusedUndefined;
1256
1257
#endif
1258
};
1259
1260
/************************************************************************
1261
 *                  *
1262
 *    Debugging related functions       *
1263
 *                  *
1264
 ************************************************************************/
1265
1266
#define STRANGE             \
1267
0
    xmlGenericError(xmlGenericErrorContext,       \
1268
0
      "Internal error at %s:%d\n",        \
1269
0
            __FILE__, __LINE__);
1270
1271
#ifdef LIBXML_DEBUG_ENABLED
1272
static void
1273
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1274
0
    int i;
1275
0
    char shift[100];
1276
1277
0
    for (i = 0;((i < depth) && (i < 25));i++)
1278
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1279
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1280
0
    if (cur == NULL) {
1281
0
  fprintf(output, "%s", shift);
1282
0
  fprintf(output, "Node is NULL !\n");
1283
0
  return;
1284
1285
0
    }
1286
1287
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1288
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1289
0
  fprintf(output, "%s", shift);
1290
0
  fprintf(output, " /\n");
1291
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1292
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1293
0
    else
1294
0
  xmlDebugDumpOneNode(output, cur, depth);
1295
0
}
1296
static void
1297
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1298
0
    xmlNodePtr tmp;
1299
0
    int i;
1300
0
    char shift[100];
1301
1302
0
    for (i = 0;((i < depth) && (i < 25));i++)
1303
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1304
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1305
0
    if (cur == NULL) {
1306
0
  fprintf(output, "%s", shift);
1307
0
  fprintf(output, "Node is NULL !\n");
1308
0
  return;
1309
1310
0
    }
1311
1312
0
    while (cur != NULL) {
1313
0
  tmp = cur;
1314
0
  cur = cur->next;
1315
0
  xmlDebugDumpOneNode(output, tmp, depth);
1316
0
    }
1317
0
}
1318
1319
static void
1320
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1321
0
    int i;
1322
0
    char shift[100];
1323
1324
0
    for (i = 0;((i < depth) && (i < 25));i++)
1325
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1326
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1327
1328
0
    if (cur == NULL) {
1329
0
  fprintf(output, "%s", shift);
1330
0
  fprintf(output, "NodeSet is NULL !\n");
1331
0
  return;
1332
1333
0
    }
1334
1335
0
    if (cur != NULL) {
1336
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1337
0
  for (i = 0;i < cur->nodeNr;i++) {
1338
0
      fprintf(output, "%s", shift);
1339
0
      fprintf(output, "%d", i + 1);
1340
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1341
0
  }
1342
0
    }
1343
0
}
1344
1345
static void
1346
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1347
0
    int i;
1348
0
    char shift[100];
1349
1350
0
    for (i = 0;((i < depth) && (i < 25));i++)
1351
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1352
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1353
1354
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1355
0
  fprintf(output, "%s", shift);
1356
0
  fprintf(output, "Value Tree is NULL !\n");
1357
0
  return;
1358
1359
0
    }
1360
1361
0
    fprintf(output, "%s", shift);
1362
0
    fprintf(output, "%d", i + 1);
1363
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1364
0
}
1365
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1366
static void
1367
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1368
    int i;
1369
    char shift[100];
1370
1371
    for (i = 0;((i < depth) && (i < 25));i++)
1372
        shift[2 * i] = shift[2 * i + 1] = ' ';
1373
    shift[2 * i] = shift[2 * i + 1] = 0;
1374
1375
    if (cur == NULL) {
1376
  fprintf(output, "%s", shift);
1377
  fprintf(output, "LocationSet is NULL !\n");
1378
  return;
1379
1380
    }
1381
1382
    for (i = 0;i < cur->locNr;i++) {
1383
  fprintf(output, "%s", shift);
1384
        fprintf(output, "%d : ", i + 1);
1385
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1386
    }
1387
}
1388
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1389
1390
/**
1391
 * xmlXPathDebugDumpObject:
1392
 * @output:  the FILE * to dump the output
1393
 * @cur:  the object to inspect
1394
 * @depth:  indentation level
1395
 *
1396
 * Dump the content of the object for debugging purposes
1397
 */
1398
void
1399
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1400
0
    int i;
1401
0
    char shift[100];
1402
1403
0
    if (output == NULL) return;
1404
1405
0
    for (i = 0;((i < depth) && (i < 25));i++)
1406
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1407
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1408
1409
1410
0
    fprintf(output, "%s", shift);
1411
1412
0
    if (cur == NULL) {
1413
0
        fprintf(output, "Object is empty (NULL)\n");
1414
0
  return;
1415
0
    }
1416
0
    switch(cur->type) {
1417
0
        case XPATH_UNDEFINED:
1418
0
      fprintf(output, "Object is uninitialized\n");
1419
0
      break;
1420
0
        case XPATH_NODESET:
1421
0
      fprintf(output, "Object is a Node Set :\n");
1422
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1423
0
      break;
1424
0
  case XPATH_XSLT_TREE:
1425
0
      fprintf(output, "Object is an XSLT value tree :\n");
1426
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1427
0
      break;
1428
0
        case XPATH_BOOLEAN:
1429
0
      fprintf(output, "Object is a Boolean : ");
1430
0
      if (cur->boolval) fprintf(output, "true\n");
1431
0
      else fprintf(output, "false\n");
1432
0
      break;
1433
0
        case XPATH_NUMBER:
1434
0
      switch (xmlXPathIsInf(cur->floatval)) {
1435
0
      case 1:
1436
0
    fprintf(output, "Object is a number : Infinity\n");
1437
0
    break;
1438
0
      case -1:
1439
0
    fprintf(output, "Object is a number : -Infinity\n");
1440
0
    break;
1441
0
      default:
1442
0
    if (xmlXPathIsNaN(cur->floatval)) {
1443
0
        fprintf(output, "Object is a number : NaN\n");
1444
0
    } else if (cur->floatval == 0) {
1445
                    /* Omit sign for negative zero. */
1446
0
        fprintf(output, "Object is a number : 0\n");
1447
0
    } else {
1448
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1449
0
    }
1450
0
      }
1451
0
      break;
1452
0
        case XPATH_STRING:
1453
0
      fprintf(output, "Object is a string : ");
1454
0
      xmlDebugDumpString(output, cur->stringval);
1455
0
      fprintf(output, "\n");
1456
0
      break;
1457
#ifdef LIBXML_XPTR_LOCS_ENABLED
1458
  case XPATH_POINT:
1459
      fprintf(output, "Object is a point : index %d in node", cur->index);
1460
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1461
      fprintf(output, "\n");
1462
      break;
1463
  case XPATH_RANGE:
1464
      if ((cur->user2 == NULL) ||
1465
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1466
    fprintf(output, "Object is a collapsed range :\n");
1467
    fprintf(output, "%s", shift);
1468
    if (cur->index >= 0)
1469
        fprintf(output, "index %d in ", cur->index);
1470
    fprintf(output, "node\n");
1471
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1472
                    depth + 1);
1473
      } else  {
1474
    fprintf(output, "Object is a range :\n");
1475
    fprintf(output, "%s", shift);
1476
    fprintf(output, "From ");
1477
    if (cur->index >= 0)
1478
        fprintf(output, "index %d in ", cur->index);
1479
    fprintf(output, "node\n");
1480
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1481
                    depth + 1);
1482
    fprintf(output, "%s", shift);
1483
    fprintf(output, "To ");
1484
    if (cur->index2 >= 0)
1485
        fprintf(output, "index %d in ", cur->index2);
1486
    fprintf(output, "node\n");
1487
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1488
                    depth + 1);
1489
    fprintf(output, "\n");
1490
      }
1491
      break;
1492
  case XPATH_LOCATIONSET:
1493
      fprintf(output, "Object is a Location Set:\n");
1494
      xmlXPathDebugDumpLocationSet(output,
1495
        (xmlLocationSetPtr) cur->user, depth);
1496
      break;
1497
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1498
0
  case XPATH_USERS:
1499
0
      fprintf(output, "Object is user defined\n");
1500
0
      break;
1501
0
    }
1502
0
}
1503
1504
static void
1505
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1506
0
                       xmlXPathStepOpPtr op, int depth) {
1507
0
    int i;
1508
0
    char shift[100];
1509
1510
0
    for (i = 0;((i < depth) && (i < 25));i++)
1511
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1512
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1513
1514
0
    fprintf(output, "%s", shift);
1515
0
    if (op == NULL) {
1516
0
  fprintf(output, "Step is NULL\n");
1517
0
  return;
1518
0
    }
1519
0
    switch (op->op) {
1520
0
        case XPATH_OP_END:
1521
0
      fprintf(output, "END"); break;
1522
0
        case XPATH_OP_AND:
1523
0
      fprintf(output, "AND"); break;
1524
0
        case XPATH_OP_OR:
1525
0
      fprintf(output, "OR"); break;
1526
0
        case XPATH_OP_EQUAL:
1527
0
       if (op->value)
1528
0
     fprintf(output, "EQUAL =");
1529
0
       else
1530
0
     fprintf(output, "EQUAL !=");
1531
0
       break;
1532
0
        case XPATH_OP_CMP:
1533
0
       if (op->value)
1534
0
     fprintf(output, "CMP <");
1535
0
       else
1536
0
     fprintf(output, "CMP >");
1537
0
       if (!op->value2)
1538
0
     fprintf(output, "=");
1539
0
       break;
1540
0
        case XPATH_OP_PLUS:
1541
0
       if (op->value == 0)
1542
0
     fprintf(output, "PLUS -");
1543
0
       else if (op->value == 1)
1544
0
     fprintf(output, "PLUS +");
1545
0
       else if (op->value == 2)
1546
0
     fprintf(output, "PLUS unary -");
1547
0
       else if (op->value == 3)
1548
0
     fprintf(output, "PLUS unary - -");
1549
0
       break;
1550
0
        case XPATH_OP_MULT:
1551
0
       if (op->value == 0)
1552
0
     fprintf(output, "MULT *");
1553
0
       else if (op->value == 1)
1554
0
     fprintf(output, "MULT div");
1555
0
       else
1556
0
     fprintf(output, "MULT mod");
1557
0
       break;
1558
0
        case XPATH_OP_UNION:
1559
0
       fprintf(output, "UNION"); break;
1560
0
        case XPATH_OP_ROOT:
1561
0
       fprintf(output, "ROOT"); break;
1562
0
        case XPATH_OP_NODE:
1563
0
       fprintf(output, "NODE"); break;
1564
0
        case XPATH_OP_SORT:
1565
0
       fprintf(output, "SORT"); break;
1566
0
        case XPATH_OP_COLLECT: {
1567
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1568
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1569
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1570
0
      const xmlChar *prefix = op->value4;
1571
0
      const xmlChar *name = op->value5;
1572
1573
0
      fprintf(output, "COLLECT ");
1574
0
      switch (axis) {
1575
0
    case AXIS_ANCESTOR:
1576
0
        fprintf(output, " 'ancestors' "); break;
1577
0
    case AXIS_ANCESTOR_OR_SELF:
1578
0
        fprintf(output, " 'ancestors-or-self' "); break;
1579
0
    case AXIS_ATTRIBUTE:
1580
0
        fprintf(output, " 'attributes' "); break;
1581
0
    case AXIS_CHILD:
1582
0
        fprintf(output, " 'child' "); break;
1583
0
    case AXIS_DESCENDANT:
1584
0
        fprintf(output, " 'descendant' "); break;
1585
0
    case AXIS_DESCENDANT_OR_SELF:
1586
0
        fprintf(output, " 'descendant-or-self' "); break;
1587
0
    case AXIS_FOLLOWING:
1588
0
        fprintf(output, " 'following' "); break;
1589
0
    case AXIS_FOLLOWING_SIBLING:
1590
0
        fprintf(output, " 'following-siblings' "); break;
1591
0
    case AXIS_NAMESPACE:
1592
0
        fprintf(output, " 'namespace' "); break;
1593
0
    case AXIS_PARENT:
1594
0
        fprintf(output, " 'parent' "); break;
1595
0
    case AXIS_PRECEDING:
1596
0
        fprintf(output, " 'preceding' "); break;
1597
0
    case AXIS_PRECEDING_SIBLING:
1598
0
        fprintf(output, " 'preceding-sibling' "); break;
1599
0
    case AXIS_SELF:
1600
0
        fprintf(output, " 'self' "); break;
1601
0
      }
1602
0
      switch (test) {
1603
0
                case NODE_TEST_NONE:
1604
0
        fprintf(output, "'none' "); break;
1605
0
                case NODE_TEST_TYPE:
1606
0
        fprintf(output, "'type' "); break;
1607
0
                case NODE_TEST_PI:
1608
0
        fprintf(output, "'PI' "); break;
1609
0
                case NODE_TEST_ALL:
1610
0
        fprintf(output, "'all' "); break;
1611
0
                case NODE_TEST_NS:
1612
0
        fprintf(output, "'namespace' "); break;
1613
0
                case NODE_TEST_NAME:
1614
0
        fprintf(output, "'name' "); break;
1615
0
      }
1616
0
      switch (type) {
1617
0
                case NODE_TYPE_NODE:
1618
0
        fprintf(output, "'node' "); break;
1619
0
                case NODE_TYPE_COMMENT:
1620
0
        fprintf(output, "'comment' "); break;
1621
0
                case NODE_TYPE_TEXT:
1622
0
        fprintf(output, "'text' "); break;
1623
0
                case NODE_TYPE_PI:
1624
0
        fprintf(output, "'PI' "); break;
1625
0
      }
1626
0
      if (prefix != NULL)
1627
0
    fprintf(output, "%s:", prefix);
1628
0
      if (name != NULL)
1629
0
    fprintf(output, "%s", (const char *) name);
1630
0
      break;
1631
1632
0
        }
1633
0
  case XPATH_OP_VALUE: {
1634
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1635
1636
0
      fprintf(output, "ELEM ");
1637
0
      xmlXPathDebugDumpObject(output, object, 0);
1638
0
      goto finish;
1639
0
  }
1640
0
  case XPATH_OP_VARIABLE: {
1641
0
      const xmlChar *prefix = op->value5;
1642
0
      const xmlChar *name = op->value4;
1643
1644
0
      if (prefix != NULL)
1645
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1646
0
      else
1647
0
    fprintf(output, "VARIABLE %s", name);
1648
0
      break;
1649
0
  }
1650
0
  case XPATH_OP_FUNCTION: {
1651
0
      int nbargs = op->value;
1652
0
      const xmlChar *prefix = op->value5;
1653
0
      const xmlChar *name = op->value4;
1654
1655
0
      if (prefix != NULL)
1656
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1657
0
      prefix, name, nbargs);
1658
0
      else
1659
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1660
0
      break;
1661
0
  }
1662
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1663
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1664
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1665
#ifdef LIBXML_XPTR_LOCS_ENABLED
1666
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1667
#endif
1668
0
  default:
1669
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1670
0
    }
1671
0
    fprintf(output, "\n");
1672
0
finish:
1673
0
    if (op->ch1 >= 0)
1674
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1675
0
    if (op->ch2 >= 0)
1676
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1677
0
}
1678
1679
/**
1680
 * xmlXPathDebugDumpCompExpr:
1681
 * @output:  the FILE * for the output
1682
 * @comp:  the precompiled XPath expression
1683
 * @depth:  the indentation level.
1684
 *
1685
 * Dumps the tree of the compiled XPath expression.
1686
 */
1687
void
1688
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1689
0
                    int depth) {
1690
0
    int i;
1691
0
    char shift[100];
1692
1693
0
    if ((output == NULL) || (comp == NULL)) return;
1694
1695
0
    for (i = 0;((i < depth) && (i < 25));i++)
1696
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1697
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1698
1699
0
    fprintf(output, "%s", shift);
1700
1701
0
#ifdef XPATH_STREAMING
1702
0
    if (comp->stream) {
1703
0
        fprintf(output, "Streaming Expression\n");
1704
0
    } else
1705
0
#endif
1706
0
    {
1707
0
        fprintf(output, "Compiled Expression : %d elements\n",
1708
0
                comp->nbStep);
1709
0
        i = comp->last;
1710
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1711
0
    }
1712
0
}
1713
1714
#ifdef XP_DEBUG_OBJ_USAGE
1715
1716
/*
1717
* XPath object usage related debugging variables.
1718
*/
1719
static int xmlXPathDebugObjCounterUndefined = 0;
1720
static int xmlXPathDebugObjCounterNodeset = 0;
1721
static int xmlXPathDebugObjCounterBool = 0;
1722
static int xmlXPathDebugObjCounterNumber = 0;
1723
static int xmlXPathDebugObjCounterString = 0;
1724
static int xmlXPathDebugObjCounterPoint = 0;
1725
static int xmlXPathDebugObjCounterRange = 0;
1726
static int xmlXPathDebugObjCounterLocset = 0;
1727
static int xmlXPathDebugObjCounterUsers = 0;
1728
static int xmlXPathDebugObjCounterXSLTTree = 0;
1729
static int xmlXPathDebugObjCounterAll = 0;
1730
1731
static int xmlXPathDebugObjTotalUndefined = 0;
1732
static int xmlXPathDebugObjTotalNodeset = 0;
1733
static int xmlXPathDebugObjTotalBool = 0;
1734
static int xmlXPathDebugObjTotalNumber = 0;
1735
static int xmlXPathDebugObjTotalString = 0;
1736
static int xmlXPathDebugObjTotalPoint = 0;
1737
static int xmlXPathDebugObjTotalRange = 0;
1738
static int xmlXPathDebugObjTotalLocset = 0;
1739
static int xmlXPathDebugObjTotalUsers = 0;
1740
static int xmlXPathDebugObjTotalXSLTTree = 0;
1741
static int xmlXPathDebugObjTotalAll = 0;
1742
1743
static int xmlXPathDebugObjMaxUndefined = 0;
1744
static int xmlXPathDebugObjMaxNodeset = 0;
1745
static int xmlXPathDebugObjMaxBool = 0;
1746
static int xmlXPathDebugObjMaxNumber = 0;
1747
static int xmlXPathDebugObjMaxString = 0;
1748
static int xmlXPathDebugObjMaxPoint = 0;
1749
static int xmlXPathDebugObjMaxRange = 0;
1750
static int xmlXPathDebugObjMaxLocset = 0;
1751
static int xmlXPathDebugObjMaxUsers = 0;
1752
static int xmlXPathDebugObjMaxXSLTTree = 0;
1753
static int xmlXPathDebugObjMaxAll = 0;
1754
1755
static void
1756
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1757
{
1758
    if (ctxt != NULL) {
1759
  if (ctxt->cache != NULL) {
1760
      xmlXPathContextCachePtr cache =
1761
    (xmlXPathContextCachePtr) ctxt->cache;
1762
1763
      cache->dbgCachedAll = 0;
1764
      cache->dbgCachedNodeset = 0;
1765
      cache->dbgCachedString = 0;
1766
      cache->dbgCachedBool = 0;
1767
      cache->dbgCachedNumber = 0;
1768
      cache->dbgCachedPoint = 0;
1769
      cache->dbgCachedRange = 0;
1770
      cache->dbgCachedLocset = 0;
1771
      cache->dbgCachedUsers = 0;
1772
      cache->dbgCachedXSLTTree = 0;
1773
      cache->dbgCachedUndefined = 0;
1774
1775
      cache->dbgReusedAll = 0;
1776
      cache->dbgReusedNodeset = 0;
1777
      cache->dbgReusedString = 0;
1778
      cache->dbgReusedBool = 0;
1779
      cache->dbgReusedNumber = 0;
1780
      cache->dbgReusedPoint = 0;
1781
      cache->dbgReusedRange = 0;
1782
      cache->dbgReusedLocset = 0;
1783
      cache->dbgReusedUsers = 0;
1784
      cache->dbgReusedXSLTTree = 0;
1785
      cache->dbgReusedUndefined = 0;
1786
  }
1787
    }
1788
1789
    xmlXPathDebugObjCounterUndefined = 0;
1790
    xmlXPathDebugObjCounterNodeset = 0;
1791
    xmlXPathDebugObjCounterBool = 0;
1792
    xmlXPathDebugObjCounterNumber = 0;
1793
    xmlXPathDebugObjCounterString = 0;
1794
    xmlXPathDebugObjCounterPoint = 0;
1795
    xmlXPathDebugObjCounterRange = 0;
1796
    xmlXPathDebugObjCounterLocset = 0;
1797
    xmlXPathDebugObjCounterUsers = 0;
1798
    xmlXPathDebugObjCounterXSLTTree = 0;
1799
    xmlXPathDebugObjCounterAll = 0;
1800
1801
    xmlXPathDebugObjTotalUndefined = 0;
1802
    xmlXPathDebugObjTotalNodeset = 0;
1803
    xmlXPathDebugObjTotalBool = 0;
1804
    xmlXPathDebugObjTotalNumber = 0;
1805
    xmlXPathDebugObjTotalString = 0;
1806
    xmlXPathDebugObjTotalPoint = 0;
1807
    xmlXPathDebugObjTotalRange = 0;
1808
    xmlXPathDebugObjTotalLocset = 0;
1809
    xmlXPathDebugObjTotalUsers = 0;
1810
    xmlXPathDebugObjTotalXSLTTree = 0;
1811
    xmlXPathDebugObjTotalAll = 0;
1812
1813
    xmlXPathDebugObjMaxUndefined = 0;
1814
    xmlXPathDebugObjMaxNodeset = 0;
1815
    xmlXPathDebugObjMaxBool = 0;
1816
    xmlXPathDebugObjMaxNumber = 0;
1817
    xmlXPathDebugObjMaxString = 0;
1818
    xmlXPathDebugObjMaxPoint = 0;
1819
    xmlXPathDebugObjMaxRange = 0;
1820
    xmlXPathDebugObjMaxLocset = 0;
1821
    xmlXPathDebugObjMaxUsers = 0;
1822
    xmlXPathDebugObjMaxXSLTTree = 0;
1823
    xmlXPathDebugObjMaxAll = 0;
1824
1825
}
1826
1827
static void
1828
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1829
            xmlXPathObjectType objType)
1830
{
1831
    int isCached = 0;
1832
1833
    if (ctxt != NULL) {
1834
  if (ctxt->cache != NULL) {
1835
      xmlXPathContextCachePtr cache =
1836
    (xmlXPathContextCachePtr) ctxt->cache;
1837
1838
      isCached = 1;
1839
1840
      cache->dbgReusedAll++;
1841
      switch (objType) {
1842
    case XPATH_UNDEFINED:
1843
        cache->dbgReusedUndefined++;
1844
        break;
1845
    case XPATH_NODESET:
1846
        cache->dbgReusedNodeset++;
1847
        break;
1848
    case XPATH_BOOLEAN:
1849
        cache->dbgReusedBool++;
1850
        break;
1851
    case XPATH_NUMBER:
1852
        cache->dbgReusedNumber++;
1853
        break;
1854
    case XPATH_STRING:
1855
        cache->dbgReusedString++;
1856
        break;
1857
#ifdef LIBXML_XPTR_LOCS_ENABLED
1858
    case XPATH_POINT:
1859
        cache->dbgReusedPoint++;
1860
        break;
1861
    case XPATH_RANGE:
1862
        cache->dbgReusedRange++;
1863
        break;
1864
    case XPATH_LOCATIONSET:
1865
        cache->dbgReusedLocset++;
1866
        break;
1867
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1868
    case XPATH_USERS:
1869
        cache->dbgReusedUsers++;
1870
        break;
1871
    case XPATH_XSLT_TREE:
1872
        cache->dbgReusedXSLTTree++;
1873
        break;
1874
    default:
1875
        break;
1876
      }
1877
  }
1878
    }
1879
1880
    switch (objType) {
1881
  case XPATH_UNDEFINED:
1882
      if (! isCached)
1883
    xmlXPathDebugObjTotalUndefined++;
1884
      xmlXPathDebugObjCounterUndefined++;
1885
      if (xmlXPathDebugObjCounterUndefined >
1886
    xmlXPathDebugObjMaxUndefined)
1887
    xmlXPathDebugObjMaxUndefined =
1888
        xmlXPathDebugObjCounterUndefined;
1889
      break;
1890
  case XPATH_NODESET:
1891
      if (! isCached)
1892
    xmlXPathDebugObjTotalNodeset++;
1893
      xmlXPathDebugObjCounterNodeset++;
1894
      if (xmlXPathDebugObjCounterNodeset >
1895
    xmlXPathDebugObjMaxNodeset)
1896
    xmlXPathDebugObjMaxNodeset =
1897
        xmlXPathDebugObjCounterNodeset;
1898
      break;
1899
  case XPATH_BOOLEAN:
1900
      if (! isCached)
1901
    xmlXPathDebugObjTotalBool++;
1902
      xmlXPathDebugObjCounterBool++;
1903
      if (xmlXPathDebugObjCounterBool >
1904
    xmlXPathDebugObjMaxBool)
1905
    xmlXPathDebugObjMaxBool =
1906
        xmlXPathDebugObjCounterBool;
1907
      break;
1908
  case XPATH_NUMBER:
1909
      if (! isCached)
1910
    xmlXPathDebugObjTotalNumber++;
1911
      xmlXPathDebugObjCounterNumber++;
1912
      if (xmlXPathDebugObjCounterNumber >
1913
    xmlXPathDebugObjMaxNumber)
1914
    xmlXPathDebugObjMaxNumber =
1915
        xmlXPathDebugObjCounterNumber;
1916
      break;
1917
  case XPATH_STRING:
1918
      if (! isCached)
1919
    xmlXPathDebugObjTotalString++;
1920
      xmlXPathDebugObjCounterString++;
1921
      if (xmlXPathDebugObjCounterString >
1922
    xmlXPathDebugObjMaxString)
1923
    xmlXPathDebugObjMaxString =
1924
        xmlXPathDebugObjCounterString;
1925
      break;
1926
#ifdef LIBXML_XPTR_LOCS_ENABLED
1927
  case XPATH_POINT:
1928
      if (! isCached)
1929
    xmlXPathDebugObjTotalPoint++;
1930
      xmlXPathDebugObjCounterPoint++;
1931
      if (xmlXPathDebugObjCounterPoint >
1932
    xmlXPathDebugObjMaxPoint)
1933
    xmlXPathDebugObjMaxPoint =
1934
        xmlXPathDebugObjCounterPoint;
1935
      break;
1936
  case XPATH_RANGE:
1937
      if (! isCached)
1938
    xmlXPathDebugObjTotalRange++;
1939
      xmlXPathDebugObjCounterRange++;
1940
      if (xmlXPathDebugObjCounterRange >
1941
    xmlXPathDebugObjMaxRange)
1942
    xmlXPathDebugObjMaxRange =
1943
        xmlXPathDebugObjCounterRange;
1944
      break;
1945
  case XPATH_LOCATIONSET:
1946
      if (! isCached)
1947
    xmlXPathDebugObjTotalLocset++;
1948
      xmlXPathDebugObjCounterLocset++;
1949
      if (xmlXPathDebugObjCounterLocset >
1950
    xmlXPathDebugObjMaxLocset)
1951
    xmlXPathDebugObjMaxLocset =
1952
        xmlXPathDebugObjCounterLocset;
1953
      break;
1954
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1955
  case XPATH_USERS:
1956
      if (! isCached)
1957
    xmlXPathDebugObjTotalUsers++;
1958
      xmlXPathDebugObjCounterUsers++;
1959
      if (xmlXPathDebugObjCounterUsers >
1960
    xmlXPathDebugObjMaxUsers)
1961
    xmlXPathDebugObjMaxUsers =
1962
        xmlXPathDebugObjCounterUsers;
1963
      break;
1964
  case XPATH_XSLT_TREE:
1965
      if (! isCached)
1966
    xmlXPathDebugObjTotalXSLTTree++;
1967
      xmlXPathDebugObjCounterXSLTTree++;
1968
      if (xmlXPathDebugObjCounterXSLTTree >
1969
    xmlXPathDebugObjMaxXSLTTree)
1970
    xmlXPathDebugObjMaxXSLTTree =
1971
        xmlXPathDebugObjCounterXSLTTree;
1972
      break;
1973
  default:
1974
      break;
1975
    }
1976
    if (! isCached)
1977
  xmlXPathDebugObjTotalAll++;
1978
    xmlXPathDebugObjCounterAll++;
1979
    if (xmlXPathDebugObjCounterAll >
1980
  xmlXPathDebugObjMaxAll)
1981
  xmlXPathDebugObjMaxAll =
1982
      xmlXPathDebugObjCounterAll;
1983
}
1984
1985
static void
1986
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1987
            xmlXPathObjectType objType)
1988
{
1989
    int isCached = 0;
1990
1991
    if (ctxt != NULL) {
1992
  if (ctxt->cache != NULL) {
1993
      xmlXPathContextCachePtr cache =
1994
    (xmlXPathContextCachePtr) ctxt->cache;
1995
1996
      isCached = 1;
1997
1998
      cache->dbgCachedAll++;
1999
      switch (objType) {
2000
    case XPATH_UNDEFINED:
2001
        cache->dbgCachedUndefined++;
2002
        break;
2003
    case XPATH_NODESET:
2004
        cache->dbgCachedNodeset++;
2005
        break;
2006
    case XPATH_BOOLEAN:
2007
        cache->dbgCachedBool++;
2008
        break;
2009
    case XPATH_NUMBER:
2010
        cache->dbgCachedNumber++;
2011
        break;
2012
    case XPATH_STRING:
2013
        cache->dbgCachedString++;
2014
        break;
2015
#ifdef LIBXML_XPTR_LOCS_ENABLED
2016
    case XPATH_POINT:
2017
        cache->dbgCachedPoint++;
2018
        break;
2019
    case XPATH_RANGE:
2020
        cache->dbgCachedRange++;
2021
        break;
2022
    case XPATH_LOCATIONSET:
2023
        cache->dbgCachedLocset++;
2024
        break;
2025
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2026
    case XPATH_USERS:
2027
        cache->dbgCachedUsers++;
2028
        break;
2029
    case XPATH_XSLT_TREE:
2030
        cache->dbgCachedXSLTTree++;
2031
        break;
2032
    default:
2033
        break;
2034
      }
2035
2036
  }
2037
    }
2038
    switch (objType) {
2039
  case XPATH_UNDEFINED:
2040
      xmlXPathDebugObjCounterUndefined--;
2041
      break;
2042
  case XPATH_NODESET:
2043
      xmlXPathDebugObjCounterNodeset--;
2044
      break;
2045
  case XPATH_BOOLEAN:
2046
      xmlXPathDebugObjCounterBool--;
2047
      break;
2048
  case XPATH_NUMBER:
2049
      xmlXPathDebugObjCounterNumber--;
2050
      break;
2051
  case XPATH_STRING:
2052
      xmlXPathDebugObjCounterString--;
2053
      break;
2054
#ifdef LIBXML_XPTR_LOCS_ENABLED
2055
  case XPATH_POINT:
2056
      xmlXPathDebugObjCounterPoint--;
2057
      break;
2058
  case XPATH_RANGE:
2059
      xmlXPathDebugObjCounterRange--;
2060
      break;
2061
  case XPATH_LOCATIONSET:
2062
      xmlXPathDebugObjCounterLocset--;
2063
      break;
2064
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2065
  case XPATH_USERS:
2066
      xmlXPathDebugObjCounterUsers--;
2067
      break;
2068
  case XPATH_XSLT_TREE:
2069
      xmlXPathDebugObjCounterXSLTTree--;
2070
      break;
2071
  default:
2072
      break;
2073
    }
2074
    xmlXPathDebugObjCounterAll--;
2075
}
2076
2077
static void
2078
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2079
{
2080
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2081
  reqXSLTTree, reqUndefined;
2082
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2083
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2084
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2085
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2086
    int leftObjs = xmlXPathDebugObjCounterAll;
2087
2088
    reqAll = xmlXPathDebugObjTotalAll;
2089
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2090
    reqString = xmlXPathDebugObjTotalString;
2091
    reqBool = xmlXPathDebugObjTotalBool;
2092
    reqNumber = xmlXPathDebugObjTotalNumber;
2093
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2094
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2095
2096
    printf("# XPath object usage:\n");
2097
2098
    if (ctxt != NULL) {
2099
  if (ctxt->cache != NULL) {
2100
      xmlXPathContextCachePtr cache =
2101
    (xmlXPathContextCachePtr) ctxt->cache;
2102
2103
      reAll = cache->dbgReusedAll;
2104
      reqAll += reAll;
2105
      reNodeset = cache->dbgReusedNodeset;
2106
      reqNodeset += reNodeset;
2107
      reString = cache->dbgReusedString;
2108
      reqString += reString;
2109
      reBool = cache->dbgReusedBool;
2110
      reqBool += reBool;
2111
      reNumber = cache->dbgReusedNumber;
2112
      reqNumber += reNumber;
2113
      reXSLTTree = cache->dbgReusedXSLTTree;
2114
      reqXSLTTree += reXSLTTree;
2115
      reUndefined = cache->dbgReusedUndefined;
2116
      reqUndefined += reUndefined;
2117
2118
      caAll = cache->dbgCachedAll;
2119
      caBool = cache->dbgCachedBool;
2120
      caNodeset = cache->dbgCachedNodeset;
2121
      caString = cache->dbgCachedString;
2122
      caNumber = cache->dbgCachedNumber;
2123
      caXSLTTree = cache->dbgCachedXSLTTree;
2124
      caUndefined = cache->dbgCachedUndefined;
2125
2126
      if (cache->nodesetObjs)
2127
    leftObjs -= cache->nodesetObjs->number;
2128
      if (cache->stringObjs)
2129
    leftObjs -= cache->stringObjs->number;
2130
      if (cache->booleanObjs)
2131
    leftObjs -= cache->booleanObjs->number;
2132
      if (cache->numberObjs)
2133
    leftObjs -= cache->numberObjs->number;
2134
      if (cache->miscObjs)
2135
    leftObjs -= cache->miscObjs->number;
2136
  }
2137
    }
2138
2139
    printf("# all\n");
2140
    printf("#   total  : %d\n", reqAll);
2141
    printf("#   left  : %d\n", leftObjs);
2142
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2143
    printf("#   reused : %d\n", reAll);
2144
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2145
2146
    printf("# node-sets\n");
2147
    printf("#   total  : %d\n", reqNodeset);
2148
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2149
    printf("#   reused : %d\n", reNodeset);
2150
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2151
2152
    printf("# strings\n");
2153
    printf("#   total  : %d\n", reqString);
2154
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2155
    printf("#   reused : %d\n", reString);
2156
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2157
2158
    printf("# booleans\n");
2159
    printf("#   total  : %d\n", reqBool);
2160
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2161
    printf("#   reused : %d\n", reBool);
2162
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2163
2164
    printf("# numbers\n");
2165
    printf("#   total  : %d\n", reqNumber);
2166
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2167
    printf("#   reused : %d\n", reNumber);
2168
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2169
2170
    printf("# XSLT result tree fragments\n");
2171
    printf("#   total  : %d\n", reqXSLTTree);
2172
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2173
    printf("#   reused : %d\n", reXSLTTree);
2174
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2175
2176
    printf("# undefined\n");
2177
    printf("#   total  : %d\n", reqUndefined);
2178
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2179
    printf("#   reused : %d\n", reUndefined);
2180
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2181
2182
}
2183
2184
#endif /* XP_DEBUG_OBJ_USAGE */
2185
2186
#endif /* LIBXML_DEBUG_ENABLED */
2187
2188
/************************************************************************
2189
 *                  *
2190
 *      XPath object caching        *
2191
 *                  *
2192
 ************************************************************************/
2193
2194
/**
2195
 * xmlXPathNewCache:
2196
 *
2197
 * Create a new object cache
2198
 *
2199
 * Returns the xmlXPathCache just allocated.
2200
 */
2201
static xmlXPathContextCachePtr
2202
xmlXPathNewCache(void)
2203
214
{
2204
214
    xmlXPathContextCachePtr ret;
2205
2206
214
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2207
214
    if (ret == NULL) {
2208
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2209
0
  return(NULL);
2210
0
    }
2211
214
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2212
214
    ret->maxNodeset = 100;
2213
214
    ret->maxString = 100;
2214
214
    ret->maxBoolean = 100;
2215
214
    ret->maxNumber = 100;
2216
214
    ret->maxMisc = 100;
2217
214
    return(ret);
2218
214
}
2219
2220
static void
2221
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2222
354
{
2223
354
    int i;
2224
354
    xmlXPathObjectPtr obj;
2225
2226
354
    if (list == NULL)
2227
0
  return;
2228
2229
5.11k
    for (i = 0; i < list->number; i++) {
2230
4.76k
  obj = list->items[i];
2231
  /*
2232
  * Note that it is already assured that we don't need to
2233
  * look out for namespace nodes in the node-set.
2234
  */
2235
4.76k
  if (obj->nodesetval != NULL) {
2236
4.02k
      if (obj->nodesetval->nodeTab != NULL)
2237
3.68k
    xmlFree(obj->nodesetval->nodeTab);
2238
4.02k
      xmlFree(obj->nodesetval);
2239
4.02k
  }
2240
4.76k
  xmlFree(obj);
2241
#ifdef XP_DEBUG_OBJ_USAGE
2242
  xmlXPathDebugObjCounterAll--;
2243
#endif
2244
4.76k
    }
2245
354
    xmlPointerListFree(list);
2246
354
}
2247
2248
static void
2249
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2250
210
{
2251
210
    if (cache == NULL)
2252
0
  return;
2253
210
    if (cache->nodesetObjs)
2254
106
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2255
210
    if (cache->stringObjs)
2256
76
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2257
210
    if (cache->booleanObjs)
2258
35
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2259
210
    if (cache->numberObjs)
2260
69
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2261
210
    if (cache->miscObjs)
2262
68
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2263
210
    xmlFree(cache);
2264
210
}
2265
2266
/**
2267
 * xmlXPathContextSetCache:
2268
 *
2269
 * @ctxt:  the XPath context
2270
 * @active: enables/disables (creates/frees) the cache
2271
 * @value: a value with semantics dependent on @options
2272
 * @options: options (currently only the value 0 is used)
2273
 *
2274
 * Creates/frees an object cache on the XPath context.
2275
 * If activates XPath objects (xmlXPathObject) will be cached internally
2276
 * to be reused.
2277
 * @options:
2278
 *   0: This will set the XPath object caching:
2279
 *      @value:
2280
 *        This will set the maximum number of XPath objects
2281
 *        to be cached per slot
2282
 *        There are 5 slots for: node-set, string, number, boolean, and
2283
 *        misc objects. Use <0 for the default number (100).
2284
 *   Other values for @options have currently no effect.
2285
 *
2286
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2287
 */
2288
int
2289
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2290
      int active,
2291
      int value,
2292
      int options)
2293
327
{
2294
327
    if (ctxt == NULL)
2295
0
  return(-1);
2296
327
    if (active) {
2297
214
  xmlXPathContextCachePtr cache;
2298
2299
214
  if (ctxt->cache == NULL) {
2300
214
      ctxt->cache = xmlXPathNewCache();
2301
214
      if (ctxt->cache == NULL)
2302
0
    return(-1);
2303
214
  }
2304
214
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2305
214
  if (options == 0) {
2306
214
      if (value < 0)
2307
214
    value = 100;
2308
214
      cache->maxNodeset = value;
2309
214
      cache->maxString = value;
2310
214
      cache->maxNumber = value;
2311
214
      cache->maxBoolean = value;
2312
214
      cache->maxMisc = value;
2313
214
  }
2314
214
    } else if (ctxt->cache != NULL) {
2315
113
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2316
113
  ctxt->cache = NULL;
2317
113
    }
2318
327
    return(0);
2319
327
}
2320
2321
/**
2322
 * xmlXPathCacheWrapNodeSet:
2323
 * @ctxt: the XPath context
2324
 * @val:  the NodePtr value
2325
 *
2326
 * This is the cached version of xmlXPathWrapNodeSet().
2327
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2328
 *
2329
 * Returns the created or reused object.
2330
 */
2331
static xmlXPathObjectPtr
2332
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2333
38.6k
{
2334
38.6k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2335
38.6k
  xmlXPathContextCachePtr cache =
2336
38.6k
      (xmlXPathContextCachePtr) ctxt->cache;
2337
2338
38.6k
  if ((cache->miscObjs != NULL) &&
2339
38.6k
      (cache->miscObjs->number != 0))
2340
17.6k
  {
2341
17.6k
      xmlXPathObjectPtr ret;
2342
2343
17.6k
      ret = (xmlXPathObjectPtr)
2344
17.6k
    cache->miscObjs->items[--cache->miscObjs->number];
2345
17.6k
      ret->type = XPATH_NODESET;
2346
17.6k
      ret->nodesetval = val;
2347
#ifdef XP_DEBUG_OBJ_USAGE
2348
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2349
#endif
2350
17.6k
      return(ret);
2351
17.6k
  }
2352
38.6k
    }
2353
2354
21.0k
    return(xmlXPathWrapNodeSet(val));
2355
2356
38.6k
}
2357
2358
/**
2359
 * xmlXPathCacheWrapString:
2360
 * @ctxt: the XPath context
2361
 * @val:  the xmlChar * value
2362
 *
2363
 * This is the cached version of xmlXPathWrapString().
2364
 * Wraps the @val string into an XPath object.
2365
 *
2366
 * Returns the created or reused object.
2367
 */
2368
static xmlXPathObjectPtr
2369
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2370
7.10k
{
2371
7.10k
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2372
7.10k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2373
2374
7.10k
  if ((cache->stringObjs != NULL) &&
2375
7.10k
      (cache->stringObjs->number != 0))
2376
5.12k
  {
2377
2378
5.12k
      xmlXPathObjectPtr ret;
2379
2380
5.12k
      ret = (xmlXPathObjectPtr)
2381
5.12k
    cache->stringObjs->items[--cache->stringObjs->number];
2382
5.12k
      ret->type = XPATH_STRING;
2383
5.12k
      ret->stringval = val;
2384
#ifdef XP_DEBUG_OBJ_USAGE
2385
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2386
#endif
2387
5.12k
      return(ret);
2388
5.12k
  } else if ((cache->miscObjs != NULL) &&
2389
1.98k
      (cache->miscObjs->number != 0))
2390
1.87k
  {
2391
1.87k
      xmlXPathObjectPtr ret;
2392
      /*
2393
      * Fallback to misc-cache.
2394
      */
2395
1.87k
      ret = (xmlXPathObjectPtr)
2396
1.87k
    cache->miscObjs->items[--cache->miscObjs->number];
2397
2398
1.87k
      ret->type = XPATH_STRING;
2399
1.87k
      ret->stringval = val;
2400
#ifdef XP_DEBUG_OBJ_USAGE
2401
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2402
#endif
2403
1.87k
      return(ret);
2404
1.87k
  }
2405
7.10k
    }
2406
105
    return(xmlXPathWrapString(val));
2407
7.10k
}
2408
2409
/**
2410
 * xmlXPathCacheNewNodeSet:
2411
 * @ctxt: the XPath context
2412
 * @val:  the NodePtr value
2413
 *
2414
 * This is the cached version of xmlXPathNewNodeSet().
2415
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2416
 * it with the single Node @val
2417
 *
2418
 * Returns the created or reused object.
2419
 */
2420
static xmlXPathObjectPtr
2421
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2422
138k
{
2423
138k
    if ((ctxt != NULL) && (ctxt->cache)) {
2424
138k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2425
2426
138k
  if ((cache->nodesetObjs != NULL) &&
2427
138k
      (cache->nodesetObjs->number != 0))
2428
134k
  {
2429
134k
      xmlXPathObjectPtr ret;
2430
      /*
2431
      * Use the nodeset-cache.
2432
      */
2433
134k
      ret = (xmlXPathObjectPtr)
2434
134k
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2435
134k
      ret->type = XPATH_NODESET;
2436
134k
      ret->boolval = 0;
2437
134k
      if (val) {
2438
124k
    if ((ret->nodesetval->nodeMax == 0) ||
2439
124k
        (val->type == XML_NAMESPACE_DECL))
2440
8.42k
    {
2441
                    /* TODO: Check memory error. */
2442
8.42k
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2443
115k
    } else {
2444
115k
        ret->nodesetval->nodeTab[0] = val;
2445
115k
        ret->nodesetval->nodeNr = 1;
2446
115k
    }
2447
124k
      }
2448
#ifdef XP_DEBUG_OBJ_USAGE
2449
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2450
#endif
2451
134k
      return(ret);
2452
134k
  } else if ((cache->miscObjs != NULL) &&
2453
3.82k
      (cache->miscObjs->number != 0))
2454
0
  {
2455
0
      xmlXPathObjectPtr ret;
2456
      /*
2457
      * Fallback to misc-cache.
2458
      */
2459
2460
0
      ret = (xmlXPathObjectPtr)
2461
0
    cache->miscObjs->items[--cache->miscObjs->number];
2462
2463
0
      ret->type = XPATH_NODESET;
2464
0
      ret->boolval = 0;
2465
0
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2466
0
      if (ret->nodesetval == NULL) {
2467
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2468
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2469
0
    return(NULL);
2470
0
      }
2471
#ifdef XP_DEBUG_OBJ_USAGE
2472
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2473
#endif
2474
0
      return(ret);
2475
0
  }
2476
138k
    }
2477
3.82k
    return(xmlXPathNewNodeSet(val));
2478
138k
}
2479
2480
/**
2481
 * xmlXPathCacheNewCString:
2482
 * @ctxt: the XPath context
2483
 * @val:  the char * value
2484
 *
2485
 * This is the cached version of xmlXPathNewCString().
2486
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2487
 *
2488
 * Returns the created or reused object.
2489
 */
2490
static xmlXPathObjectPtr
2491
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2492
216
{
2493
216
    if ((ctxt != NULL) && (ctxt->cache)) {
2494
216
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2495
2496
216
  if ((cache->stringObjs != NULL) &&
2497
216
      (cache->stringObjs->number != 0))
2498
200
  {
2499
200
      xmlXPathObjectPtr ret;
2500
2501
200
      ret = (xmlXPathObjectPtr)
2502
200
    cache->stringObjs->items[--cache->stringObjs->number];
2503
2504
200
      ret->type = XPATH_STRING;
2505
200
      ret->stringval = xmlStrdup(BAD_CAST val);
2506
#ifdef XP_DEBUG_OBJ_USAGE
2507
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2508
#endif
2509
200
      return(ret);
2510
200
  } else if ((cache->miscObjs != NULL) &&
2511
16
      (cache->miscObjs->number != 0))
2512
14
  {
2513
14
      xmlXPathObjectPtr ret;
2514
2515
14
      ret = (xmlXPathObjectPtr)
2516
14
    cache->miscObjs->items[--cache->miscObjs->number];
2517
2518
14
      ret->type = XPATH_STRING;
2519
14
      ret->stringval = xmlStrdup(BAD_CAST val);
2520
#ifdef XP_DEBUG_OBJ_USAGE
2521
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2522
#endif
2523
14
      return(ret);
2524
14
  }
2525
216
    }
2526
2
    return(xmlXPathNewCString(val));
2527
216
}
2528
2529
/**
2530
 * xmlXPathCacheNewString:
2531
 * @ctxt: the XPath context
2532
 * @val:  the xmlChar * value
2533
 *
2534
 * This is the cached version of xmlXPathNewString().
2535
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2536
 *
2537
 * Returns the created or reused object.
2538
 */
2539
static xmlXPathObjectPtr
2540
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2541
2.13M
{
2542
2.13M
    if ((ctxt != NULL) && (ctxt->cache)) {
2543
2.13M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2544
2545
2.13M
  if ((cache->stringObjs != NULL) &&
2546
2.13M
      (cache->stringObjs->number != 0))
2547
2.13M
  {
2548
2.13M
      xmlXPathObjectPtr ret;
2549
2550
2.13M
      ret = (xmlXPathObjectPtr)
2551
2.13M
    cache->stringObjs->items[--cache->stringObjs->number];
2552
2.13M
      ret->type = XPATH_STRING;
2553
2.13M
      if (val != NULL)
2554
2.13M
    ret->stringval = xmlStrdup(val);
2555
0
      else
2556
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2557
#ifdef XP_DEBUG_OBJ_USAGE
2558
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2559
#endif
2560
2.13M
      return(ret);
2561
2.13M
  } else if ((cache->miscObjs != NULL) &&
2562
1.65k
      (cache->miscObjs->number != 0))
2563
69
  {
2564
69
      xmlXPathObjectPtr ret;
2565
2566
69
      ret = (xmlXPathObjectPtr)
2567
69
    cache->miscObjs->items[--cache->miscObjs->number];
2568
2569
69
      ret->type = XPATH_STRING;
2570
69
      if (val != NULL)
2571
69
    ret->stringval = xmlStrdup(val);
2572
0
      else
2573
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2574
#ifdef XP_DEBUG_OBJ_USAGE
2575
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2576
#endif
2577
69
      return(ret);
2578
69
  }
2579
2.13M
    }
2580
1.58k
    return(xmlXPathNewString(val));
2581
2.13M
}
2582
2583
/**
2584
 * xmlXPathCacheNewBoolean:
2585
 * @ctxt: the XPath context
2586
 * @val:  the boolean value
2587
 *
2588
 * This is the cached version of xmlXPathNewBoolean().
2589
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2590
 *
2591
 * Returns the created or reused object.
2592
 */
2593
static xmlXPathObjectPtr
2594
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2595
5.84k
{
2596
5.84k
    if ((ctxt != NULL) && (ctxt->cache)) {
2597
5.84k
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2598
2599
5.84k
  if ((cache->booleanObjs != NULL) &&
2600
5.84k
      (cache->booleanObjs->number != 0))
2601
4.68k
  {
2602
4.68k
      xmlXPathObjectPtr ret;
2603
2604
4.68k
      ret = (xmlXPathObjectPtr)
2605
4.68k
    cache->booleanObjs->items[--cache->booleanObjs->number];
2606
4.68k
      ret->type = XPATH_BOOLEAN;
2607
4.68k
      ret->boolval = (val != 0);
2608
#ifdef XP_DEBUG_OBJ_USAGE
2609
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2610
#endif
2611
4.68k
      return(ret);
2612
4.68k
  } else if ((cache->miscObjs != NULL) &&
2613
1.16k
      (cache->miscObjs->number != 0))
2614
271
  {
2615
271
      xmlXPathObjectPtr ret;
2616
2617
271
      ret = (xmlXPathObjectPtr)
2618
271
    cache->miscObjs->items[--cache->miscObjs->number];
2619
2620
271
      ret->type = XPATH_BOOLEAN;
2621
271
      ret->boolval = (val != 0);
2622
#ifdef XP_DEBUG_OBJ_USAGE
2623
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2624
#endif
2625
271
      return(ret);
2626
271
  }
2627
5.84k
    }
2628
892
    return(xmlXPathNewBoolean(val));
2629
5.84k
}
2630
2631
/**
2632
 * xmlXPathCacheNewFloat:
2633
 * @ctxt: the XPath context
2634
 * @val:  the double value
2635
 *
2636
 * This is the cached version of xmlXPathNewFloat().
2637
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2638
 *
2639
 * Returns the created or reused object.
2640
 */
2641
static xmlXPathObjectPtr
2642
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2643
2.20M
{
2644
2.20M
     if ((ctxt != NULL) && (ctxt->cache)) {
2645
2.20M
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2646
2647
2.20M
  if ((cache->numberObjs != NULL) &&
2648
2.20M
      (cache->numberObjs->number != 0))
2649
2.17M
  {
2650
2.17M
      xmlXPathObjectPtr ret;
2651
2652
2.17M
      ret = (xmlXPathObjectPtr)
2653
2.17M
    cache->numberObjs->items[--cache->numberObjs->number];
2654
2.17M
      ret->type = XPATH_NUMBER;
2655
2.17M
      ret->floatval = val;
2656
#ifdef XP_DEBUG_OBJ_USAGE
2657
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2658
#endif
2659
2.17M
      return(ret);
2660
2.17M
  } else if ((cache->miscObjs != NULL) &&
2661
34.3k
      (cache->miscObjs->number != 0))
2662
3.22k
  {
2663
3.22k
      xmlXPathObjectPtr ret;
2664
2665
3.22k
      ret = (xmlXPathObjectPtr)
2666
3.22k
    cache->miscObjs->items[--cache->miscObjs->number];
2667
2668
3.22k
      ret->type = XPATH_NUMBER;
2669
3.22k
      ret->floatval = val;
2670
#ifdef XP_DEBUG_OBJ_USAGE
2671
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2672
#endif
2673
3.22k
      return(ret);
2674
3.22k
  }
2675
2.20M
    }
2676
31.1k
    return(xmlXPathNewFloat(val));
2677
2.20M
}
2678
2679
/**
2680
 * xmlXPathCacheConvertString:
2681
 * @ctxt: the XPath context
2682
 * @val:  an XPath object
2683
 *
2684
 * This is the cached version of xmlXPathConvertString().
2685
 * Converts an existing object to its string() equivalent
2686
 *
2687
 * Returns a created or reused object, the old one is freed (cached)
2688
 *         (or the operation is done directly on @val)
2689
 */
2690
2691
static xmlXPathObjectPtr
2692
7.47k
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2693
7.47k
    xmlChar *res = NULL;
2694
2695
7.47k
    if (val == NULL)
2696
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2697
2698
7.47k
    switch (val->type) {
2699
0
    case XPATH_UNDEFINED:
2700
#ifdef DEBUG_EXPR
2701
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2702
#endif
2703
0
  break;
2704
7.00k
    case XPATH_NODESET:
2705
7.00k
    case XPATH_XSLT_TREE:
2706
7.00k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2707
7.00k
  break;
2708
371
    case XPATH_STRING:
2709
371
  return(val);
2710
96
    case XPATH_BOOLEAN:
2711
96
  res = xmlXPathCastBooleanToString(val->boolval);
2712
96
  break;
2713
0
    case XPATH_NUMBER:
2714
0
  res = xmlXPathCastNumberToString(val->floatval);
2715
0
  break;
2716
0
    case XPATH_USERS:
2717
#ifdef LIBXML_XPTR_LOCS_ENABLED
2718
    case XPATH_POINT:
2719
    case XPATH_RANGE:
2720
    case XPATH_LOCATIONSET:
2721
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2722
0
  TODO;
2723
0
  break;
2724
7.47k
    }
2725
7.10k
    xmlXPathReleaseObject(ctxt, val);
2726
7.10k
    if (res == NULL)
2727
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2728
7.10k
    return(xmlXPathCacheWrapString(ctxt, res));
2729
7.10k
}
2730
2731
/**
2732
 * xmlXPathCacheObjectCopy:
2733
 * @ctxt: the XPath context
2734
 * @val:  the original object
2735
 *
2736
 * This is the cached version of xmlXPathObjectCopy().
2737
 * Acquire a copy of a given object
2738
 *
2739
 * Returns a created or reused created object.
2740
 */
2741
static xmlXPathObjectPtr
2742
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2743
14.8k
{
2744
14.8k
    if (val == NULL)
2745
0
  return(NULL);
2746
2747
14.8k
    if (XP_HAS_CACHE(ctxt)) {
2748
14.8k
  switch (val->type) {
2749
0
      case XPATH_NODESET:
2750
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2751
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2752
6.72k
      case XPATH_STRING:
2753
6.72k
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2754
0
      case XPATH_BOOLEAN:
2755
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2756
8.13k
      case XPATH_NUMBER:
2757
8.13k
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2758
0
      default:
2759
0
    break;
2760
14.8k
  }
2761
14.8k
    }
2762
0
    return(xmlXPathObjectCopy(val));
2763
14.8k
}
2764
2765
/**
2766
 * xmlXPathCacheConvertBoolean:
2767
 * @ctxt: the XPath context
2768
 * @val:  an XPath object
2769
 *
2770
 * This is the cached version of xmlXPathConvertBoolean().
2771
 * Converts an existing object to its boolean() equivalent
2772
 *
2773
 * Returns a created or reused object, the old one is freed (or the operation
2774
 *         is done directly on @val)
2775
 */
2776
static xmlXPathObjectPtr
2777
1.97k
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2778
1.97k
    xmlXPathObjectPtr ret;
2779
2780
1.97k
    if (val == NULL)
2781
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2782
1.97k
    if (val->type == XPATH_BOOLEAN)
2783
0
  return(val);
2784
1.97k
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2785
1.97k
    xmlXPathReleaseObject(ctxt, val);
2786
1.97k
    return(ret);
2787
1.97k
}
2788
2789
/**
2790
 * xmlXPathCacheConvertNumber:
2791
 * @ctxt: the XPath context
2792
 * @val:  an XPath object
2793
 *
2794
 * This is the cached version of xmlXPathConvertNumber().
2795
 * Converts an existing object to its number() equivalent
2796
 *
2797
 * Returns a created or reused object, the old one is freed (or the operation
2798
 *         is done directly on @val)
2799
 */
2800
static xmlXPathObjectPtr
2801
2.12M
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2802
2.12M
    xmlXPathObjectPtr ret;
2803
2804
2.12M
    if (val == NULL)
2805
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2806
2.12M
    if (val->type == XPATH_NUMBER)
2807
0
  return(val);
2808
2.12M
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2809
2.12M
    xmlXPathReleaseObject(ctxt, val);
2810
2.12M
    return(ret);
2811
2.12M
}
2812
2813
/************************************************************************
2814
 *                  *
2815
 *    Parser stacks related functions and macros    *
2816
 *                  *
2817
 ************************************************************************/
2818
2819
/**
2820
 * xmlXPathSetFrame:
2821
 * @ctxt: an XPath parser context
2822
 *
2823
 * Set the callee evaluation frame
2824
 *
2825
 * Returns the previous frame value to be restored once done
2826
 */
2827
static int
2828
60.8k
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2829
60.8k
    int ret;
2830
2831
60.8k
    if (ctxt == NULL)
2832
0
        return(0);
2833
60.8k
    ret = ctxt->valueFrame;
2834
60.8k
    ctxt->valueFrame = ctxt->valueNr;
2835
60.8k
    return(ret);
2836
60.8k
}
2837
2838
/**
2839
 * xmlXPathPopFrame:
2840
 * @ctxt: an XPath parser context
2841
 * @frame: the previous frame value
2842
 *
2843
 * Remove the callee evaluation frame
2844
 */
2845
static void
2846
60.3k
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2847
60.3k
    if (ctxt == NULL)
2848
0
        return;
2849
60.3k
    if (ctxt->valueNr < ctxt->valueFrame) {
2850
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2851
0
    }
2852
60.3k
    ctxt->valueFrame = frame;
2853
60.3k
}
2854
2855
/**
2856
 * valuePop:
2857
 * @ctxt: an XPath evaluation context
2858
 *
2859
 * Pops the top XPath object from the value stack
2860
 *
2861
 * Returns the XPath object just removed
2862
 */
2863
xmlXPathObjectPtr
2864
valuePop(xmlXPathParserContextPtr ctxt)
2865
4.51M
{
2866
4.51M
    xmlXPathObjectPtr ret;
2867
2868
4.51M
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2869
180
        return (NULL);
2870
2871
4.51M
    if (ctxt->valueNr <= ctxt->valueFrame) {
2872
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2873
0
        return (NULL);
2874
0
    }
2875
2876
4.51M
    ctxt->valueNr--;
2877
4.51M
    if (ctxt->valueNr > 0)
2878
77.5k
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2879
4.43M
    else
2880
4.43M
        ctxt->value = NULL;
2881
4.51M
    ret = ctxt->valueTab[ctxt->valueNr];
2882
4.51M
    ctxt->valueTab[ctxt->valueNr] = NULL;
2883
4.51M
    return (ret);
2884
4.51M
}
2885
/**
2886
 * valuePush:
2887
 * @ctxt:  an XPath evaluation context
2888
 * @value:  the XPath object
2889
 *
2890
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2891
 * a memory error is recorded in the parser context.
2892
 *
2893
 * Returns the number of items on the value stack, or -1 in case of error.
2894
 */
2895
int
2896
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2897
4.51M
{
2898
4.51M
    if (ctxt == NULL) return(-1);
2899
4.51M
    if (value == NULL) {
2900
        /*
2901
         * A NULL value typically indicates that a memory allocation failed,
2902
         * so we set ctxt->error here to propagate the error.
2903
         */
2904
0
  ctxt->error = XPATH_MEMORY_ERROR;
2905
0
        return(-1);
2906
0
    }
2907
4.51M
    if (ctxt->valueNr >= ctxt->valueMax) {
2908
0
        xmlXPathObjectPtr *tmp;
2909
2910
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2911
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2912
0
            return (-1);
2913
0
        }
2914
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2915
0
                                             2 * ctxt->valueMax *
2916
0
                                             sizeof(ctxt->valueTab[0]));
2917
0
        if (tmp == NULL) {
2918
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2919
0
            return (-1);
2920
0
        }
2921
0
        ctxt->valueMax *= 2;
2922
0
  ctxt->valueTab = tmp;
2923
0
    }
2924
4.51M
    ctxt->valueTab[ctxt->valueNr] = value;
2925
4.51M
    ctxt->value = value;
2926
4.51M
    return (ctxt->valueNr++);
2927
4.51M
}
2928
2929
/**
2930
 * xmlXPathPopBoolean:
2931
 * @ctxt:  an XPath parser context
2932
 *
2933
 * Pops a boolean from the stack, handling conversion if needed.
2934
 * Check error with #xmlXPathCheckError.
2935
 *
2936
 * Returns the boolean
2937
 */
2938
int
2939
11
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2940
11
    xmlXPathObjectPtr obj;
2941
11
    int ret;
2942
2943
11
    obj = valuePop(ctxt);
2944
11
    if (obj == NULL) {
2945
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2946
0
  return(0);
2947
0
    }
2948
11
    if (obj->type != XPATH_BOOLEAN)
2949
2
  ret = xmlXPathCastToBoolean(obj);
2950
9
    else
2951
9
        ret = obj->boolval;
2952
11
    xmlXPathReleaseObject(ctxt->context, obj);
2953
11
    return(ret);
2954
11
}
2955
2956
/**
2957
 * xmlXPathPopNumber:
2958
 * @ctxt:  an XPath parser context
2959
 *
2960
 * Pops a number from the stack, handling conversion if needed.
2961
 * Check error with #xmlXPathCheckError.
2962
 *
2963
 * Returns the number
2964
 */
2965
double
2966
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2967
0
    xmlXPathObjectPtr obj;
2968
0
    double ret;
2969
2970
0
    obj = valuePop(ctxt);
2971
0
    if (obj == NULL) {
2972
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2973
0
  return(0);
2974
0
    }
2975
0
    if (obj->type != XPATH_NUMBER)
2976
0
  ret = xmlXPathCastToNumber(obj);
2977
0
    else
2978
0
        ret = obj->floatval;
2979
0
    xmlXPathReleaseObject(ctxt->context, obj);
2980
0
    return(ret);
2981
0
}
2982
2983
/**
2984
 * xmlXPathPopString:
2985
 * @ctxt:  an XPath parser context
2986
 *
2987
 * Pops a string from the stack, handling conversion if needed.
2988
 * Check error with #xmlXPathCheckError.
2989
 *
2990
 * Returns the string
2991
 */
2992
xmlChar *
2993
5.89k
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2994
5.89k
    xmlXPathObjectPtr obj;
2995
5.89k
    xmlChar * ret;
2996
2997
5.89k
    obj = valuePop(ctxt);
2998
5.89k
    if (obj == NULL) {
2999
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3000
0
  return(NULL);
3001
0
    }
3002
5.89k
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
3003
    /* TODO: needs refactoring somewhere else */
3004
5.89k
    if (obj->stringval == ret)
3005
0
  obj->stringval = NULL;
3006
5.89k
    xmlXPathReleaseObject(ctxt->context, obj);
3007
5.89k
    return(ret);
3008
5.89k
}
3009
3010
/**
3011
 * xmlXPathPopNodeSet:
3012
 * @ctxt:  an XPath parser context
3013
 *
3014
 * Pops a node-set from the stack, handling conversion if needed.
3015
 * Check error with #xmlXPathCheckError.
3016
 *
3017
 * Returns the node-set
3018
 */
3019
xmlNodeSetPtr
3020
7.53k
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3021
7.53k
    xmlXPathObjectPtr obj;
3022
7.53k
    xmlNodeSetPtr ret;
3023
3024
7.53k
    if (ctxt == NULL) return(NULL);
3025
7.53k
    if (ctxt->value == NULL) {
3026
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3027
0
  return(NULL);
3028
0
    }
3029
7.53k
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3030
0
  xmlXPathSetTypeError(ctxt);
3031
0
  return(NULL);
3032
0
    }
3033
7.53k
    obj = valuePop(ctxt);
3034
7.53k
    ret = obj->nodesetval;
3035
#if 0
3036
    /* to fix memory leak of not clearing obj->user */
3037
    if (obj->boolval && obj->user != NULL)
3038
        xmlFreeNodeList((xmlNodePtr) obj->user);
3039
#endif
3040
7.53k
    obj->nodesetval = NULL;
3041
7.53k
    xmlXPathReleaseObject(ctxt->context, obj);
3042
7.53k
    return(ret);
3043
7.53k
}
3044
3045
/**
3046
 * xmlXPathPopExternal:
3047
 * @ctxt:  an XPath parser context
3048
 *
3049
 * Pops an external object from the stack, handling conversion if needed.
3050
 * Check error with #xmlXPathCheckError.
3051
 *
3052
 * Returns the object
3053
 */
3054
void *
3055
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3056
0
    xmlXPathObjectPtr obj;
3057
0
    void * ret;
3058
3059
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3060
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3061
0
  return(NULL);
3062
0
    }
3063
0
    if (ctxt->value->type != XPATH_USERS) {
3064
0
  xmlXPathSetTypeError(ctxt);
3065
0
  return(NULL);
3066
0
    }
3067
0
    obj = valuePop(ctxt);
3068
0
    ret = obj->user;
3069
0
    obj->user = NULL;
3070
0
    xmlXPathReleaseObject(ctxt->context, obj);
3071
0
    return(ret);
3072
0
}
3073
3074
/*
3075
 * Macros for accessing the content. Those should be used only by the parser,
3076
 * and not exported.
3077
 *
3078
 * Dirty macros, i.e. one need to make assumption on the context to use them
3079
 *
3080
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3081
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3082
 *           in ISO-Latin or UTF-8.
3083
 *           This should be used internally by the parser
3084
 *           only to compare to ASCII values otherwise it would break when
3085
 *           running with UTF-8 encoding.
3086
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3087
 *           to compare on ASCII based substring.
3088
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3089
 *           strings within the parser.
3090
 *   CURRENT Returns the current char value, with the full decoding of
3091
 *           UTF-8 if we are using this mode. It returns an int.
3092
 *   NEXT    Skip to the next character, this does the proper decoding
3093
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3094
 *           It returns the pointer to the current xmlChar.
3095
 */
3096
3097
172M
#define CUR (*ctxt->cur)
3098
32.4k
#define SKIP(val) ctxt->cur += (val)
3099
59.4M
#define NXT(val) ctxt->cur[(val)]
3100
2.90k
#define CUR_PTR ctxt->cur
3101
29.0M
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3102
3103
#define COPY_BUF(l,b,i,v)                                              \
3104
7.91M
    if (l == 1) b[i++] = v;                                            \
3105
7.91M
    else i += xmlCopyChar(l,&b[i],v)
3106
3107
16.0M
#define NEXTL(l)  ctxt->cur += l
3108
3109
#define SKIP_BLANKS             \
3110
85.3M
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3111
3112
#define CURRENT (*ctxt->cur)
3113
68.5M
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3114
3115
3116
#ifndef DBL_DIG
3117
#define DBL_DIG 16
3118
#endif
3119
#ifndef DBL_EPSILON
3120
#define DBL_EPSILON 1E-9
3121
#endif
3122
3123
218
#define UPPER_DOUBLE 1E9
3124
218
#define LOWER_DOUBLE 1E-5
3125
#define LOWER_DOUBLE_EXP 5
3126
3127
#define INTEGER_DIGITS DBL_DIG
3128
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3129
0
#define EXPONENT_DIGITS (3 + 2)
3130
3131
/**
3132
 * xmlXPathFormatNumber:
3133
 * @number:     number to format
3134
 * @buffer:     output buffer
3135
 * @buffersize: size of output buffer
3136
 *
3137
 * Convert the number into a string representation.
3138
 */
3139
static void
3140
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3141
2.58k
{
3142
2.58k
    switch (xmlXPathIsInf(number)) {
3143
0
    case 1:
3144
0
  if (buffersize > (int)sizeof("Infinity"))
3145
0
      snprintf(buffer, buffersize, "Infinity");
3146
0
  break;
3147
0
    case -1:
3148
0
  if (buffersize > (int)sizeof("-Infinity"))
3149
0
      snprintf(buffer, buffersize, "-Infinity");
3150
0
  break;
3151
2.58k
    default:
3152
2.58k
  if (xmlXPathIsNaN(number)) {
3153
0
      if (buffersize > (int)sizeof("NaN"))
3154
0
    snprintf(buffer, buffersize, "NaN");
3155
2.58k
  } else if (number == 0) {
3156
            /* Omit sign for negative zero. */
3157
0
      snprintf(buffer, buffersize, "0");
3158
2.58k
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3159
2.58k
                   (number == (int) number)) {
3160
2.36k
      char work[30];
3161
2.36k
      char *ptr, *cur;
3162
2.36k
      int value = (int) number;
3163
3164
2.36k
            ptr = &buffer[0];
3165
2.36k
      if (value == 0) {
3166
0
    *ptr++ = '0';
3167
2.36k
      } else {
3168
2.36k
    snprintf(work, 29, "%d", value);
3169
2.36k
    cur = &work[0];
3170
5.01k
    while ((*cur) && (ptr - buffer < buffersize)) {
3171
2.65k
        *ptr++ = *cur++;
3172
2.65k
    }
3173
2.36k
      }
3174
2.36k
      if (ptr - buffer < buffersize) {
3175
2.36k
    *ptr = 0;
3176
2.36k
      } else if (buffersize > 0) {
3177
0
    ptr--;
3178
0
    *ptr = 0;
3179
0
      }
3180
2.36k
  } else {
3181
      /*
3182
        For the dimension of work,
3183
            DBL_DIG is number of significant digits
3184
      EXPONENT is only needed for "scientific notation"
3185
            3 is sign, decimal point, and terminating zero
3186
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3187
        Note that this dimension is slightly (a few characters)
3188
        larger than actually necessary.
3189
      */
3190
218
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3191
218
      int integer_place, fraction_place;
3192
218
      char *ptr;
3193
218
      char *after_fraction;
3194
218
      double absolute_value;
3195
218
      int size;
3196
3197
218
      absolute_value = fabs(number);
3198
3199
      /*
3200
       * First choose format - scientific or regular floating point.
3201
       * In either case, result is in work, and after_fraction points
3202
       * just past the fractional part.
3203
      */
3204
218
      if ( ((absolute_value > UPPER_DOUBLE) ||
3205
218
      (absolute_value < LOWER_DOUBLE)) &&
3206
218
     (absolute_value != 0.0) ) {
3207
    /* Use scientific notation */
3208
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3209
0
    fraction_place = DBL_DIG - 1;
3210
0
    size = snprintf(work, sizeof(work),"%*.*e",
3211
0
       integer_place, fraction_place, number);
3212
0
    while ((size > 0) && (work[size] != 'e')) size--;
3213
3214
0
      }
3215
218
      else {
3216
    /* Use regular notation */
3217
218
    if (absolute_value > 0.0) {
3218
218
        integer_place = (int)log10(absolute_value);
3219
218
        if (integer_place > 0)
3220
0
            fraction_place = DBL_DIG - integer_place - 1;
3221
218
        else
3222
218
            fraction_place = DBL_DIG - integer_place;
3223
218
    } else {
3224
0
        fraction_place = 1;
3225
0
    }
3226
218
    size = snprintf(work, sizeof(work), "%0.*f",
3227
218
        fraction_place, number);
3228
218
      }
3229
3230
      /* Remove leading spaces sometimes inserted by snprintf */
3231
218
      while (work[0] == ' ') {
3232
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3233
0
    size--;
3234
0
      }
3235
3236
      /* Remove fractional trailing zeroes */
3237
218
      after_fraction = work + size;
3238
218
      ptr = after_fraction;
3239
3.27k
      while (*(--ptr) == '0')
3240
3.05k
    ;
3241
218
      if (*ptr != '.')
3242
218
          ptr++;
3243
218
      while ((*ptr++ = *after_fraction++) != 0);
3244
3245
      /* Finally copy result back to caller */
3246
218
      size = strlen(work) + 1;
3247
218
      if (size > buffersize) {
3248
0
    work[buffersize - 1] = 0;
3249
0
    size = buffersize;
3250
0
      }
3251
218
      memmove(buffer, work, size);
3252
218
  }
3253
2.58k
  break;
3254
2.58k
    }
3255
2.58k
}
3256
3257
3258
/************************************************************************
3259
 *                  *
3260
 *      Routines to handle NodeSets     *
3261
 *                  *
3262
 ************************************************************************/
3263
3264
/**
3265
 * xmlXPathOrderDocElems:
3266
 * @doc:  an input document
3267
 *
3268
 * Call this routine to speed up XPath computation on static documents.
3269
 * This stamps all the element nodes with the document order
3270
 * Like for line information, the order is kept in the element->content
3271
 * field, the value stored is actually - the node number (starting at -1)
3272
 * to be able to differentiate from line numbers.
3273
 *
3274
 * Returns the number of elements found in the document or -1 in case
3275
 *    of error.
3276
 */
3277
long
3278
37
xmlXPathOrderDocElems(xmlDocPtr doc) {
3279
37
    ptrdiff_t count = 0;
3280
37
    xmlNodePtr cur;
3281
3282
37
    if (doc == NULL)
3283
0
  return(-1);
3284
37
    cur = doc->children;
3285
1.58k
    while (cur != NULL) {
3286
1.54k
  if (cur->type == XML_ELEMENT_NODE) {
3287
479
      cur->content = (void *) (-(++count));
3288
479
      if (cur->children != NULL) {
3289
368
    cur = cur->children;
3290
368
    continue;
3291
368
      }
3292
479
  }
3293
1.18k
  if (cur->next != NULL) {
3294
812
      cur = cur->next;
3295
812
      continue;
3296
812
  }
3297
405
  do {
3298
405
      cur = cur->parent;
3299
405
      if (cur == NULL)
3300
0
    break;
3301
405
      if (cur == (xmlNodePtr) doc) {
3302
37
    cur = NULL;
3303
37
    break;
3304
37
      }
3305
368
      if (cur->next != NULL) {
3306
331
    cur = cur->next;
3307
331
    break;
3308
331
      }
3309
368
  } while (cur != NULL);
3310
368
    }
3311
37
    return(count);
3312
37
}
3313
3314
/**
3315
 * xmlXPathCmpNodes:
3316
 * @node1:  the first node
3317
 * @node2:  the second node
3318
 *
3319
 * Compare two nodes w.r.t document order
3320
 *
3321
 * Returns -2 in case of error 1 if first point < second point, 0 if
3322
 *         it's the same node, -1 otherwise
3323
 */
3324
int
3325
422
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3326
422
    int depth1, depth2;
3327
422
    int attr1 = 0, attr2 = 0;
3328
422
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3329
422
    xmlNodePtr cur, root;
3330
3331
422
    if ((node1 == NULL) || (node2 == NULL))
3332
0
  return(-2);
3333
    /*
3334
     * a couple of optimizations which will avoid computations in most cases
3335
     */
3336
422
    if (node1 == node2)    /* trivial case */
3337
0
  return(0);
3338
422
    if (node1->type == XML_ATTRIBUTE_NODE) {
3339
0
  attr1 = 1;
3340
0
  attrNode1 = node1;
3341
0
  node1 = node1->parent;
3342
0
    }
3343
422
    if (node2->type == XML_ATTRIBUTE_NODE) {
3344
312
  attr2 = 1;
3345
312
  attrNode2 = node2;
3346
312
  node2 = node2->parent;
3347
312
    }
3348
422
    if (node1 == node2) {
3349
0
  if (attr1 == attr2) {
3350
      /* not required, but we keep attributes in order */
3351
0
      if (attr1 != 0) {
3352
0
          cur = attrNode2->prev;
3353
0
    while (cur != NULL) {
3354
0
        if (cur == attrNode1)
3355
0
            return (1);
3356
0
        cur = cur->prev;
3357
0
    }
3358
0
    return (-1);
3359
0
      }
3360
0
      return(0);
3361
0
  }
3362
0
  if (attr2 == 1)
3363
0
      return(1);
3364
0
  return(-1);
3365
0
    }
3366
422
    if ((node1->type == XML_NAMESPACE_DECL) ||
3367
422
        (node2->type == XML_NAMESPACE_DECL))
3368
110
  return(1);
3369
312
    if (node1 == node2->prev)
3370
78
  return(1);
3371
234
    if (node1 == node2->next)
3372
0
  return(-1);
3373
3374
    /*
3375
     * Speedup using document order if available.
3376
     */
3377
234
    if ((node1->type == XML_ELEMENT_NODE) &&
3378
234
  (node2->type == XML_ELEMENT_NODE) &&
3379
234
  (0 > (ptrdiff_t) node1->content) &&
3380
234
  (0 > (ptrdiff_t) node2->content) &&
3381
234
  (node1->doc == node2->doc)) {
3382
0
  ptrdiff_t l1, l2;
3383
3384
0
  l1 = -((ptrdiff_t) node1->content);
3385
0
  l2 = -((ptrdiff_t) node2->content);
3386
0
  if (l1 < l2)
3387
0
      return(1);
3388
0
  if (l1 > l2)
3389
0
      return(-1);
3390
0
    }
3391
3392
    /*
3393
     * compute depth to root
3394
     */
3395
858
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3396
624
  if (cur->parent == node1)
3397
0
      return(1);
3398
624
  depth2++;
3399
624
    }
3400
234
    root = cur;
3401
702
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3402
468
  if (cur->parent == node2)
3403
0
      return(-1);
3404
468
  depth1++;
3405
468
    }
3406
    /*
3407
     * Distinct document (or distinct entities :-( ) case.
3408
     */
3409
234
    if (root != cur) {
3410
0
  return(-2);
3411
0
    }
3412
    /*
3413
     * get the nearest common ancestor.
3414
     */
3415
234
    while (depth1 > depth2) {
3416
0
  depth1--;
3417
0
  node1 = node1->parent;
3418
0
    }
3419
390
    while (depth2 > depth1) {
3420
156
  depth2--;
3421
156
  node2 = node2->parent;
3422
156
    }
3423
234
    while (node1->parent != node2->parent) {
3424
0
  node1 = node1->parent;
3425
0
  node2 = node2->parent;
3426
  /* should not happen but just in case ... */
3427
0
  if ((node1 == NULL) || (node2 == NULL))
3428
0
      return(-2);
3429
0
    }
3430
    /*
3431
     * Find who's first.
3432
     */
3433
234
    if (node1 == node2->prev)
3434
78
  return(1);
3435
156
    if (node1 == node2->next)
3436
0
  return(-1);
3437
    /*
3438
     * Speedup using document order if available.
3439
     */
3440
156
    if ((node1->type == XML_ELEMENT_NODE) &&
3441
156
  (node2->type == XML_ELEMENT_NODE) &&
3442
156
  (0 > (ptrdiff_t) node1->content) &&
3443
156
  (0 > (ptrdiff_t) node2->content) &&
3444
156
  (node1->doc == node2->doc)) {
3445
0
  ptrdiff_t l1, l2;
3446
3447
0
  l1 = -((ptrdiff_t) node1->content);
3448
0
  l2 = -((ptrdiff_t) node2->content);
3449
0
  if (l1 < l2)
3450
0
      return(1);
3451
0
  if (l1 > l2)
3452
0
      return(-1);
3453
0
    }
3454
3455
780
    for (cur = node1->next;cur != NULL;cur = cur->next)
3456
780
  if (cur == node2)
3457
156
      return(1);
3458
0
    return(-1); /* assume there is no sibling list corruption */
3459
156
}
3460
3461
/**
3462
 * xmlXPathNodeSetSort:
3463
 * @set:  the node set
3464
 *
3465
 * Sort the node set in document order
3466
 */
3467
void
3468
2.00k
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3469
#ifndef WITH_TIM_SORT
3470
    int i, j, incr, len;
3471
    xmlNodePtr tmp;
3472
#endif
3473
3474
2.00k
    if (set == NULL)
3475
0
  return;
3476
3477
#ifndef WITH_TIM_SORT
3478
    /*
3479
     * Use the old Shell's sort implementation to sort the node-set
3480
     * Timsort ought to be quite faster
3481
     */
3482
    len = set->nodeNr;
3483
    for (incr = len / 2; incr > 0; incr /= 2) {
3484
  for (i = incr; i < len; i++) {
3485
      j = i - incr;
3486
      while (j >= 0) {
3487
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3488
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3489
      set->nodeTab[j + incr]) == -1)
3490
#else
3491
    if (xmlXPathCmpNodes(set->nodeTab[j],
3492
      set->nodeTab[j + incr]) == -1)
3493
#endif
3494
    {
3495
        tmp = set->nodeTab[j];
3496
        set->nodeTab[j] = set->nodeTab[j + incr];
3497
        set->nodeTab[j + incr] = tmp;
3498
        j -= incr;
3499
    } else
3500
        break;
3501
      }
3502
  }
3503
    }
3504
#else /* WITH_TIM_SORT */
3505
2.00k
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3506
2.00k
#endif /* WITH_TIM_SORT */
3507
2.00k
}
3508
3509
107k
#define XML_NODESET_DEFAULT 10
3510
/**
3511
 * xmlXPathNodeSetDupNs:
3512
 * @node:  the parent node of the namespace XPath node
3513
 * @ns:  the libxml namespace declaration node.
3514
 *
3515
 * Namespace node in libxml don't match the XPath semantic. In a node set
3516
 * the namespace nodes are duplicated and the next pointer is set to the
3517
 * parent node in the XPath semantic.
3518
 *
3519
 * Returns the newly created object.
3520
 */
3521
static xmlNodePtr
3522
172
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3523
172
    xmlNsPtr cur;
3524
3525
172
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3526
0
  return(NULL);
3527
172
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3528
0
  return((xmlNodePtr) ns);
3529
3530
    /*
3531
     * Allocate a new Namespace and fill the fields.
3532
     */
3533
172
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3534
172
    if (cur == NULL) {
3535
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3536
0
  return(NULL);
3537
0
    }
3538
172
    memset(cur, 0, sizeof(xmlNs));
3539
172
    cur->type = XML_NAMESPACE_DECL;
3540
172
    if (ns->href != NULL)
3541
172
  cur->href = xmlStrdup(ns->href);
3542
172
    if (ns->prefix != NULL)
3543
172
  cur->prefix = xmlStrdup(ns->prefix);
3544
172
    cur->next = (xmlNsPtr) node;
3545
172
    return((xmlNodePtr) cur);
3546
172
}
3547
3548
/**
3549
 * xmlXPathNodeSetFreeNs:
3550
 * @ns:  the XPath namespace node found in a nodeset.
3551
 *
3552
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3553
 * the namespace nodes are duplicated and the next pointer is set to the
3554
 * parent node in the XPath semantic. Check if such a node needs to be freed
3555
 */
3556
void
3557
152
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3558
152
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3559
0
  return;
3560
3561
152
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3562
152
  if (ns->href != NULL)
3563
152
      xmlFree((xmlChar *)ns->href);
3564
152
  if (ns->prefix != NULL)
3565
152
      xmlFree((xmlChar *)ns->prefix);
3566
152
  xmlFree(ns);
3567
152
    }
3568
152
}
3569
3570
/**
3571
 * xmlXPathNodeSetCreate:
3572
 * @val:  an initial xmlNodePtr, or NULL
3573
 *
3574
 * Create a new xmlNodeSetPtr of type double and of value @val
3575
 *
3576
 * Returns the newly created object.
3577
 */
3578
xmlNodeSetPtr
3579
46.4k
xmlXPathNodeSetCreate(xmlNodePtr val) {
3580
46.4k
    xmlNodeSetPtr ret;
3581
3582
46.4k
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3583
46.4k
    if (ret == NULL) {
3584
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3585
0
  return(NULL);
3586
0
    }
3587
46.4k
    memset(ret, 0 , sizeof(xmlNodeSet));
3588
46.4k
    if (val != NULL) {
3589
6.68k
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3590
6.68k
               sizeof(xmlNodePtr));
3591
6.68k
  if (ret->nodeTab == NULL) {
3592
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3593
0
      xmlFree(ret);
3594
0
      return(NULL);
3595
0
  }
3596
6.68k
  memset(ret->nodeTab, 0 ,
3597
6.68k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3598
6.68k
        ret->nodeMax = XML_NODESET_DEFAULT;
3599
6.68k
  if (val->type == XML_NAMESPACE_DECL) {
3600
0
      xmlNsPtr ns = (xmlNsPtr) val;
3601
3602
            /* TODO: Check memory error. */
3603
0
      ret->nodeTab[ret->nodeNr++] =
3604
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3605
0
  } else
3606
6.68k
      ret->nodeTab[ret->nodeNr++] = val;
3607
6.68k
    }
3608
46.4k
    return(ret);
3609
46.4k
}
3610
3611
/**
3612
 * xmlXPathNodeSetContains:
3613
 * @cur:  the node-set
3614
 * @val:  the node
3615
 *
3616
 * checks whether @cur contains @val
3617
 *
3618
 * Returns true (1) if @cur contains @val, false (0) otherwise
3619
 */
3620
int
3621
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3622
0
    int i;
3623
3624
0
    if ((cur == NULL) || (val == NULL)) return(0);
3625
0
    if (val->type == XML_NAMESPACE_DECL) {
3626
0
  for (i = 0; i < cur->nodeNr; i++) {
3627
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3628
0
    xmlNsPtr ns1, ns2;
3629
3630
0
    ns1 = (xmlNsPtr) val;
3631
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3632
0
    if (ns1 == ns2)
3633
0
        return(1);
3634
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3635
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3636
0
        return(1);
3637
0
      }
3638
0
  }
3639
0
    } else {
3640
0
  for (i = 0; i < cur->nodeNr; i++) {
3641
0
      if (cur->nodeTab[i] == val)
3642
0
    return(1);
3643
0
  }
3644
0
    }
3645
0
    return(0);
3646
0
}
3647
3648
/**
3649
 * xmlXPathNodeSetAddNs:
3650
 * @cur:  the initial node set
3651
 * @node:  the hosting node
3652
 * @ns:  a the namespace node
3653
 *
3654
 * add a new namespace node to an existing NodeSet
3655
 *
3656
 * Returns 0 in case of success and -1 in case of error
3657
 */
3658
int
3659
86
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3660
86
    int i;
3661
3662
3663
86
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3664
86
        (ns->type != XML_NAMESPACE_DECL) ||
3665
86
  (node->type != XML_ELEMENT_NODE))
3666
0
  return(-1);
3667
3668
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3669
    /*
3670
     * prevent duplicates
3671
     */
3672
168
    for (i = 0;i < cur->nodeNr;i++) {
3673
82
        if ((cur->nodeTab[i] != NULL) &&
3674
82
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3675
82
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3676
82
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3677
0
      return(0);
3678
82
    }
3679
3680
    /*
3681
     * grow the nodeTab if needed
3682
     */
3683
86
    if (cur->nodeMax == 0) {
3684
26
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3685
26
               sizeof(xmlNodePtr));
3686
26
  if (cur->nodeTab == NULL) {
3687
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3688
0
      return(-1);
3689
0
  }
3690
26
  memset(cur->nodeTab, 0 ,
3691
26
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3692
26
        cur->nodeMax = XML_NODESET_DEFAULT;
3693
60
    } else if (cur->nodeNr == cur->nodeMax) {
3694
0
        xmlNodePtr *temp;
3695
3696
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3697
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3698
0
            return(-1);
3699
0
        }
3700
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3701
0
              sizeof(xmlNodePtr));
3702
0
  if (temp == NULL) {
3703
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3704
0
      return(-1);
3705
0
  }
3706
0
        cur->nodeMax *= 2;
3707
0
  cur->nodeTab = temp;
3708
0
    }
3709
    /* TODO: Check memory error. */
3710
86
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3711
86
    return(0);
3712
86
}
3713
3714
/**
3715
 * xmlXPathNodeSetAdd:
3716
 * @cur:  the initial node set
3717
 * @val:  a new xmlNodePtr
3718
 *
3719
 * add a new xmlNodePtr to an existing NodeSet
3720
 *
3721
 * Returns 0 in case of success, and -1 in case of error
3722
 */
3723
int
3724
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3725
0
    int i;
3726
3727
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3728
3729
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3730
    /*
3731
     * prevent duplicates
3732
     */
3733
0
    for (i = 0;i < cur->nodeNr;i++)
3734
0
        if (cur->nodeTab[i] == val) return(0);
3735
3736
    /*
3737
     * grow the nodeTab if needed
3738
     */
3739
0
    if (cur->nodeMax == 0) {
3740
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3741
0
               sizeof(xmlNodePtr));
3742
0
  if (cur->nodeTab == NULL) {
3743
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3744
0
      return(-1);
3745
0
  }
3746
0
  memset(cur->nodeTab, 0 ,
3747
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3748
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3749
0
    } else if (cur->nodeNr == cur->nodeMax) {
3750
0
        xmlNodePtr *temp;
3751
3752
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3753
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3754
0
            return(-1);
3755
0
        }
3756
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3757
0
              sizeof(xmlNodePtr));
3758
0
  if (temp == NULL) {
3759
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3760
0
      return(-1);
3761
0
  }
3762
0
        cur->nodeMax *= 2;
3763
0
  cur->nodeTab = temp;
3764
0
    }
3765
0
    if (val->type == XML_NAMESPACE_DECL) {
3766
0
  xmlNsPtr ns = (xmlNsPtr) val;
3767
3768
        /* TODO: Check memory error. */
3769
0
  cur->nodeTab[cur->nodeNr++] =
3770
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3771
0
    } else
3772
0
  cur->nodeTab[cur->nodeNr++] = val;
3773
0
    return(0);
3774
0
}
3775
3776
/**
3777
 * xmlXPathNodeSetAddUnique:
3778
 * @cur:  the initial node set
3779
 * @val:  a new xmlNodePtr
3780
 *
3781
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3782
 * when we are sure the node is not already in the set.
3783
 *
3784
 * Returns 0 in case of success and -1 in case of failure
3785
 */
3786
int
3787
13.3M
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3788
13.3M
    if ((cur == NULL) || (val == NULL)) return(-1);
3789
3790
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3791
    /*
3792
     * grow the nodeTab if needed
3793
     */
3794
13.3M
    if (cur->nodeMax == 0) {
3795
26.4k
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3796
26.4k
               sizeof(xmlNodePtr));
3797
26.4k
  if (cur->nodeTab == NULL) {
3798
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3799
0
      return(-1);
3800
0
  }
3801
26.4k
  memset(cur->nodeTab, 0 ,
3802
26.4k
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3803
26.4k
        cur->nodeMax = XML_NODESET_DEFAULT;
3804
13.3M
    } else if (cur->nodeNr == cur->nodeMax) {
3805
9.91k
        xmlNodePtr *temp;
3806
3807
9.91k
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3808
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3809
0
            return(-1);
3810
0
        }
3811
9.91k
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3812
9.91k
              sizeof(xmlNodePtr));
3813
9.91k
  if (temp == NULL) {
3814
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3815
0
      return(-1);
3816
0
  }
3817
9.91k
  cur->nodeTab = temp;
3818
9.91k
        cur->nodeMax *= 2;
3819
9.91k
    }
3820
13.3M
    if (val->type == XML_NAMESPACE_DECL) {
3821
0
  xmlNsPtr ns = (xmlNsPtr) val;
3822
3823
        /* TODO: Check memory error. */
3824
0
  cur->nodeTab[cur->nodeNr++] =
3825
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3826
0
    } else
3827
13.3M
  cur->nodeTab[cur->nodeNr++] = val;
3828
13.3M
    return(0);
3829
13.3M
}
3830
3831
/**
3832
 * xmlXPathNodeSetMerge:
3833
 * @val1:  the first NodeSet or NULL
3834
 * @val2:  the second NodeSet
3835
 *
3836
 * Merges two nodesets, all nodes from @val2 are added to @val1
3837
 * if @val1 is NULL, a new set is created and copied from @val2
3838
 *
3839
 * Returns @val1 once extended or NULL in case of error.
3840
 */
3841
xmlNodeSetPtr
3842
3.91k
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3843
3.91k
    int i, j, initNr, skip;
3844
3.91k
    xmlNodePtr n1, n2;
3845
3846
3.91k
    if (val2 == NULL) return(val1);
3847
3.91k
    if (val1 == NULL) {
3848
550
  val1 = xmlXPathNodeSetCreate(NULL);
3849
550
    if (val1 == NULL)
3850
0
        return (NULL);
3851
#if 0
3852
  /*
3853
  * TODO: The optimization won't work in every case, since
3854
  *  those nasty namespace nodes need to be added with
3855
  *  xmlXPathNodeSetDupNs() to the set; thus a pure
3856
  *  memcpy is not possible.
3857
  *  If there was a flag on the nodesetval, indicating that
3858
  *  some temporary nodes are in, that would be helpful.
3859
  */
3860
  /*
3861
  * Optimization: Create an equally sized node-set
3862
  * and memcpy the content.
3863
  */
3864
  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3865
  if (val1 == NULL)
3866
      return(NULL);
3867
  if (val2->nodeNr != 0) {
3868
      if (val2->nodeNr == 1)
3869
    *(val1->nodeTab) = *(val2->nodeTab);
3870
      else {
3871
    memcpy(val1->nodeTab, val2->nodeTab,
3872
        val2->nodeNr * sizeof(xmlNodePtr));
3873
      }
3874
      val1->nodeNr = val2->nodeNr;
3875
  }
3876
  return(val1);
3877
#endif
3878
550
    }
3879
3880
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3881
3.91k
    initNr = val1->nodeNr;
3882
3883
708k
    for (i = 0;i < val2->nodeNr;i++) {
3884
704k
  n2 = val2->nodeTab[i];
3885
  /*
3886
   * check against duplicates
3887
   */
3888
704k
  skip = 0;
3889
567M
  for (j = 0; j < initNr; j++) {
3890
567M
      n1 = val1->nodeTab[j];
3891
567M
      if (n1 == n2) {
3892
222
    skip = 1;
3893
222
    break;
3894
567M
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3895
567M
           (n2->type == XML_NAMESPACE_DECL)) {
3896
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3897
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3898
0
      ((xmlNsPtr) n2)->prefix)))
3899
0
    {
3900
0
        skip = 1;
3901
0
        break;
3902
0
    }
3903
0
      }
3904
567M
  }
3905
704k
  if (skip)
3906
222
      continue;
3907
3908
  /*
3909
   * grow the nodeTab if needed
3910
   */
3911
703k
  if (val1->nodeMax == 0) {
3912
1.01k
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3913
1.01k
                sizeof(xmlNodePtr));
3914
1.01k
      if (val1->nodeTab == NULL) {
3915
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3916
0
    return(NULL);
3917
0
      }
3918
1.01k
      memset(val1->nodeTab, 0 ,
3919
1.01k
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3920
1.01k
      val1->nodeMax = XML_NODESET_DEFAULT;
3921
702k
  } else if (val1->nodeNr == val1->nodeMax) {
3922
929
      xmlNodePtr *temp;
3923
3924
929
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3925
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3926
0
                return(NULL);
3927
0
            }
3928
929
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3929
929
               sizeof(xmlNodePtr));
3930
929
      if (temp == NULL) {
3931
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3932
0
    return(NULL);
3933
0
      }
3934
929
      val1->nodeTab = temp;
3935
929
      val1->nodeMax *= 2;
3936
929
  }
3937
703k
  if (n2->type == XML_NAMESPACE_DECL) {
3938
86
      xmlNsPtr ns = (xmlNsPtr) n2;
3939
3940
            /* TODO: Check memory error. */
3941
86
      val1->nodeTab[val1->nodeNr++] =
3942
86
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3943
86
  } else
3944
703k
      val1->nodeTab[val1->nodeNr++] = n2;
3945
703k
    }
3946
3947
3.91k
    return(val1);
3948
3.91k
}
3949
3950
3951
/**
3952
 * xmlXPathNodeSetMergeAndClear:
3953
 * @set1:  the first NodeSet or NULL
3954
 * @set2:  the second NodeSet
3955
 *
3956
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3957
 * Checks for duplicate nodes. Clears set2.
3958
 *
3959
 * Returns @set1 once extended or NULL in case of error.
3960
 */
3961
static xmlNodeSetPtr
3962
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3963
255k
{
3964
255k
    {
3965
255k
  int i, j, initNbSet1;
3966
255k
  xmlNodePtr n1, n2;
3967
3968
255k
  initNbSet1 = set1->nodeNr;
3969
526k
  for (i = 0;i < set2->nodeNr;i++) {
3970
271k
      n2 = set2->nodeTab[i];
3971
      /*
3972
      * Skip duplicates.
3973
      */
3974
632k
      for (j = 0; j < initNbSet1; j++) {
3975
630k
    n1 = set1->nodeTab[j];
3976
630k
    if (n1 == n2) {
3977
269k
        goto skip_node;
3978
361k
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3979
361k
        (n2->type == XML_NAMESPACE_DECL))
3980
0
    {
3981
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3982
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3983
0
      ((xmlNsPtr) n2)->prefix)))
3984
0
        {
3985
      /*
3986
      * Free the namespace node.
3987
      */
3988
0
      set2->nodeTab[i] = NULL;
3989
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3990
0
      goto skip_node;
3991
0
        }
3992
0
    }
3993
630k
      }
3994
      /*
3995
      * grow the nodeTab if needed
3996
      */
3997
1.89k
      if (set1->nodeMax == 0) {
3998
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3999
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4000
0
    if (set1->nodeTab == NULL) {
4001
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4002
0
        return(NULL);
4003
0
    }
4004
0
    memset(set1->nodeTab, 0,
4005
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4006
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4007
1.89k
      } else if (set1->nodeNr >= set1->nodeMax) {
4008
154
    xmlNodePtr *temp;
4009
4010
154
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4011
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4012
0
                    return(NULL);
4013
0
                }
4014
154
    temp = (xmlNodePtr *) xmlRealloc(
4015
154
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4016
154
    if (temp == NULL) {
4017
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4018
0
        return(NULL);
4019
0
    }
4020
154
    set1->nodeTab = temp;
4021
154
    set1->nodeMax *= 2;
4022
154
      }
4023
1.89k
      set1->nodeTab[set1->nodeNr++] = n2;
4024
271k
skip_node:
4025
271k
      {}
4026
271k
  }
4027
255k
    }
4028
255k
    set2->nodeNr = 0;
4029
255k
    return(set1);
4030
255k
}
4031
4032
/**
4033
 * xmlXPathNodeSetMergeAndClearNoDupls:
4034
 * @set1:  the first NodeSet or NULL
4035
 * @set2:  the second NodeSet
4036
 *
4037
 * Merges two nodesets, all nodes from @set2 are added to @set1.
4038
 * Doesn't check for duplicate nodes. Clears set2.
4039
 *
4040
 * Returns @set1 once extended or NULL in case of error.
4041
 */
4042
static xmlNodeSetPtr
4043
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4044
1.62k
{
4045
1.62k
    {
4046
1.62k
  int i;
4047
1.62k
  xmlNodePtr n2;
4048
4049
82.2k
  for (i = 0;i < set2->nodeNr;i++) {
4050
80.6k
      n2 = set2->nodeTab[i];
4051
80.6k
      if (set1->nodeMax == 0) {
4052
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4053
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4054
0
    if (set1->nodeTab == NULL) {
4055
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4056
0
        return(NULL);
4057
0
    }
4058
0
    memset(set1->nodeTab, 0,
4059
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4060
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4061
80.6k
      } else if (set1->nodeNr >= set1->nodeMax) {
4062
127
    xmlNodePtr *temp;
4063
4064
127
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4065
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4066
0
                    return(NULL);
4067
0
                }
4068
127
    temp = (xmlNodePtr *) xmlRealloc(
4069
127
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4070
127
    if (temp == NULL) {
4071
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4072
0
        return(NULL);
4073
0
    }
4074
127
    set1->nodeTab = temp;
4075
127
    set1->nodeMax *= 2;
4076
127
      }
4077
80.6k
      set1->nodeTab[set1->nodeNr++] = n2;
4078
80.6k
  }
4079
1.62k
    }
4080
1.62k
    set2->nodeNr = 0;
4081
1.62k
    return(set1);
4082
1.62k
}
4083
4084
/**
4085
 * xmlXPathNodeSetDel:
4086
 * @cur:  the initial node set
4087
 * @val:  an xmlNodePtr
4088
 *
4089
 * Removes an xmlNodePtr from an existing NodeSet
4090
 */
4091
void
4092
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4093
0
    int i;
4094
4095
0
    if (cur == NULL) return;
4096
0
    if (val == NULL) return;
4097
4098
    /*
4099
     * find node in nodeTab
4100
     */
4101
0
    for (i = 0;i < cur->nodeNr;i++)
4102
0
        if (cur->nodeTab[i] == val) break;
4103
4104
0
    if (i >= cur->nodeNr) { /* not found */
4105
#ifdef DEBUG
4106
        xmlGenericError(xmlGenericErrorContext,
4107
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4108
    val->name);
4109
#endif
4110
0
        return;
4111
0
    }
4112
0
    if ((cur->nodeTab[i] != NULL) &&
4113
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4114
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4115
0
    cur->nodeNr--;
4116
0
    for (;i < cur->nodeNr;i++)
4117
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4118
0
    cur->nodeTab[cur->nodeNr] = NULL;
4119
0
}
4120
4121
/**
4122
 * xmlXPathNodeSetRemove:
4123
 * @cur:  the initial node set
4124
 * @val:  the index to remove
4125
 *
4126
 * Removes an entry from an existing NodeSet list.
4127
 */
4128
void
4129
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4130
0
    if (cur == NULL) return;
4131
0
    if (val >= cur->nodeNr) return;
4132
0
    if ((cur->nodeTab[val] != NULL) &&
4133
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4134
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4135
0
    cur->nodeNr--;
4136
0
    for (;val < cur->nodeNr;val++)
4137
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4138
0
    cur->nodeTab[cur->nodeNr] = NULL;
4139
0
}
4140
4141
/**
4142
 * xmlXPathFreeNodeSet:
4143
 * @obj:  the xmlNodeSetPtr to free
4144
 *
4145
 * Free the NodeSet compound (not the actual nodes !).
4146
 */
4147
void
4148
42.4k
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4149
42.4k
    if (obj == NULL) return;
4150
42.3k
    if (obj->nodeTab != NULL) {
4151
30.5k
  int i;
4152
4153
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4154
10.6M
  for (i = 0;i < obj->nodeNr;i++)
4155
10.6M
      if ((obj->nodeTab[i] != NULL) &&
4156
10.6M
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4157
96
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4158
30.5k
  xmlFree(obj->nodeTab);
4159
30.5k
    }
4160
42.3k
    xmlFree(obj);
4161
42.3k
}
4162
4163
/**
4164
 * xmlXPathNodeSetClearFromPos:
4165
 * @set: the node set to be cleared
4166
 * @pos: the start position to clear from
4167
 *
4168
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4169
 * are feed) starting with the entry at @pos, but does *not* free the list
4170
 * itself. Sets the length of the list to @pos.
4171
 */
4172
static void
4173
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4174
12
{
4175
12
    if ((set == NULL) || (pos >= set->nodeNr))
4176
0
  return;
4177
12
    else if ((hasNsNodes)) {
4178
12
  int i;
4179
12
  xmlNodePtr node;
4180
4181
3.17M
  for (i = pos; i < set->nodeNr; i++) {
4182
3.17M
      node = set->nodeTab[i];
4183
3.17M
      if ((node != NULL) &&
4184
3.17M
    (node->type == XML_NAMESPACE_DECL))
4185
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
3.17M
  }
4187
12
    }
4188
12
    set->nodeNr = pos;
4189
12
}
4190
4191
/**
4192
 * xmlXPathNodeSetClear:
4193
 * @set:  the node set to clear
4194
 *
4195
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4196
 * are feed), but does *not* free the list itself. Sets the length of the
4197
 * list to 0.
4198
 */
4199
static void
4200
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4201
0
{
4202
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4203
0
}
4204
4205
/**
4206
 * xmlXPathNodeSetKeepLast:
4207
 * @set: the node set to be cleared
4208
 *
4209
 * Move the last node to the first position and clear temporary XPath objects
4210
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4211
 * to 1.
4212
 */
4213
static void
4214
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4215
0
{
4216
0
    int i;
4217
0
    xmlNodePtr node;
4218
4219
0
    if ((set == NULL) || (set->nodeNr <= 1))
4220
0
  return;
4221
0
    for (i = 0; i < set->nodeNr - 1; i++) {
4222
0
        node = set->nodeTab[i];
4223
0
        if ((node != NULL) &&
4224
0
            (node->type == XML_NAMESPACE_DECL))
4225
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4226
0
    }
4227
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4228
0
    set->nodeNr = 1;
4229
0
}
4230
4231
/**
4232
 * xmlXPathFreeValueTree:
4233
 * @obj:  the xmlNodeSetPtr to free
4234
 *
4235
 * Free the NodeSet compound and the actual tree, this is different
4236
 * from xmlXPathFreeNodeSet()
4237
 */
4238
static void
4239
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4240
0
    int i;
4241
4242
0
    if (obj == NULL) return;
4243
4244
0
    if (obj->nodeTab != NULL) {
4245
0
  for (i = 0;i < obj->nodeNr;i++) {
4246
0
      if (obj->nodeTab[i] != NULL) {
4247
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4248
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4249
0
    } else {
4250
0
        xmlFreeNodeList(obj->nodeTab[i]);
4251
0
    }
4252
0
      }
4253
0
  }
4254
0
  xmlFree(obj->nodeTab);
4255
0
    }
4256
0
    xmlFree(obj);
4257
0
}
4258
4259
#if defined(DEBUG) || defined(DEBUG_STEP)
4260
/**
4261
 * xmlGenericErrorContextNodeSet:
4262
 * @output:  a FILE * for the output
4263
 * @obj:  the xmlNodeSetPtr to display
4264
 *
4265
 * Quick display of a NodeSet
4266
 */
4267
void
4268
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4269
    int i;
4270
4271
    if (output == NULL) output = xmlGenericErrorContext;
4272
    if (obj == NULL)  {
4273
        fprintf(output, "NodeSet == NULL !\n");
4274
  return;
4275
    }
4276
    if (obj->nodeNr == 0) {
4277
        fprintf(output, "NodeSet is empty\n");
4278
  return;
4279
    }
4280
    if (obj->nodeTab == NULL) {
4281
  fprintf(output, " nodeTab == NULL !\n");
4282
  return;
4283
    }
4284
    for (i = 0; i < obj->nodeNr; i++) {
4285
        if (obj->nodeTab[i] == NULL) {
4286
      fprintf(output, " NULL !\n");
4287
      return;
4288
        }
4289
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4290
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4291
      fprintf(output, " /");
4292
  else if (obj->nodeTab[i]->name == NULL)
4293
      fprintf(output, " noname!");
4294
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4295
    }
4296
    fprintf(output, "\n");
4297
}
4298
#endif
4299
4300
/**
4301
 * xmlXPathNewNodeSet:
4302
 * @val:  the NodePtr value
4303
 *
4304
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4305
 * it with the single Node @val
4306
 *
4307
 * Returns the newly created object.
4308
 */
4309
xmlXPathObjectPtr
4310
9.72k
xmlXPathNewNodeSet(xmlNodePtr val) {
4311
9.72k
    xmlXPathObjectPtr ret;
4312
4313
9.72k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4314
9.72k
    if (ret == NULL) {
4315
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4316
0
  return(NULL);
4317
0
    }
4318
9.72k
    memset(ret, 0 , sizeof(xmlXPathObject));
4319
9.72k
    ret->type = XPATH_NODESET;
4320
9.72k
    ret->boolval = 0;
4321
    /* TODO: Check memory error. */
4322
9.72k
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4323
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4324
#ifdef XP_DEBUG_OBJ_USAGE
4325
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4326
#endif
4327
9.72k
    return(ret);
4328
9.72k
}
4329
4330
/**
4331
 * xmlXPathNewValueTree:
4332
 * @val:  the NodePtr value
4333
 *
4334
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4335
 * it with the tree root @val
4336
 *
4337
 * Returns the newly created object.
4338
 */
4339
xmlXPathObjectPtr
4340
0
xmlXPathNewValueTree(xmlNodePtr val) {
4341
0
    xmlXPathObjectPtr ret;
4342
4343
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4344
0
    if (ret == NULL) {
4345
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4346
0
  return(NULL);
4347
0
    }
4348
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4349
0
    ret->type = XPATH_XSLT_TREE;
4350
0
    ret->boolval = 1;
4351
0
    ret->user = (void *) val;
4352
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4353
#ifdef XP_DEBUG_OBJ_USAGE
4354
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4355
#endif
4356
0
    return(ret);
4357
0
}
4358
4359
/**
4360
 * xmlXPathNewNodeSetList:
4361
 * @val:  an existing NodeSet
4362
 *
4363
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4364
 * it with the Nodeset @val
4365
 *
4366
 * Returns the newly created object.
4367
 */
4368
xmlXPathObjectPtr
4369
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4370
0
{
4371
0
    xmlXPathObjectPtr ret;
4372
0
    int i;
4373
4374
0
    if (val == NULL)
4375
0
        ret = NULL;
4376
0
    else if (val->nodeTab == NULL)
4377
0
        ret = xmlXPathNewNodeSet(NULL);
4378
0
    else {
4379
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4380
0
        if (ret) {
4381
0
            for (i = 1; i < val->nodeNr; ++i) {
4382
                /* TODO: Propagate memory error. */
4383
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4384
0
        < 0) break;
4385
0
      }
4386
0
  }
4387
0
    }
4388
4389
0
    return (ret);
4390
0
}
4391
4392
/**
4393
 * xmlXPathWrapNodeSet:
4394
 * @val:  the NodePtr value
4395
 *
4396
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4397
 *
4398
 * Returns the newly created object.
4399
 */
4400
xmlXPathObjectPtr
4401
21.0k
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4402
21.0k
    xmlXPathObjectPtr ret;
4403
4404
21.0k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4405
21.0k
    if (ret == NULL) {
4406
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4407
0
  return(NULL);
4408
0
    }
4409
21.0k
    memset(ret, 0 , sizeof(xmlXPathObject));
4410
21.0k
    ret->type = XPATH_NODESET;
4411
21.0k
    ret->nodesetval = val;
4412
#ifdef XP_DEBUG_OBJ_USAGE
4413
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4414
#endif
4415
21.0k
    return(ret);
4416
21.0k
}
4417
4418
/**
4419
 * xmlXPathFreeNodeSetList:
4420
 * @obj:  an existing NodeSetList object
4421
 *
4422
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4423
 * the list contrary to xmlXPathFreeObject().
4424
 */
4425
void
4426
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4427
0
    if (obj == NULL) return;
4428
#ifdef XP_DEBUG_OBJ_USAGE
4429
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4430
#endif
4431
0
    xmlFree(obj);
4432
0
}
4433
4434
/**
4435
 * xmlXPathDifference:
4436
 * @nodes1:  a node-set
4437
 * @nodes2:  a node-set
4438
 *
4439
 * Implements the EXSLT - Sets difference() function:
4440
 *    node-set set:difference (node-set, node-set)
4441
 *
4442
 * Returns the difference between the two node sets, or nodes1 if
4443
 *         nodes2 is empty
4444
 */
4445
xmlNodeSetPtr
4446
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4447
0
    xmlNodeSetPtr ret;
4448
0
    int i, l1;
4449
0
    xmlNodePtr cur;
4450
4451
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4452
0
  return(nodes1);
4453
4454
    /* TODO: Check memory error. */
4455
0
    ret = xmlXPathNodeSetCreate(NULL);
4456
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4457
0
  return(ret);
4458
4459
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4460
4461
0
    for (i = 0; i < l1; i++) {
4462
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4463
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4464
            /* TODO: Propagate memory error. */
4465
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4466
0
          break;
4467
0
  }
4468
0
    }
4469
0
    return(ret);
4470
0
}
4471
4472
/**
4473
 * xmlXPathIntersection:
4474
 * @nodes1:  a node-set
4475
 * @nodes2:  a node-set
4476
 *
4477
 * Implements the EXSLT - Sets intersection() function:
4478
 *    node-set set:intersection (node-set, node-set)
4479
 *
4480
 * Returns a node set comprising the nodes that are within both the
4481
 *         node sets passed as arguments
4482
 */
4483
xmlNodeSetPtr
4484
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4485
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4486
0
    int i, l1;
4487
0
    xmlNodePtr cur;
4488
4489
0
    if (ret == NULL)
4490
0
        return(ret);
4491
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4492
0
  return(ret);
4493
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4494
0
  return(ret);
4495
4496
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4497
4498
0
    for (i = 0; i < l1; i++) {
4499
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4500
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4501
            /* TODO: Propagate memory error. */
4502
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4503
0
          break;
4504
0
  }
4505
0
    }
4506
0
    return(ret);
4507
0
}
4508
4509
/**
4510
 * xmlXPathDistinctSorted:
4511
 * @nodes:  a node-set, sorted by document order
4512
 *
4513
 * Implements the EXSLT - Sets distinct() function:
4514
 *    node-set set:distinct (node-set)
4515
 *
4516
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4517
 *         it is empty
4518
 */
4519
xmlNodeSetPtr
4520
3
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4521
3
    xmlNodeSetPtr ret;
4522
3
    xmlHashTablePtr hash;
4523
3
    int i, l;
4524
3
    xmlChar * strval;
4525
3
    xmlNodePtr cur;
4526
4527
3
    if (xmlXPathNodeSetIsEmpty(nodes))
4528
0
  return(nodes);
4529
4530
3
    ret = xmlXPathNodeSetCreate(NULL);
4531
3
    if (ret == NULL)
4532
0
        return(ret);
4533
3
    l = xmlXPathNodeSetGetLength(nodes);
4534
3
    hash = xmlHashCreate (l);
4535
938k
    for (i = 0; i < l; i++) {
4536
938k
  cur = xmlXPathNodeSetItem(nodes, i);
4537
938k
  strval = xmlXPathCastNodeToString(cur);
4538
938k
  if (xmlHashLookup(hash, strval) == NULL) {
4539
134
      xmlHashAddEntry(hash, strval, strval);
4540
            /* TODO: Propagate memory error. */
4541
134
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4542
0
          break;
4543
938k
  } else {
4544
938k
      xmlFree(strval);
4545
938k
  }
4546
938k
    }
4547
3
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4548
3
    return(ret);
4549
3
}
4550
4551
/**
4552
 * xmlXPathDistinct:
4553
 * @nodes:  a node-set
4554
 *
4555
 * Implements the EXSLT - Sets distinct() function:
4556
 *    node-set set:distinct (node-set)
4557
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4558
 * is called with the sorted node-set
4559
 *
4560
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4561
 *         it is empty
4562
 */
4563
xmlNodeSetPtr
4564
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4565
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4566
0
  return(nodes);
4567
4568
0
    xmlXPathNodeSetSort(nodes);
4569
0
    return(xmlXPathDistinctSorted(nodes));
4570
0
}
4571
4572
/**
4573
 * xmlXPathHasSameNodes:
4574
 * @nodes1:  a node-set
4575
 * @nodes2:  a node-set
4576
 *
4577
 * Implements the EXSLT - Sets has-same-nodes function:
4578
 *    boolean set:has-same-node(node-set, node-set)
4579
 *
4580
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4581
 *         otherwise
4582
 */
4583
int
4584
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4585
0
    int i, l;
4586
0
    xmlNodePtr cur;
4587
4588
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4589
0
  xmlXPathNodeSetIsEmpty(nodes2))
4590
0
  return(0);
4591
4592
0
    l = xmlXPathNodeSetGetLength(nodes1);
4593
0
    for (i = 0; i < l; i++) {
4594
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4595
0
  if (xmlXPathNodeSetContains(nodes2, cur))
4596
0
      return(1);
4597
0
    }
4598
0
    return(0);
4599
0
}
4600
4601
/**
4602
 * xmlXPathNodeLeadingSorted:
4603
 * @nodes: a node-set, sorted by document order
4604
 * @node: a node
4605
 *
4606
 * Implements the EXSLT - Sets leading() function:
4607
 *    node-set set:leading (node-set, node-set)
4608
 *
4609
 * Returns the nodes in @nodes that precede @node in document order,
4610
 *         @nodes if @node is NULL or an empty node-set if @nodes
4611
 *         doesn't contain @node
4612
 */
4613
xmlNodeSetPtr
4614
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4615
0
    int i, l;
4616
0
    xmlNodePtr cur;
4617
0
    xmlNodeSetPtr ret;
4618
4619
0
    if (node == NULL)
4620
0
  return(nodes);
4621
4622
0
    ret = xmlXPathNodeSetCreate(NULL);
4623
0
    if (ret == NULL)
4624
0
        return(ret);
4625
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4626
0
  (!xmlXPathNodeSetContains(nodes, node)))
4627
0
  return(ret);
4628
4629
0
    l = xmlXPathNodeSetGetLength(nodes);
4630
0
    for (i = 0; i < l; i++) {
4631
0
  cur = xmlXPathNodeSetItem(nodes, i);
4632
0
  if (cur == node)
4633
0
      break;
4634
        /* TODO: Propagate memory error. */
4635
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4636
0
      break;
4637
0
    }
4638
0
    return(ret);
4639
0
}
4640
4641
/**
4642
 * xmlXPathNodeLeading:
4643
 * @nodes:  a node-set
4644
 * @node:  a node
4645
 *
4646
 * Implements the EXSLT - Sets leading() function:
4647
 *    node-set set:leading (node-set, node-set)
4648
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4649
 * is called.
4650
 *
4651
 * Returns the nodes in @nodes that precede @node in document order,
4652
 *         @nodes if @node is NULL or an empty node-set if @nodes
4653
 *         doesn't contain @node
4654
 */
4655
xmlNodeSetPtr
4656
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4657
0
    xmlXPathNodeSetSort(nodes);
4658
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4659
0
}
4660
4661
/**
4662
 * xmlXPathLeadingSorted:
4663
 * @nodes1:  a node-set, sorted by document order
4664
 * @nodes2:  a node-set, sorted by document order
4665
 *
4666
 * Implements the EXSLT - Sets leading() function:
4667
 *    node-set set:leading (node-set, node-set)
4668
 *
4669
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4670
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4671
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4672
 */
4673
xmlNodeSetPtr
4674
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4675
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4676
0
  return(nodes1);
4677
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4678
0
             xmlXPathNodeSetItem(nodes2, 1)));
4679
0
}
4680
4681
/**
4682
 * xmlXPathLeading:
4683
 * @nodes1:  a node-set
4684
 * @nodes2:  a node-set
4685
 *
4686
 * Implements the EXSLT - Sets leading() function:
4687
 *    node-set set:leading (node-set, node-set)
4688
 * @nodes1 and @nodes2 are sorted by document order, then
4689
 * #exslSetsLeadingSorted is called.
4690
 *
4691
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4692
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4693
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4694
 */
4695
xmlNodeSetPtr
4696
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4697
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4698
0
  return(nodes1);
4699
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4700
0
  return(xmlXPathNodeSetCreate(NULL));
4701
0
    xmlXPathNodeSetSort(nodes1);
4702
0
    xmlXPathNodeSetSort(nodes2);
4703
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4704
0
             xmlXPathNodeSetItem(nodes2, 1)));
4705
0
}
4706
4707
/**
4708
 * xmlXPathNodeTrailingSorted:
4709
 * @nodes: a node-set, sorted by document order
4710
 * @node: a node
4711
 *
4712
 * Implements the EXSLT - Sets trailing() function:
4713
 *    node-set set:trailing (node-set, node-set)
4714
 *
4715
 * Returns the nodes in @nodes that follow @node in document order,
4716
 *         @nodes if @node is NULL or an empty node-set if @nodes
4717
 *         doesn't contain @node
4718
 */
4719
xmlNodeSetPtr
4720
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4721
0
    int i, l;
4722
0
    xmlNodePtr cur;
4723
0
    xmlNodeSetPtr ret;
4724
4725
0
    if (node == NULL)
4726
0
  return(nodes);
4727
4728
0
    ret = xmlXPathNodeSetCreate(NULL);
4729
0
    if (ret == NULL)
4730
0
        return(ret);
4731
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4732
0
  (!xmlXPathNodeSetContains(nodes, node)))
4733
0
  return(ret);
4734
4735
0
    l = xmlXPathNodeSetGetLength(nodes);
4736
0
    for (i = l - 1; i >= 0; i--) {
4737
0
  cur = xmlXPathNodeSetItem(nodes, i);
4738
0
  if (cur == node)
4739
0
      break;
4740
        /* TODO: Propagate memory error. */
4741
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4742
0
      break;
4743
0
    }
4744
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4745
0
    return(ret);
4746
0
}
4747
4748
/**
4749
 * xmlXPathNodeTrailing:
4750
 * @nodes:  a node-set
4751
 * @node:  a node
4752
 *
4753
 * Implements the EXSLT - Sets trailing() function:
4754
 *    node-set set:trailing (node-set, node-set)
4755
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4756
 * is called.
4757
 *
4758
 * Returns the nodes in @nodes that follow @node in document order,
4759
 *         @nodes if @node is NULL or an empty node-set if @nodes
4760
 *         doesn't contain @node
4761
 */
4762
xmlNodeSetPtr
4763
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4764
0
    xmlXPathNodeSetSort(nodes);
4765
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4766
0
}
4767
4768
/**
4769
 * xmlXPathTrailingSorted:
4770
 * @nodes1:  a node-set, sorted by document order
4771
 * @nodes2:  a node-set, sorted by document order
4772
 *
4773
 * Implements the EXSLT - Sets trailing() function:
4774
 *    node-set set:trailing (node-set, node-set)
4775
 *
4776
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4777
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4778
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4779
 */
4780
xmlNodeSetPtr
4781
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4782
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4783
0
  return(nodes1);
4784
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4785
0
              xmlXPathNodeSetItem(nodes2, 0)));
4786
0
}
4787
4788
/**
4789
 * xmlXPathTrailing:
4790
 * @nodes1:  a node-set
4791
 * @nodes2:  a node-set
4792
 *
4793
 * Implements the EXSLT - Sets trailing() function:
4794
 *    node-set set:trailing (node-set, node-set)
4795
 * @nodes1 and @nodes2 are sorted by document order, then
4796
 * #xmlXPathTrailingSorted is called.
4797
 *
4798
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4799
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4800
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4801
 */
4802
xmlNodeSetPtr
4803
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4804
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4805
0
  return(nodes1);
4806
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4807
0
  return(xmlXPathNodeSetCreate(NULL));
4808
0
    xmlXPathNodeSetSort(nodes1);
4809
0
    xmlXPathNodeSetSort(nodes2);
4810
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4811
0
              xmlXPathNodeSetItem(nodes2, 0)));
4812
0
}
4813
4814
/************************************************************************
4815
 *                  *
4816
 *    Routines to handle extra functions      *
4817
 *                  *
4818
 ************************************************************************/
4819
4820
/**
4821
 * xmlXPathRegisterFunc:
4822
 * @ctxt:  the XPath context
4823
 * @name:  the function name
4824
 * @f:  the function implementation or NULL
4825
 *
4826
 * Register a new function. If @f is NULL it unregisters the function
4827
 *
4828
 * Returns 0 in case of success, -1 in case of error
4829
 */
4830
int
4831
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4832
3.49k
         xmlXPathFunction f) {
4833
3.49k
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4834
3.49k
}
4835
4836
/**
4837
 * xmlXPathRegisterFuncNS:
4838
 * @ctxt:  the XPath context
4839
 * @name:  the function name
4840
 * @ns_uri:  the function namespace URI
4841
 * @f:  the function implementation or NULL
4842
 *
4843
 * Register a new function. If @f is NULL it unregisters the function
4844
 *
4845
 * Returns 0 in case of success, -1 in case of error
4846
 */
4847
int
4848
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4849
3.60k
           const xmlChar *ns_uri, xmlXPathFunction f) {
4850
3.60k
    if (ctxt == NULL)
4851
0
  return(-1);
4852
3.60k
    if (name == NULL)
4853
0
  return(-1);
4854
4855
3.60k
    if (ctxt->funcHash == NULL)
4856
0
  ctxt->funcHash = xmlHashCreate(0);
4857
3.60k
    if (ctxt->funcHash == NULL)
4858
0
  return(-1);
4859
3.60k
    if (f == NULL)
4860
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4861
3.60k
XML_IGNORE_FPTR_CAST_WARNINGS
4862
3.60k
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4863
3.60k
XML_POP_WARNINGS
4864
3.60k
}
4865
4866
/**
4867
 * xmlXPathRegisterFuncLookup:
4868
 * @ctxt:  the XPath context
4869
 * @f:  the lookup function
4870
 * @funcCtxt:  the lookup data
4871
 *
4872
 * Registers an external mechanism to do function lookup.
4873
 */
4874
void
4875
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4876
          xmlXPathFuncLookupFunc f,
4877
37
          void *funcCtxt) {
4878
37
    if (ctxt == NULL)
4879
0
  return;
4880
37
    ctxt->funcLookupFunc = f;
4881
37
    ctxt->funcLookupData = funcCtxt;
4882
37
}
4883
4884
/**
4885
 * xmlXPathFunctionLookup:
4886
 * @ctxt:  the XPath context
4887
 * @name:  the function name
4888
 *
4889
 * Search in the Function array of the context for the given
4890
 * function.
4891
 *
4892
 * Returns the xmlXPathFunction or NULL if not found
4893
 */
4894
xmlXPathFunction
4895
3.78k
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4896
3.78k
    if (ctxt == NULL)
4897
0
  return (NULL);
4898
4899
3.78k
    if (ctxt->funcLookupFunc != NULL) {
4900
3.78k
  xmlXPathFunction ret;
4901
3.78k
  xmlXPathFuncLookupFunc f;
4902
4903
3.78k
  f = ctxt->funcLookupFunc;
4904
3.78k
  ret = f(ctxt->funcLookupData, name, NULL);
4905
3.78k
  if (ret != NULL)
4906
0
      return(ret);
4907
3.78k
    }
4908
3.78k
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4909
3.78k
}
4910
4911
/**
4912
 * xmlXPathFunctionLookupNS:
4913
 * @ctxt:  the XPath context
4914
 * @name:  the function name
4915
 * @ns_uri:  the function namespace URI
4916
 *
4917
 * Search in the Function array of the context for the given
4918
 * function.
4919
 *
4920
 * Returns the xmlXPathFunction or NULL if not found
4921
 */
4922
xmlXPathFunction
4923
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4924
3.92k
       const xmlChar *ns_uri) {
4925
3.92k
    xmlXPathFunction ret;
4926
4927
3.92k
    if (ctxt == NULL)
4928
0
  return(NULL);
4929
3.92k
    if (name == NULL)
4930
0
  return(NULL);
4931
4932
3.92k
    if (ctxt->funcLookupFunc != NULL) {
4933
3.92k
  xmlXPathFuncLookupFunc f;
4934
4935
3.92k
  f = ctxt->funcLookupFunc;
4936
3.92k
  ret = f(ctxt->funcLookupData, name, ns_uri);
4937
3.92k
  if (ret != NULL)
4938
121
      return(ret);
4939
3.92k
    }
4940
4941
3.80k
    if (ctxt->funcHash == NULL)
4942
0
  return(NULL);
4943
4944
3.80k
XML_IGNORE_FPTR_CAST_WARNINGS
4945
3.80k
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4946
3.80k
XML_POP_WARNINGS
4947
3.80k
    return(ret);
4948
3.80k
}
4949
4950
/**
4951
 * xmlXPathRegisteredFuncsCleanup:
4952
 * @ctxt:  the XPath context
4953
 *
4954
 * Cleanup the XPath context data associated to registered functions
4955
 */
4956
void
4957
113
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4958
113
    if (ctxt == NULL)
4959
0
  return;
4960
4961
113
    xmlHashFree(ctxt->funcHash, NULL);
4962
113
    ctxt->funcHash = NULL;
4963
113
}
4964
4965
/************************************************************************
4966
 *                  *
4967
 *      Routines to handle Variables      *
4968
 *                  *
4969
 ************************************************************************/
4970
4971
/**
4972
 * xmlXPathRegisterVariable:
4973
 * @ctxt:  the XPath context
4974
 * @name:  the variable name
4975
 * @value:  the variable value or NULL
4976
 *
4977
 * Register a new variable value. If @value is NULL it unregisters
4978
 * the variable
4979
 *
4980
 * Returns 0 in case of success, -1 in case of error
4981
 */
4982
int
4983
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4984
8
       xmlXPathObjectPtr value) {
4985
8
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4986
8
}
4987
4988
/**
4989
 * xmlXPathRegisterVariableNS:
4990
 * @ctxt:  the XPath context
4991
 * @name:  the variable name
4992
 * @ns_uri:  the variable namespace URI
4993
 * @value:  the variable value or NULL
4994
 *
4995
 * Register a new variable value. If @value is NULL it unregisters
4996
 * the variable
4997
 *
4998
 * Returns 0 in case of success, -1 in case of error
4999
 */
5000
int
5001
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5002
         const xmlChar *ns_uri,
5003
8
         xmlXPathObjectPtr value) {
5004
8
    if (ctxt == NULL)
5005
0
  return(-1);
5006
8
    if (name == NULL)
5007
0
  return(-1);
5008
5009
8
    if (ctxt->varHash == NULL)
5010
2
  ctxt->varHash = xmlHashCreate(0);
5011
8
    if (ctxt->varHash == NULL)
5012
0
  return(-1);
5013
8
    if (value == NULL)
5014
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5015
0
                             xmlXPathFreeObjectEntry));
5016
8
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5017
8
             (void *) value, xmlXPathFreeObjectEntry));
5018
8
}
5019
5020
/**
5021
 * xmlXPathRegisterVariableLookup:
5022
 * @ctxt:  the XPath context
5023
 * @f:  the lookup function
5024
 * @data:  the lookup data
5025
 *
5026
 * register an external mechanism to do variable lookup
5027
 */
5028
void
5029
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5030
37
   xmlXPathVariableLookupFunc f, void *data) {
5031
37
    if (ctxt == NULL)
5032
0
  return;
5033
37
    ctxt->varLookupFunc = f;
5034
37
    ctxt->varLookupData = data;
5035
37
}
5036
5037
/**
5038
 * xmlXPathVariableLookup:
5039
 * @ctxt:  the XPath context
5040
 * @name:  the variable name
5041
 *
5042
 * Search in the Variable array of the context for the given
5043
 * variable value.
5044
 *
5045
 * Returns a copy of the value or NULL if not found
5046
 */
5047
xmlXPathObjectPtr
5048
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5049
0
    if (ctxt == NULL)
5050
0
  return(NULL);
5051
5052
0
    if (ctxt->varLookupFunc != NULL) {
5053
0
  xmlXPathObjectPtr ret;
5054
5055
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5056
0
          (ctxt->varLookupData, name, NULL);
5057
0
  return(ret);
5058
0
    }
5059
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5060
0
}
5061
5062
/**
5063
 * xmlXPathVariableLookupNS:
5064
 * @ctxt:  the XPath context
5065
 * @name:  the variable name
5066
 * @ns_uri:  the variable namespace URI
5067
 *
5068
 * Search in the Variable array of the context for the given
5069
 * variable value.
5070
 *
5071
 * Returns the a copy of the value or NULL if not found
5072
 */
5073
xmlXPathObjectPtr
5074
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5075
0
       const xmlChar *ns_uri) {
5076
0
    if (ctxt == NULL)
5077
0
  return(NULL);
5078
5079
0
    if (ctxt->varLookupFunc != NULL) {
5080
0
  xmlXPathObjectPtr ret;
5081
5082
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5083
0
          (ctxt->varLookupData, name, ns_uri);
5084
0
  if (ret != NULL) return(ret);
5085
0
    }
5086
5087
0
    if (ctxt->varHash == NULL)
5088
0
  return(NULL);
5089
0
    if (name == NULL)
5090
0
  return(NULL);
5091
5092
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5093
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5094
0
}
5095
5096
/**
5097
 * xmlXPathRegisteredVariablesCleanup:
5098
 * @ctxt:  the XPath context
5099
 *
5100
 * Cleanup the XPath context data associated to registered variables
5101
 */
5102
void
5103
113
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5104
113
    if (ctxt == NULL)
5105
0
  return;
5106
5107
113
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5108
113
    ctxt->varHash = NULL;
5109
113
}
5110
5111
/**
5112
 * xmlXPathRegisterNs:
5113
 * @ctxt:  the XPath context
5114
 * @prefix:  the namespace prefix cannot be NULL or empty string
5115
 * @ns_uri:  the namespace name
5116
 *
5117
 * Register a new namespace. If @ns_uri is NULL it unregisters
5118
 * the namespace
5119
 *
5120
 * Returns 0 in case of success, -1 in case of error
5121
 */
5122
int
5123
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5124
22
         const xmlChar *ns_uri) {
5125
22
    if (ctxt == NULL)
5126
0
  return(-1);
5127
22
    if (prefix == NULL)
5128
0
  return(-1);
5129
22
    if (prefix[0] == 0)
5130
0
  return(-1);
5131
5132
22
    if (ctxt->nsHash == NULL)
5133
2
  ctxt->nsHash = xmlHashCreate(10);
5134
22
    if (ctxt->nsHash == NULL)
5135
0
  return(-1);
5136
22
    if (ns_uri == NULL)
5137
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5138
0
                            xmlHashDefaultDeallocator));
5139
22
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5140
22
            xmlHashDefaultDeallocator));
5141
22
}
5142
5143
/**
5144
 * xmlXPathNsLookup:
5145
 * @ctxt:  the XPath context
5146
 * @prefix:  the namespace prefix value
5147
 *
5148
 * Search in the namespace declaration array of the context for the given
5149
 * namespace name associated to the given prefix
5150
 *
5151
 * Returns the value or NULL if not found
5152
 */
5153
const xmlChar *
5154
4.51k
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5155
4.51k
    if (ctxt == NULL)
5156
0
  return(NULL);
5157
4.51k
    if (prefix == NULL)
5158
0
  return(NULL);
5159
5160
4.51k
#ifdef XML_XML_NAMESPACE
5161
4.51k
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5162
0
  return(XML_XML_NAMESPACE);
5163
4.51k
#endif
5164
5165
4.51k
    if (ctxt->namespaces != NULL) {
5166
630
  int i;
5167
5168
2.07k
  for (i = 0;i < ctxt->nsNr;i++) {
5169
1.98k
      if ((ctxt->namespaces[i] != NULL) &&
5170
1.98k
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5171
531
    return(ctxt->namespaces[i]->href);
5172
1.98k
  }
5173
630
    }
5174
5175
3.97k
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5176
4.51k
}
5177
5178
/**
5179
 * xmlXPathRegisteredNsCleanup:
5180
 * @ctxt:  the XPath context
5181
 *
5182
 * Cleanup the XPath context data associated to registered variables
5183
 */
5184
void
5185
113
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5186
113
    if (ctxt == NULL)
5187
0
  return;
5188
5189
113
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5190
113
    ctxt->nsHash = NULL;
5191
113
}
5192
5193
/************************************************************************
5194
 *                  *
5195
 *      Routines to handle Values     *
5196
 *                  *
5197
 ************************************************************************/
5198
5199
/* Allocations are terrible, one needs to optimize all this !!! */
5200
5201
/**
5202
 * xmlXPathNewFloat:
5203
 * @val:  the double value
5204
 *
5205
 * Create a new xmlXPathObjectPtr of type double and of value @val
5206
 *
5207
 * Returns the newly created object.
5208
 */
5209
xmlXPathObjectPtr
5210
33.8k
xmlXPathNewFloat(double val) {
5211
33.8k
    xmlXPathObjectPtr ret;
5212
5213
33.8k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5214
33.8k
    if (ret == NULL) {
5215
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5216
0
  return(NULL);
5217
0
    }
5218
33.8k
    memset(ret, 0 , sizeof(xmlXPathObject));
5219
33.8k
    ret->type = XPATH_NUMBER;
5220
33.8k
    ret->floatval = val;
5221
#ifdef XP_DEBUG_OBJ_USAGE
5222
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5223
#endif
5224
33.8k
    return(ret);
5225
33.8k
}
5226
5227
/**
5228
 * xmlXPathNewBoolean:
5229
 * @val:  the boolean value
5230
 *
5231
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5232
 *
5233
 * Returns the newly created object.
5234
 */
5235
xmlXPathObjectPtr
5236
894
xmlXPathNewBoolean(int val) {
5237
894
    xmlXPathObjectPtr ret;
5238
5239
894
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5240
894
    if (ret == NULL) {
5241
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5242
0
  return(NULL);
5243
0
    }
5244
894
    memset(ret, 0 , sizeof(xmlXPathObject));
5245
894
    ret->type = XPATH_BOOLEAN;
5246
894
    ret->boolval = (val != 0);
5247
#ifdef XP_DEBUG_OBJ_USAGE
5248
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5249
#endif
5250
894
    return(ret);
5251
894
}
5252
5253
/**
5254
 * xmlXPathNewString:
5255
 * @val:  the xmlChar * value
5256
 *
5257
 * Create a new xmlXPathObjectPtr of type string and of value @val
5258
 *
5259
 * Returns the newly created object.
5260
 */
5261
xmlXPathObjectPtr
5262
3.44k
xmlXPathNewString(const xmlChar *val) {
5263
3.44k
    xmlXPathObjectPtr ret;
5264
5265
3.44k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5266
3.44k
    if (ret == NULL) {
5267
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5268
0
  return(NULL);
5269
0
    }
5270
3.44k
    memset(ret, 0 , sizeof(xmlXPathObject));
5271
3.44k
    ret->type = XPATH_STRING;
5272
3.44k
    if (val != NULL)
5273
3.44k
  ret->stringval = xmlStrdup(val);
5274
1
    else
5275
1
  ret->stringval = xmlStrdup((const xmlChar *)"");
5276
#ifdef XP_DEBUG_OBJ_USAGE
5277
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5278
#endif
5279
3.44k
    return(ret);
5280
3.44k
}
5281
5282
/**
5283
 * xmlXPathWrapString:
5284
 * @val:  the xmlChar * value
5285
 *
5286
 * Wraps the @val string into an XPath object.
5287
 *
5288
 * Returns the newly created object.
5289
 */
5290
xmlXPathObjectPtr
5291
26.5k
xmlXPathWrapString (xmlChar *val) {
5292
26.5k
    xmlXPathObjectPtr ret;
5293
5294
26.5k
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5295
26.5k
    if (ret == NULL) {
5296
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5297
0
  return(NULL);
5298
0
    }
5299
26.5k
    memset(ret, 0 , sizeof(xmlXPathObject));
5300
26.5k
    ret->type = XPATH_STRING;
5301
26.5k
    ret->stringval = val;
5302
#ifdef XP_DEBUG_OBJ_USAGE
5303
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5304
#endif
5305
26.5k
    return(ret);
5306
26.5k
}
5307
5308
/**
5309
 * xmlXPathNewCString:
5310
 * @val:  the char * value
5311
 *
5312
 * Create a new xmlXPathObjectPtr of type string and of value @val
5313
 *
5314
 * Returns the newly created object.
5315
 */
5316
xmlXPathObjectPtr
5317
56
xmlXPathNewCString(const char *val) {
5318
56
    xmlXPathObjectPtr ret;
5319
5320
56
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5321
56
    if (ret == NULL) {
5322
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5323
0
  return(NULL);
5324
0
    }
5325
56
    memset(ret, 0 , sizeof(xmlXPathObject));
5326
56
    ret->type = XPATH_STRING;
5327
56
    ret->stringval = xmlStrdup(BAD_CAST val);
5328
#ifdef XP_DEBUG_OBJ_USAGE
5329
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5330
#endif
5331
56
    return(ret);
5332
56
}
5333
5334
/**
5335
 * xmlXPathWrapCString:
5336
 * @val:  the char * value
5337
 *
5338
 * Wraps a string into an XPath object.
5339
 *
5340
 * Returns the newly created object.
5341
 */
5342
xmlXPathObjectPtr
5343
0
xmlXPathWrapCString (char * val) {
5344
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5345
0
}
5346
5347
/**
5348
 * xmlXPathWrapExternal:
5349
 * @val:  the user data
5350
 *
5351
 * Wraps the @val data into an XPath object.
5352
 *
5353
 * Returns the newly created object.
5354
 */
5355
xmlXPathObjectPtr
5356
0
xmlXPathWrapExternal (void *val) {
5357
0
    xmlXPathObjectPtr ret;
5358
5359
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5360
0
    if (ret == NULL) {
5361
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5362
0
  return(NULL);
5363
0
    }
5364
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5365
0
    ret->type = XPATH_USERS;
5366
0
    ret->user = val;
5367
#ifdef XP_DEBUG_OBJ_USAGE
5368
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5369
#endif
5370
0
    return(ret);
5371
0
}
5372
5373
/**
5374
 * xmlXPathObjectCopy:
5375
 * @val:  the original object
5376
 *
5377
 * allocate a new copy of a given object
5378
 *
5379
 * Returns the newly created object.
5380
 */
5381
xmlXPathObjectPtr
5382
52
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5383
52
    xmlXPathObjectPtr ret;
5384
5385
52
    if (val == NULL)
5386
0
  return(NULL);
5387
5388
52
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5389
52
    if (ret == NULL) {
5390
0
        xmlXPathErrMemory(NULL, "copying object\n");
5391
0
  return(NULL);
5392
0
    }
5393
52
    memcpy(ret, val , sizeof(xmlXPathObject));
5394
#ifdef XP_DEBUG_OBJ_USAGE
5395
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5396
#endif
5397
52
    switch (val->type) {
5398
0
  case XPATH_BOOLEAN:
5399
0
  case XPATH_NUMBER:
5400
#ifdef LIBXML_XPTR_LOCS_ENABLED
5401
  case XPATH_POINT:
5402
  case XPATH_RANGE:
5403
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5404
0
      break;
5405
0
  case XPATH_STRING:
5406
0
      ret->stringval = xmlStrdup(val->stringval);
5407
0
      break;
5408
0
  case XPATH_XSLT_TREE:
5409
#if 0
5410
/*
5411
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5412
  this previous handling is no longer correct, and can cause some serious
5413
  problems (ref. bug 145547)
5414
*/
5415
      if ((val->nodesetval != NULL) &&
5416
    (val->nodesetval->nodeTab != NULL)) {
5417
    xmlNodePtr cur, tmp;
5418
    xmlDocPtr top;
5419
5420
    ret->boolval = 1;
5421
    top =  xmlNewDoc(NULL);
5422
    top->name = (char *)
5423
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5424
    ret->user = top;
5425
    if (top != NULL) {
5426
        top->doc = top;
5427
        cur = val->nodesetval->nodeTab[0]->children;
5428
        while (cur != NULL) {
5429
      tmp = xmlDocCopyNode(cur, top, 1);
5430
      xmlAddChild((xmlNodePtr) top, tmp);
5431
      cur = cur->next;
5432
        }
5433
    }
5434
5435
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5436
      } else
5437
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5438
      /* Deallocate the copied tree value */
5439
      break;
5440
#endif
5441
52
  case XPATH_NODESET:
5442
            /* TODO: Check memory error. */
5443
52
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5444
      /* Do not deallocate the copied tree value */
5445
52
      ret->boolval = 0;
5446
52
      break;
5447
#ifdef LIBXML_XPTR_LOCS_ENABLED
5448
  case XPATH_LOCATIONSET:
5449
  {
5450
      xmlLocationSetPtr loc = val->user;
5451
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5452
      break;
5453
  }
5454
#endif
5455
0
        case XPATH_USERS:
5456
0
      ret->user = val->user;
5457
0
      break;
5458
0
        case XPATH_UNDEFINED:
5459
0
      xmlGenericError(xmlGenericErrorContext,
5460
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5461
0
        val->type);
5462
0
      break;
5463
52
    }
5464
52
    return(ret);
5465
52
}
5466
5467
/**
5468
 * xmlXPathFreeObject:
5469
 * @obj:  the object to free
5470
 *
5471
 * Free up an xmlXPathObjectPtr object.
5472
 */
5473
void
5474
90.5k
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5475
90.5k
    if (obj == NULL) return;
5476
90.4k
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5477
20.5k
  if (obj->boolval) {
5478
#if 0
5479
      if (obj->user != NULL) {
5480
                xmlXPathFreeNodeSet(obj->nodesetval);
5481
    xmlFreeNodeList((xmlNodePtr) obj->user);
5482
      } else
5483
#endif
5484
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5485
0
      if (obj->nodesetval != NULL)
5486
0
    xmlXPathFreeValueTree(obj->nodesetval);
5487
20.5k
  } else {
5488
20.5k
      if (obj->nodesetval != NULL)
5489
20.1k
    xmlXPathFreeNodeSet(obj->nodesetval);
5490
20.5k
  }
5491
#ifdef LIBXML_XPTR_LOCS_ENABLED
5492
    } else if (obj->type == XPATH_LOCATIONSET) {
5493
  if (obj->user != NULL)
5494
      xmlXPtrFreeLocationSet(obj->user);
5495
#endif
5496
69.8k
    } else if (obj->type == XPATH_STRING) {
5497
31.7k
  if (obj->stringval != NULL)
5498
17.5k
      xmlFree(obj->stringval);
5499
31.7k
    }
5500
#ifdef XP_DEBUG_OBJ_USAGE
5501
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5502
#endif
5503
90.4k
    xmlFree(obj);
5504
90.4k
}
5505
5506
static void
5507
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5508
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5509
0
}
5510
5511
/**
5512
 * xmlXPathReleaseObject:
5513
 * @obj:  the xmlXPathObjectPtr to free or to cache
5514
 *
5515
 * Depending on the state of the cache this frees the given
5516
 * XPath object or stores it in the cache.
5517
 */
5518
static void
5519
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5520
4.47M
{
5521
4.47M
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5522
355
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5523
4.47M
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5524
5525
4.48M
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5526
5527
4.47M
    if (obj == NULL)
5528
5
  return;
5529
4.47M
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5530
26
   xmlXPathFreeObject(obj);
5531
4.47M
    } else {
5532
4.47M
  xmlXPathContextCachePtr cache =
5533
4.47M
      (xmlXPathContextCachePtr) ctxt->cache;
5534
5535
4.47M
  switch (obj->type) {
5536
162k
      case XPATH_NODESET:
5537
162k
      case XPATH_XSLT_TREE:
5538
162k
    if (obj->nodesetval != NULL) {
5539
153k
        if (obj->boolval) {
5540
      /*
5541
      * It looks like the @boolval is used for
5542
      * evaluation if this an XSLT Result Tree Fragment.
5543
      * TODO: Check if this assumption is correct.
5544
      */
5545
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5546
0
      xmlXPathFreeValueTree(obj->nodesetval);
5547
0
      obj->nodesetval = NULL;
5548
153k
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5549
153k
      (XP_CACHE_WANTS(cache->nodesetObjs,
5550
151k
          cache->maxNodeset)))
5551
138k
        {
5552
138k
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5553
138k
      goto obj_cached;
5554
138k
        } else {
5555
14.7k
      xmlXPathFreeNodeSet(obj->nodesetval);
5556
14.7k
      obj->nodesetval = NULL;
5557
14.7k
        }
5558
153k
    }
5559
23.8k
    break;
5560
2.13M
      case XPATH_STRING:
5561
2.13M
    if (obj->stringval != NULL)
5562
2.13M
        xmlFree(obj->stringval);
5563
5564
2.13M
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5565
2.13M
        XP_CACHE_ADD(cache->stringObjs, obj);
5566
2.13M
        goto obj_cached;
5567
2.13M
    }
5568
0
    break;
5569
4.70k
      case XPATH_BOOLEAN:
5570
4.70k
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5571
4.70k
        XP_CACHE_ADD(cache->booleanObjs, obj);
5572
4.70k
        goto obj_cached;
5573
4.70k
    }
5574
0
    break;
5575
2.17M
      case XPATH_NUMBER:
5576
2.17M
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5577
2.17M
        XP_CACHE_ADD(cache->numberObjs, obj);
5578
2.17M
        goto obj_cached;
5579
2.17M
    }
5580
0
    break;
5581
#ifdef LIBXML_XPTR_LOCS_ENABLED
5582
      case XPATH_LOCATIONSET:
5583
    if (obj->user != NULL) {
5584
        xmlXPtrFreeLocationSet(obj->user);
5585
    }
5586
    goto free_obj;
5587
#endif
5588
0
      default:
5589
0
    goto free_obj;
5590
4.47M
  }
5591
5592
  /*
5593
  * Fallback to adding to the misc-objects slot.
5594
  */
5595
23.8k
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5596
23.5k
      XP_CACHE_ADD(cache->miscObjs, obj);
5597
23.5k
  } else
5598
364
      goto free_obj;
5599
5600
4.47M
obj_cached:
5601
5602
#ifdef XP_DEBUG_OBJ_USAGE
5603
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5604
#endif
5605
5606
4.47M
  if (obj->nodesetval != NULL) {
5607
138k
      xmlNodeSetPtr tmpset = obj->nodesetval;
5608
5609
      /*
5610
      * TODO: Due to those nasty ns-nodes, we need to traverse
5611
      *  the list and free the ns-nodes.
5612
      * URGENT TODO: Check if it's actually slowing things down.
5613
      *  Maybe we shouldn't try to preserve the list.
5614
      */
5615
138k
      if (tmpset->nodeNr > 1) {
5616
2.30k
    int i;
5617
2.30k
    xmlNodePtr node;
5618
5619
23.8k
    for (i = 0; i < tmpset->nodeNr; i++) {
5620
21.5k
        node = tmpset->nodeTab[i];
5621
21.5k
        if ((node != NULL) &&
5622
21.5k
      (node->type == XML_NAMESPACE_DECL))
5623
56
        {
5624
56
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5625
56
        }
5626
21.5k
    }
5627
136k
      } else if (tmpset->nodeNr == 1) {
5628
126k
    if ((tmpset->nodeTab[0] != NULL) &&
5629
126k
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5630
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5631
126k
      }
5632
138k
      tmpset->nodeNr = 0;
5633
138k
      memset(obj, 0, sizeof(xmlXPathObject));
5634
138k
      obj->nodesetval = tmpset;
5635
138k
  } else
5636
4.33M
      memset(obj, 0, sizeof(xmlXPathObject));
5637
5638
4.47M
  return;
5639
5640
364
free_obj:
5641
  /*
5642
  * Cache is full; free the object.
5643
  */
5644
364
  if (obj->nodesetval != NULL)
5645
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5646
#ifdef XP_DEBUG_OBJ_USAGE
5647
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5648
#endif
5649
364
  xmlFree(obj);
5650
364
    }
5651
390
    return;
5652
4.47M
}
5653
5654
5655
/************************************************************************
5656
 *                  *
5657
 *      Type Casting Routines       *
5658
 *                  *
5659
 ************************************************************************/
5660
5661
/**
5662
 * xmlXPathCastBooleanToString:
5663
 * @val:  a boolean
5664
 *
5665
 * Converts a boolean to its string value.
5666
 *
5667
 * Returns a newly allocated string.
5668
 */
5669
xmlChar *
5670
1.07k
xmlXPathCastBooleanToString (int val) {
5671
1.07k
    xmlChar *ret;
5672
1.07k
    if (val)
5673
508
  ret = xmlStrdup((const xmlChar *) "true");
5674
562
    else
5675
562
  ret = xmlStrdup((const xmlChar *) "false");
5676
1.07k
    return(ret);
5677
1.07k
}
5678
5679
/**
5680
 * xmlXPathCastNumberToString:
5681
 * @val:  a number
5682
 *
5683
 * Converts a number to its string value.
5684
 *
5685
 * Returns a newly allocated string.
5686
 */
5687
xmlChar *
5688
7.54k
xmlXPathCastNumberToString (double val) {
5689
7.54k
    xmlChar *ret;
5690
7.54k
    switch (xmlXPathIsInf(val)) {
5691
0
    case 1:
5692
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
5693
0
  break;
5694
0
    case -1:
5695
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5696
0
  break;
5697
7.54k
    default:
5698
7.54k
  if (xmlXPathIsNaN(val)) {
5699
243
      ret = xmlStrdup((const xmlChar *) "NaN");
5700
7.30k
  } else if (val == 0) {
5701
            /* Omit sign for negative zero. */
5702
4.72k
      ret = xmlStrdup((const xmlChar *) "0");
5703
4.72k
  } else {
5704
      /* could be improved */
5705
2.58k
      char buf[100];
5706
2.58k
      xmlXPathFormatNumber(val, buf, 99);
5707
2.58k
      buf[99] = 0;
5708
2.58k
      ret = xmlStrdup((const xmlChar *) buf);
5709
2.58k
  }
5710
7.54k
    }
5711
7.54k
    return(ret);
5712
7.54k
}
5713
5714
/**
5715
 * xmlXPathCastNodeToString:
5716
 * @node:  a node
5717
 *
5718
 * Converts a node to its string value.
5719
 *
5720
 * Returns a newly allocated string.
5721
 */
5722
xmlChar *
5723
3.75M
xmlXPathCastNodeToString (xmlNodePtr node) {
5724
3.75M
xmlChar *ret;
5725
3.75M
    if ((ret = xmlNodeGetContent(node)) == NULL)
5726
0
  ret = xmlStrdup((const xmlChar *) "");
5727
3.75M
    return(ret);
5728
3.75M
}
5729
5730
/**
5731
 * xmlXPathCastNodeSetToString:
5732
 * @ns:  a node-set
5733
 *
5734
 * Converts a node-set to its string value.
5735
 *
5736
 * Returns a newly allocated string.
5737
 */
5738
xmlChar *
5739
32.3k
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5740
32.3k
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5741
12.2k
  return(xmlStrdup((const xmlChar *) ""));
5742
5743
20.0k
    if (ns->nodeNr > 1)
5744
1.23k
  xmlXPathNodeSetSort(ns);
5745
20.0k
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5746
32.3k
}
5747
5748
/**
5749
 * xmlXPathCastToString:
5750
 * @val:  an XPath object
5751
 *
5752
 * Converts an existing object to its string() equivalent
5753
 *
5754
 * Returns the allocated string value of the object, NULL in case of error.
5755
 *         It's up to the caller to free the string memory with xmlFree().
5756
 */
5757
xmlChar *
5758
6.11k
xmlXPathCastToString(xmlXPathObjectPtr val) {
5759
6.11k
    xmlChar *ret = NULL;
5760
5761
6.11k
    if (val == NULL)
5762
0
  return(xmlStrdup((const xmlChar *) ""));
5763
6.11k
    switch (val->type) {
5764
0
  case XPATH_UNDEFINED:
5765
#ifdef DEBUG_EXPR
5766
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5767
#endif
5768
0
      ret = xmlStrdup((const xmlChar *) "");
5769
0
      break;
5770
3.10k
        case XPATH_NODESET:
5771
3.10k
        case XPATH_XSLT_TREE:
5772
3.10k
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5773
3.10k
      break;
5774
2.94k
  case XPATH_STRING:
5775
2.94k
      return(xmlStrdup(val->stringval));
5776
44
        case XPATH_BOOLEAN:
5777
44
      ret = xmlXPathCastBooleanToString(val->boolval);
5778
44
      break;
5779
15
  case XPATH_NUMBER: {
5780
15
      ret = xmlXPathCastNumberToString(val->floatval);
5781
15
      break;
5782
3.10k
  }
5783
0
  case XPATH_USERS:
5784
#ifdef LIBXML_XPTR_LOCS_ENABLED
5785
  case XPATH_POINT:
5786
  case XPATH_RANGE:
5787
  case XPATH_LOCATIONSET:
5788
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5789
0
      TODO
5790
0
      ret = xmlStrdup((const xmlChar *) "");
5791
0
      break;
5792
6.11k
    }
5793
3.16k
    return(ret);
5794
6.11k
}
5795
5796
/**
5797
 * xmlXPathConvertString:
5798
 * @val:  an XPath object
5799
 *
5800
 * Converts an existing object to its string() equivalent
5801
 *
5802
 * Returns the new object, the old one is freed (or the operation
5803
 *         is done directly on @val)
5804
 */
5805
xmlXPathObjectPtr
5806
26.3k
xmlXPathConvertString(xmlXPathObjectPtr val) {
5807
26.3k
    xmlChar *res = NULL;
5808
5809
26.3k
    if (val == NULL)
5810
0
  return(xmlXPathNewCString(""));
5811
5812
26.3k
    switch (val->type) {
5813
0
    case XPATH_UNDEFINED:
5814
#ifdef DEBUG_EXPR
5815
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5816
#endif
5817
0
  break;
5818
17.9k
    case XPATH_NODESET:
5819
17.9k
    case XPATH_XSLT_TREE:
5820
17.9k
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5821
17.9k
  break;
5822
0
    case XPATH_STRING:
5823
0
  return(val);
5824
930
    case XPATH_BOOLEAN:
5825
930
  res = xmlXPathCastBooleanToString(val->boolval);
5826
930
  break;
5827
7.47k
    case XPATH_NUMBER:
5828
7.47k
  res = xmlXPathCastNumberToString(val->floatval);
5829
7.47k
  break;
5830
0
    case XPATH_USERS:
5831
#ifdef LIBXML_XPTR_LOCS_ENABLED
5832
    case XPATH_POINT:
5833
    case XPATH_RANGE:
5834
    case XPATH_LOCATIONSET:
5835
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5836
0
  TODO;
5837
0
  break;
5838
26.3k
    }
5839
26.3k
    xmlXPathFreeObject(val);
5840
26.3k
    if (res == NULL)
5841
0
  return(xmlXPathNewCString(""));
5842
26.3k
    return(xmlXPathWrapString(res));
5843
26.3k
}
5844
5845
/**
5846
 * xmlXPathCastBooleanToNumber:
5847
 * @val:  a boolean
5848
 *
5849
 * Converts a boolean to its number value
5850
 *
5851
 * Returns the number value
5852
 */
5853
double
5854
9
xmlXPathCastBooleanToNumber(int val) {
5855
9
    if (val)
5856
0
  return(1.0);
5857
9
    return(0.0);
5858
9
}
5859
5860
/**
5861
 * xmlXPathCastStringToNumber:
5862
 * @val:  a string
5863
 *
5864
 * Converts a string to its number value
5865
 *
5866
 * Returns the number value
5867
 */
5868
double
5869
2.13M
xmlXPathCastStringToNumber(const xmlChar * val) {
5870
2.13M
    return(xmlXPathStringEvalNumber(val));
5871
2.13M
}
5872
5873
/**
5874
 * xmlXPathCastNodeToNumber:
5875
 * @node:  a node
5876
 *
5877
 * Converts a node to its number value
5878
 *
5879
 * Returns the number value
5880
 */
5881
double
5882
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5883
0
    xmlChar *strval;
5884
0
    double ret;
5885
5886
0
    if (node == NULL)
5887
0
  return(xmlXPathNAN);
5888
0
    strval = xmlXPathCastNodeToString(node);
5889
0
    if (strval == NULL)
5890
0
  return(xmlXPathNAN);
5891
0
    ret = xmlXPathCastStringToNumber(strval);
5892
0
    xmlFree(strval);
5893
5894
0
    return(ret);
5895
0
}
5896
5897
/**
5898
 * xmlXPathCastNodeSetToNumber:
5899
 * @ns:  a node-set
5900
 *
5901
 * Converts a node-set to its number value
5902
 *
5903
 * Returns the number value
5904
 */
5905
double
5906
4.47k
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5907
4.47k
    xmlChar *str;
5908
4.47k
    double ret;
5909
5910
4.47k
    if (ns == NULL)
5911
201
  return(xmlXPathNAN);
5912
4.27k
    str = xmlXPathCastNodeSetToString(ns);
5913
4.27k
    ret = xmlXPathCastStringToNumber(str);
5914
4.27k
    xmlFree(str);
5915
4.27k
    return(ret);
5916
4.47k
}
5917
5918
/**
5919
 * xmlXPathCastToNumber:
5920
 * @val:  an XPath object
5921
 *
5922
 * Converts an XPath object to its number value
5923
 *
5924
 * Returns the number value
5925
 */
5926
double
5927
2.13M
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5928
2.13M
    double ret = 0.0;
5929
5930
2.13M
    if (val == NULL)
5931
0
  return(xmlXPathNAN);
5932
2.13M
    switch (val->type) {
5933
0
    case XPATH_UNDEFINED:
5934
#ifdef DEBUG_EXPR
5935
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5936
#endif
5937
0
  ret = xmlXPathNAN;
5938
0
  break;
5939
4.47k
    case XPATH_NODESET:
5940
4.47k
    case XPATH_XSLT_TREE:
5941
4.47k
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5942
4.47k
  break;
5943
2.12M
    case XPATH_STRING:
5944
2.12M
  ret = xmlXPathCastStringToNumber(val->stringval);
5945
2.12M
  break;
5946
765
    case XPATH_NUMBER:
5947
765
  ret = val->floatval;
5948
765
  break;
5949
9
    case XPATH_BOOLEAN:
5950
9
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5951
9
  break;
5952
0
    case XPATH_USERS:
5953
#ifdef LIBXML_XPTR_LOCS_ENABLED
5954
    case XPATH_POINT:
5955
    case XPATH_RANGE:
5956
    case XPATH_LOCATIONSET:
5957
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5958
0
  TODO;
5959
0
  ret = xmlXPathNAN;
5960
0
  break;
5961
2.13M
    }
5962
2.13M
    return(ret);
5963
2.13M
}
5964
5965
/**
5966
 * xmlXPathConvertNumber:
5967
 * @val:  an XPath object
5968
 *
5969
 * Converts an existing object to its number() equivalent
5970
 *
5971
 * Returns the new object, the old one is freed (or the operation
5972
 *         is done directly on @val)
5973
 */
5974
xmlXPathObjectPtr
5975
2.63k
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5976
2.63k
    xmlXPathObjectPtr ret;
5977
5978
2.63k
    if (val == NULL)
5979
0
  return(xmlXPathNewFloat(0.0));
5980
2.63k
    if (val->type == XPATH_NUMBER)
5981
0
  return(val);
5982
2.63k
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5983
2.63k
    xmlXPathFreeObject(val);
5984
2.63k
    return(ret);
5985
2.63k
}
5986
5987
/**
5988
 * xmlXPathCastNumberToBoolean:
5989
 * @val:  a number
5990
 *
5991
 * Converts a number to its boolean value
5992
 *
5993
 * Returns the boolean value
5994
 */
5995
int
5996
190
xmlXPathCastNumberToBoolean (double val) {
5997
190
     if (xmlXPathIsNaN(val) || (val == 0.0))
5998
2
   return(0);
5999
188
     return(1);
6000
190
}
6001
6002
/**
6003
 * xmlXPathCastStringToBoolean:
6004
 * @val:  a string
6005
 *
6006
 * Converts a string to its boolean value
6007
 *
6008
 * Returns the boolean value
6009
 */
6010
int
6011
1.73k
xmlXPathCastStringToBoolean (const xmlChar *val) {
6012
1.73k
    if ((val == NULL) || (xmlStrlen(val) == 0))
6013
0
  return(0);
6014
1.73k
    return(1);
6015
1.73k
}
6016
6017
/**
6018
 * xmlXPathCastNodeSetToBoolean:
6019
 * @ns:  a node-set
6020
 *
6021
 * Converts a node-set to its boolean value
6022
 *
6023
 * Returns the boolean value
6024
 */
6025
int
6026
246
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6027
246
    if ((ns == NULL) || (ns->nodeNr == 0))
6028
122
  return(0);
6029
124
    return(1);
6030
246
}
6031
6032
/**
6033
 * xmlXPathCastToBoolean:
6034
 * @val:  an XPath object
6035
 *
6036
 * Converts an XPath object to its boolean value
6037
 *
6038
 * Returns the boolean value
6039
 */
6040
int
6041
1.98k
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6042
1.98k
    int ret = 0;
6043
6044
1.98k
    if (val == NULL)
6045
0
  return(0);
6046
1.98k
    switch (val->type) {
6047
0
    case XPATH_UNDEFINED:
6048
#ifdef DEBUG_EXPR
6049
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6050
#endif
6051
0
  ret = 0;
6052
0
  break;
6053
246
    case XPATH_NODESET:
6054
246
    case XPATH_XSLT_TREE:
6055
246
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6056
246
  break;
6057
1.73k
    case XPATH_STRING:
6058
1.73k
  ret = xmlXPathCastStringToBoolean(val->stringval);
6059
1.73k
  break;
6060
0
    case XPATH_NUMBER:
6061
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6062
0
  break;
6063
0
    case XPATH_BOOLEAN:
6064
0
  ret = val->boolval;
6065
0
  break;
6066
0
    case XPATH_USERS:
6067
#ifdef LIBXML_XPTR_LOCS_ENABLED
6068
    case XPATH_POINT:
6069
    case XPATH_RANGE:
6070
    case XPATH_LOCATIONSET:
6071
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6072
0
  TODO;
6073
0
  ret = 0;
6074
0
  break;
6075
1.98k
    }
6076
1.98k
    return(ret);
6077
1.98k
}
6078
6079
6080
/**
6081
 * xmlXPathConvertBoolean:
6082
 * @val:  an XPath object
6083
 *
6084
 * Converts an existing object to its boolean() equivalent
6085
 *
6086
 * Returns the new object, the old one is freed (or the operation
6087
 *         is done directly on @val)
6088
 */
6089
xmlXPathObjectPtr
6090
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6091
0
    xmlXPathObjectPtr ret;
6092
6093
0
    if (val == NULL)
6094
0
  return(xmlXPathNewBoolean(0));
6095
0
    if (val->type == XPATH_BOOLEAN)
6096
0
  return(val);
6097
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6098
0
    xmlXPathFreeObject(val);
6099
0
    return(ret);
6100
0
}
6101
6102
/************************************************************************
6103
 *                  *
6104
 *    Routines to handle XPath contexts     *
6105
 *                  *
6106
 ************************************************************************/
6107
6108
/**
6109
 * xmlXPathNewContext:
6110
 * @doc:  the XML document
6111
 *
6112
 * Create a new xmlXPathContext
6113
 *
6114
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6115
 */
6116
xmlXPathContextPtr
6117
117
xmlXPathNewContext(xmlDocPtr doc) {
6118
117
    xmlXPathContextPtr ret;
6119
6120
117
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6121
117
    if (ret == NULL) {
6122
0
        xmlXPathErrMemory(NULL, "creating context\n");
6123
0
  return(NULL);
6124
0
    }
6125
117
    memset(ret, 0 , sizeof(xmlXPathContext));
6126
117
    ret->doc = doc;
6127
117
    ret->node = NULL;
6128
6129
117
    ret->varHash = NULL;
6130
6131
117
    ret->nb_types = 0;
6132
117
    ret->max_types = 0;
6133
117
    ret->types = NULL;
6134
6135
117
    ret->funcHash = xmlHashCreate(0);
6136
6137
117
    ret->nb_axis = 0;
6138
117
    ret->max_axis = 0;
6139
117
    ret->axis = NULL;
6140
6141
117
    ret->nsHash = NULL;
6142
117
    ret->user = NULL;
6143
6144
117
    ret->contextSize = -1;
6145
117
    ret->proximityPosition = -1;
6146
6147
#ifdef XP_DEFAULT_CACHE_ON
6148
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6149
  xmlXPathFreeContext(ret);
6150
  return(NULL);
6151
    }
6152
#endif
6153
6154
117
    xmlXPathRegisterAllFunctions(ret);
6155
6156
117
    return(ret);
6157
117
}
6158
6159
/**
6160
 * xmlXPathFreeContext:
6161
 * @ctxt:  the context to free
6162
 *
6163
 * Free up an xmlXPathContext
6164
 */
6165
void
6166
113
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6167
113
    if (ctxt == NULL) return;
6168
6169
113
    if (ctxt->cache != NULL)
6170
97
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6171
113
    xmlXPathRegisteredNsCleanup(ctxt);
6172
113
    xmlXPathRegisteredFuncsCleanup(ctxt);
6173
113
    xmlXPathRegisteredVariablesCleanup(ctxt);
6174
113
    xmlResetError(&ctxt->lastError);
6175
113
    xmlFree(ctxt);
6176
113
}
6177
6178
/************************************************************************
6179
 *                  *
6180
 *    Routines to handle XPath parser contexts    *
6181
 *                  *
6182
 ************************************************************************/
6183
6184
#define CHECK_CTXT(ctxt)            \
6185
38
    if (ctxt == NULL) {           \
6186
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6187
0
    NULL, NULL, XML_FROM_XPATH,       \
6188
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6189
0
    __FILE__, __LINE__,         \
6190
0
    NULL, NULL, NULL, 0, 0,         \
6191
0
    "NULL context pointer\n");        \
6192
0
  return(NULL);             \
6193
0
    }                  \
6194
6195
#define CHECK_CTXT_NEG(ctxt)            \
6196
49.7k
    if (ctxt == NULL) {           \
6197
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6198
0
    NULL, NULL, XML_FROM_XPATH,       \
6199
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6200
0
    __FILE__, __LINE__,         \
6201
0
    NULL, NULL, NULL, 0, 0,         \
6202
0
    "NULL context pointer\n");        \
6203
0
  return(-1);             \
6204
0
    }                  \
6205
6206
6207
#define CHECK_CONTEXT(ctxt)           \
6208
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6209
        (ctxt->doc->children == NULL)) {        \
6210
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6211
  return(NULL);             \
6212
    }
6213
6214
6215
/**
6216
 * xmlXPathNewParserContext:
6217
 * @str:  the XPath expression
6218
 * @ctxt:  the XPath context
6219
 *
6220
 * Create a new xmlXPathParserContext
6221
 *
6222
 * Returns the xmlXPathParserContext just allocated.
6223
 */
6224
xmlXPathParserContextPtr
6225
36.0k
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6226
36.0k
    xmlXPathParserContextPtr ret;
6227
6228
36.0k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6229
36.0k
    if (ret == NULL) {
6230
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6231
0
  return(NULL);
6232
0
    }
6233
36.0k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6234
36.0k
    ret->cur = ret->base = str;
6235
36.0k
    ret->context = ctxt;
6236
6237
36.0k
    ret->comp = xmlXPathNewCompExpr();
6238
36.0k
    if (ret->comp == NULL) {
6239
0
  xmlFree(ret->valueTab);
6240
0
  xmlFree(ret);
6241
0
  return(NULL);
6242
0
    }
6243
36.0k
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6244
10.3k
        ret->comp->dict = ctxt->dict;
6245
10.3k
  xmlDictReference(ret->comp->dict);
6246
10.3k
    }
6247
6248
36.0k
    return(ret);
6249
36.0k
}
6250
6251
/**
6252
 * xmlXPathCompParserContext:
6253
 * @comp:  the XPath compiled expression
6254
 * @ctxt:  the XPath context
6255
 *
6256
 * Create a new xmlXPathParserContext when processing a compiled expression
6257
 *
6258
 * Returns the xmlXPathParserContext just allocated.
6259
 */
6260
static xmlXPathParserContextPtr
6261
31.0k
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6262
31.0k
    xmlXPathParserContextPtr ret;
6263
6264
31.0k
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6265
31.0k
    if (ret == NULL) {
6266
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6267
0
  return(NULL);
6268
0
    }
6269
31.0k
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6270
6271
    /* Allocate the value stack */
6272
31.0k
    ret->valueTab = (xmlXPathObjectPtr *)
6273
31.0k
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6274
31.0k
    if (ret->valueTab == NULL) {
6275
0
  xmlFree(ret);
6276
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6277
0
  return(NULL);
6278
0
    }
6279
31.0k
    ret->valueNr = 0;
6280
31.0k
    ret->valueMax = 10;
6281
31.0k
    ret->value = NULL;
6282
31.0k
    ret->valueFrame = 0;
6283
6284
31.0k
    ret->context = ctxt;
6285
31.0k
    ret->comp = comp;
6286
6287
31.0k
    return(ret);
6288
31.0k
}
6289
6290
/**
6291
 * xmlXPathFreeParserContext:
6292
 * @ctxt:  the context to free
6293
 *
6294
 * Free up an xmlXPathParserContext
6295
 */
6296
void
6297
67.0k
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6298
67.0k
    int i;
6299
6300
67.0k
    if (ctxt->valueTab != NULL) {
6301
33.2k
        for (i = 0; i < ctxt->valueNr; i++) {
6302
2.20k
            if (ctxt->context)
6303
2.20k
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6304
0
            else
6305
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6306
2.20k
        }
6307
31.0k
        xmlFree(ctxt->valueTab);
6308
31.0k
    }
6309
67.0k
    if (ctxt->comp != NULL) {
6310
22.9k
#ifdef XPATH_STREAMING
6311
22.9k
  if (ctxt->comp->stream != NULL) {
6312
0
      xmlFreePatternList(ctxt->comp->stream);
6313
0
      ctxt->comp->stream = NULL;
6314
0
  }
6315
22.9k
#endif
6316
22.9k
  xmlXPathFreeCompExpr(ctxt->comp);
6317
22.9k
    }
6318
67.0k
    xmlFree(ctxt);
6319
67.0k
}
6320
6321
/************************************************************************
6322
 *                  *
6323
 *    The implicit core function library      *
6324
 *                  *
6325
 ************************************************************************/
6326
6327
/**
6328
 * xmlXPathNodeValHash:
6329
 * @node:  a node pointer
6330
 *
6331
 * Function computing the beginning of the string value of the node,
6332
 * used to speed up comparisons
6333
 *
6334
 * Returns an int usable as a hash
6335
 */
6336
static unsigned int
6337
1
xmlXPathNodeValHash(xmlNodePtr node) {
6338
1
    int len = 2;
6339
1
    const xmlChar * string = NULL;
6340
1
    xmlNodePtr tmp = NULL;
6341
1
    unsigned int ret = 0;
6342
6343
1
    if (node == NULL)
6344
0
  return(0);
6345
6346
1
    if (node->type == XML_DOCUMENT_NODE) {
6347
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6348
0
  if (tmp == NULL)
6349
0
      node = node->children;
6350
0
  else
6351
0
      node = tmp;
6352
6353
0
  if (node == NULL)
6354
0
      return(0);
6355
0
    }
6356
6357
1
    switch (node->type) {
6358
0
  case XML_COMMENT_NODE:
6359
0
  case XML_PI_NODE:
6360
0
  case XML_CDATA_SECTION_NODE:
6361
0
  case XML_TEXT_NODE:
6362
0
      string = node->content;
6363
0
      if (string == NULL)
6364
0
    return(0);
6365
0
      if (string[0] == 0)
6366
0
    return(0);
6367
0
      return(string[0] + (string[1] << 8));
6368
0
  case XML_NAMESPACE_DECL:
6369
0
      string = ((xmlNsPtr)node)->href;
6370
0
      if (string == NULL)
6371
0
    return(0);
6372
0
      if (string[0] == 0)
6373
0
    return(0);
6374
0
      return(string[0] + (string[1] << 8));
6375
0
  case XML_ATTRIBUTE_NODE:
6376
0
      tmp = ((xmlAttrPtr) node)->children;
6377
0
      break;
6378
1
  case XML_ELEMENT_NODE:
6379
1
      tmp = node->children;
6380
1
      break;
6381
0
  default:
6382
0
      return(0);
6383
1
    }
6384
1
    while (tmp != NULL) {
6385
1
  switch (tmp->type) {
6386
0
      case XML_CDATA_SECTION_NODE:
6387
1
      case XML_TEXT_NODE:
6388
1
    string = tmp->content;
6389
1
    break;
6390
0
      default:
6391
0
                string = NULL;
6392
0
    break;
6393
1
  }
6394
1
  if ((string != NULL) && (string[0] != 0)) {
6395
1
      if (len == 1) {
6396
0
    return(ret + (string[0] << 8));
6397
0
      }
6398
1
      if (string[1] == 0) {
6399
0
    len = 1;
6400
0
    ret = string[0];
6401
1
      } else {
6402
1
    return(string[0] + (string[1] << 8));
6403
1
      }
6404
1
  }
6405
  /*
6406
   * Skip to next node
6407
   */
6408
0
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6409
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6410
0
    tmp = tmp->children;
6411
0
    continue;
6412
0
      }
6413
0
  }
6414
0
  if (tmp == node)
6415
0
      break;
6416
6417
0
  if (tmp->next != NULL) {
6418
0
      tmp = tmp->next;
6419
0
      continue;
6420
0
  }
6421
6422
0
  do {
6423
0
      tmp = tmp->parent;
6424
0
      if (tmp == NULL)
6425
0
    break;
6426
0
      if (tmp == node) {
6427
0
    tmp = NULL;
6428
0
    break;
6429
0
      }
6430
0
      if (tmp->next != NULL) {
6431
0
    tmp = tmp->next;
6432
0
    break;
6433
0
      }
6434
0
  } while (tmp != NULL);
6435
0
    }
6436
0
    return(ret);
6437
1
}
6438
6439
/**
6440
 * xmlXPathStringHash:
6441
 * @string:  a string
6442
 *
6443
 * Function computing the beginning of the string value of the node,
6444
 * used to speed up comparisons
6445
 *
6446
 * Returns an int usable as a hash
6447
 */
6448
static unsigned int
6449
1
xmlXPathStringHash(const xmlChar * string) {
6450
1
    if (string == NULL)
6451
0
  return(0);
6452
1
    if (string[0] == 0)
6453
1
  return(0);
6454
0
    return(string[0] + (string[1] << 8));
6455
1
}
6456
6457
/**
6458
 * xmlXPathCompareNodeSetFloat:
6459
 * @ctxt:  the XPath Parser context
6460
 * @inf:  less than (1) or greater than (0)
6461
 * @strict:  is the comparison strict
6462
 * @arg:  the node set
6463
 * @f:  the value
6464
 *
6465
 * Implement the compare operation between a nodeset and a number
6466
 *     @ns < @val    (1, 1, ...
6467
 *     @ns <= @val   (1, 0, ...
6468
 *     @ns > @val    (0, 1, ...
6469
 *     @ns >= @val   (0, 0, ...
6470
 *
6471
 * If one object to be compared is a node-set and the other is a number,
6472
 * then the comparison will be true if and only if there is a node in the
6473
 * node-set such that the result of performing the comparison on the number
6474
 * to be compared and on the result of converting the string-value of that
6475
 * node to a number using the number function is true.
6476
 *
6477
 * Returns 0 or 1 depending on the results of the test.
6478
 */
6479
static int
6480
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6481
219
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6482
219
    int i, ret = 0;
6483
219
    xmlNodeSetPtr ns;
6484
219
    xmlChar *str2;
6485
6486
219
    if ((f == NULL) || (arg == NULL) ||
6487
219
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6488
0
  xmlXPathReleaseObject(ctxt->context, arg);
6489
0
  xmlXPathReleaseObject(ctxt->context, f);
6490
0
        return(0);
6491
0
    }
6492
219
    ns = arg->nodesetval;
6493
219
    if (ns != NULL) {
6494
386
  for (i = 0;i < ns->nodeNr;i++) {
6495
171
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6496
171
       if (str2 != NULL) {
6497
171
     valuePush(ctxt,
6498
171
         xmlXPathCacheNewString(ctxt->context, str2));
6499
171
     xmlFree(str2);
6500
171
     xmlXPathNumberFunction(ctxt, 1);
6501
171
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6502
171
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6503
171
     if (ret)
6504
0
         break;
6505
171
       }
6506
171
  }
6507
215
    }
6508
219
    xmlXPathReleaseObject(ctxt->context, arg);
6509
219
    xmlXPathReleaseObject(ctxt->context, f);
6510
219
    return(ret);
6511
219
}
6512
6513
/**
6514
 * xmlXPathCompareNodeSetString:
6515
 * @ctxt:  the XPath Parser context
6516
 * @inf:  less than (1) or greater than (0)
6517
 * @strict:  is the comparison strict
6518
 * @arg:  the node set
6519
 * @s:  the value
6520
 *
6521
 * Implement the compare operation between a nodeset and a string
6522
 *     @ns < @val    (1, 1, ...
6523
 *     @ns <= @val   (1, 0, ...
6524
 *     @ns > @val    (0, 1, ...
6525
 *     @ns >= @val   (0, 0, ...
6526
 *
6527
 * If one object to be compared is a node-set and the other is a string,
6528
 * then the comparison will be true if and only if there is a node in
6529
 * the node-set such that the result of performing the comparison on the
6530
 * string-value of the node and the other string is true.
6531
 *
6532
 * Returns 0 or 1 depending on the results of the test.
6533
 */
6534
static int
6535
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6536
3
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6537
3
    int i, ret = 0;
6538
3
    xmlNodeSetPtr ns;
6539
3
    xmlChar *str2;
6540
6541
3
    if ((s == NULL) || (arg == NULL) ||
6542
3
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6543
0
  xmlXPathReleaseObject(ctxt->context, arg);
6544
0
  xmlXPathReleaseObject(ctxt->context, s);
6545
0
        return(0);
6546
0
    }
6547
3
    ns = arg->nodesetval;
6548
3
    if (ns != NULL) {
6549
9
  for (i = 0;i < ns->nodeNr;i++) {
6550
6
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6551
6
       if (str2 != NULL) {
6552
6
     valuePush(ctxt,
6553
6
         xmlXPathCacheNewString(ctxt->context, str2));
6554
6
     xmlFree(str2);
6555
6
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6556
6
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6557
6
     if (ret)
6558
0
         break;
6559
6
       }
6560
6
  }
6561
3
    }
6562
3
    xmlXPathReleaseObject(ctxt->context, arg);
6563
3
    xmlXPathReleaseObject(ctxt->context, s);
6564
3
    return(ret);
6565
3
}
6566
6567
/**
6568
 * xmlXPathCompareNodeSets:
6569
 * @inf:  less than (1) or greater than (0)
6570
 * @strict:  is the comparison strict
6571
 * @arg1:  the first node set object
6572
 * @arg2:  the second node set object
6573
 *
6574
 * Implement the compare operation on nodesets:
6575
 *
6576
 * If both objects to be compared are node-sets, then the comparison
6577
 * will be true if and only if there is a node in the first node-set
6578
 * and a node in the second node-set such that the result of performing
6579
 * the comparison on the string-values of the two nodes is true.
6580
 * ....
6581
 * When neither object to be compared is a node-set and the operator
6582
 * is <=, <, >= or >, then the objects are compared by converting both
6583
 * objects to numbers and comparing the numbers according to IEEE 754.
6584
 * ....
6585
 * The number function converts its argument to a number as follows:
6586
 *  - a string that consists of optional whitespace followed by an
6587
 *    optional minus sign followed by a Number followed by whitespace
6588
 *    is converted to the IEEE 754 number that is nearest (according
6589
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6590
 *    represented by the string; any other string is converted to NaN
6591
 *
6592
 * Conclusion all nodes need to be converted first to their string value
6593
 * and then the comparison must be done when possible
6594
 */
6595
static int
6596
xmlXPathCompareNodeSets(int inf, int strict,
6597
190
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6598
190
    int i, j, init = 0;
6599
190
    double val1;
6600
190
    double *values2;
6601
190
    int ret = 0;
6602
190
    xmlNodeSetPtr ns1;
6603
190
    xmlNodeSetPtr ns2;
6604
6605
190
    if ((arg1 == NULL) ||
6606
190
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6607
0
  xmlXPathFreeObject(arg2);
6608
0
        return(0);
6609
0
    }
6610
190
    if ((arg2 == NULL) ||
6611
190
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6612
0
  xmlXPathFreeObject(arg1);
6613
0
  xmlXPathFreeObject(arg2);
6614
0
        return(0);
6615
0
    }
6616
6617
190
    ns1 = arg1->nodesetval;
6618
190
    ns2 = arg2->nodesetval;
6619
6620
190
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6621
190
  xmlXPathFreeObject(arg1);
6622
190
  xmlXPathFreeObject(arg2);
6623
190
  return(0);
6624
190
    }
6625
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6626
0
  xmlXPathFreeObject(arg1);
6627
0
  xmlXPathFreeObject(arg2);
6628
0
  return(0);
6629
0
    }
6630
6631
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6632
0
    if (values2 == NULL) {
6633
        /* TODO: Propagate memory error. */
6634
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6635
0
  xmlXPathFreeObject(arg1);
6636
0
  xmlXPathFreeObject(arg2);
6637
0
  return(0);
6638
0
    }
6639
0
    for (i = 0;i < ns1->nodeNr;i++) {
6640
0
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6641
0
  if (xmlXPathIsNaN(val1))
6642
0
      continue;
6643
0
  for (j = 0;j < ns2->nodeNr;j++) {
6644
0
      if (init == 0) {
6645
0
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6646
0
      }
6647
0
      if (xmlXPathIsNaN(values2[j]))
6648
0
    continue;
6649
0
      if (inf && strict)
6650
0
    ret = (val1 < values2[j]);
6651
0
      else if (inf && !strict)
6652
0
    ret = (val1 <= values2[j]);
6653
0
      else if (!inf && strict)
6654
0
    ret = (val1 > values2[j]);
6655
0
      else if (!inf && !strict)
6656
0
    ret = (val1 >= values2[j]);
6657
0
      if (ret)
6658
0
    break;
6659
0
  }
6660
0
  if (ret)
6661
0
      break;
6662
0
  init = 1;
6663
0
    }
6664
0
    xmlFree(values2);
6665
0
    xmlXPathFreeObject(arg1);
6666
0
    xmlXPathFreeObject(arg2);
6667
0
    return(ret);
6668
0
}
6669
6670
/**
6671
 * xmlXPathCompareNodeSetValue:
6672
 * @ctxt:  the XPath Parser context
6673
 * @inf:  less than (1) or greater than (0)
6674
 * @strict:  is the comparison strict
6675
 * @arg:  the node set
6676
 * @val:  the value
6677
 *
6678
 * Implement the compare operation between a nodeset and a value
6679
 *     @ns < @val    (1, 1, ...
6680
 *     @ns <= @val   (1, 0, ...
6681
 *     @ns > @val    (0, 1, ...
6682
 *     @ns >= @val   (0, 0, ...
6683
 *
6684
 * If one object to be compared is a node-set and the other is a boolean,
6685
 * then the comparison will be true if and only if the result of performing
6686
 * the comparison on the boolean and on the result of converting
6687
 * the node-set to a boolean using the boolean function is true.
6688
 *
6689
 * Returns 0 or 1 depending on the results of the test.
6690
 */
6691
static int
6692
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6693
225
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6694
225
    if ((val == NULL) || (arg == NULL) ||
6695
225
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6696
0
        return(0);
6697
6698
225
    switch(val->type) {
6699
219
        case XPATH_NUMBER:
6700
219
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6701
0
        case XPATH_NODESET:
6702
0
        case XPATH_XSLT_TREE:
6703
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6704
3
        case XPATH_STRING:
6705
3
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6706
3
        case XPATH_BOOLEAN:
6707
3
      valuePush(ctxt, arg);
6708
3
      xmlXPathBooleanFunction(ctxt, 1);
6709
3
      valuePush(ctxt, val);
6710
3
      return(xmlXPathCompareValues(ctxt, inf, strict));
6711
0
  default:
6712
0
            xmlGenericError(xmlGenericErrorContext,
6713
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6714
0
                    "and object of type %d\n",
6715
0
                    val->type);
6716
0
            xmlXPathReleaseObject(ctxt->context, arg);
6717
0
            xmlXPathReleaseObject(ctxt->context, val);
6718
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6719
225
    }
6720
0
    return(0);
6721
225
}
6722
6723
/**
6724
 * xmlXPathEqualNodeSetString:
6725
 * @arg:  the nodeset object argument
6726
 * @str:  the string to compare to.
6727
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6728
 *
6729
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6730
 * If one object to be compared is a node-set and the other is a string,
6731
 * then the comparison will be true if and only if there is a node in
6732
 * the node-set such that the result of performing the comparison on the
6733
 * string-value of the node and the other string is true.
6734
 *
6735
 * Returns 0 or 1 depending on the results of the test.
6736
 */
6737
static int
6738
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6739
1
{
6740
1
    int i;
6741
1
    xmlNodeSetPtr ns;
6742
1
    xmlChar *str2;
6743
1
    unsigned int hash;
6744
6745
1
    if ((str == NULL) || (arg == NULL) ||
6746
1
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6747
0
        return (0);
6748
1
    ns = arg->nodesetval;
6749
    /*
6750
     * A NULL nodeset compared with a string is always false
6751
     * (since there is no node equal, and no node not equal)
6752
     */
6753
1
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6754
0
        return (0);
6755
1
    hash = xmlXPathStringHash(str);
6756
1
    for (i = 0; i < ns->nodeNr; i++) {
6757
1
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6758
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6759
0
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6760
0
                xmlFree(str2);
6761
0
    if (neq)
6762
0
        continue;
6763
0
                return (1);
6764
0
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6765
0
    if (neq)
6766
0
        continue;
6767
0
                return (1);
6768
0
            } else if (neq) {
6769
0
    if (str2 != NULL)
6770
0
        xmlFree(str2);
6771
0
    return (1);
6772
0
      }
6773
0
            if (str2 != NULL)
6774
0
                xmlFree(str2);
6775
1
        } else if (neq)
6776
1
      return (1);
6777
1
    }
6778
0
    return (0);
6779
1
}
6780
6781
/**
6782
 * xmlXPathEqualNodeSetFloat:
6783
 * @arg:  the nodeset object argument
6784
 * @f:  the float to compare to
6785
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6786
 *
6787
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6788
 * If one object to be compared is a node-set and the other is a number,
6789
 * then the comparison will be true if and only if there is a node in
6790
 * the node-set such that the result of performing the comparison on the
6791
 * number to be compared and on the result of converting the string-value
6792
 * of that node to a number using the number function is true.
6793
 *
6794
 * Returns 0 or 1 depending on the results of the test.
6795
 */
6796
static int
6797
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6798
313
    xmlXPathObjectPtr arg, double f, int neq) {
6799
313
  int i, ret=0;
6800
313
  xmlNodeSetPtr ns;
6801
313
  xmlChar *str2;
6802
313
  xmlXPathObjectPtr val;
6803
313
  double v;
6804
6805
313
    if ((arg == NULL) ||
6806
313
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6807
0
        return(0);
6808
6809
313
    ns = arg->nodesetval;
6810
313
    if (ns != NULL) {
6811
2.12M
  for (i=0;i<ns->nodeNr;i++) {
6812
2.12M
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6813
2.12M
      if (str2 != NULL) {
6814
2.12M
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6815
2.12M
    xmlFree(str2);
6816
2.12M
    xmlXPathNumberFunction(ctxt, 1);
6817
2.12M
    val = valuePop(ctxt);
6818
2.12M
    v = val->floatval;
6819
2.12M
    xmlXPathReleaseObject(ctxt->context, val);
6820
2.12M
    if (!xmlXPathIsNaN(v)) {
6821
1.16k
        if ((!neq) && (v==f)) {
6822
0
      ret = 1;
6823
0
      break;
6824
1.16k
        } else if ((neq) && (v!=f)) {
6825
0
      ret = 1;
6826
0
      break;
6827
0
        }
6828
2.12M
    } else { /* NaN is unequal to any value */
6829
2.12M
        if (neq)
6830
0
      ret = 1;
6831
2.12M
    }
6832
2.12M
      }
6833
2.12M
  }
6834
313
    }
6835
6836
313
    return(ret);
6837
313
}
6838
6839
6840
/**
6841
 * xmlXPathEqualNodeSets:
6842
 * @arg1:  first nodeset object argument
6843
 * @arg2:  second nodeset object argument
6844
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6845
 *
6846
 * Implement the equal / not equal operation on XPath nodesets:
6847
 * @arg1 == @arg2  or  @arg1 != @arg2
6848
 * If both objects to be compared are node-sets, then the comparison
6849
 * will be true if and only if there is a node in the first node-set and
6850
 * a node in the second node-set such that the result of performing the
6851
 * comparison on the string-values of the two nodes is true.
6852
 *
6853
 * (needless to say, this is a costly operation)
6854
 *
6855
 * Returns 0 or 1 depending on the results of the test.
6856
 */
6857
static int
6858
435
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6859
435
    int i, j;
6860
435
    unsigned int *hashs1;
6861
435
    unsigned int *hashs2;
6862
435
    xmlChar **values1;
6863
435
    xmlChar **values2;
6864
435
    int ret = 0;
6865
435
    xmlNodeSetPtr ns1;
6866
435
    xmlNodeSetPtr ns2;
6867
6868
435
    if ((arg1 == NULL) ||
6869
435
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6870
0
        return(0);
6871
435
    if ((arg2 == NULL) ||
6872
435
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6873
0
        return(0);
6874
6875
435
    ns1 = arg1->nodesetval;
6876
435
    ns2 = arg2->nodesetval;
6877
6878
435
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6879
435
  return(0);
6880
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6881
0
  return(0);
6882
6883
    /*
6884
     * for equal, check if there is a node pertaining to both sets
6885
     */
6886
0
    if (neq == 0)
6887
0
  for (i = 0;i < ns1->nodeNr;i++)
6888
0
      for (j = 0;j < ns2->nodeNr;j++)
6889
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6890
0
        return(1);
6891
6892
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6893
0
    if (values1 == NULL) {
6894
        /* TODO: Propagate memory error. */
6895
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896
0
  return(0);
6897
0
    }
6898
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6899
0
    if (hashs1 == NULL) {
6900
        /* TODO: Propagate memory error. */
6901
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902
0
  xmlFree(values1);
6903
0
  return(0);
6904
0
    }
6905
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6906
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6907
0
    if (values2 == NULL) {
6908
        /* TODO: Propagate memory error. */
6909
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910
0
  xmlFree(hashs1);
6911
0
  xmlFree(values1);
6912
0
  return(0);
6913
0
    }
6914
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6915
0
    if (hashs2 == NULL) {
6916
        /* TODO: Propagate memory error. */
6917
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918
0
  xmlFree(hashs1);
6919
0
  xmlFree(values1);
6920
0
  xmlFree(values2);
6921
0
  return(0);
6922
0
    }
6923
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6924
0
    for (i = 0;i < ns1->nodeNr;i++) {
6925
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6926
0
  for (j = 0;j < ns2->nodeNr;j++) {
6927
0
      if (i == 0)
6928
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6929
0
      if (hashs1[i] != hashs2[j]) {
6930
0
    if (neq) {
6931
0
        ret = 1;
6932
0
        break;
6933
0
    }
6934
0
      }
6935
0
      else {
6936
0
    if (values1[i] == NULL)
6937
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6938
0
    if (values2[j] == NULL)
6939
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6940
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6941
0
    if (ret)
6942
0
        break;
6943
0
      }
6944
0
  }
6945
0
  if (ret)
6946
0
      break;
6947
0
    }
6948
0
    for (i = 0;i < ns1->nodeNr;i++)
6949
0
  if (values1[i] != NULL)
6950
0
      xmlFree(values1[i]);
6951
0
    for (j = 0;j < ns2->nodeNr;j++)
6952
0
  if (values2[j] != NULL)
6953
0
      xmlFree(values2[j]);
6954
0
    xmlFree(values1);
6955
0
    xmlFree(values2);
6956
0
    xmlFree(hashs1);
6957
0
    xmlFree(hashs2);
6958
0
    return(ret);
6959
0
}
6960
6961
static int
6962
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6963
662
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6964
662
    int ret = 0;
6965
    /*
6966
     *At this point we are assured neither arg1 nor arg2
6967
     *is a nodeset, so we can just pick the appropriate routine.
6968
     */
6969
662
    switch (arg1->type) {
6970
0
        case XPATH_UNDEFINED:
6971
#ifdef DEBUG_EXPR
6972
      xmlGenericError(xmlGenericErrorContext,
6973
        "Equal: undefined\n");
6974
#endif
6975
0
      break;
6976
188
        case XPATH_BOOLEAN:
6977
188
      switch (arg2->type) {
6978
0
          case XPATH_UNDEFINED:
6979
#ifdef DEBUG_EXPR
6980
        xmlGenericError(xmlGenericErrorContext,
6981
          "Equal: undefined\n");
6982
#endif
6983
0
        break;
6984
0
    case XPATH_BOOLEAN:
6985
#ifdef DEBUG_EXPR
6986
        xmlGenericError(xmlGenericErrorContext,
6987
          "Equal: %d boolean %d \n",
6988
          arg1->boolval, arg2->boolval);
6989
#endif
6990
0
        ret = (arg1->boolval == arg2->boolval);
6991
0
        break;
6992
188
    case XPATH_NUMBER:
6993
188
        ret = (arg1->boolval ==
6994
188
         xmlXPathCastNumberToBoolean(arg2->floatval));
6995
188
        break;
6996
0
    case XPATH_STRING:
6997
0
        if ((arg2->stringval == NULL) ||
6998
0
      (arg2->stringval[0] == 0)) ret = 0;
6999
0
        else
7000
0
      ret = 1;
7001
0
        ret = (arg1->boolval == ret);
7002
0
        break;
7003
0
    case XPATH_USERS:
7004
#ifdef LIBXML_XPTR_LOCS_ENABLED
7005
    case XPATH_POINT:
7006
    case XPATH_RANGE:
7007
    case XPATH_LOCATIONSET:
7008
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7009
0
        TODO
7010
0
        break;
7011
0
    case XPATH_NODESET:
7012
0
    case XPATH_XSLT_TREE:
7013
0
        break;
7014
188
      }
7015
188
      break;
7016
474
        case XPATH_NUMBER:
7017
474
      switch (arg2->type) {
7018
0
          case XPATH_UNDEFINED:
7019
#ifdef DEBUG_EXPR
7020
        xmlGenericError(xmlGenericErrorContext,
7021
          "Equal: undefined\n");
7022
#endif
7023
0
        break;
7024
2
    case XPATH_BOOLEAN:
7025
2
        ret = (arg2->boolval==
7026
2
         xmlXPathCastNumberToBoolean(arg1->floatval));
7027
2
        break;
7028
0
    case XPATH_STRING:
7029
0
        valuePush(ctxt, arg2);
7030
0
        xmlXPathNumberFunction(ctxt, 1);
7031
0
        arg2 = valuePop(ctxt);
7032
                    /* Falls through. */
7033
472
    case XPATH_NUMBER:
7034
        /* Hand check NaN and Infinity equalities */
7035
472
        if (xmlXPathIsNaN(arg1->floatval) ||
7036
472
          xmlXPathIsNaN(arg2->floatval)) {
7037
2
            ret = 0;
7038
470
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7039
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
7040
0
          ret = 1;
7041
0
      else
7042
0
          ret = 0;
7043
470
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7044
470
      if (xmlXPathIsInf(arg2->floatval) == -1)
7045
464
          ret = 1;
7046
6
      else
7047
6
          ret = 0;
7048
470
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7049
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7050
0
          ret = 1;
7051
0
      else
7052
0
          ret = 0;
7053
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7054
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7055
0
          ret = 1;
7056
0
      else
7057
0
          ret = 0;
7058
0
        } else {
7059
0
            ret = (arg1->floatval == arg2->floatval);
7060
0
        }
7061
472
        break;
7062
0
    case XPATH_USERS:
7063
#ifdef LIBXML_XPTR_LOCS_ENABLED
7064
    case XPATH_POINT:
7065
    case XPATH_RANGE:
7066
    case XPATH_LOCATIONSET:
7067
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7068
0
        TODO
7069
0
        break;
7070
0
    case XPATH_NODESET:
7071
0
    case XPATH_XSLT_TREE:
7072
0
        break;
7073
474
      }
7074
474
      break;
7075
474
        case XPATH_STRING:
7076
0
      switch (arg2->type) {
7077
0
          case XPATH_UNDEFINED:
7078
#ifdef DEBUG_EXPR
7079
        xmlGenericError(xmlGenericErrorContext,
7080
          "Equal: undefined\n");
7081
#endif
7082
0
        break;
7083
0
    case XPATH_BOOLEAN:
7084
0
        if ((arg1->stringval == NULL) ||
7085
0
      (arg1->stringval[0] == 0)) ret = 0;
7086
0
        else
7087
0
      ret = 1;
7088
0
        ret = (arg2->boolval == ret);
7089
0
        break;
7090
0
    case XPATH_STRING:
7091
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7092
0
        break;
7093
0
    case XPATH_NUMBER:
7094
0
        valuePush(ctxt, arg1);
7095
0
        xmlXPathNumberFunction(ctxt, 1);
7096
0
        arg1 = valuePop(ctxt);
7097
        /* Hand check NaN and Infinity equalities */
7098
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7099
0
          xmlXPathIsNaN(arg2->floatval)) {
7100
0
            ret = 0;
7101
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7102
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7103
0
          ret = 1;
7104
0
      else
7105
0
          ret = 0;
7106
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7107
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7108
0
          ret = 1;
7109
0
      else
7110
0
          ret = 0;
7111
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7112
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7113
0
          ret = 1;
7114
0
      else
7115
0
          ret = 0;
7116
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7117
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7118
0
          ret = 1;
7119
0
      else
7120
0
          ret = 0;
7121
0
        } else {
7122
0
            ret = (arg1->floatval == arg2->floatval);
7123
0
        }
7124
0
        break;
7125
0
    case XPATH_USERS:
7126
#ifdef LIBXML_XPTR_LOCS_ENABLED
7127
    case XPATH_POINT:
7128
    case XPATH_RANGE:
7129
    case XPATH_LOCATIONSET:
7130
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7131
0
        TODO
7132
0
        break;
7133
0
    case XPATH_NODESET:
7134
0
    case XPATH_XSLT_TREE:
7135
0
        break;
7136
0
      }
7137
0
      break;
7138
0
        case XPATH_USERS:
7139
#ifdef LIBXML_XPTR_LOCS_ENABLED
7140
  case XPATH_POINT:
7141
  case XPATH_RANGE:
7142
  case XPATH_LOCATIONSET:
7143
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7144
0
      TODO
7145
0
      break;
7146
0
  case XPATH_NODESET:
7147
0
  case XPATH_XSLT_TREE:
7148
0
      break;
7149
662
    }
7150
662
    xmlXPathReleaseObject(ctxt->context, arg1);
7151
662
    xmlXPathReleaseObject(ctxt->context, arg2);
7152
662
    return(ret);
7153
662
}
7154
7155
/**
7156
 * xmlXPathEqualValues:
7157
 * @ctxt:  the XPath Parser context
7158
 *
7159
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7160
 *
7161
 * Returns 0 or 1 depending on the results of the test.
7162
 */
7163
int
7164
1.25k
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7165
1.25k
    xmlXPathObjectPtr arg1, arg2, argtmp;
7166
1.25k
    int ret = 0;
7167
7168
1.25k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7169
1.25k
    arg2 = valuePop(ctxt);
7170
1.25k
    arg1 = valuePop(ctxt);
7171
1.25k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7172
0
  if (arg1 != NULL)
7173
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7174
0
  else
7175
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7176
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7177
0
    }
7178
7179
1.25k
    if (arg1 == arg2) {
7180
#ifdef DEBUG_EXPR
7181
        xmlGenericError(xmlGenericErrorContext,
7182
    "Equal: by pointer\n");
7183
#endif
7184
0
  xmlXPathFreeObject(arg1);
7185
0
        return(1);
7186
0
    }
7187
7188
    /*
7189
     *If either argument is a nodeset, it's a 'special case'
7190
     */
7191
1.25k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7192
1.25k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7193
  /*
7194
   *Hack it to assure arg1 is the nodeset
7195
   */
7196
596
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7197
321
    argtmp = arg2;
7198
321
    arg2 = arg1;
7199
321
    arg1 = argtmp;
7200
321
  }
7201
596
  switch (arg2->type) {
7202
0
      case XPATH_UNDEFINED:
7203
#ifdef DEBUG_EXPR
7204
    xmlGenericError(xmlGenericErrorContext,
7205
      "Equal: undefined\n");
7206
#endif
7207
0
    break;
7208
239
      case XPATH_NODESET:
7209
239
      case XPATH_XSLT_TREE:
7210
239
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7211
239
    break;
7212
44
      case XPATH_BOOLEAN:
7213
44
    if ((arg1->nodesetval == NULL) ||
7214
44
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7215
0
    else
7216
0
        ret = 1;
7217
44
    ret = (ret == arg2->boolval);
7218
44
    break;
7219
313
      case XPATH_NUMBER:
7220
313
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7221
313
    break;
7222
0
      case XPATH_STRING:
7223
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7224
0
    break;
7225
0
      case XPATH_USERS:
7226
#ifdef LIBXML_XPTR_LOCS_ENABLED
7227
      case XPATH_POINT:
7228
      case XPATH_RANGE:
7229
      case XPATH_LOCATIONSET:
7230
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7231
0
    TODO
7232
0
    break;
7233
596
  }
7234
596
  xmlXPathReleaseObject(ctxt->context, arg1);
7235
596
  xmlXPathReleaseObject(ctxt->context, arg2);
7236
596
  return(ret);
7237
596
    }
7238
7239
662
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7240
1.25k
}
7241
7242
/**
7243
 * xmlXPathNotEqualValues:
7244
 * @ctxt:  the XPath Parser context
7245
 *
7246
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7247
 *
7248
 * Returns 0 or 1 depending on the results of the test.
7249
 */
7250
int
7251
198
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7252
198
    xmlXPathObjectPtr arg1, arg2, argtmp;
7253
198
    int ret = 0;
7254
7255
198
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7256
198
    arg2 = valuePop(ctxt);
7257
198
    arg1 = valuePop(ctxt);
7258
198
    if ((arg1 == NULL) || (arg2 == NULL)) {
7259
0
  if (arg1 != NULL)
7260
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7261
0
  else
7262
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7263
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7264
0
    }
7265
7266
198
    if (arg1 == arg2) {
7267
#ifdef DEBUG_EXPR
7268
        xmlGenericError(xmlGenericErrorContext,
7269
    "NotEqual: by pointer\n");
7270
#endif
7271
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7272
0
        return(0);
7273
0
    }
7274
7275
    /*
7276
     *If either argument is a nodeset, it's a 'special case'
7277
     */
7278
198
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7279
198
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7280
  /*
7281
   *Hack it to assure arg1 is the nodeset
7282
   */
7283
198
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7284
2
    argtmp = arg2;
7285
2
    arg2 = arg1;
7286
2
    arg1 = argtmp;
7287
2
  }
7288
198
  switch (arg2->type) {
7289
0
      case XPATH_UNDEFINED:
7290
#ifdef DEBUG_EXPR
7291
    xmlGenericError(xmlGenericErrorContext,
7292
      "NotEqual: undefined\n");
7293
#endif
7294
0
    break;
7295
196
      case XPATH_NODESET:
7296
196
      case XPATH_XSLT_TREE:
7297
196
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7298
196
    break;
7299
1
      case XPATH_BOOLEAN:
7300
1
    if ((arg1->nodesetval == NULL) ||
7301
1
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7302
1
    else
7303
1
        ret = 1;
7304
1
    ret = (ret != arg2->boolval);
7305
1
    break;
7306
0
      case XPATH_NUMBER:
7307
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7308
0
    break;
7309
1
      case XPATH_STRING:
7310
1
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7311
1
    break;
7312
0
      case XPATH_USERS:
7313
#ifdef LIBXML_XPTR_LOCS_ENABLED
7314
      case XPATH_POINT:
7315
      case XPATH_RANGE:
7316
      case XPATH_LOCATIONSET:
7317
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7318
0
    TODO
7319
0
    break;
7320
198
  }
7321
198
  xmlXPathReleaseObject(ctxt->context, arg1);
7322
198
  xmlXPathReleaseObject(ctxt->context, arg2);
7323
198
  return(ret);
7324
198
    }
7325
7326
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7327
198
}
7328
7329
/**
7330
 * xmlXPathCompareValues:
7331
 * @ctxt:  the XPath Parser context
7332
 * @inf:  less than (1) or greater than (0)
7333
 * @strict:  is the comparison strict
7334
 *
7335
 * Implement the compare operation on XPath objects:
7336
 *     @arg1 < @arg2    (1, 1, ...
7337
 *     @arg1 <= @arg2   (1, 0, ...
7338
 *     @arg1 > @arg2    (0, 1, ...
7339
 *     @arg1 >= @arg2   (0, 0, ...
7340
 *
7341
 * When neither object to be compared is a node-set and the operator is
7342
 * <=, <, >=, >, then the objects are compared by converted both objects
7343
 * to numbers and comparing the numbers according to IEEE 754. The <
7344
 * comparison will be true if and only if the first number is less than the
7345
 * second number. The <= comparison will be true if and only if the first
7346
 * number is less than or equal to the second number. The > comparison
7347
 * will be true if and only if the first number is greater than the second
7348
 * number. The >= comparison will be true if and only if the first number
7349
 * is greater than or equal to the second number.
7350
 *
7351
 * Returns 1 if the comparison succeeded, 0 if it failed
7352
 */
7353
int
7354
2.41k
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7355
2.41k
    int ret = 0, arg1i = 0, arg2i = 0;
7356
2.41k
    xmlXPathObjectPtr arg1, arg2;
7357
7358
2.41k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7359
2.41k
    arg2 = valuePop(ctxt);
7360
2.41k
    arg1 = valuePop(ctxt);
7361
2.41k
    if ((arg1 == NULL) || (arg2 == NULL)) {
7362
0
  if (arg1 != NULL)
7363
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7364
0
  else
7365
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7366
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7367
0
    }
7368
7369
2.41k
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7370
2.41k
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7371
  /*
7372
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7373
   * are not freed from within this routine; they will be freed from the
7374
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7375
   */
7376
415
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7377
415
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7378
190
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7379
225
  } else {
7380
225
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7381
7
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7382
7
                                arg1, arg2);
7383
218
      } else {
7384
218
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7385
218
                                arg2, arg1);
7386
218
      }
7387
225
  }
7388
415
  return(ret);
7389
415
    }
7390
7391
1.99k
    if (arg1->type != XPATH_NUMBER) {
7392
12
  valuePush(ctxt, arg1);
7393
12
  xmlXPathNumberFunction(ctxt, 1);
7394
12
  arg1 = valuePop(ctxt);
7395
12
    }
7396
1.99k
    if (arg1->type != XPATH_NUMBER) {
7397
0
  xmlXPathFreeObject(arg1);
7398
0
  xmlXPathFreeObject(arg2);
7399
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7400
0
    }
7401
1.99k
    if (arg2->type != XPATH_NUMBER) {
7402
12
  valuePush(ctxt, arg2);
7403
12
  xmlXPathNumberFunction(ctxt, 1);
7404
12
  arg2 = valuePop(ctxt);
7405
12
    }
7406
1.99k
    if (arg2->type != XPATH_NUMBER) {
7407
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7408
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7409
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7410
0
    }
7411
    /*
7412
     * Add tests for infinity and nan
7413
     * => feedback on 3.4 for Inf and NaN
7414
     */
7415
    /* Hand check NaN and Infinity comparisons */
7416
1.99k
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7417
1.99k
  ret=0;
7418
1.99k
    } else {
7419
3
  arg1i=xmlXPathIsInf(arg1->floatval);
7420
3
  arg2i=xmlXPathIsInf(arg2->floatval);
7421
3
  if (inf && strict) {
7422
3
      if ((arg1i == -1 && arg2i != -1) ||
7423
3
    (arg2i == 1 && arg1i != 1)) {
7424
0
    ret = 1;
7425
3
      } else if (arg1i == 0 && arg2i == 0) {
7426
3
    ret = (arg1->floatval < arg2->floatval);
7427
3
      } else {
7428
0
    ret = 0;
7429
0
      }
7430
3
  }
7431
0
  else if (inf && !strict) {
7432
0
      if (arg1i == -1 || arg2i == 1) {
7433
0
    ret = 1;
7434
0
      } else if (arg1i == 0 && arg2i == 0) {
7435
0
    ret = (arg1->floatval <= arg2->floatval);
7436
0
      } else {
7437
0
    ret = 0;
7438
0
      }
7439
0
  }
7440
0
  else if (!inf && strict) {
7441
0
      if ((arg1i == 1 && arg2i != 1) ||
7442
0
    (arg2i == -1 && arg1i != -1)) {
7443
0
    ret = 1;
7444
0
      } else if (arg1i == 0 && arg2i == 0) {
7445
0
    ret = (arg1->floatval > arg2->floatval);
7446
0
      } else {
7447
0
    ret = 0;
7448
0
      }
7449
0
  }
7450
0
  else if (!inf && !strict) {
7451
0
      if (arg1i == 1 || arg2i == -1) {
7452
0
    ret = 1;
7453
0
      } else if (arg1i == 0 && arg2i == 0) {
7454
0
    ret = (arg1->floatval >= arg2->floatval);
7455
0
      } else {
7456
0
    ret = 0;
7457
0
      }
7458
0
  }
7459
3
    }
7460
1.99k
    xmlXPathReleaseObject(ctxt->context, arg1);
7461
1.99k
    xmlXPathReleaseObject(ctxt->context, arg2);
7462
1.99k
    return(ret);
7463
1.99k
}
7464
7465
/**
7466
 * xmlXPathValueFlipSign:
7467
 * @ctxt:  the XPath Parser context
7468
 *
7469
 * Implement the unary - operation on an XPath object
7470
 * The numeric operators convert their operands to numbers as if
7471
 * by calling the number function.
7472
 */
7473
void
7474
1.17k
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7475
1.17k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7476
1.17k
    CAST_TO_NUMBER;
7477
1.17k
    CHECK_TYPE(XPATH_NUMBER);
7478
1.17k
    ctxt->value->floatval = -ctxt->value->floatval;
7479
1.17k
}
7480
7481
/**
7482
 * xmlXPathAddValues:
7483
 * @ctxt:  the XPath Parser context
7484
 *
7485
 * Implement the add operation on XPath objects:
7486
 * The numeric operators convert their operands to numbers as if
7487
 * by calling the number function.
7488
 */
7489
void
7490
1.16k
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7491
1.16k
    xmlXPathObjectPtr arg;
7492
1.16k
    double val;
7493
7494
1.16k
    arg = valuePop(ctxt);
7495
1.16k
    if (arg == NULL)
7496
1.16k
  XP_ERROR(XPATH_INVALID_OPERAND);
7497
1.16k
    val = xmlXPathCastToNumber(arg);
7498
1.16k
    xmlXPathReleaseObject(ctxt->context, arg);
7499
1.16k
    CAST_TO_NUMBER;
7500
1.16k
    CHECK_TYPE(XPATH_NUMBER);
7501
1.16k
    ctxt->value->floatval += val;
7502
1.16k
}
7503
7504
/**
7505
 * xmlXPathSubValues:
7506
 * @ctxt:  the XPath Parser context
7507
 *
7508
 * Implement the subtraction operation on XPath objects:
7509
 * The numeric operators convert their operands to numbers as if
7510
 * by calling the number function.
7511
 */
7512
void
7513
482
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7514
482
    xmlXPathObjectPtr arg;
7515
482
    double val;
7516
7517
482
    arg = valuePop(ctxt);
7518
482
    if (arg == NULL)
7519
482
  XP_ERROR(XPATH_INVALID_OPERAND);
7520
482
    val = xmlXPathCastToNumber(arg);
7521
482
    xmlXPathReleaseObject(ctxt->context, arg);
7522
482
    CAST_TO_NUMBER;
7523
482
    CHECK_TYPE(XPATH_NUMBER);
7524
482
    ctxt->value->floatval -= val;
7525
482
}
7526
7527
/**
7528
 * xmlXPathMultValues:
7529
 * @ctxt:  the XPath Parser context
7530
 *
7531
 * Implement the multiply operation on XPath objects:
7532
 * The numeric operators convert their operands to numbers as if
7533
 * by calling the number function.
7534
 */
7535
void
7536
3.29k
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7537
3.29k
    xmlXPathObjectPtr arg;
7538
3.29k
    double val;
7539
7540
3.29k
    arg = valuePop(ctxt);
7541
3.29k
    if (arg == NULL)
7542
3.29k
  XP_ERROR(XPATH_INVALID_OPERAND);
7543
3.29k
    val = xmlXPathCastToNumber(arg);
7544
3.29k
    xmlXPathReleaseObject(ctxt->context, arg);
7545
3.29k
    CAST_TO_NUMBER;
7546
3.29k
    CHECK_TYPE(XPATH_NUMBER);
7547
3.29k
    ctxt->value->floatval *= val;
7548
3.29k
}
7549
7550
/**
7551
 * xmlXPathDivValues:
7552
 * @ctxt:  the XPath Parser context
7553
 *
7554
 * Implement the div operation on XPath objects @arg1 / @arg2:
7555
 * The numeric operators convert their operands to numbers as if
7556
 * by calling the number function.
7557
 */
7558
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7559
void
7560
13
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7561
13
    xmlXPathObjectPtr arg;
7562
13
    double val;
7563
7564
13
    arg = valuePop(ctxt);
7565
13
    if (arg == NULL)
7566
13
  XP_ERROR(XPATH_INVALID_OPERAND);
7567
13
    val = xmlXPathCastToNumber(arg);
7568
13
    xmlXPathReleaseObject(ctxt->context, arg);
7569
13
    CAST_TO_NUMBER;
7570
13
    CHECK_TYPE(XPATH_NUMBER);
7571
13
    ctxt->value->floatval /= val;
7572
13
}
7573
7574
/**
7575
 * xmlXPathModValues:
7576
 * @ctxt:  the XPath Parser context
7577
 *
7578
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7579
 * The numeric operators convert their operands to numbers as if
7580
 * by calling the number function.
7581
 */
7582
void
7583
113
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7584
113
    xmlXPathObjectPtr arg;
7585
113
    double arg1, arg2;
7586
7587
113
    arg = valuePop(ctxt);
7588
113
    if (arg == NULL)
7589
113
  XP_ERROR(XPATH_INVALID_OPERAND);
7590
113
    arg2 = xmlXPathCastToNumber(arg);
7591
113
    xmlXPathReleaseObject(ctxt->context, arg);
7592
113
    CAST_TO_NUMBER;
7593
113
    CHECK_TYPE(XPATH_NUMBER);
7594
113
    arg1 = ctxt->value->floatval;
7595
113
    if (arg2 == 0)
7596
0
  ctxt->value->floatval = xmlXPathNAN;
7597
113
    else {
7598
113
  ctxt->value->floatval = fmod(arg1, arg2);
7599
113
    }
7600
113
}
7601
7602
/************************************************************************
7603
 *                  *
7604
 *    The traversal functions         *
7605
 *                  *
7606
 ************************************************************************/
7607
7608
/*
7609
 * A traversal function enumerates nodes along an axis.
7610
 * Initially it must be called with NULL, and it indicates
7611
 * termination on the axis by returning NULL.
7612
 */
7613
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7614
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7615
7616
/*
7617
 * xmlXPathTraversalFunctionExt:
7618
 * A traversal function enumerates nodes along an axis.
7619
 * Initially it must be called with NULL, and it indicates
7620
 * termination on the axis by returning NULL.
7621
 * The context node of the traversal is specified via @contextNode.
7622
 */
7623
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7624
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7625
7626
/*
7627
 * xmlXPathNodeSetMergeFunction:
7628
 * Used for merging node sets in xmlXPathCollectAndTest().
7629
 */
7630
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7631
        (xmlNodeSetPtr, xmlNodeSetPtr);
7632
7633
7634
/**
7635
 * xmlXPathNextSelf:
7636
 * @ctxt:  the XPath Parser context
7637
 * @cur:  the current node in the traversal
7638
 *
7639
 * Traversal function for the "self" direction
7640
 * The self axis contains just the context node itself
7641
 *
7642
 * Returns the next element following that axis
7643
 */
7644
xmlNodePtr
7645
4
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7646
4
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7647
4
    if (cur == NULL)
7648
2
        return(ctxt->context->node);
7649
2
    return(NULL);
7650
4
}
7651
7652
/**
7653
 * xmlXPathNextChild:
7654
 * @ctxt:  the XPath Parser context
7655
 * @cur:  the current node in the traversal
7656
 *
7657
 * Traversal function for the "child" direction
7658
 * The child axis contains the children of the context node in document order.
7659
 *
7660
 * Returns the next element following that axis
7661
 */
7662
xmlNodePtr
7663
30.0k
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7664
30.0k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7665
30.0k
    if (cur == NULL) {
7666
12.2k
  if (ctxt->context->node == NULL) return(NULL);
7667
12.2k
  switch (ctxt->context->node->type) {
7668
4.83k
            case XML_ELEMENT_NODE:
7669
11.5k
            case XML_TEXT_NODE:
7670
11.7k
            case XML_CDATA_SECTION_NODE:
7671
11.7k
            case XML_ENTITY_REF_NODE:
7672
11.7k
            case XML_ENTITY_NODE:
7673
11.8k
            case XML_PI_NODE:
7674
12.1k
            case XML_COMMENT_NODE:
7675
12.1k
            case XML_NOTATION_NODE:
7676
12.1k
            case XML_DTD_NODE:
7677
12.1k
    return(ctxt->context->node->children);
7678
84
            case XML_DOCUMENT_NODE:
7679
84
            case XML_DOCUMENT_TYPE_NODE:
7680
84
            case XML_DOCUMENT_FRAG_NODE:
7681
84
            case XML_HTML_DOCUMENT_NODE:
7682
84
    return(((xmlDocPtr) ctxt->context->node)->children);
7683
0
      case XML_ELEMENT_DECL:
7684
0
      case XML_ATTRIBUTE_DECL:
7685
0
      case XML_ENTITY_DECL:
7686
0
            case XML_ATTRIBUTE_NODE:
7687
0
      case XML_NAMESPACE_DECL:
7688
0
      case XML_XINCLUDE_START:
7689
0
      case XML_XINCLUDE_END:
7690
0
    return(NULL);
7691
12.2k
  }
7692
0
  return(NULL);
7693
12.2k
    }
7694
17.7k
    if ((cur->type == XML_DOCUMENT_NODE) ||
7695
17.7k
        (cur->type == XML_HTML_DOCUMENT_NODE))
7696
0
  return(NULL);
7697
17.7k
    return(cur->next);
7698
17.7k
}
7699
7700
/**
7701
 * xmlXPathNextChildElement:
7702
 * @ctxt:  the XPath Parser context
7703
 * @cur:  the current node in the traversal
7704
 *
7705
 * Traversal function for the "child" direction and nodes of type element.
7706
 * The child axis contains the children of the context node in document order.
7707
 *
7708
 * Returns the next element following that axis
7709
 */
7710
static xmlNodePtr
7711
228k
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7712
228k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713
228k
    if (cur == NULL) {
7714
114k
  cur = ctxt->context->node;
7715
114k
  if (cur == NULL) return(NULL);
7716
  /*
7717
  * Get the first element child.
7718
  */
7719
114k
  switch (cur->type) {
7720
87.6k
            case XML_ELEMENT_NODE:
7721
87.6k
      case XML_DOCUMENT_FRAG_NODE:
7722
87.6k
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7723
87.6k
            case XML_ENTITY_NODE:
7724
87.6k
    cur = cur->children;
7725
87.6k
    if (cur != NULL) {
7726
7.58k
        if (cur->type == XML_ELEMENT_NODE)
7727
658
      return(cur);
7728
6.92k
        do {
7729
6.92k
      cur = cur->next;
7730
6.92k
        } while ((cur != NULL) &&
7731
6.92k
      (cur->type != XML_ELEMENT_NODE));
7732
6.92k
        return(cur);
7733
7.58k
    }
7734
80.0k
    return(NULL);
7735
2.94k
            case XML_DOCUMENT_NODE:
7736
2.94k
            case XML_HTML_DOCUMENT_NODE:
7737
2.94k
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7738
23.8k
      default:
7739
23.8k
    return(NULL);
7740
114k
  }
7741
0
  return(NULL);
7742
114k
    }
7743
    /*
7744
    * Get the next sibling element node.
7745
    */
7746
114k
    switch (cur->type) {
7747
114k
  case XML_ELEMENT_NODE:
7748
114k
  case XML_TEXT_NODE:
7749
114k
  case XML_ENTITY_REF_NODE:
7750
114k
  case XML_ENTITY_NODE:
7751
114k
  case XML_CDATA_SECTION_NODE:
7752
114k
  case XML_PI_NODE:
7753
114k
  case XML_COMMENT_NODE:
7754
114k
  case XML_XINCLUDE_END:
7755
114k
      break;
7756
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7757
0
  default:
7758
0
      return(NULL);
7759
114k
    }
7760
114k
    if (cur->next != NULL) {
7761
111k
  if (cur->next->type == XML_ELEMENT_NODE)
7762
84.1k
      return(cur->next);
7763
27.3k
  cur = cur->next;
7764
38.5k
  do {
7765
38.5k
      cur = cur->next;
7766
38.5k
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7767
27.3k
  return(cur);
7768
111k
    }
7769
2.94k
    return(NULL);
7770
114k
}
7771
7772
#if 0
7773
/**
7774
 * xmlXPathNextDescendantOrSelfElemParent:
7775
 * @ctxt:  the XPath Parser context
7776
 * @cur:  the current node in the traversal
7777
 *
7778
 * Traversal function for the "descendant-or-self" axis.
7779
 * Additionally it returns only nodes which can be parents of
7780
 * element nodes.
7781
 *
7782
 *
7783
 * Returns the next element following that axis
7784
 */
7785
static xmlNodePtr
7786
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7787
               xmlNodePtr contextNode)
7788
{
7789
    if (cur == NULL) {
7790
  if (contextNode == NULL)
7791
      return(NULL);
7792
  switch (contextNode->type) {
7793
      case XML_ELEMENT_NODE:
7794
      case XML_XINCLUDE_START:
7795
      case XML_DOCUMENT_FRAG_NODE:
7796
      case XML_DOCUMENT_NODE:
7797
      case XML_HTML_DOCUMENT_NODE:
7798
    return(contextNode);
7799
      default:
7800
    return(NULL);
7801
  }
7802
  return(NULL);
7803
    } else {
7804
  xmlNodePtr start = cur;
7805
7806
  while (cur != NULL) {
7807
      switch (cur->type) {
7808
    case XML_ELEMENT_NODE:
7809
    /* TODO: OK to have XInclude here? */
7810
    case XML_XINCLUDE_START:
7811
    case XML_DOCUMENT_FRAG_NODE:
7812
        if (cur != start)
7813
      return(cur);
7814
        if (cur->children != NULL) {
7815
      cur = cur->children;
7816
      continue;
7817
        }
7818
        break;
7819
    /* Not sure if we need those here. */
7820
    case XML_DOCUMENT_NODE:
7821
    case XML_HTML_DOCUMENT_NODE:
7822
        if (cur != start)
7823
      return(cur);
7824
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7825
    default:
7826
        break;
7827
      }
7828
7829
next_sibling:
7830
      if ((cur == NULL) || (cur == contextNode))
7831
    return(NULL);
7832
      if (cur->next != NULL) {
7833
    cur = cur->next;
7834
      } else {
7835
    cur = cur->parent;
7836
    goto next_sibling;
7837
      }
7838
  }
7839
    }
7840
    return(NULL);
7841
}
7842
#endif
7843
7844
/**
7845
 * xmlXPathNextDescendant:
7846
 * @ctxt:  the XPath Parser context
7847
 * @cur:  the current node in the traversal
7848
 *
7849
 * Traversal function for the "descendant" direction
7850
 * the descendant axis contains the descendants of the context node in document
7851
 * order; a descendant is a child or a child of a child and so on.
7852
 *
7853
 * Returns the next element following that axis
7854
 */
7855
xmlNodePtr
7856
325k
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7857
325k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7858
325k
    if (cur == NULL) {
7859
7.02k
  if (ctxt->context->node == NULL)
7860
0
      return(NULL);
7861
7.02k
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7862
7.02k
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7863
0
      return(NULL);
7864
7865
7.02k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7866
3.29k
      return(ctxt->context->doc->children);
7867
3.72k
        return(ctxt->context->node->children);
7868
7.02k
    }
7869
7870
318k
    if (cur->type == XML_NAMESPACE_DECL)
7871
0
        return(NULL);
7872
318k
    if (cur->children != NULL) {
7873
  /*
7874
   * Do not descend on entities declarations
7875
   */
7876
46.0k
  if (cur->children->type != XML_ENTITY_DECL) {
7877
46.0k
      cur = cur->children;
7878
      /*
7879
       * Skip DTDs
7880
       */
7881
46.0k
      if (cur->type != XML_DTD_NODE)
7882
46.0k
    return(cur);
7883
46.0k
  }
7884
46.0k
    }
7885
7886
272k
    if (cur == ctxt->context->node) return(NULL);
7887
7888
272k
    while (cur->next != NULL) {
7889
226k
  cur = cur->next;
7890
226k
  if ((cur->type != XML_ENTITY_DECL) &&
7891
226k
      (cur->type != XML_DTD_NODE))
7892
226k
      return(cur);
7893
226k
    }
7894
7895
50.2k
    do {
7896
50.2k
        cur = cur->parent;
7897
50.2k
  if (cur == NULL) break;
7898
50.2k
  if (cur == ctxt->context->node) return(NULL);
7899
44.4k
  if (cur->next != NULL) {
7900
40.1k
      cur = cur->next;
7901
40.1k
      return(cur);
7902
40.1k
  }
7903
44.4k
    } while (cur != NULL);
7904
0
    return(cur);
7905
46.0k
}
7906
7907
/**
7908
 * xmlXPathNextDescendantOrSelf:
7909
 * @ctxt:  the XPath Parser context
7910
 * @cur:  the current node in the traversal
7911
 *
7912
 * Traversal function for the "descendant-or-self" direction
7913
 * the descendant-or-self axis contains the context node and the descendants
7914
 * of the context node in document order; thus the context node is the first
7915
 * node on the axis, and the first child of the context node is the second node
7916
 * on the axis
7917
 *
7918
 * Returns the next element following that axis
7919
 */
7920
xmlNodePtr
7921
181k
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922
181k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923
181k
    if (cur == NULL)
7924
1.86k
        return(ctxt->context->node);
7925
7926
180k
    if (ctxt->context->node == NULL)
7927
0
        return(NULL);
7928
180k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7929
180k
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7930
14
        return(NULL);
7931
7932
180k
    return(xmlXPathNextDescendant(ctxt, cur));
7933
180k
}
7934
7935
/**
7936
 * xmlXPathNextParent:
7937
 * @ctxt:  the XPath Parser context
7938
 * @cur:  the current node in the traversal
7939
 *
7940
 * Traversal function for the "parent" direction
7941
 * The parent axis contains the parent of the context node, if there is one.
7942
 *
7943
 * Returns the next element following that axis
7944
 */
7945
xmlNodePtr
7946
513k
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7947
513k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7948
    /*
7949
     * the parent of an attribute or namespace node is the element
7950
     * to which the attribute or namespace node is attached
7951
     * Namespace handling !!!
7952
     */
7953
513k
    if (cur == NULL) {
7954
256k
  if (ctxt->context->node == NULL) return(NULL);
7955
256k
  switch (ctxt->context->node->type) {
7956
252k
            case XML_ELEMENT_NODE:
7957
256k
            case XML_TEXT_NODE:
7958
256k
            case XML_CDATA_SECTION_NODE:
7959
256k
            case XML_ENTITY_REF_NODE:
7960
256k
            case XML_ENTITY_NODE:
7961
256k
            case XML_PI_NODE:
7962
256k
            case XML_COMMENT_NODE:
7963
256k
            case XML_NOTATION_NODE:
7964
256k
            case XML_DTD_NODE:
7965
256k
      case XML_ELEMENT_DECL:
7966
256k
      case XML_ATTRIBUTE_DECL:
7967
256k
      case XML_XINCLUDE_START:
7968
256k
      case XML_XINCLUDE_END:
7969
256k
      case XML_ENTITY_DECL:
7970
256k
    if (ctxt->context->node->parent == NULL)
7971
0
        return((xmlNodePtr) ctxt->context->doc);
7972
256k
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7973
256k
        ((ctxt->context->node->parent->name[0] == ' ') ||
7974
6.24k
         (xmlStrEqual(ctxt->context->node->parent->name,
7975
6.24k
         BAD_CAST "fake node libxslt"))))
7976
0
        return(NULL);
7977
256k
    return(ctxt->context->node->parent);
7978
36
            case XML_ATTRIBUTE_NODE: {
7979
36
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7980
7981
36
    return(att->parent);
7982
256k
      }
7983
103
            case XML_DOCUMENT_NODE:
7984
103
            case XML_DOCUMENT_TYPE_NODE:
7985
103
            case XML_DOCUMENT_FRAG_NODE:
7986
103
            case XML_HTML_DOCUMENT_NODE:
7987
103
                return(NULL);
7988
0
      case XML_NAMESPACE_DECL: {
7989
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7990
7991
0
    if ((ns->next != NULL) &&
7992
0
        (ns->next->type != XML_NAMESPACE_DECL))
7993
0
        return((xmlNodePtr) ns->next);
7994
0
                return(NULL);
7995
0
      }
7996
256k
  }
7997
256k
    }
7998
256k
    return(NULL);
7999
513k
}
8000
8001
/**
8002
 * xmlXPathNextAncestor:
8003
 * @ctxt:  the XPath Parser context
8004
 * @cur:  the current node in the traversal
8005
 *
8006
 * Traversal function for the "ancestor" direction
8007
 * the ancestor axis contains the ancestors of the context node; the ancestors
8008
 * of the context node consist of the parent of context node and the parent's
8009
 * parent and so on; the nodes are ordered in reverse document order; thus the
8010
 * parent is the first node on the axis, and the parent's parent is the second
8011
 * node on the axis
8012
 *
8013
 * Returns the next element following that axis
8014
 */
8015
xmlNodePtr
8016
22
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8017
22
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8018
    /*
8019
     * the parent of an attribute or namespace node is the element
8020
     * to which the attribute or namespace node is attached
8021
     * !!!!!!!!!!!!!
8022
     */
8023
22
    if (cur == NULL) {
8024
0
  if (ctxt->context->node == NULL) return(NULL);
8025
0
  switch (ctxt->context->node->type) {
8026
0
            case XML_ELEMENT_NODE:
8027
0
            case XML_TEXT_NODE:
8028
0
            case XML_CDATA_SECTION_NODE:
8029
0
            case XML_ENTITY_REF_NODE:
8030
0
            case XML_ENTITY_NODE:
8031
0
            case XML_PI_NODE:
8032
0
            case XML_COMMENT_NODE:
8033
0
      case XML_DTD_NODE:
8034
0
      case XML_ELEMENT_DECL:
8035
0
      case XML_ATTRIBUTE_DECL:
8036
0
      case XML_ENTITY_DECL:
8037
0
            case XML_NOTATION_NODE:
8038
0
      case XML_XINCLUDE_START:
8039
0
      case XML_XINCLUDE_END:
8040
0
    if (ctxt->context->node->parent == NULL)
8041
0
        return((xmlNodePtr) ctxt->context->doc);
8042
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8043
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
8044
0
         (xmlStrEqual(ctxt->context->node->parent->name,
8045
0
         BAD_CAST "fake node libxslt"))))
8046
0
        return(NULL);
8047
0
    return(ctxt->context->node->parent);
8048
0
            case XML_ATTRIBUTE_NODE: {
8049
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8050
8051
0
    return(tmp->parent);
8052
0
      }
8053
0
            case XML_DOCUMENT_NODE:
8054
0
            case XML_DOCUMENT_TYPE_NODE:
8055
0
            case XML_DOCUMENT_FRAG_NODE:
8056
0
            case XML_HTML_DOCUMENT_NODE:
8057
0
                return(NULL);
8058
0
      case XML_NAMESPACE_DECL: {
8059
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8060
8061
0
    if ((ns->next != NULL) &&
8062
0
        (ns->next->type != XML_NAMESPACE_DECL))
8063
0
        return((xmlNodePtr) ns->next);
8064
    /* Bad, how did that namespace end up here ? */
8065
0
                return(NULL);
8066
0
      }
8067
0
  }
8068
0
  return(NULL);
8069
0
    }
8070
22
    if (cur == ctxt->context->doc->children)
8071
2
  return((xmlNodePtr) ctxt->context->doc);
8072
20
    if (cur == (xmlNodePtr) ctxt->context->doc)
8073
10
  return(NULL);
8074
10
    switch (cur->type) {
8075
8
  case XML_ELEMENT_NODE:
8076
10
  case XML_TEXT_NODE:
8077
10
  case XML_CDATA_SECTION_NODE:
8078
10
  case XML_ENTITY_REF_NODE:
8079
10
  case XML_ENTITY_NODE:
8080
10
  case XML_PI_NODE:
8081
10
  case XML_COMMENT_NODE:
8082
10
  case XML_NOTATION_NODE:
8083
10
  case XML_DTD_NODE:
8084
10
        case XML_ELEMENT_DECL:
8085
10
        case XML_ATTRIBUTE_DECL:
8086
10
        case XML_ENTITY_DECL:
8087
10
  case XML_XINCLUDE_START:
8088
10
  case XML_XINCLUDE_END:
8089
10
      if (cur->parent == NULL)
8090
0
    return(NULL);
8091
10
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8092
10
    ((cur->parent->name[0] == ' ') ||
8093
4
     (xmlStrEqual(cur->parent->name,
8094
4
            BAD_CAST "fake node libxslt"))))
8095
0
    return(NULL);
8096
10
      return(cur->parent);
8097
0
  case XML_ATTRIBUTE_NODE: {
8098
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8099
8100
0
      return(att->parent);
8101
10
  }
8102
0
  case XML_NAMESPACE_DECL: {
8103
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8104
8105
0
      if ((ns->next != NULL) &&
8106
0
          (ns->next->type != XML_NAMESPACE_DECL))
8107
0
          return((xmlNodePtr) ns->next);
8108
      /* Bad, how did that namespace end up here ? */
8109
0
            return(NULL);
8110
0
  }
8111
0
  case XML_DOCUMENT_NODE:
8112
0
  case XML_DOCUMENT_TYPE_NODE:
8113
0
  case XML_DOCUMENT_FRAG_NODE:
8114
0
  case XML_HTML_DOCUMENT_NODE:
8115
0
      return(NULL);
8116
10
    }
8117
0
    return(NULL);
8118
10
}
8119
8120
/**
8121
 * xmlXPathNextAncestorOrSelf:
8122
 * @ctxt:  the XPath Parser context
8123
 * @cur:  the current node in the traversal
8124
 *
8125
 * Traversal function for the "ancestor-or-self" direction
8126
 * he ancestor-or-self axis contains the context node and ancestors of
8127
 * the context node in reverse document order; thus the context node is
8128
 * the first node on the axis, and the context node's parent the second;
8129
 * parent here is defined the same as with the parent axis.
8130
 *
8131
 * Returns the next element following that axis
8132
 */
8133
xmlNodePtr
8134
32
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8135
32
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8136
32
    if (cur == NULL)
8137
10
        return(ctxt->context->node);
8138
22
    return(xmlXPathNextAncestor(ctxt, cur));
8139
32
}
8140
8141
/**
8142
 * xmlXPathNextFollowingSibling:
8143
 * @ctxt:  the XPath Parser context
8144
 * @cur:  the current node in the traversal
8145
 *
8146
 * Traversal function for the "following-sibling" direction
8147
 * The following-sibling axis contains the following siblings of the context
8148
 * node in document order.
8149
 *
8150
 * Returns the next element following that axis
8151
 */
8152
xmlNodePtr
8153
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8157
0
  return(NULL);
8158
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8159
0
        return(NULL);
8160
0
    if (cur == NULL)
8161
0
        return(ctxt->context->node->next);
8162
0
    return(cur->next);
8163
0
}
8164
8165
/**
8166
 * xmlXPathNextPrecedingSibling:
8167
 * @ctxt:  the XPath Parser context
8168
 * @cur:  the current node in the traversal
8169
 *
8170
 * Traversal function for the "preceding-sibling" direction
8171
 * The preceding-sibling axis contains the preceding siblings of the context
8172
 * node in reverse document order; the first preceding sibling is first on the
8173
 * axis; the sibling preceding that node is the second on the axis and so on.
8174
 *
8175
 * Returns the next element following that axis
8176
 */
8177
xmlNodePtr
8178
23.7k
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8179
23.7k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8180
23.7k
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8181
23.7k
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8182
0
  return(NULL);
8183
23.7k
    if (cur == (xmlNodePtr) ctxt->context->doc)
8184
0
        return(NULL);
8185
23.7k
    if (cur == NULL)
8186
5.07k
        return(ctxt->context->node->prev);
8187
18.6k
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8188
0
  cur = cur->prev;
8189
0
  if (cur == NULL)
8190
0
      return(ctxt->context->node->prev);
8191
0
    }
8192
18.6k
    return(cur->prev);
8193
18.6k
}
8194
8195
/**
8196
 * xmlXPathNextFollowing:
8197
 * @ctxt:  the XPath Parser context
8198
 * @cur:  the current node in the traversal
8199
 *
8200
 * Traversal function for the "following" direction
8201
 * The following axis contains all nodes in the same document as the context
8202
 * node that are after the context node in document order, excluding any
8203
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8204
 * are ordered in document order
8205
 *
8206
 * Returns the next element following that axis
8207
 */
8208
xmlNodePtr
8209
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8210
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8211
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8212
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8213
0
        return(cur->children);
8214
8215
0
    if (cur == NULL) {
8216
0
        cur = ctxt->context->node;
8217
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8218
0
            cur = cur->parent;
8219
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8220
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8221
8222
0
            if ((ns->next == NULL) ||
8223
0
                (ns->next->type == XML_NAMESPACE_DECL))
8224
0
                return (NULL);
8225
0
            cur = (xmlNodePtr) ns->next;
8226
0
        }
8227
0
    }
8228
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8229
0
    if (cur->next != NULL) return(cur->next) ;
8230
0
    do {
8231
0
        cur = cur->parent;
8232
0
        if (cur == NULL) break;
8233
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8234
0
        if (cur->next != NULL) return(cur->next);
8235
0
    } while (cur != NULL);
8236
0
    return(cur);
8237
0
}
8238
8239
/*
8240
 * xmlXPathIsAncestor:
8241
 * @ancestor:  the ancestor node
8242
 * @node:  the current node
8243
 *
8244
 * Check that @ancestor is a @node's ancestor
8245
 *
8246
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8247
 */
8248
static int
8249
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8250
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8251
0
    if (node->type == XML_NAMESPACE_DECL)
8252
0
        return(0);
8253
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8254
0
        return(0);
8255
    /* nodes need to be in the same document */
8256
0
    if (ancestor->doc != node->doc) return(0);
8257
    /* avoid searching if ancestor or node is the root node */
8258
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8259
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8260
0
    while (node->parent != NULL) {
8261
0
        if (node->parent == ancestor)
8262
0
            return(1);
8263
0
  node = node->parent;
8264
0
    }
8265
0
    return(0);
8266
0
}
8267
8268
/**
8269
 * xmlXPathNextPreceding:
8270
 * @ctxt:  the XPath Parser context
8271
 * @cur:  the current node in the traversal
8272
 *
8273
 * Traversal function for the "preceding" direction
8274
 * the preceding axis contains all nodes in the same document as the context
8275
 * node that are before the context node in document order, excluding any
8276
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8277
 * ordered in reverse document order
8278
 *
8279
 * Returns the next element following that axis
8280
 */
8281
xmlNodePtr
8282
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8283
0
{
8284
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8285
0
    if (cur == NULL) {
8286
0
        cur = ctxt->context->node;
8287
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8288
0
            cur = cur->parent;
8289
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8290
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8291
8292
0
            if ((ns->next == NULL) ||
8293
0
                (ns->next->type == XML_NAMESPACE_DECL))
8294
0
                return (NULL);
8295
0
            cur = (xmlNodePtr) ns->next;
8296
0
        }
8297
0
    }
8298
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8299
0
  return (NULL);
8300
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8301
0
  cur = cur->prev;
8302
0
    do {
8303
0
        if (cur->prev != NULL) {
8304
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8305
0
            return (cur);
8306
0
        }
8307
8308
0
        cur = cur->parent;
8309
0
        if (cur == NULL)
8310
0
            return (NULL);
8311
0
        if (cur == ctxt->context->doc->children)
8312
0
            return (NULL);
8313
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8314
0
    return (cur);
8315
0
}
8316
8317
/**
8318
 * xmlXPathNextPrecedingInternal:
8319
 * @ctxt:  the XPath Parser context
8320
 * @cur:  the current node in the traversal
8321
 *
8322
 * Traversal function for the "preceding" direction
8323
 * the preceding axis contains all nodes in the same document as the context
8324
 * node that are before the context node in document order, excluding any
8325
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8326
 * ordered in reverse document order
8327
 * This is a faster implementation but internal only since it requires a
8328
 * state kept in the parser context: ctxt->ancestor.
8329
 *
8330
 * Returns the next element following that axis
8331
 */
8332
static xmlNodePtr
8333
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8334
                              xmlNodePtr cur)
8335
4.27M
{
8336
4.27M
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8337
4.27M
    if (cur == NULL) {
8338
10.5k
        cur = ctxt->context->node;
8339
10.5k
        if (cur == NULL)
8340
0
            return (NULL);
8341
10.5k
        if (cur->type == XML_ATTRIBUTE_NODE) {
8342
14
            cur = cur->parent;
8343
10.4k
        } else if (cur->type == XML_NAMESPACE_DECL) {
8344
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8345
8346
0
            if ((ns->next == NULL) ||
8347
0
                (ns->next->type == XML_NAMESPACE_DECL))
8348
0
                return (NULL);
8349
0
            cur = (xmlNodePtr) ns->next;
8350
0
        }
8351
10.5k
        ctxt->ancestor = cur->parent;
8352
10.5k
    }
8353
4.27M
    if (cur->type == XML_NAMESPACE_DECL)
8354
0
        return(NULL);
8355
4.27M
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8356
0
  cur = cur->prev;
8357
4.30M
    while (cur->prev == NULL) {
8358
2.14M
        cur = cur->parent;
8359
2.14M
        if (cur == NULL)
8360
9.45k
            return (NULL);
8361
2.13M
        if (cur == ctxt->context->doc->children)
8362
1.04k
            return (NULL);
8363
2.13M
        if (cur != ctxt->ancestor)
8364
2.11M
            return (cur);
8365
25.1k
        ctxt->ancestor = cur->parent;
8366
25.1k
    }
8367
2.15M
    cur = cur->prev;
8368
4.26M
    while (cur->last != NULL)
8369
2.11M
        cur = cur->last;
8370
2.15M
    return (cur);
8371
4.27M
}
8372
8373
/**
8374
 * xmlXPathNextNamespace:
8375
 * @ctxt:  the XPath Parser context
8376
 * @cur:  the current attribute in the traversal
8377
 *
8378
 * Traversal function for the "namespace" direction
8379
 * the namespace axis contains the namespace nodes of the context node;
8380
 * the order of nodes on this axis is implementation-defined; the axis will
8381
 * be empty unless the context node is an element
8382
 *
8383
 * We keep the XML namespace node at the end of the list.
8384
 *
8385
 * Returns the next element following that axis
8386
 */
8387
xmlNodePtr
8388
488
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8389
488
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8390
488
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8391
116
    if (cur == NULL) {
8392
30
        if (ctxt->context->tmpNsList != NULL)
8393
0
      xmlFree(ctxt->context->tmpNsList);
8394
30
  ctxt->context->tmpNsList =
8395
30
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8396
30
  ctxt->context->tmpNsNr = 0;
8397
30
  if (ctxt->context->tmpNsList != NULL) {
8398
86
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8399
56
    ctxt->context->tmpNsNr++;
8400
56
      }
8401
30
  }
8402
30
  return((xmlNodePtr) xmlXPathXMLNamespace);
8403
30
    }
8404
86
    if (ctxt->context->tmpNsNr > 0) {
8405
56
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8406
56
    } else {
8407
30
  if (ctxt->context->tmpNsList != NULL)
8408
30
      xmlFree(ctxt->context->tmpNsList);
8409
30
  ctxt->context->tmpNsList = NULL;
8410
30
  return(NULL);
8411
30
    }
8412
86
}
8413
8414
/**
8415
 * xmlXPathNextAttribute:
8416
 * @ctxt:  the XPath Parser context
8417
 * @cur:  the current attribute in the traversal
8418
 *
8419
 * Traversal function for the "attribute" direction
8420
 * TODO: support DTD inherited default attributes
8421
 *
8422
 * Returns the next element following that axis
8423
 */
8424
xmlNodePtr
8425
12.6k
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8426
12.6k
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8427
12.6k
    if (ctxt->context->node == NULL)
8428
0
  return(NULL);
8429
12.6k
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8430
6.58k
  return(NULL);
8431
6.09k
    if (cur == NULL) {
8432
3.59k
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8433
0
      return(NULL);
8434
3.59k
        return((xmlNodePtr)ctxt->context->node->properties);
8435
3.59k
    }
8436
2.50k
    return((xmlNodePtr)cur->next);
8437
6.09k
}
8438
8439
/************************************************************************
8440
 *                  *
8441
 *    NodeTest Functions          *
8442
 *                  *
8443
 ************************************************************************/
8444
8445
#define IS_FUNCTION     200
8446
8447
8448
/************************************************************************
8449
 *                  *
8450
 *    Implicit tree core function library     *
8451
 *                  *
8452
 ************************************************************************/
8453
8454
/**
8455
 * xmlXPathRoot:
8456
 * @ctxt:  the XPath Parser context
8457
 *
8458
 * Initialize the context to the root of the document
8459
 */
8460
void
8461
8.98k
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8462
8.98k
    if ((ctxt == NULL) || (ctxt->context == NULL))
8463
0
  return;
8464
8.98k
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8465
8.98k
  (xmlNodePtr) ctxt->context->doc));
8466
8.98k
}
8467
8468
/************************************************************************
8469
 *                  *
8470
 *    The explicit core function library      *
8471
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8472
 *                  *
8473
 ************************************************************************/
8474
8475
8476
/**
8477
 * xmlXPathLastFunction:
8478
 * @ctxt:  the XPath Parser context
8479
 * @nargs:  the number of arguments
8480
 *
8481
 * Implement the last() XPath function
8482
 *    number last()
8483
 * The last function returns the number of nodes in the context node list.
8484
 */
8485
void
8486
6.74k
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8487
20.2k
    CHECK_ARITY(0);
8488
20.2k
    if (ctxt->context->contextSize >= 0) {
8489
6.74k
  valuePush(ctxt,
8490
6.74k
      xmlXPathCacheNewFloat(ctxt->context,
8491
6.74k
    (double) ctxt->context->contextSize));
8492
#ifdef DEBUG_EXPR
8493
  xmlGenericError(xmlGenericErrorContext,
8494
    "last() : %d\n", ctxt->context->contextSize);
8495
#endif
8496
6.74k
    } else {
8497
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8498
0
    }
8499
20.2k
}
8500
8501
/**
8502
 * xmlXPathPositionFunction:
8503
 * @ctxt:  the XPath Parser context
8504
 * @nargs:  the number of arguments
8505
 *
8506
 * Implement the position() XPath function
8507
 *    number position()
8508
 * The position function returns the position of the context node in the
8509
 * context node list. The first position is 1, and so the last position
8510
 * will be equal to last().
8511
 */
8512
void
8513
33.8k
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514
101k
    CHECK_ARITY(0);
8515
101k
    if (ctxt->context->proximityPosition >= 0) {
8516
33.8k
  valuePush(ctxt,
8517
33.8k
        xmlXPathCacheNewFloat(ctxt->context,
8518
33.8k
    (double) ctxt->context->proximityPosition));
8519
#ifdef DEBUG_EXPR
8520
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8521
    ctxt->context->proximityPosition);
8522
#endif
8523
33.8k
    } else {
8524
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8525
0
    }
8526
101k
}
8527
8528
/**
8529
 * xmlXPathCountFunction:
8530
 * @ctxt:  the XPath Parser context
8531
 * @nargs:  the number of arguments
8532
 *
8533
 * Implement the count() XPath function
8534
 *    number count(node-set)
8535
 */
8536
void
8537
7.15k
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8538
7.15k
    xmlXPathObjectPtr cur;
8539
8540
20.2k
    CHECK_ARITY(1);
8541
20.2k
    if ((ctxt->value == NULL) ||
8542
6.56k
  ((ctxt->value->type != XPATH_NODESET) &&
8543
6.56k
   (ctxt->value->type != XPATH_XSLT_TREE)))
8544
6.56k
  XP_ERROR(XPATH_INVALID_TYPE);
8545
6.56k
    cur = valuePop(ctxt);
8546
8547
6.56k
    if ((cur == NULL) || (cur->nodesetval == NULL))
8548
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8549
6.56k
    else
8550
6.56k
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8551
6.56k
      (double) cur->nodesetval->nodeNr));
8552
6.56k
    xmlXPathReleaseObject(ctxt->context, cur);
8553
6.56k
}
8554
8555
/**
8556
 * xmlXPathGetElementsByIds:
8557
 * @doc:  the document
8558
 * @ids:  a whitespace separated list of IDs
8559
 *
8560
 * Selects elements by their unique ID.
8561
 *
8562
 * Returns a node-set of selected elements.
8563
 */
8564
static xmlNodeSetPtr
8565
1.10k
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8566
1.10k
    xmlNodeSetPtr ret;
8567
1.10k
    const xmlChar *cur = ids;
8568
1.10k
    xmlChar *ID;
8569
1.10k
    xmlAttrPtr attr;
8570
1.10k
    xmlNodePtr elem = NULL;
8571
8572
1.10k
    if (ids == NULL) return(NULL);
8573
8574
1.10k
    ret = xmlXPathNodeSetCreate(NULL);
8575
1.10k
    if (ret == NULL)
8576
0
        return(ret);
8577
8578
5.03k
    while (IS_BLANK_CH(*cur)) cur++;
8579
1.96k
    while (*cur != 0) {
8580
4.62k
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8581
3.76k
      cur++;
8582
8583
861
        ID = xmlStrndup(ids, cur - ids);
8584
861
  if (ID != NULL) {
8585
      /*
8586
       * We used to check the fact that the value passed
8587
       * was an NCName, but this generated much troubles for
8588
       * me and Aleksey Sanin, people blatantly violated that
8589
       * constraint, like Visa3D spec.
8590
       * if (xmlValidateNCName(ID, 1) == 0)
8591
       */
8592
861
      attr = xmlGetID(doc, ID);
8593
861
      if (attr != NULL) {
8594
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8595
0
        elem = attr->parent;
8596
0
    else if (attr->type == XML_ELEMENT_NODE)
8597
0
        elem = (xmlNodePtr) attr;
8598
0
    else
8599
0
        elem = NULL;
8600
                /* TODO: Check memory error. */
8601
0
    if (elem != NULL)
8602
0
        xmlXPathNodeSetAdd(ret, elem);
8603
0
      }
8604
861
      xmlFree(ID);
8605
861
  }
8606
8607
4.99k
  while (IS_BLANK_CH(*cur)) cur++;
8608
861
  ids = cur;
8609
861
    }
8610
1.10k
    return(ret);
8611
1.10k
}
8612
8613
/**
8614
 * xmlXPathIdFunction:
8615
 * @ctxt:  the XPath Parser context
8616
 * @nargs:  the number of arguments
8617
 *
8618
 * Implement the id() XPath function
8619
 *    node-set id(object)
8620
 * The id function selects elements by their unique ID
8621
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8622
 * then the result is the union of the result of applying id to the
8623
 * string value of each of the nodes in the argument node-set. When the
8624
 * argument to id is of any other type, the argument is converted to a
8625
 * string as if by a call to the string function; the string is split
8626
 * into a whitespace-separated list of tokens (whitespace is any sequence
8627
 * of characters matching the production S); the result is a node-set
8628
 * containing the elements in the same document as the context node that
8629
 * have a unique ID equal to any of the tokens in the list.
8630
 */
8631
void
8632
168
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8633
168
    xmlChar *tokens;
8634
168
    xmlNodeSetPtr ret;
8635
168
    xmlXPathObjectPtr obj;
8636
8637
504
    CHECK_ARITY(1);
8638
504
    obj = valuePop(ctxt);
8639
504
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8640
168
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8641
158
  xmlNodeSetPtr ns;
8642
158
  int i;
8643
8644
        /* TODO: Check memory error. */
8645
158
  ret = xmlXPathNodeSetCreate(NULL);
8646
8647
158
  if (obj->nodesetval != NULL) {
8648
1.24k
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8649
1.09k
    tokens =
8650
1.09k
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8651
1.09k
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8652
                /* TODO: Check memory error. */
8653
1.09k
    ret = xmlXPathNodeSetMerge(ret, ns);
8654
1.09k
    xmlXPathFreeNodeSet(ns);
8655
1.09k
    if (tokens != NULL)
8656
1.09k
        xmlFree(tokens);
8657
1.09k
      }
8658
151
  }
8659
158
  xmlXPathReleaseObject(ctxt->context, obj);
8660
158
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8661
158
  return;
8662
158
    }
8663
10
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8664
10
    if (obj == NULL) return;
8665
10
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8666
10
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8667
10
    xmlXPathReleaseObject(ctxt->context, obj);
8668
10
    return;
8669
10
}
8670
8671
/**
8672
 * xmlXPathLocalNameFunction:
8673
 * @ctxt:  the XPath Parser context
8674
 * @nargs:  the number of arguments
8675
 *
8676
 * Implement the local-name() XPath function
8677
 *    string local-name(node-set?)
8678
 * The local-name function returns a string containing the local part
8679
 * of the name of the node in the argument node-set that is first in
8680
 * document order. If the node-set is empty or the first node has no
8681
 * name, an empty string is returned. If the argument is omitted it
8682
 * defaults to the context node.
8683
 */
8684
void
8685
231
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8686
231
    xmlXPathObjectPtr cur;
8687
8688
231
    if (ctxt == NULL) return;
8689
8690
231
    if (nargs == 0) {
8691
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8692
0
      ctxt->context->node));
8693
0
  nargs = 1;
8694
0
    }
8695
8696
693
    CHECK_ARITY(1);
8697
693
    if ((ctxt->value == NULL) ||
8698
231
  ((ctxt->value->type != XPATH_NODESET) &&
8699
231
   (ctxt->value->type != XPATH_XSLT_TREE)))
8700
199
  XP_ERROR(XPATH_INVALID_TYPE);
8701
199
    cur = valuePop(ctxt);
8702
8703
199
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8704
182
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8705
182
    } else {
8706
17
  int i = 0; /* Should be first in document order !!!!! */
8707
17
  switch (cur->nodesetval->nodeTab[i]->type) {
8708
0
  case XML_ELEMENT_NODE:
8709
17
  case XML_ATTRIBUTE_NODE:
8710
17
  case XML_PI_NODE:
8711
17
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8712
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
17
      else
8714
17
    valuePush(ctxt,
8715
17
          xmlXPathCacheNewString(ctxt->context,
8716
17
      cur->nodesetval->nodeTab[i]->name));
8717
17
      break;
8718
0
  case XML_NAMESPACE_DECL:
8719
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8720
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8721
0
      break;
8722
0
  default:
8723
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8724
17
  }
8725
17
    }
8726
199
    xmlXPathReleaseObject(ctxt->context, cur);
8727
199
}
8728
8729
/**
8730
 * xmlXPathNamespaceURIFunction:
8731
 * @ctxt:  the XPath Parser context
8732
 * @nargs:  the number of arguments
8733
 *
8734
 * Implement the namespace-uri() XPath function
8735
 *    string namespace-uri(node-set?)
8736
 * The namespace-uri function returns a string containing the
8737
 * namespace URI of the expanded name of the node in the argument
8738
 * node-set that is first in document order. If the node-set is empty,
8739
 * the first node has no name, or the expanded name has no namespace
8740
 * URI, an empty string is returned. If the argument is omitted it
8741
 * defaults to the context node.
8742
 */
8743
void
8744
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8745
0
    xmlXPathObjectPtr cur;
8746
8747
0
    if (ctxt == NULL) return;
8748
8749
0
    if (nargs == 0) {
8750
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8751
0
      ctxt->context->node));
8752
0
  nargs = 1;
8753
0
    }
8754
0
    CHECK_ARITY(1);
8755
0
    if ((ctxt->value == NULL) ||
8756
0
  ((ctxt->value->type != XPATH_NODESET) &&
8757
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8758
0
  XP_ERROR(XPATH_INVALID_TYPE);
8759
0
    cur = valuePop(ctxt);
8760
8761
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8762
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763
0
    } else {
8764
0
  int i = 0; /* Should be first in document order !!!!! */
8765
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8766
0
  case XML_ELEMENT_NODE:
8767
0
  case XML_ATTRIBUTE_NODE:
8768
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8769
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8770
0
      else
8771
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8772
0
        cur->nodesetval->nodeTab[i]->ns->href));
8773
0
      break;
8774
0
  default:
8775
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8776
0
  }
8777
0
    }
8778
0
    xmlXPathReleaseObject(ctxt->context, cur);
8779
0
}
8780
8781
/**
8782
 * xmlXPathNameFunction:
8783
 * @ctxt:  the XPath Parser context
8784
 * @nargs:  the number of arguments
8785
 *
8786
 * Implement the name() XPath function
8787
 *    string name(node-set?)
8788
 * The name function returns a string containing a QName representing
8789
 * the name of the node in the argument node-set that is first in document
8790
 * order. The QName must represent the name with respect to the namespace
8791
 * declarations in effect on the node whose name is being represented.
8792
 * Typically, this will be the form in which the name occurred in the XML
8793
 * source. This need not be the case if there are namespace declarations
8794
 * in effect on the node that associate multiple prefixes with the same
8795
 * namespace. However, an implementation may include information about
8796
 * the original prefix in its representation of nodes; in this case, an
8797
 * implementation can ensure that the returned string is always the same
8798
 * as the QName used in the XML source. If the argument it omitted it
8799
 * defaults to the context node.
8800
 * Libxml keep the original prefix so the "real qualified name" used is
8801
 * returned.
8802
 */
8803
static void
8804
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8805
72
{
8806
72
    xmlXPathObjectPtr cur;
8807
8808
72
    if (nargs == 0) {
8809
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8810
0
      ctxt->context->node));
8811
0
        nargs = 1;
8812
0
    }
8813
8814
216
    CHECK_ARITY(1);
8815
216
    if ((ctxt->value == NULL) ||
8816
72
        ((ctxt->value->type != XPATH_NODESET) &&
8817
72
         (ctxt->value->type != XPATH_XSLT_TREE)))
8818
38
        XP_ERROR(XPATH_INVALID_TYPE);
8819
34
    cur = valuePop(ctxt);
8820
8821
34
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8822
34
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8823
34
    } else {
8824
0
        int i = 0;              /* Should be first in document order !!!!! */
8825
8826
0
        switch (cur->nodesetval->nodeTab[i]->type) {
8827
0
            case XML_ELEMENT_NODE:
8828
0
            case XML_ATTRIBUTE_NODE:
8829
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8830
0
        valuePush(ctxt,
8831
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8832
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8833
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8834
0
        valuePush(ctxt,
8835
0
            xmlXPathCacheNewString(ctxt->context,
8836
0
          cur->nodesetval->nodeTab[i]->name));
8837
0
    } else {
8838
0
        xmlChar *fullname;
8839
8840
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8841
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8842
0
             NULL, 0);
8843
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8844
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8845
0
        if (fullname == NULL) {
8846
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8847
0
        }
8848
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8849
0
      ctxt->context, fullname));
8850
0
                }
8851
0
                break;
8852
0
            default:
8853
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8854
0
        cur->nodesetval->nodeTab[i]));
8855
0
                xmlXPathLocalNameFunction(ctxt, 1);
8856
0
        }
8857
0
    }
8858
34
    xmlXPathReleaseObject(ctxt->context, cur);
8859
34
}
8860
8861
8862
/**
8863
 * xmlXPathStringFunction:
8864
 * @ctxt:  the XPath Parser context
8865
 * @nargs:  the number of arguments
8866
 *
8867
 * Implement the string() XPath function
8868
 *    string string(object?)
8869
 * The string function converts an object to a string as follows:
8870
 *    - A node-set is converted to a string by returning the value of
8871
 *      the node in the node-set that is first in document order.
8872
 *      If the node-set is empty, an empty string is returned.
8873
 *    - A number is converted to a string as follows
8874
 *      + NaN is converted to the string NaN
8875
 *      + positive zero is converted to the string 0
8876
 *      + negative zero is converted to the string 0
8877
 *      + positive infinity is converted to the string Infinity
8878
 *      + negative infinity is converted to the string -Infinity
8879
 *      + if the number is an integer, the number is represented in
8880
 *        decimal form as a Number with no decimal point and no leading
8881
 *        zeros, preceded by a minus sign (-) if the number is negative
8882
 *      + otherwise, the number is represented in decimal form as a
8883
 *        Number including a decimal point with at least one digit
8884
 *        before the decimal point and at least one digit after the
8885
 *        decimal point, preceded by a minus sign (-) if the number
8886
 *        is negative; there must be no leading zeros before the decimal
8887
 *        point apart possibly from the one required digit immediately
8888
 *        before the decimal point; beyond the one required digit
8889
 *        after the decimal point there must be as many, but only as
8890
 *        many, more digits as are needed to uniquely distinguish the
8891
 *        number from all other IEEE 754 numeric values.
8892
 *    - The boolean false value is converted to the string false.
8893
 *      The boolean true value is converted to the string true.
8894
 *
8895
 * If the argument is omitted, it defaults to a node-set with the
8896
 * context node as its only member.
8897
 */
8898
void
8899
7.46k
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900
7.46k
    xmlXPathObjectPtr cur;
8901
8902
7.46k
    if (ctxt == NULL) return;
8903
7.46k
    if (nargs == 0) {
8904
0
    valuePush(ctxt,
8905
0
  xmlXPathCacheWrapString(ctxt->context,
8906
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8907
0
  return;
8908
0
    }
8909
8910
29.8k
    CHECK_ARITY(1);
8911
29.8k
    cur = valuePop(ctxt);
8912
29.8k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8913
7.46k
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8914
7.46k
}
8915
8916
/**
8917
 * xmlXPathStringLengthFunction:
8918
 * @ctxt:  the XPath Parser context
8919
 * @nargs:  the number of arguments
8920
 *
8921
 * Implement the string-length() XPath function
8922
 *    number string-length(string?)
8923
 * The string-length returns the number of characters in the string
8924
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8925
 * the context node converted to a string, in other words the value
8926
 * of the context node.
8927
 */
8928
void
8929
136
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8930
136
    xmlXPathObjectPtr cur;
8931
8932
136
    if (nargs == 0) {
8933
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8934
0
      return;
8935
0
  if (ctxt->context->node == NULL) {
8936
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8937
0
  } else {
8938
0
      xmlChar *content;
8939
8940
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8941
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8942
0
    xmlUTF8Strlen(content)));
8943
0
      xmlFree(content);
8944
0
  }
8945
0
  return;
8946
0
    }
8947
544
    CHECK_ARITY(1);
8948
544
    CAST_TO_STRING;
8949
544
    CHECK_TYPE(XPATH_STRING);
8950
136
    cur = valuePop(ctxt);
8951
136
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8952
136
  xmlUTF8Strlen(cur->stringval)));
8953
136
    xmlXPathReleaseObject(ctxt->context, cur);
8954
136
}
8955
8956
/**
8957
 * xmlXPathConcatFunction:
8958
 * @ctxt:  the XPath Parser context
8959
 * @nargs:  the number of arguments
8960
 *
8961
 * Implement the concat() XPath function
8962
 *    string concat(string, string, string*)
8963
 * The concat function returns the concatenation of its arguments.
8964
 */
8965
void
8966
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8967
0
    xmlXPathObjectPtr cur, newobj;
8968
0
    xmlChar *tmp;
8969
8970
0
    if (ctxt == NULL) return;
8971
0
    if (nargs < 2) {
8972
0
  CHECK_ARITY(2);
8973
0
    }
8974
8975
0
    CAST_TO_STRING;
8976
0
    cur = valuePop(ctxt);
8977
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8978
0
  xmlXPathReleaseObject(ctxt->context, cur);
8979
0
  return;
8980
0
    }
8981
0
    nargs--;
8982
8983
0
    while (nargs > 0) {
8984
0
  CAST_TO_STRING;
8985
0
  newobj = valuePop(ctxt);
8986
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8987
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8988
0
      xmlXPathReleaseObject(ctxt->context, cur);
8989
0
      XP_ERROR(XPATH_INVALID_TYPE);
8990
0
  }
8991
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8992
0
  newobj->stringval = cur->stringval;
8993
0
  cur->stringval = tmp;
8994
0
  xmlXPathReleaseObject(ctxt->context, newobj);
8995
0
  nargs--;
8996
0
    }
8997
0
    valuePush(ctxt, cur);
8998
0
}
8999
9000
/**
9001
 * xmlXPathContainsFunction:
9002
 * @ctxt:  the XPath Parser context
9003
 * @nargs:  the number of arguments
9004
 *
9005
 * Implement the contains() XPath function
9006
 *    boolean contains(string, string)
9007
 * The contains function returns true if the first argument string
9008
 * contains the second argument string, and otherwise returns false.
9009
 */
9010
void
9011
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9012
0
    xmlXPathObjectPtr hay, needle;
9013
9014
0
    CHECK_ARITY(2);
9015
0
    CAST_TO_STRING;
9016
0
    CHECK_TYPE(XPATH_STRING);
9017
0
    needle = valuePop(ctxt);
9018
0
    CAST_TO_STRING;
9019
0
    hay = valuePop(ctxt);
9020
9021
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9022
0
  xmlXPathReleaseObject(ctxt->context, hay);
9023
0
  xmlXPathReleaseObject(ctxt->context, needle);
9024
0
  XP_ERROR(XPATH_INVALID_TYPE);
9025
0
    }
9026
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9027
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9028
0
    else
9029
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9030
0
    xmlXPathReleaseObject(ctxt->context, hay);
9031
0
    xmlXPathReleaseObject(ctxt->context, needle);
9032
0
}
9033
9034
/**
9035
 * xmlXPathStartsWithFunction:
9036
 * @ctxt:  the XPath Parser context
9037
 * @nargs:  the number of arguments
9038
 *
9039
 * Implement the starts-with() XPath function
9040
 *    boolean starts-with(string, string)
9041
 * The starts-with function returns true if the first argument string
9042
 * starts with the second argument string, and otherwise returns false.
9043
 */
9044
void
9045
179
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9046
179
    xmlXPathObjectPtr hay, needle;
9047
179
    int n;
9048
9049
533
    CHECK_ARITY(2);
9050
533
    CAST_TO_STRING;
9051
533
    CHECK_TYPE(XPATH_STRING);
9052
177
    needle = valuePop(ctxt);
9053
177
    CAST_TO_STRING;
9054
177
    hay = valuePop(ctxt);
9055
9056
177
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9057
0
  xmlXPathReleaseObject(ctxt->context, hay);
9058
0
  xmlXPathReleaseObject(ctxt->context, needle);
9059
0
  XP_ERROR(XPATH_INVALID_TYPE);
9060
0
    }
9061
177
    n = xmlStrlen(needle->stringval);
9062
177
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9063
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9064
177
    else
9065
177
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9066
177
    xmlXPathReleaseObject(ctxt->context, hay);
9067
177
    xmlXPathReleaseObject(ctxt->context, needle);
9068
177
}
9069
9070
/**
9071
 * xmlXPathSubstringFunction:
9072
 * @ctxt:  the XPath Parser context
9073
 * @nargs:  the number of arguments
9074
 *
9075
 * Implement the substring() XPath function
9076
 *    string substring(string, number, number?)
9077
 * The substring function returns the substring of the first argument
9078
 * starting at the position specified in the second argument with
9079
 * length specified in the third argument. For example,
9080
 * substring("12345",2,3) returns "234". If the third argument is not
9081
 * specified, it returns the substring starting at the position specified
9082
 * in the second argument and continuing to the end of the string. For
9083
 * example, substring("12345",2) returns "2345".  More precisely, each
9084
 * character in the string (see [3.6 Strings]) is considered to have a
9085
 * numeric position: the position of the first character is 1, the position
9086
 * of the second character is 2 and so on. The returned substring contains
9087
 * those characters for which the position of the character is greater than
9088
 * or equal to the second argument and, if the third argument is specified,
9089
 * less than the sum of the second and third arguments; the comparisons
9090
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9091
 *  - substring("12345", 1.5, 2.6) returns "234"
9092
 *  - substring("12345", 0, 3) returns "12"
9093
 *  - substring("12345", 0 div 0, 3) returns ""
9094
 *  - substring("12345", 1, 0 div 0) returns ""
9095
 *  - substring("12345", -42, 1 div 0) returns "12345"
9096
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9097
 */
9098
void
9099
1
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9100
1
    xmlXPathObjectPtr str, start, len;
9101
1
    double le=0, in;
9102
1
    int i = 1, j = INT_MAX;
9103
9104
1
    if (nargs < 2) {
9105
0
  CHECK_ARITY(2);
9106
0
    }
9107
1
    if (nargs > 3) {
9108
0
  CHECK_ARITY(3);
9109
0
    }
9110
    /*
9111
     * take care of possible last (position) argument
9112
    */
9113
1
    if (nargs == 3) {
9114
1
  CAST_TO_NUMBER;
9115
1
  CHECK_TYPE(XPATH_NUMBER);
9116
1
  len = valuePop(ctxt);
9117
1
  le = len->floatval;
9118
1
  xmlXPathReleaseObject(ctxt->context, len);
9119
1
    }
9120
9121
1
    CAST_TO_NUMBER;
9122
1
    CHECK_TYPE(XPATH_NUMBER);
9123
1
    start = valuePop(ctxt);
9124
1
    in = start->floatval;
9125
1
    xmlXPathReleaseObject(ctxt->context, start);
9126
1
    CAST_TO_STRING;
9127
1
    CHECK_TYPE(XPATH_STRING);
9128
1
    str = valuePop(ctxt);
9129
9130
1
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9131
0
        i = INT_MAX;
9132
1
    } else if (in >= 1.0) {
9133
1
        i = (int)in;
9134
1
        if (in - floor(in) >= 0.5)
9135
1
            i += 1;
9136
1
    }
9137
9138
1
    if (nargs == 3) {
9139
1
        double rin, rle, end;
9140
9141
1
        rin = floor(in);
9142
1
        if (in - rin >= 0.5)
9143
1
            rin += 1.0;
9144
9145
1
        rle = floor(le);
9146
1
        if (le - rle >= 0.5)
9147
0
            rle += 1.0;
9148
9149
1
        end = rin + rle;
9150
1
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9151
0
            j = 1;
9152
1
        } else if (end < INT_MAX) {
9153
0
            j = (int)end;
9154
0
        }
9155
1
    }
9156
9157
1
    if (i < j) {
9158
1
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9159
1
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9160
1
  xmlFree(ret);
9161
1
    } else {
9162
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9163
0
    }
9164
9165
1
    xmlXPathReleaseObject(ctxt->context, str);
9166
1
}
9167
9168
/**
9169
 * xmlXPathSubstringBeforeFunction:
9170
 * @ctxt:  the XPath Parser context
9171
 * @nargs:  the number of arguments
9172
 *
9173
 * Implement the substring-before() XPath function
9174
 *    string substring-before(string, string)
9175
 * The substring-before function returns the substring of the first
9176
 * argument string that precedes the first occurrence of the second
9177
 * argument string in the first argument string, or the empty string
9178
 * if the first argument string does not contain the second argument
9179
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9180
 */
9181
void
9182
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9183
0
  xmlXPathObjectPtr str;
9184
0
  xmlXPathObjectPtr find;
9185
0
  xmlBufPtr target;
9186
0
  const xmlChar *point;
9187
0
  int offset;
9188
9189
0
  CHECK_ARITY(2);
9190
0
  CAST_TO_STRING;
9191
0
  find = valuePop(ctxt);
9192
0
  CAST_TO_STRING;
9193
0
  str = valuePop(ctxt);
9194
9195
0
  target = xmlBufCreate();
9196
0
  if (target) {
9197
0
    point = xmlStrstr(str->stringval, find->stringval);
9198
0
    if (point) {
9199
0
      offset = point - str->stringval;
9200
0
      xmlBufAdd(target, str->stringval, offset);
9201
0
    }
9202
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9203
0
  xmlBufContent(target)));
9204
0
    xmlBufFree(target);
9205
0
  }
9206
0
  xmlXPathReleaseObject(ctxt->context, str);
9207
0
  xmlXPathReleaseObject(ctxt->context, find);
9208
0
}
9209
9210
/**
9211
 * xmlXPathSubstringAfterFunction:
9212
 * @ctxt:  the XPath Parser context
9213
 * @nargs:  the number of arguments
9214
 *
9215
 * Implement the substring-after() XPath function
9216
 *    string substring-after(string, string)
9217
 * The substring-after function returns the substring of the first
9218
 * argument string that follows the first occurrence of the second
9219
 * argument string in the first argument string, or the empty stringi
9220
 * if the first argument string does not contain the second argument
9221
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9222
 * and substring-after("1999/04/01","19") returns 99/04/01.
9223
 */
9224
void
9225
2.91k
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9226
2.91k
  xmlXPathObjectPtr str;
9227
2.91k
  xmlXPathObjectPtr find;
9228
2.91k
  xmlBufPtr target;
9229
2.91k
  const xmlChar *point;
9230
2.91k
  int offset;
9231
9232
8.73k
  CHECK_ARITY(2);
9233
8.73k
  CAST_TO_STRING;
9234
8.73k
  find = valuePop(ctxt);
9235
8.73k
  CAST_TO_STRING;
9236
8.73k
  str = valuePop(ctxt);
9237
9238
8.73k
  target = xmlBufCreate();
9239
8.73k
  if (target) {
9240
2.91k
    point = xmlStrstr(str->stringval, find->stringval);
9241
2.91k
    if (point) {
9242
2.57k
      offset = point - str->stringval + xmlStrlen(find->stringval);
9243
2.57k
      xmlBufAdd(target, &str->stringval[offset],
9244
2.57k
       xmlStrlen(str->stringval) - offset);
9245
2.57k
    }
9246
2.91k
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9247
2.91k
  xmlBufContent(target)));
9248
2.91k
    xmlBufFree(target);
9249
2.91k
  }
9250
8.73k
  xmlXPathReleaseObject(ctxt->context, str);
9251
8.73k
  xmlXPathReleaseObject(ctxt->context, find);
9252
8.73k
}
9253
9254
/**
9255
 * xmlXPathNormalizeFunction:
9256
 * @ctxt:  the XPath Parser context
9257
 * @nargs:  the number of arguments
9258
 *
9259
 * Implement the normalize-space() XPath function
9260
 *    string normalize-space(string?)
9261
 * The normalize-space function returns the argument string with white
9262
 * space normalized by stripping leading and trailing whitespace
9263
 * and replacing sequences of whitespace characters by a single
9264
 * space. Whitespace characters are the same allowed by the S production
9265
 * in XML. If the argument is omitted, it defaults to the context
9266
 * node converted to a string, in other words the value of the context node.
9267
 */
9268
void
9269
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9270
0
    xmlChar *source, *target;
9271
0
    int blank;
9272
9273
0
    if (ctxt == NULL) return;
9274
0
    if (nargs == 0) {
9275
        /* Use current context node */
9276
0
        valuePush(ctxt,
9277
0
            xmlXPathCacheWrapString(ctxt->context,
9278
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9279
0
        nargs = 1;
9280
0
    }
9281
9282
0
    CHECK_ARITY(1);
9283
0
    CAST_TO_STRING;
9284
0
    CHECK_TYPE(XPATH_STRING);
9285
0
    source = ctxt->value->stringval;
9286
0
    if (source == NULL)
9287
0
        return;
9288
0
    target = source;
9289
9290
    /* Skip leading whitespaces */
9291
0
    while (IS_BLANK_CH(*source))
9292
0
        source++;
9293
9294
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9295
0
    blank = 0;
9296
0
    while (*source) {
9297
0
        if (IS_BLANK_CH(*source)) {
9298
0
      blank = 1;
9299
0
        } else {
9300
0
            if (blank) {
9301
0
                *target++ = 0x20;
9302
0
                blank = 0;
9303
0
            }
9304
0
            *target++ = *source;
9305
0
        }
9306
0
        source++;
9307
0
    }
9308
0
    *target = 0;
9309
0
}
9310
9311
/**
9312
 * xmlXPathTranslateFunction:
9313
 * @ctxt:  the XPath Parser context
9314
 * @nargs:  the number of arguments
9315
 *
9316
 * Implement the translate() XPath function
9317
 *    string translate(string, string, string)
9318
 * The translate function returns the first argument string with
9319
 * occurrences of characters in the second argument string replaced
9320
 * by the character at the corresponding position in the third argument
9321
 * string. For example, translate("bar","abc","ABC") returns the string
9322
 * BAr. If there is a character in the second argument string with no
9323
 * character at a corresponding position in the third argument string
9324
 * (because the second argument string is longer than the third argument
9325
 * string), then occurrences of that character in the first argument
9326
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9327
 * returns "AAA". If a character occurs more than once in second
9328
 * argument string, then the first occurrence determines the replacement
9329
 * character. If the third argument string is longer than the second
9330
 * argument string, then excess characters are ignored.
9331
 */
9332
void
9333
6
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334
6
    xmlXPathObjectPtr str;
9335
6
    xmlXPathObjectPtr from;
9336
6
    xmlXPathObjectPtr to;
9337
6
    xmlBufPtr target;
9338
6
    int offset, max;
9339
6
    xmlChar ch;
9340
6
    const xmlChar *point;
9341
6
    xmlChar *cptr;
9342
9343
18
    CHECK_ARITY(3);
9344
9345
18
    CAST_TO_STRING;
9346
18
    to = valuePop(ctxt);
9347
18
    CAST_TO_STRING;
9348
18
    from = valuePop(ctxt);
9349
18
    CAST_TO_STRING;
9350
18
    str = valuePop(ctxt);
9351
9352
18
    target = xmlBufCreate();
9353
18
    if (target) {
9354
6
  max = xmlUTF8Strlen(to->stringval);
9355
828
  for (cptr = str->stringval; (ch=*cptr); ) {
9356
822
      offset = xmlUTF8Strloc(from->stringval, cptr);
9357
822
      if (offset >= 0) {
9358
600
    if (offset < max) {
9359
576
        point = xmlUTF8Strpos(to->stringval, offset);
9360
576
        if (point)
9361
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9362
576
    }
9363
600
      } else
9364
222
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9365
9366
      /* Step to next character in input */
9367
822
      cptr++;
9368
822
      if ( ch & 0x80 ) {
9369
    /* if not simple ascii, verify proper format */
9370
18
    if ( (ch & 0xc0) != 0xc0 ) {
9371
0
        xmlGenericError(xmlGenericErrorContext,
9372
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9373
                    /* not asserting an XPath error is probably better */
9374
0
        break;
9375
0
    }
9376
    /* then skip over remaining bytes for this char */
9377
48
    while ( (ch <<= 1) & 0x80 )
9378
30
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9379
0
      xmlGenericError(xmlGenericErrorContext,
9380
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                        /* not asserting an XPath error is probably better */
9382
0
      break;
9383
0
        }
9384
18
    if (ch & 0x80) /* must have had error encountered */
9385
0
        break;
9386
18
      }
9387
822
  }
9388
6
    }
9389
18
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9390
18
  xmlBufContent(target)));
9391
18
    xmlBufFree(target);
9392
18
    xmlXPathReleaseObject(ctxt->context, str);
9393
18
    xmlXPathReleaseObject(ctxt->context, from);
9394
18
    xmlXPathReleaseObject(ctxt->context, to);
9395
18
}
9396
9397
/**
9398
 * xmlXPathBooleanFunction:
9399
 * @ctxt:  the XPath Parser context
9400
 * @nargs:  the number of arguments
9401
 *
9402
 * Implement the boolean() XPath function
9403
 *    boolean boolean(object)
9404
 * The boolean function converts its argument to a boolean as follows:
9405
 *    - a number is true if and only if it is neither positive or
9406
 *      negative zero nor NaN
9407
 *    - a node-set is true if and only if it is non-empty
9408
 *    - a string is true if and only if its length is non-zero
9409
 */
9410
void
9411
1.97k
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412
1.97k
    xmlXPathObjectPtr cur;
9413
9414
5.92k
    CHECK_ARITY(1);
9415
5.92k
    cur = valuePop(ctxt);
9416
5.92k
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9417
1.97k
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9418
1.97k
    valuePush(ctxt, cur);
9419
1.97k
}
9420
9421
/**
9422
 * xmlXPathNotFunction:
9423
 * @ctxt:  the XPath Parser context
9424
 * @nargs:  the number of arguments
9425
 *
9426
 * Implement the not() XPath function
9427
 *    boolean not(boolean)
9428
 * The not function returns true if its argument is false,
9429
 * and false otherwise.
9430
 */
9431
void
9432
394
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433
394
    CHECK_ARITY(1);
9434
394
    CAST_TO_BOOLEAN;
9435
394
    CHECK_TYPE(XPATH_BOOLEAN);
9436
0
    ctxt->value->boolval = ! ctxt->value->boolval;
9437
0
}
9438
9439
/**
9440
 * xmlXPathTrueFunction:
9441
 * @ctxt:  the XPath Parser context
9442
 * @nargs:  the number of arguments
9443
 *
9444
 * Implement the true() XPath function
9445
 *    boolean true()
9446
 */
9447
void
9448
9
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9449
27
    CHECK_ARITY(0);
9450
27
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9451
27
}
9452
9453
/**
9454
 * xmlXPathFalseFunction:
9455
 * @ctxt:  the XPath Parser context
9456
 * @nargs:  the number of arguments
9457
 *
9458
 * Implement the false() XPath function
9459
 *    boolean false()
9460
 */
9461
void
9462
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463
0
    CHECK_ARITY(0);
9464
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9465
0
}
9466
9467
/**
9468
 * xmlXPathLangFunction:
9469
 * @ctxt:  the XPath Parser context
9470
 * @nargs:  the number of arguments
9471
 *
9472
 * Implement the lang() XPath function
9473
 *    boolean lang(string)
9474
 * The lang function returns true or false depending on whether the
9475
 * language of the context node as specified by xml:lang attributes
9476
 * is the same as or is a sublanguage of the language specified by
9477
 * the argument string. The language of the context node is determined
9478
 * by the value of the xml:lang attribute on the context node, or, if
9479
 * the context node has no xml:lang attribute, by the value of the
9480
 * xml:lang attribute on the nearest ancestor of the context node that
9481
 * has an xml:lang attribute. If there is no such attribute, then lang
9482
 * returns false. If there is such an attribute, then lang returns
9483
 * true if the attribute value is equal to the argument ignoring case,
9484
 * or if there is some suffix starting with - such that the attribute
9485
 * value is equal to the argument ignoring that suffix of the attribute
9486
 * value and ignoring case.
9487
 */
9488
void
9489
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9490
0
    xmlXPathObjectPtr val = NULL;
9491
0
    const xmlChar *theLang = NULL;
9492
0
    const xmlChar *lang;
9493
0
    int ret = 0;
9494
0
    int i;
9495
9496
0
    CHECK_ARITY(1);
9497
0
    CAST_TO_STRING;
9498
0
    CHECK_TYPE(XPATH_STRING);
9499
0
    val = valuePop(ctxt);
9500
0
    lang = val->stringval;
9501
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9502
0
    if ((theLang != NULL) && (lang != NULL)) {
9503
0
        for (i = 0;lang[i] != 0;i++)
9504
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9505
0
          goto not_equal;
9506
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9507
0
      ret = 1;
9508
0
    }
9509
0
not_equal:
9510
0
    if (theLang != NULL)
9511
0
  xmlFree((void *)theLang);
9512
9513
0
    xmlXPathReleaseObject(ctxt->context, val);
9514
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9515
0
}
9516
9517
/**
9518
 * xmlXPathNumberFunction:
9519
 * @ctxt:  the XPath Parser context
9520
 * @nargs:  the number of arguments
9521
 *
9522
 * Implement the number() XPath function
9523
 *    number number(object?)
9524
 */
9525
void
9526
2.12M
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527
2.12M
    xmlXPathObjectPtr cur;
9528
2.12M
    double res;
9529
9530
2.12M
    if (ctxt == NULL) return;
9531
2.12M
    if (nargs == 0) {
9532
0
  if (ctxt->context->node == NULL) {
9533
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9534
0
  } else {
9535
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9536
9537
0
      res = xmlXPathStringEvalNumber(content);
9538
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9539
0
      xmlFree(content);
9540
0
  }
9541
0
  return;
9542
0
    }
9543
9544
8.50M
    CHECK_ARITY(1);
9545
8.50M
    cur = valuePop(ctxt);
9546
8.50M
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9547
8.50M
}
9548
9549
/**
9550
 * xmlXPathSumFunction:
9551
 * @ctxt:  the XPath Parser context
9552
 * @nargs:  the number of arguments
9553
 *
9554
 * Implement the sum() XPath function
9555
 *    number sum(node-set)
9556
 * The sum function returns the sum of the values of the nodes in
9557
 * the argument node-set.
9558
 */
9559
void
9560
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561
0
    xmlXPathObjectPtr cur;
9562
0
    int i;
9563
0
    double res = 0.0;
9564
9565
0
    CHECK_ARITY(1);
9566
0
    if ((ctxt->value == NULL) ||
9567
0
  ((ctxt->value->type != XPATH_NODESET) &&
9568
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
9569
0
  XP_ERROR(XPATH_INVALID_TYPE);
9570
0
    cur = valuePop(ctxt);
9571
9572
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9573
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9574
0
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9575
0
  }
9576
0
    }
9577
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9578
0
    xmlXPathReleaseObject(ctxt->context, cur);
9579
0
}
9580
9581
/**
9582
 * xmlXPathFloorFunction:
9583
 * @ctxt:  the XPath Parser context
9584
 * @nargs:  the number of arguments
9585
 *
9586
 * Implement the floor() XPath function
9587
 *    number floor(number)
9588
 * The floor function returns the largest (closest to positive infinity)
9589
 * number that is not greater than the argument and that is an integer.
9590
 */
9591
void
9592
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593
0
    CHECK_ARITY(1);
9594
0
    CAST_TO_NUMBER;
9595
0
    CHECK_TYPE(XPATH_NUMBER);
9596
9597
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9598
0
}
9599
9600
/**
9601
 * xmlXPathCeilingFunction:
9602
 * @ctxt:  the XPath Parser context
9603
 * @nargs:  the number of arguments
9604
 *
9605
 * Implement the ceiling() XPath function
9606
 *    number ceiling(number)
9607
 * The ceiling function returns the smallest (closest to negative infinity)
9608
 * number that is not less than the argument and that is an integer.
9609
 */
9610
void
9611
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612
0
    CHECK_ARITY(1);
9613
0
    CAST_TO_NUMBER;
9614
0
    CHECK_TYPE(XPATH_NUMBER);
9615
9616
#ifdef _AIX
9617
    /* Work around buggy ceil() function on AIX */
9618
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9619
#else
9620
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9621
0
#endif
9622
0
}
9623
9624
/**
9625
 * xmlXPathRoundFunction:
9626
 * @ctxt:  the XPath Parser context
9627
 * @nargs:  the number of arguments
9628
 *
9629
 * Implement the round() XPath function
9630
 *    number round(number)
9631
 * The round function returns the number that is closest to the
9632
 * argument and that is an integer. If there are two such numbers,
9633
 * then the one that is closest to positive infinity is returned.
9634
 */
9635
void
9636
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9637
0
    double f;
9638
9639
0
    CHECK_ARITY(1);
9640
0
    CAST_TO_NUMBER;
9641
0
    CHECK_TYPE(XPATH_NUMBER);
9642
9643
0
    f = ctxt->value->floatval;
9644
9645
0
    if ((f >= -0.5) && (f < 0.5)) {
9646
        /* Handles negative zero. */
9647
0
        ctxt->value->floatval *= 0.0;
9648
0
    }
9649
0
    else {
9650
0
        double rounded = floor(f);
9651
0
        if (f - rounded >= 0.5)
9652
0
            rounded += 1.0;
9653
0
        ctxt->value->floatval = rounded;
9654
0
    }
9655
0
}
9656
9657
/************************************************************************
9658
 *                  *
9659
 *      The Parser          *
9660
 *                  *
9661
 ************************************************************************/
9662
9663
/*
9664
 * a few forward declarations since we use a recursive call based
9665
 * implementation.
9666
 */
9667
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9668
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9669
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9670
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9671
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9672
                                    int qualified);
9673
9674
/**
9675
 * xmlXPathCurrentChar:
9676
 * @ctxt:  the XPath parser context
9677
 * @cur:  pointer to the beginning of the char
9678
 * @len:  pointer to the length of the char read
9679
 *
9680
 * The current char value, if using UTF-8 this may actually span multiple
9681
 * bytes in the input buffer.
9682
 *
9683
 * Returns the current char value and its length
9684
 */
9685
9686
static int
9687
29.0M
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9688
29.0M
    unsigned char c;
9689
29.0M
    unsigned int val;
9690
29.0M
    const xmlChar *cur;
9691
9692
29.0M
    if (ctxt == NULL)
9693
0
  return(0);
9694
29.0M
    cur = ctxt->cur;
9695
9696
    /*
9697
     * We are supposed to handle UTF8, check it's valid
9698
     * From rfc2044: encoding of the Unicode values on UTF-8:
9699
     *
9700
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9701
     * 0000 0000-0000 007F   0xxxxxxx
9702
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9703
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9704
     *
9705
     * Check for the 0x110000 limit too
9706
     */
9707
29.0M
    c = *cur;
9708
29.0M
    if (c & 0x80) {
9709
2.80M
  if ((cur[1] & 0xc0) != 0x80)
9710
0
      goto encoding_error;
9711
2.80M
  if ((c & 0xe0) == 0xe0) {
9712
9713
556k
      if ((cur[2] & 0xc0) != 0x80)
9714
1
    goto encoding_error;
9715
556k
      if ((c & 0xf0) == 0xf0) {
9716
0
    if (((c & 0xf8) != 0xf0) ||
9717
0
        ((cur[3] & 0xc0) != 0x80))
9718
0
        goto encoding_error;
9719
    /* 4-byte code */
9720
0
    *len = 4;
9721
0
    val = (cur[0] & 0x7) << 18;
9722
0
    val |= (cur[1] & 0x3f) << 12;
9723
0
    val |= (cur[2] & 0x3f) << 6;
9724
0
    val |= cur[3] & 0x3f;
9725
556k
      } else {
9726
        /* 3-byte code */
9727
556k
    *len = 3;
9728
556k
    val = (cur[0] & 0xf) << 12;
9729
556k
    val |= (cur[1] & 0x3f) << 6;
9730
556k
    val |= cur[2] & 0x3f;
9731
556k
      }
9732
2.24M
  } else {
9733
    /* 2-byte code */
9734
2.24M
      *len = 2;
9735
2.24M
      val = (cur[0] & 0x1f) << 6;
9736
2.24M
      val |= cur[1] & 0x3f;
9737
2.24M
  }
9738
2.80M
  if (!IS_CHAR(val)) {
9739
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9740
0
  }
9741
2.80M
  return(val);
9742
26.2M
    } else {
9743
  /* 1-byte code */
9744
26.2M
  *len = 1;
9745
26.2M
  return(*cur);
9746
26.2M
    }
9747
1
encoding_error:
9748
    /*
9749
     * If we detect an UTF8 error that probably means that the
9750
     * input encoding didn't get properly advertised in the
9751
     * declaration header. Report the error and switch the encoding
9752
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9753
     * encoding !)
9754
     */
9755
1
    *len = 0;
9756
1
    XP_ERROR0(XPATH_ENCODING_ERROR);
9757
0
}
9758
9759
/**
9760
 * xmlXPathParseNCName:
9761
 * @ctxt:  the XPath Parser context
9762
 *
9763
 * parse an XML namespace non qualified name.
9764
 *
9765
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9766
 *
9767
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9768
 *                       CombiningChar | Extender
9769
 *
9770
 * Returns the namespace name or NULL
9771
 */
9772
9773
xmlChar *
9774
7.35M
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9775
7.35M
    const xmlChar *in;
9776
7.35M
    xmlChar *ret;
9777
7.35M
    int count = 0;
9778
9779
7.35M
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9780
    /*
9781
     * Accelerator for simple ASCII names
9782
     */
9783
7.35M
    in = ctxt->cur;
9784
7.35M
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9785
7.35M
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9786
7.35M
  (*in == '_')) {
9787
7.34M
  in++;
9788
7.60M
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9789
7.60M
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9790
7.60M
         ((*in >= 0x30) && (*in <= 0x39)) ||
9791
7.60M
         (*in == '_') || (*in == '.') ||
9792
7.60M
         (*in == '-'))
9793
262k
      in++;
9794
7.34M
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9795
7.34M
            (*in == '[') || (*in == ']') || (*in == ':') ||
9796
7.34M
            (*in == '@') || (*in == '*')) {
9797
863k
      count = in - ctxt->cur;
9798
863k
      if (count == 0)
9799
0
    return(NULL);
9800
863k
      ret = xmlStrndup(ctxt->cur, count);
9801
863k
      ctxt->cur = in;
9802
863k
      return(ret);
9803
863k
  }
9804
7.34M
    }
9805
6.49M
    return(xmlXPathParseNameComplex(ctxt, 0));
9806
7.35M
}
9807
9808
9809
/**
9810
 * xmlXPathParseQName:
9811
 * @ctxt:  the XPath Parser context
9812
 * @prefix:  a xmlChar **
9813
 *
9814
 * parse an XML qualified name
9815
 *
9816
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9817
 *
9818
 * [NS 6] Prefix ::= NCName
9819
 *
9820
 * [NS 7] LocalPart ::= NCName
9821
 *
9822
 * Returns the function returns the local part, and prefix is updated
9823
 *   to get the Prefix if any.
9824
 */
9825
9826
static xmlChar *
9827
11.6k
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9828
11.6k
    xmlChar *ret = NULL;
9829
9830
11.6k
    *prefix = NULL;
9831
11.6k
    ret = xmlXPathParseNCName(ctxt);
9832
11.6k
    if (ret && CUR == ':') {
9833
696
        *prefix = ret;
9834
696
  NEXT;
9835
696
  ret = xmlXPathParseNCName(ctxt);
9836
696
    }
9837
11.6k
    return(ret);
9838
11.6k
}
9839
9840
/**
9841
 * xmlXPathParseName:
9842
 * @ctxt:  the XPath Parser context
9843
 *
9844
 * parse an XML name
9845
 *
9846
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9847
 *                  CombiningChar | Extender
9848
 *
9849
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9850
 *
9851
 * Returns the namespace name or NULL
9852
 */
9853
9854
xmlChar *
9855
20
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9856
20
    const xmlChar *in;
9857
20
    xmlChar *ret;
9858
20
    size_t count = 0;
9859
9860
20
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9861
    /*
9862
     * Accelerator for simple ASCII names
9863
     */
9864
20
    in = ctxt->cur;
9865
20
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9866
20
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9867
20
  (*in == '_') || (*in == ':')) {
9868
16
  in++;
9869
90
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9870
90
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9871
90
         ((*in >= 0x30) && (*in <= 0x39)) ||
9872
90
         (*in == '_') || (*in == '-') ||
9873
90
         (*in == ':') || (*in == '.'))
9874
74
      in++;
9875
16
  if ((*in > 0) && (*in < 0x80)) {
9876
16
      count = in - ctxt->cur;
9877
16
            if (count > XML_MAX_NAME_LENGTH) {
9878
0
                ctxt->cur = in;
9879
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9880
0
            }
9881
16
      ret = xmlStrndup(ctxt->cur, count);
9882
16
      ctxt->cur = in;
9883
16
      return(ret);
9884
16
  }
9885
16
    }
9886
4
    return(xmlXPathParseNameComplex(ctxt, 1));
9887
20
}
9888
9889
static xmlChar *
9890
6.49M
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9891
6.49M
    xmlChar buf[XML_MAX_NAMELEN + 5];
9892
6.49M
    int len = 0, l;
9893
6.49M
    int c;
9894
9895
    /*
9896
     * Handler for more complex cases
9897
     */
9898
6.49M
    c = CUR_CHAR(l);
9899
6.49M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9900
6.49M
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9901
6.49M
        (c == '*') || /* accelerators */
9902
6.49M
  (!IS_LETTER(c) && (c != '_') &&
9903
6.48M
         ((!qualified) || (c != ':')))) {
9904
8.23k
  return(NULL);
9905
8.23k
    }
9906
9907
13.1M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9908
13.1M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9909
13.1M
            (c == '.') || (c == '-') ||
9910
13.1M
      (c == '_') || ((qualified) && (c == ':')) ||
9911
13.1M
      (IS_COMBINING(c)) ||
9912
13.1M
      (IS_EXTENDER(c)))) {
9913
6.64M
  COPY_BUF(l,buf,len,c);
9914
6.64M
  NEXTL(l);
9915
6.64M
  c = CUR_CHAR(l);
9916
6.64M
  if (len >= XML_MAX_NAMELEN) {
9917
      /*
9918
       * Okay someone managed to make a huge name, so he's ready to pay
9919
       * for the processing speed.
9920
       */
9921
333
      xmlChar *buffer;
9922
333
      int max = len * 2;
9923
9924
333
            if (len > XML_MAX_NAME_LENGTH) {
9925
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9926
0
            }
9927
333
      buffer = (xmlChar *) xmlMallocAtomic(max);
9928
333
      if (buffer == NULL) {
9929
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9930
0
      }
9931
333
      memcpy(buffer, buf, len);
9932
1.27M
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9933
1.27M
       (c == '.') || (c == '-') ||
9934
1.27M
       (c == '_') || ((qualified) && (c == ':')) ||
9935
1.27M
       (IS_COMBINING(c)) ||
9936
1.27M
       (IS_EXTENDER(c))) {
9937
1.27M
    if (len + 10 > max) {
9938
891
                    xmlChar *tmp;
9939
891
                    if (max > XML_MAX_NAME_LENGTH) {
9940
26
                        xmlFree(buffer);
9941
26
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9942
0
                    }
9943
865
        max *= 2;
9944
865
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9945
865
        if (tmp == NULL) {
9946
0
                        xmlFree(buffer);
9947
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9948
0
        }
9949
865
                    buffer = tmp;
9950
865
    }
9951
1.27M
    COPY_BUF(l,buffer,len,c);
9952
1.27M
    NEXTL(l);
9953
1.27M
    c = CUR_CHAR(l);
9954
1.27M
      }
9955
307
      buffer[len] = 0;
9956
307
      return(buffer);
9957
333
  }
9958
6.64M
    }
9959
6.48M
    if (len == 0)
9960
0
  return(NULL);
9961
6.48M
    return(xmlStrndup(buf, len));
9962
6.48M
}
9963
9964
287
#define MAX_FRAC 20
9965
9966
/**
9967
 * xmlXPathStringEvalNumber:
9968
 * @str:  A string to scan
9969
 *
9970
 *  [30a]  Float  ::= Number ('e' Digits?)?
9971
 *
9972
 *  [30]   Number ::=   Digits ('.' Digits?)?
9973
 *                    | '.' Digits
9974
 *  [31]   Digits ::=   [0-9]+
9975
 *
9976
 * Compile a Number in the string
9977
 * In complement of the Number expression, this function also handles
9978
 * negative values : '-' Number.
9979
 *
9980
 * Returns the double value.
9981
 */
9982
double
9983
2.13M
xmlXPathStringEvalNumber(const xmlChar *str) {
9984
2.13M
    const xmlChar *cur = str;
9985
2.13M
    double ret;
9986
2.13M
    int ok = 0;
9987
2.13M
    int isneg = 0;
9988
2.13M
    int exponent = 0;
9989
2.13M
    int is_exponent_negative = 0;
9990
2.13M
#ifdef __GNUC__
9991
2.13M
    unsigned long tmp = 0;
9992
2.13M
    double temp;
9993
2.13M
#endif
9994
2.13M
    if (cur == NULL) return(0);
9995
2.13M
    while (IS_BLANK_CH(*cur)) cur++;
9996
2.13M
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9997
2.12M
        return(xmlXPathNAN);
9998
2.12M
    }
9999
4.73k
    if (*cur == '-') {
10000
1.19k
  isneg = 1;
10001
1.19k
  cur++;
10002
1.19k
    }
10003
10004
4.73k
#ifdef __GNUC__
10005
    /*
10006
     * tmp/temp is a workaround against a gcc compiler bug
10007
     * http://veillard.com/gcc.bug
10008
     */
10009
4.73k
    ret = 0;
10010
8.38k
    while ((*cur >= '0') && (*cur <= '9')) {
10011
3.65k
  ret = ret * 10;
10012
3.65k
  tmp = (*cur - '0');
10013
3.65k
  ok = 1;
10014
3.65k
  cur++;
10015
3.65k
  temp = (double) tmp;
10016
3.65k
  ret = ret + temp;
10017
3.65k
    }
10018
#else
10019
    ret = 0;
10020
    while ((*cur >= '0') && (*cur <= '9')) {
10021
  ret = ret * 10 + (*cur - '0');
10022
  ok = 1;
10023
  cur++;
10024
    }
10025
#endif
10026
10027
4.73k
    if (*cur == '.') {
10028
431
  int v, frac = 0, max;
10029
431
  double fraction = 0;
10030
10031
431
        cur++;
10032
431
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10033
427
      return(xmlXPathNAN);
10034
427
  }
10035
8
        while (*cur == '0') {
10036
4
      frac = frac + 1;
10037
4
      cur++;
10038
4
        }
10039
4
        max = frac + MAX_FRAC;
10040
4
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10041
0
      v = (*cur - '0');
10042
0
      fraction = fraction * 10 + v;
10043
0
      frac = frac + 1;
10044
0
      cur++;
10045
0
  }
10046
4
  fraction /= pow(10.0, frac);
10047
4
  ret = ret + fraction;
10048
4
  while ((*cur >= '0') && (*cur <= '9'))
10049
0
      cur++;
10050
4
    }
10051
4.30k
    if ((*cur == 'e') || (*cur == 'E')) {
10052
470
      cur++;
10053
470
      if (*cur == '-') {
10054
0
  is_exponent_negative = 1;
10055
0
  cur++;
10056
470
      } else if (*cur == '+') {
10057
0
        cur++;
10058
0
      }
10059
2.82k
      while ((*cur >= '0') && (*cur <= '9')) {
10060
2.35k
        if (exponent < 1000000)
10061
2.35k
    exponent = exponent * 10 + (*cur - '0');
10062
2.35k
  cur++;
10063
2.35k
      }
10064
470
    }
10065
4.30k
    while (IS_BLANK_CH(*cur)) cur++;
10066
4.30k
    if (*cur != 0) return(xmlXPathNAN);
10067
4.30k
    if (isneg) ret = -ret;
10068
4.30k
    if (is_exponent_negative) exponent = -exponent;
10069
4.30k
    ret *= pow(10.0, (double)exponent);
10070
4.30k
    return(ret);
10071
4.30k
}
10072
10073
/**
10074
 * xmlXPathCompNumber:
10075
 * @ctxt:  the XPath Parser context
10076
 *
10077
 *  [30]   Number ::=   Digits ('.' Digits?)?
10078
 *                    | '.' Digits
10079
 *  [31]   Digits ::=   [0-9]+
10080
 *
10081
 * Compile a Number, then push it on the stack
10082
 *
10083
 */
10084
static void
10085
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10086
24.9k
{
10087
24.9k
    double ret = 0.0;
10088
24.9k
    int ok = 0;
10089
24.9k
    int exponent = 0;
10090
24.9k
    int is_exponent_negative = 0;
10091
24.9k
    xmlXPathObjectPtr num;
10092
24.9k
#ifdef __GNUC__
10093
24.9k
    unsigned long tmp = 0;
10094
24.9k
    double temp;
10095
24.9k
#endif
10096
10097
24.9k
    CHECK_ERROR;
10098
24.9k
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10099
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10100
0
    }
10101
24.9k
#ifdef __GNUC__
10102
    /*
10103
     * tmp/temp is a workaround against a gcc compiler bug
10104
     * http://veillard.com/gcc.bug
10105
     */
10106
24.9k
    ret = 0;
10107
58.0k
    while ((CUR >= '0') && (CUR <= '9')) {
10108
33.1k
  ret = ret * 10;
10109
33.1k
  tmp = (CUR - '0');
10110
33.1k
        ok = 1;
10111
33.1k
        NEXT;
10112
33.1k
  temp = (double) tmp;
10113
33.1k
  ret = ret + temp;
10114
33.1k
    }
10115
#else
10116
    ret = 0;
10117
    while ((CUR >= '0') && (CUR <= '9')) {
10118
  ret = ret * 10 + (CUR - '0');
10119
  ok = 1;
10120
  NEXT;
10121
    }
10122
#endif
10123
24.9k
    if (CUR == '.') {
10124
283
  int v, frac = 0, max;
10125
283
  double fraction = 0;
10126
10127
283
        NEXT;
10128
283
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10129
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10130
0
        }
10131
546
        while (CUR == '0') {
10132
263
            frac = frac + 1;
10133
263
            NEXT;
10134
263
        }
10135
283
        max = frac + MAX_FRAC;
10136
549
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10137
266
      v = (CUR - '0');
10138
266
      fraction = fraction * 10 + v;
10139
266
      frac = frac + 1;
10140
266
            NEXT;
10141
266
        }
10142
283
        fraction /= pow(10.0, frac);
10143
283
        ret = ret + fraction;
10144
283
        while ((CUR >= '0') && (CUR <= '9'))
10145
0
            NEXT;
10146
283
    }
10147
24.9k
    if ((CUR == 'e') || (CUR == 'E')) {
10148
3.65k
        NEXT;
10149
3.65k
        if (CUR == '-') {
10150
712
            is_exponent_negative = 1;
10151
712
            NEXT;
10152
2.93k
        } else if (CUR == '+') {
10153
0
      NEXT;
10154
0
  }
10155
23.1k
        while ((CUR >= '0') && (CUR <= '9')) {
10156
19.5k
            if (exponent < 1000000)
10157
12.3k
                exponent = exponent * 10 + (CUR - '0');
10158
19.5k
            NEXT;
10159
19.5k
        }
10160
3.65k
        if (is_exponent_negative)
10161
712
            exponent = -exponent;
10162
3.65k
        ret *= pow(10.0, (double) exponent);
10163
3.65k
    }
10164
24.9k
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10165
24.9k
    if (num == NULL) {
10166
0
  ctxt->error = XPATH_MEMORY_ERROR;
10167
24.9k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10168
24.9k
                              NULL) == -1) {
10169
0
        xmlXPathReleaseObject(ctxt->context, num);
10170
0
    }
10171
24.9k
}
10172
10173
/**
10174
 * xmlXPathParseLiteral:
10175
 * @ctxt:  the XPath Parser context
10176
 *
10177
 * Parse a Literal
10178
 *
10179
 *  [29]   Literal ::=   '"' [^"]* '"'
10180
 *                    | "'" [^']* "'"
10181
 *
10182
 * Returns the value found or NULL in case of error
10183
 */
10184
static xmlChar *
10185
88
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10186
88
    const xmlChar *q;
10187
88
    xmlChar *ret = NULL;
10188
10189
88
    if (CUR == '"') {
10190
0
        NEXT;
10191
0
  q = CUR_PTR;
10192
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10193
0
      NEXT;
10194
0
  if (!IS_CHAR_CH(CUR)) {
10195
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10196
0
  } else {
10197
0
      ret = xmlStrndup(q, CUR_PTR - q);
10198
0
      NEXT;
10199
0
        }
10200
88
    } else if (CUR == '\'') {
10201
76
        NEXT;
10202
76
  q = CUR_PTR;
10203
66.4k
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10204
66.3k
      NEXT;
10205
76
  if (!IS_CHAR_CH(CUR)) {
10206
24
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10207
52
  } else {
10208
52
      ret = xmlStrndup(q, CUR_PTR - q);
10209
52
      NEXT;
10210
52
        }
10211
76
    } else {
10212
12
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10213
0
    }
10214
52
    return(ret);
10215
88
}
10216
10217
/**
10218
 * xmlXPathCompLiteral:
10219
 * @ctxt:  the XPath Parser context
10220
 *
10221
 * Parse a Literal and push it on the stack.
10222
 *
10223
 *  [29]   Literal ::=   '"' [^"]* '"'
10224
 *                    | "'" [^']* "'"
10225
 *
10226
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10227
 */
10228
static void
10229
1.38k
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10230
1.38k
    const xmlChar *q;
10231
1.38k
    xmlChar *ret = NULL;
10232
1.38k
    xmlXPathObjectPtr lit;
10233
10234
1.38k
    if (CUR == '"') {
10235
6
        NEXT;
10236
6
  q = CUR_PTR;
10237
824k
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10238
824k
      NEXT;
10239
6
  if (!IS_CHAR_CH(CUR)) {
10240
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10241
6
  } else {
10242
6
      ret = xmlStrndup(q, CUR_PTR - q);
10243
6
      NEXT;
10244
6
        }
10245
1.38k
    } else if (CUR == '\'') {
10246
1.38k
        NEXT;
10247
1.38k
  q = CUR_PTR;
10248
23.1M
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10249
23.1M
      NEXT;
10250
1.38k
  if (!IS_CHAR_CH(CUR)) {
10251
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10252
1.38k
  } else {
10253
1.38k
      ret = xmlStrndup(q, CUR_PTR - q);
10254
1.38k
      NEXT;
10255
1.38k
        }
10256
1.38k
    } else {
10257
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10258
0
    }
10259
1.38k
    if (ret == NULL) return;
10260
1.38k
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10261
1.38k
    if (lit == NULL) {
10262
0
  ctxt->error = XPATH_MEMORY_ERROR;
10263
1.38k
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10264
1.38k
                              NULL) == -1) {
10265
0
        xmlXPathReleaseObject(ctxt->context, lit);
10266
0
    }
10267
1.38k
    xmlFree(ret);
10268
1.38k
}
10269
10270
/**
10271
 * xmlXPathCompVariableReference:
10272
 * @ctxt:  the XPath Parser context
10273
 *
10274
 * Parse a VariableReference, evaluate it and push it on the stack.
10275
 *
10276
 * The variable bindings consist of a mapping from variable names
10277
 * to variable values. The value of a variable is an object, which can be
10278
 * of any of the types that are possible for the value of an expression,
10279
 * and may also be of additional types not specified here.
10280
 *
10281
 * Early evaluation is possible since:
10282
 * The variable bindings [...] used to evaluate a subexpression are
10283
 * always the same as those used to evaluate the containing expression.
10284
 *
10285
 *  [36]   VariableReference ::=   '$' QName
10286
 */
10287
static void
10288
201
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10289
201
    xmlChar *name;
10290
201
    xmlChar *prefix;
10291
10292
201
    SKIP_BLANKS;
10293
201
    if (CUR != '$') {
10294
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10295
0
    }
10296
201
    NEXT;
10297
201
    name = xmlXPathParseQName(ctxt, &prefix);
10298
201
    if (name == NULL) {
10299
159
        xmlFree(prefix);
10300
159
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10301
0
    }
10302
42
    ctxt->comp->last = -1;
10303
42
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10304
0
        xmlFree(prefix);
10305
0
        xmlFree(name);
10306
0
    }
10307
42
    SKIP_BLANKS;
10308
42
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10309
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10310
0
    }
10311
42
}
10312
10313
/**
10314
 * xmlXPathIsNodeType:
10315
 * @name:  a name string
10316
 *
10317
 * Is the name given a NodeType one.
10318
 *
10319
 *  [38]   NodeType ::=   'comment'
10320
 *                    | 'text'
10321
 *                    | 'processing-instruction'
10322
 *                    | 'node'
10323
 *
10324
 * Returns 1 if true 0 otherwise
10325
 */
10326
int
10327
22.7k
xmlXPathIsNodeType(const xmlChar *name) {
10328
22.7k
    if (name == NULL)
10329
0
  return(0);
10330
10331
22.7k
    if (xmlStrEqual(name, BAD_CAST "node"))
10332
1.30k
  return(1);
10333
21.4k
    if (xmlStrEqual(name, BAD_CAST "text"))
10334
32
  return(1);
10335
21.4k
    if (xmlStrEqual(name, BAD_CAST "comment"))
10336
0
  return(1);
10337
21.4k
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10338
0
  return(1);
10339
21.4k
    return(0);
10340
21.4k
}
10341
10342
/**
10343
 * xmlXPathCompFunctionCall:
10344
 * @ctxt:  the XPath Parser context
10345
 *
10346
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10347
 *  [17]   Argument ::=   Expr
10348
 *
10349
 * Compile a function call, the evaluation of all arguments are
10350
 * pushed on the stack
10351
 */
10352
static void
10353
11.4k
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10354
11.4k
    xmlChar *name;
10355
11.4k
    xmlChar *prefix;
10356
11.4k
    int nbargs = 0;
10357
11.4k
    int sort = 1;
10358
10359
11.4k
    name = xmlXPathParseQName(ctxt, &prefix);
10360
11.4k
    if (name == NULL) {
10361
115
  xmlFree(prefix);
10362
115
  XP_ERROR(XPATH_EXPR_ERROR);
10363
0
    }
10364
11.3k
    SKIP_BLANKS;
10365
#ifdef DEBUG_EXPR
10366
    if (prefix == NULL)
10367
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10368
      name);
10369
    else
10370
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10371
      prefix, name);
10372
#endif
10373
10374
11.3k
    if (CUR != '(') {
10375
60
  xmlFree(name);
10376
60
  xmlFree(prefix);
10377
60
  XP_ERROR(XPATH_EXPR_ERROR);
10378
0
    }
10379
11.2k
    NEXT;
10380
11.2k
    SKIP_BLANKS;
10381
10382
    /*
10383
    * Optimization for count(): we don't need the node-set to be sorted.
10384
    */
10385
11.2k
    if ((prefix == NULL) && (name[0] == 'c') &&
10386
11.2k
  xmlStrEqual(name, BAD_CAST "count"))
10387
1.25k
    {
10388
1.25k
  sort = 0;
10389
1.25k
    }
10390
11.2k
    ctxt->comp->last = -1;
10391
11.2k
    if (CUR != ')') {
10392
10.7k
  while (CUR != 0) {
10393
10.1k
      int op1 = ctxt->comp->last;
10394
10.1k
      ctxt->comp->last = -1;
10395
10.1k
      xmlXPathCompileExpr(ctxt, sort);
10396
10.1k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10397
2.29k
    xmlFree(name);
10398
2.29k
    xmlFree(prefix);
10399
2.29k
    return;
10400
2.29k
      }
10401
7.89k
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10402
7.89k
      nbargs++;
10403
7.89k
      if (CUR == ')') break;
10404
2.74k
      if (CUR != ',') {
10405
740
    xmlFree(name);
10406
740
    xmlFree(prefix);
10407
740
    XP_ERROR(XPATH_EXPR_ERROR);
10408
0
      }
10409
2.00k
      NEXT;
10410
2.00k
      SKIP_BLANKS;
10411
2.00k
  }
10412
8.73k
    }
10413
8.23k
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10414
1
        xmlFree(prefix);
10415
1
        xmlFree(name);
10416
1
    }
10417
8.23k
    NEXT;
10418
8.23k
    SKIP_BLANKS;
10419
8.23k
}
10420
10421
/**
10422
 * xmlXPathCompPrimaryExpr:
10423
 * @ctxt:  the XPath Parser context
10424
 *
10425
 *  [15]   PrimaryExpr ::=   VariableReference
10426
 *                | '(' Expr ')'
10427
 *                | Literal
10428
 *                | Number
10429
 *                | FunctionCall
10430
 *
10431
 * Compile a primary expression.
10432
 */
10433
static void
10434
42.9k
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10435
42.9k
    SKIP_BLANKS;
10436
42.9k
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10437
42.7k
    else if (CUR == '(') {
10438
5.01k
  NEXT;
10439
5.01k
  SKIP_BLANKS;
10440
5.01k
  xmlXPathCompileExpr(ctxt, 1);
10441
5.01k
  CHECK_ERROR;
10442
1.75k
  if (CUR != ')') {
10443
349
      XP_ERROR(XPATH_EXPR_ERROR);
10444
0
  }
10445
1.40k
  NEXT;
10446
1.40k
  SKIP_BLANKS;
10447
37.7k
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10448
24.9k
  xmlXPathCompNumber(ctxt);
10449
24.9k
    } else if ((CUR == '\'') || (CUR == '"')) {
10450
1.38k
  xmlXPathCompLiteral(ctxt);
10451
11.4k
    } else {
10452
11.4k
  xmlXPathCompFunctionCall(ctxt);
10453
11.4k
    }
10454
39.3k
    SKIP_BLANKS;
10455
39.3k
}
10456
10457
/**
10458
 * xmlXPathCompFilterExpr:
10459
 * @ctxt:  the XPath Parser context
10460
 *
10461
 *  [20]   FilterExpr ::=   PrimaryExpr
10462
 *               | FilterExpr Predicate
10463
 *
10464
 * Compile a filter expression.
10465
 * Square brackets are used to filter expressions in the same way that
10466
 * they are used in location paths. It is an error if the expression to
10467
 * be filtered does not evaluate to a node-set. The context node list
10468
 * used for evaluating the expression in square brackets is the node-set
10469
 * to be filtered listed in document order.
10470
 */
10471
10472
static void
10473
42.9k
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10474
42.9k
    xmlXPathCompPrimaryExpr(ctxt);
10475
42.9k
    CHECK_ERROR;
10476
36.0k
    SKIP_BLANKS;
10477
10478
38.0k
    while (CUR == '[') {
10479
2.00k
  xmlXPathCompPredicate(ctxt, 1);
10480
2.00k
  SKIP_BLANKS;
10481
2.00k
    }
10482
10483
10484
36.0k
}
10485
10486
/**
10487
 * xmlXPathScanName:
10488
 * @ctxt:  the XPath Parser context
10489
 *
10490
 * Trickery: parse an XML name but without consuming the input flow
10491
 * Needed to avoid insanity in the parser state.
10492
 *
10493
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10494
 *                  CombiningChar | Extender
10495
 *
10496
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10497
 *
10498
 * [6] Names ::= Name (S Name)*
10499
 *
10500
 * Returns the Name parsed or NULL
10501
 */
10502
10503
static xmlChar *
10504
6.48M
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10505
6.48M
    int l;
10506
6.48M
    int c;
10507
6.48M
    const xmlChar *cur;
10508
6.48M
    xmlChar *ret;
10509
10510
6.48M
    cur = ctxt->cur;
10511
10512
6.48M
    c = CUR_CHAR(l);
10513
6.48M
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10514
6.48M
  (!IS_LETTER(c) && (c != '_') &&
10515
6.48M
         (c != ':'))) {
10516
4.94k
  return(NULL);
10517
4.94k
    }
10518
10519
14.6M
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10520
14.6M
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10521
14.6M
            (c == '.') || (c == '-') ||
10522
14.6M
      (c == '_') || (c == ':') ||
10523
14.6M
      (IS_COMBINING(c)) ||
10524
14.6M
      (IS_EXTENDER(c)))) {
10525
8.16M
  NEXTL(l);
10526
8.16M
  c = CUR_CHAR(l);
10527
8.16M
    }
10528
6.48M
    ret = xmlStrndup(cur, ctxt->cur - cur);
10529
6.48M
    ctxt->cur = cur;
10530
6.48M
    return(ret);
10531
6.48M
}
10532
10533
/**
10534
 * xmlXPathCompPathExpr:
10535
 * @ctxt:  the XPath Parser context
10536
 *
10537
 *  [19]   PathExpr ::=   LocationPath
10538
 *               | FilterExpr
10539
 *               | FilterExpr '/' RelativeLocationPath
10540
 *               | FilterExpr '//' RelativeLocationPath
10541
 *
10542
 * Compile a path expression.
10543
 * The / operator and // operators combine an arbitrary expression
10544
 * and a relative location path. It is an error if the expression
10545
 * does not evaluate to a node-set.
10546
 * The / operator does composition in the same way as when / is
10547
 * used in a location path. As in location paths, // is short for
10548
 * /descendant-or-self::node()/.
10549
 */
10550
10551
static void
10552
6.54M
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10553
6.54M
    int lc = 1;           /* Should we branch to LocationPath ?         */
10554
6.54M
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10555
10556
6.54M
    SKIP_BLANKS;
10557
6.54M
    if ((CUR == '$') || (CUR == '(') ||
10558
6.54M
  (IS_ASCII_DIGIT(CUR)) ||
10559
6.54M
        (CUR == '\'') || (CUR == '"') ||
10560
6.54M
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10561
31.5k
  lc = 0;
10562
6.51M
    } else if (CUR == '*') {
10563
  /* relative or absolute location path */
10564
2.41k
  lc = 1;
10565
6.51M
    } else if (CUR == '/') {
10566
  /* relative or absolute location path */
10567
17.8k
  lc = 1;
10568
6.49M
    } else if (CUR == '@') {
10569
  /* relative abbreviated attribute location path */
10570
1.71k
  lc = 1;
10571
6.49M
    } else if (CUR == '.') {
10572
  /* relative abbreviated attribute location path */
10573
3.57k
  lc = 1;
10574
6.48M
    } else {
10575
  /*
10576
   * Problem is finding if we have a name here whether it's:
10577
   *   - a nodetype
10578
   *   - a function call in which case it's followed by '('
10579
   *   - an axis in which case it's followed by ':'
10580
   *   - a element name
10581
   * We do an a priori analysis here rather than having to
10582
   * maintain parsed token content through the recursive function
10583
   * calls. This looks uglier but makes the code easier to
10584
   * read/write/debug.
10585
   */
10586
6.48M
  SKIP_BLANKS;
10587
6.48M
  name = xmlXPathScanName(ctxt);
10588
6.48M
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10589
#ifdef DEBUG_STEP
10590
      xmlGenericError(xmlGenericErrorContext,
10591
        "PathExpr: Axis\n");
10592
#endif
10593
1.05k
      lc = 1;
10594
1.05k
      xmlFree(name);
10595
6.48M
  } else if (name != NULL) {
10596
6.48M
      int len =xmlStrlen(name);
10597
10598
10599
6.48M
      while (NXT(len) != 0) {
10600
6.48M
    if (NXT(len) == '/') {
10601
        /* element name */
10602
#ifdef DEBUG_STEP
10603
        xmlGenericError(xmlGenericErrorContext,
10604
          "PathExpr: AbbrRelLocation\n");
10605
#endif
10606
2.28k
        lc = 1;
10607
2.28k
        break;
10608
6.48M
    } else if (IS_BLANK_CH(NXT(len))) {
10609
        /* ignore blanks */
10610
6.50k
        ;
10611
6.47M
    } else if (NXT(len) == ':') {
10612
#ifdef DEBUG_STEP
10613
        xmlGenericError(xmlGenericErrorContext,
10614
          "PathExpr: AbbrRelLocation\n");
10615
#endif
10616
7
        lc = 1;
10617
7
        break;
10618
6.47M
    } else if ((NXT(len) == '(')) {
10619
        /* Node Type or Function */
10620
11.7k
        if (xmlXPathIsNodeType(name)) {
10621
#ifdef DEBUG_STEP
10622
            xmlGenericError(xmlGenericErrorContext,
10623
        "PathExpr: Type search\n");
10624
#endif
10625
275
      lc = 1;
10626
#ifdef LIBXML_XPTR_LOCS_ENABLED
10627
                    } else if (ctxt->xptr &&
10628
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10629
                        lc = 1;
10630
#endif
10631
11.4k
        } else {
10632
#ifdef DEBUG_STEP
10633
            xmlGenericError(xmlGenericErrorContext,
10634
        "PathExpr: function call\n");
10635
#endif
10636
11.4k
      lc = 0;
10637
11.4k
        }
10638
11.7k
                    break;
10639
6.46M
    } else if ((NXT(len) == '[')) {
10640
        /* element name */
10641
#ifdef DEBUG_STEP
10642
        xmlGenericError(xmlGenericErrorContext,
10643
          "PathExpr: AbbrRelLocation\n");
10644
#endif
10645
1.39k
        lc = 1;
10646
1.39k
        break;
10647
6.46M
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10648
6.46M
         (NXT(len) == '=')) {
10649
8.67k
        lc = 1;
10650
8.67k
        break;
10651
6.45M
    } else {
10652
6.45M
        lc = 1;
10653
6.45M
        break;
10654
6.45M
    }
10655
6.50k
    len++;
10656
6.50k
      }
10657
6.48M
      if (NXT(len) == 0) {
10658
#ifdef DEBUG_STEP
10659
    xmlGenericError(xmlGenericErrorContext,
10660
      "PathExpr: AbbrRelLocation\n");
10661
#endif
10662
    /* element name */
10663
1.24k
    lc = 1;
10664
1.24k
      }
10665
6.48M
      xmlFree(name);
10666
6.48M
  } else {
10667
      /* make sure all cases are covered explicitly */
10668
4.94k
      XP_ERROR(XPATH_EXPR_ERROR);
10669
0
  }
10670
6.48M
    }
10671
10672
6.54M
    if (lc) {
10673
6.49M
  if (CUR == '/') {
10674
17.8k
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10675
6.47M
  } else {
10676
6.47M
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10677
6.47M
  }
10678
6.49M
  xmlXPathCompLocationPath(ctxt);
10679
6.49M
    } else {
10680
42.9k
  xmlXPathCompFilterExpr(ctxt);
10681
42.9k
  CHECK_ERROR;
10682
35.6k
  if ((CUR == '/') && (NXT(1) == '/')) {
10683
264
      SKIP(2);
10684
264
      SKIP_BLANKS;
10685
10686
264
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10687
264
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10688
10689
264
      xmlXPathCompRelativeLocationPath(ctxt);
10690
35.3k
  } else if (CUR == '/') {
10691
380
      xmlXPathCompRelativeLocationPath(ctxt);
10692
380
  }
10693
35.6k
    }
10694
6.53M
    SKIP_BLANKS;
10695
6.53M
}
10696
10697
/**
10698
 * xmlXPathCompUnionExpr:
10699
 * @ctxt:  the XPath Parser context
10700
 *
10701
 *  [18]   UnionExpr ::=   PathExpr
10702
 *               | UnionExpr '|' PathExpr
10703
 *
10704
 * Compile an union expression.
10705
 */
10706
10707
static void
10708
76.7k
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10709
76.7k
    xmlXPathCompPathExpr(ctxt);
10710
76.7k
    CHECK_ERROR;
10711
59.3k
    SKIP_BLANKS;
10712
6.52M
    while (CUR == '|') {
10713
6.46M
  int op1 = ctxt->comp->last;
10714
6.46M
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10715
10716
6.46M
  NEXT;
10717
6.46M
  SKIP_BLANKS;
10718
6.46M
  xmlXPathCompPathExpr(ctxt);
10719
10720
6.46M
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10721
10722
6.46M
  SKIP_BLANKS;
10723
6.46M
    }
10724
59.3k
}
10725
10726
/**
10727
 * xmlXPathCompUnaryExpr:
10728
 * @ctxt:  the XPath Parser context
10729
 *
10730
 *  [27]   UnaryExpr ::=   UnionExpr
10731
 *                   | '-' UnaryExpr
10732
 *
10733
 * Compile an unary expression.
10734
 */
10735
10736
static void
10737
76.7k
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10738
76.7k
    int minus = 0;
10739
76.7k
    int found = 0;
10740
10741
76.7k
    SKIP_BLANKS;
10742
80.9k
    while (CUR == '-') {
10743
4.24k
        minus = 1 - minus;
10744
4.24k
  found = 1;
10745
4.24k
  NEXT;
10746
4.24k
  SKIP_BLANKS;
10747
4.24k
    }
10748
10749
76.7k
    xmlXPathCompUnionExpr(ctxt);
10750
76.7k
    CHECK_ERROR;
10751
57.8k
    if (found) {
10752
2.43k
  if (minus)
10753
2.42k
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10754
10
  else
10755
10
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10756
2.43k
    }
10757
57.8k
}
10758
10759
/**
10760
 * xmlXPathCompMultiplicativeExpr:
10761
 * @ctxt:  the XPath Parser context
10762
 *
10763
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10764
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10765
 *                   | MultiplicativeExpr 'div' UnaryExpr
10766
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10767
 *  [34]   MultiplyOperator ::=   '*'
10768
 *
10769
 * Compile an Additive expression.
10770
 */
10771
10772
static void
10773
71.6k
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10774
71.6k
    xmlXPathCompUnaryExpr(ctxt);
10775
71.6k
    CHECK_ERROR;
10776
53.2k
    SKIP_BLANKS;
10777
57.8k
    while ((CUR == '*') ||
10778
57.8k
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10779
57.8k
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10780
5.09k
  int op = -1;
10781
5.09k
  int op1 = ctxt->comp->last;
10782
10783
5.09k
        if (CUR == '*') {
10784
4.93k
      op = 0;
10785
4.93k
      NEXT;
10786
4.93k
  } else if (CUR == 'd') {
10787
23
      op = 1;
10788
23
      SKIP(3);
10789
138
  } else if (CUR == 'm') {
10790
138
      op = 2;
10791
138
      SKIP(3);
10792
138
  }
10793
5.09k
  SKIP_BLANKS;
10794
5.09k
        xmlXPathCompUnaryExpr(ctxt);
10795
5.09k
  CHECK_ERROR;
10796
4.62k
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10797
4.62k
  SKIP_BLANKS;
10798
4.62k
    }
10799
53.2k
}
10800
10801
/**
10802
 * xmlXPathCompAdditiveExpr:
10803
 * @ctxt:  the XPath Parser context
10804
 *
10805
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10806
 *                   | AdditiveExpr '+' MultiplicativeExpr
10807
 *                   | AdditiveExpr '-' MultiplicativeExpr
10808
 *
10809
 * Compile an Additive expression.
10810
 */
10811
10812
static void
10813
70.3k
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10814
10815
70.3k
    xmlXPathCompMultiplicativeExpr(ctxt);
10816
70.3k
    CHECK_ERROR;
10817
51.8k
    SKIP_BLANKS;
10818
52.7k
    while ((CUR == '+') || (CUR == '-')) {
10819
1.28k
  int plus;
10820
1.28k
  int op1 = ctxt->comp->last;
10821
10822
1.28k
        if (CUR == '+') plus = 1;
10823
734
  else plus = 0;
10824
1.28k
  NEXT;
10825
1.28k
  SKIP_BLANKS;
10826
1.28k
        xmlXPathCompMultiplicativeExpr(ctxt);
10827
1.28k
  CHECK_ERROR;
10828
911
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10829
911
  SKIP_BLANKS;
10830
911
    }
10831
51.8k
}
10832
10833
/**
10834
 * xmlXPathCompRelationalExpr:
10835
 * @ctxt:  the XPath Parser context
10836
 *
10837
 *  [24]   RelationalExpr ::=   AdditiveExpr
10838
 *                 | RelationalExpr '<' AdditiveExpr
10839
 *                 | RelationalExpr '>' AdditiveExpr
10840
 *                 | RelationalExpr '<=' AdditiveExpr
10841
 *                 | RelationalExpr '>=' AdditiveExpr
10842
 *
10843
 *  A <= B > C is allowed ? Answer from James, yes with
10844
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10845
 *  which is basically what got implemented.
10846
 *
10847
 * Compile a Relational expression, then push the result
10848
 * on the stack
10849
 */
10850
10851
static void
10852
62.0k
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10853
62.0k
    xmlXPathCompAdditiveExpr(ctxt);
10854
62.0k
    CHECK_ERROR;
10855
43.2k
    SKIP_BLANKS;
10856
51.4k
    while ((CUR == '<') || (CUR == '>')) {
10857
8.29k
  int inf, strict;
10858
8.29k
  int op1 = ctxt->comp->last;
10859
10860
8.29k
        if (CUR == '<') inf = 1;
10861
518
  else inf = 0;
10862
8.29k
  if (NXT(1) == '=') strict = 0;
10863
8.28k
  else strict = 1;
10864
8.29k
  NEXT;
10865
8.29k
  if (!strict) NEXT;
10866
8.29k
  SKIP_BLANKS;
10867
8.29k
        xmlXPathCompAdditiveExpr(ctxt);
10868
8.29k
  CHECK_ERROR;
10869
8.20k
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10870
8.20k
  SKIP_BLANKS;
10871
8.20k
    }
10872
43.2k
}
10873
10874
/**
10875
 * xmlXPathCompEqualityExpr:
10876
 * @ctxt:  the XPath Parser context
10877
 *
10878
 *  [23]   EqualityExpr ::=   RelationalExpr
10879
 *                 | EqualityExpr '=' RelationalExpr
10880
 *                 | EqualityExpr '!=' RelationalExpr
10881
 *
10882
 *  A != B != C is allowed ? Answer from James, yes with
10883
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10884
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10885
 *  which is basically what got implemented.
10886
 *
10887
 * Compile an Equality expression.
10888
 *
10889
 */
10890
static void
10891
58.3k
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10892
58.3k
    xmlXPathCompRelationalExpr(ctxt);
10893
58.3k
    CHECK_ERROR;
10894
41.2k
    SKIP_BLANKS;
10895
43.2k
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10896
3.73k
  int eq;
10897
3.73k
  int op1 = ctxt->comp->last;
10898
10899
3.73k
        if (CUR == '=') eq = 1;
10900
1.19k
  else eq = 0;
10901
3.73k
  NEXT;
10902
3.73k
  if (!eq) NEXT;
10903
3.73k
  SKIP_BLANKS;
10904
3.73k
        xmlXPathCompRelationalExpr(ctxt);
10905
3.73k
  CHECK_ERROR;
10906
1.91k
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10907
1.91k
  SKIP_BLANKS;
10908
1.91k
    }
10909
41.2k
}
10910
10911
/**
10912
 * xmlXPathCompAndExpr:
10913
 * @ctxt:  the XPath Parser context
10914
 *
10915
 *  [22]   AndExpr ::=   EqualityExpr
10916
 *                 | AndExpr 'and' EqualityExpr
10917
 *
10918
 * Compile an AND expression.
10919
 *
10920
 */
10921
static void
10922
58.1k
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10923
58.1k
    xmlXPathCompEqualityExpr(ctxt);
10924
58.1k
    CHECK_ERROR;
10925
39.2k
    SKIP_BLANKS;
10926
39.4k
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10927
178
  int op1 = ctxt->comp->last;
10928
178
        SKIP(3);
10929
178
  SKIP_BLANKS;
10930
178
        xmlXPathCompEqualityExpr(ctxt);
10931
178
  CHECK_ERROR;
10932
175
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10933
175
  SKIP_BLANKS;
10934
175
    }
10935
39.2k
}
10936
10937
/**
10938
 * xmlXPathCompileExpr:
10939
 * @ctxt:  the XPath Parser context
10940
 *
10941
 *  [14]   Expr ::=   OrExpr
10942
 *  [21]   OrExpr ::=   AndExpr
10943
 *                 | OrExpr 'or' AndExpr
10944
 *
10945
 * Parse and compile an expression
10946
 */
10947
static void
10948
57.9k
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10949
57.9k
    xmlXPathContextPtr xpctxt = ctxt->context;
10950
10951
57.9k
    if (xpctxt != NULL) {
10952
57.9k
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10953
57.9k
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10954
        /*
10955
         * Parsing a single '(' pushes about 10 functions on the call stack
10956
         * before recursing!
10957
         */
10958
57.9k
        xpctxt->depth += 10;
10959
57.9k
    }
10960
10961
57.9k
    xmlXPathCompAndExpr(ctxt);
10962
57.9k
    CHECK_ERROR;
10963
39.0k
    SKIP_BLANKS;
10964
39.2k
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10965
194
  int op1 = ctxt->comp->last;
10966
194
        SKIP(2);
10967
194
  SKIP_BLANKS;
10968
194
        xmlXPathCompAndExpr(ctxt);
10969
194
  CHECK_ERROR;
10970
194
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10971
194
  SKIP_BLANKS;
10972
194
    }
10973
39.0k
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10974
  /* more ops could be optimized too */
10975
  /*
10976
  * This is the main place to eliminate sorting for
10977
  * operations which don't require a sorted node-set.
10978
  * E.g. count().
10979
  */
10980
23.5k
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10981
23.5k
    }
10982
10983
39.0k
    if (xpctxt != NULL)
10984
39.0k
        xpctxt->depth -= 10;
10985
39.0k
}
10986
10987
/**
10988
 * xmlXPathCompPredicate:
10989
 * @ctxt:  the XPath Parser context
10990
 * @filter:  act as a filter
10991
 *
10992
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10993
 *  [9]   PredicateExpr ::=   Expr
10994
 *
10995
 * Compile a predicate expression
10996
 */
10997
static void
10998
6.71k
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10999
6.71k
    int op1 = ctxt->comp->last;
11000
11001
6.71k
    SKIP_BLANKS;
11002
6.71k
    if (CUR != '[') {
11003
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11004
0
    }
11005
6.71k
    NEXT;
11006
6.71k
    SKIP_BLANKS;
11007
11008
6.71k
    ctxt->comp->last = -1;
11009
    /*
11010
    * This call to xmlXPathCompileExpr() will deactivate sorting
11011
    * of the predicate result.
11012
    * TODO: Sorting is still activated for filters, since I'm not
11013
    *  sure if needed. Normally sorting should not be needed, since
11014
    *  a filter can only diminish the number of items in a sequence,
11015
    *  but won't change its order; so if the initial sequence is sorted,
11016
    *  subsequent sorting is not needed.
11017
    */
11018
6.71k
    if (! filter)
11019
4.70k
  xmlXPathCompileExpr(ctxt, 0);
11020
2.00k
    else
11021
2.00k
  xmlXPathCompileExpr(ctxt, 1);
11022
6.71k
    CHECK_ERROR;
11023
11024
6.18k
    if (CUR != ']') {
11025
1.12k
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11026
0
    }
11027
11028
5.06k
    if (filter)
11029
1.65k
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11030
3.41k
    else
11031
3.41k
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11032
11033
5.06k
    NEXT;
11034
5.06k
    SKIP_BLANKS;
11035
5.06k
}
11036
11037
/**
11038
 * xmlXPathCompNodeTest:
11039
 * @ctxt:  the XPath Parser context
11040
 * @test:  pointer to a xmlXPathTestVal
11041
 * @type:  pointer to a xmlXPathTypeVal
11042
 * @prefix:  placeholder for a possible name prefix
11043
 *
11044
 * [7] NodeTest ::=   NameTest
11045
 *        | NodeType '(' ')'
11046
 *        | 'processing-instruction' '(' Literal ')'
11047
 *
11048
 * [37] NameTest ::=  '*'
11049
 *        | NCName ':' '*'
11050
 *        | QName
11051
 * [38] NodeType ::= 'comment'
11052
 *       | 'text'
11053
 *       | 'processing-instruction'
11054
 *       | 'node'
11055
 *
11056
 * Returns the name found and updates @test, @type and @prefix appropriately
11057
 */
11058
static xmlChar *
11059
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11060
               xmlXPathTypeVal *type, xmlChar **prefix,
11061
7.67M
         xmlChar *name) {
11062
7.67M
    int blanks;
11063
11064
7.67M
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11065
0
  STRANGE;
11066
0
  return(NULL);
11067
0
    }
11068
7.67M
    *type = (xmlXPathTypeVal) 0;
11069
7.67M
    *test = (xmlXPathTestVal) 0;
11070
7.67M
    *prefix = NULL;
11071
7.67M
    SKIP_BLANKS;
11072
11073
7.67M
    if ((name == NULL) && (CUR == '*')) {
11074
  /*
11075
   * All elements
11076
   */
11077
345k
  NEXT;
11078
345k
  *test = NODE_TEST_ALL;
11079
345k
  return(NULL);
11080
345k
    }
11081
11082
7.32M
    if (name == NULL)
11083
7.97k
  name = xmlXPathParseNCName(ctxt);
11084
7.32M
    if (name == NULL) {
11085
3.27k
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11086
0
    }
11087
11088
7.32M
    blanks = IS_BLANK_CH(CUR);
11089
7.32M
    SKIP_BLANKS;
11090
7.32M
    if (CUR == '(') {
11091
3.08k
  NEXT;
11092
  /*
11093
   * NodeType or PI search
11094
   */
11095
3.08k
  if (xmlStrEqual(name, BAD_CAST "comment"))
11096
88
      *type = NODE_TYPE_COMMENT;
11097
2.99k
  else if (xmlStrEqual(name, BAD_CAST "node"))
11098
1.09k
      *type = NODE_TYPE_NODE;
11099
1.90k
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11100
143
      *type = NODE_TYPE_PI;
11101
1.75k
  else if (xmlStrEqual(name, BAD_CAST "text"))
11102
1.64k
      *type = NODE_TYPE_TEXT;
11103
118
  else {
11104
118
      if (name != NULL)
11105
118
    xmlFree(name);
11106
118
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11107
0
  }
11108
11109
2.96k
  *test = NODE_TEST_TYPE;
11110
11111
2.96k
  SKIP_BLANKS;
11112
2.96k
  if (*type == NODE_TYPE_PI) {
11113
      /*
11114
       * Specific case: search a PI by name.
11115
       */
11116
143
      if (name != NULL)
11117
143
    xmlFree(name);
11118
143
      name = NULL;
11119
143
      if (CUR != ')') {
11120
88
    name = xmlXPathParseLiteral(ctxt);
11121
88
                if (name == NULL) {
11122
36
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11123
0
                }
11124
52
    *test = NODE_TEST_PI;
11125
52
    SKIP_BLANKS;
11126
52
      }
11127
143
  }
11128
2.93k
  if (CUR != ')') {
11129
52
      if (name != NULL)
11130
52
    xmlFree(name);
11131
52
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11132
0
  }
11133
2.88k
  NEXT;
11134
2.88k
  return(name);
11135
2.93k
    }
11136
7.32M
    *test = NODE_TEST_NAME;
11137
7.32M
    if ((!blanks) && (CUR == ':')) {
11138
7.49k
  NEXT;
11139
11140
  /*
11141
   * Since currently the parser context don't have a
11142
   * namespace list associated:
11143
   * The namespace name for this prefix can be computed
11144
   * only at evaluation time. The compilation is done
11145
   * outside of any context.
11146
   */
11147
#if 0
11148
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11149
  if (name != NULL)
11150
      xmlFree(name);
11151
  if (*prefix == NULL) {
11152
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11153
  }
11154
#else
11155
7.49k
  *prefix = name;
11156
7.49k
#endif
11157
11158
7.49k
  if (CUR == '*') {
11159
      /*
11160
       * All elements
11161
       */
11162
4.52k
      NEXT;
11163
4.52k
      *test = NODE_TEST_ALL;
11164
4.52k
      return(NULL);
11165
4.52k
  }
11166
11167
2.97k
  name = xmlXPathParseNCName(ctxt);
11168
2.97k
  if (name == NULL) {
11169
1.76k
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11170
0
  }
11171
2.97k
    }
11172
7.31M
    return(name);
11173
7.32M
}
11174
11175
/**
11176
 * xmlXPathIsAxisName:
11177
 * @name:  a preparsed name token
11178
 *
11179
 * [6] AxisName ::=   'ancestor'
11180
 *                  | 'ancestor-or-self'
11181
 *                  | 'attribute'
11182
 *                  | 'child'
11183
 *                  | 'descendant'
11184
 *                  | 'descendant-or-self'
11185
 *                  | 'following'
11186
 *                  | 'following-sibling'
11187
 *                  | 'namespace'
11188
 *                  | 'parent'
11189
 *                  | 'preceding'
11190
 *                  | 'preceding-sibling'
11191
 *                  | 'self'
11192
 *
11193
 * Returns the axis or 0
11194
 */
11195
static xmlXPathAxisVal
11196
7.32M
xmlXPathIsAxisName(const xmlChar *name) {
11197
7.32M
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11198
7.32M
    switch (name[0]) {
11199
368k
  case 'a':
11200
368k
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11201
0
    ret = AXIS_ANCESTOR;
11202
368k
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11203
2
    ret = AXIS_ANCESTOR_OR_SELF;
11204
368k
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11205
248
    ret = AXIS_ATTRIBUTE;
11206
368k
      break;
11207
4.74k
  case 'c':
11208
4.74k
      if (xmlStrEqual(name, BAD_CAST "child"))
11209
3.01k
    ret = AXIS_CHILD;
11210
4.74k
      break;
11211
1.55k
  case 'd':
11212
1.55k
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11213
22
    ret = AXIS_DESCENDANT;
11214
1.55k
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11215
6
    ret = AXIS_DESCENDANT_OR_SELF;
11216
1.55k
      break;
11217
5
  case 'f':
11218
5
      if (xmlStrEqual(name, BAD_CAST "following"))
11219
0
    ret = AXIS_FOLLOWING;
11220
5
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11221
0
    ret = AXIS_FOLLOWING_SIBLING;
11222
5
      break;
11223
2.56k
  case 'n':
11224
2.56k
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11225
1.07k
    ret = AXIS_NAMESPACE;
11226
2.56k
      break;
11227
3.35k
  case 'p':
11228
3.35k
      if (xmlStrEqual(name, BAD_CAST "parent"))
11229
11
    ret = AXIS_PARENT;
11230
3.35k
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11231
1.06k
    ret = AXIS_PRECEDING;
11232
3.35k
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11233
174
    ret = AXIS_PRECEDING_SIBLING;
11234
3.35k
      break;
11235
2.44k
  case 's':
11236
2.44k
      if (xmlStrEqual(name, BAD_CAST "self"))
11237
2
    ret = AXIS_SELF;
11238
2.44k
      break;
11239
7.32M
    }
11240
7.32M
    return(ret);
11241
7.32M
}
11242
11243
/**
11244
 * xmlXPathCompStep:
11245
 * @ctxt:  the XPath Parser context
11246
 *
11247
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11248
 *                  | AbbreviatedStep
11249
 *
11250
 * [12] AbbreviatedStep ::=   '.' | '..'
11251
 *
11252
 * [5] AxisSpecifier ::= AxisName '::'
11253
 *                  | AbbreviatedAxisSpecifier
11254
 *
11255
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11256
 *
11257
 * Modified for XPtr range support as:
11258
 *
11259
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11260
 *                     | AbbreviatedStep
11261
 *                     | 'range-to' '(' Expr ')' Predicate*
11262
 *
11263
 * Compile one step in a Location Path
11264
 * A location step of . is short for self::node(). This is
11265
 * particularly useful in conjunction with //. For example, the
11266
 * location path .//para is short for
11267
 * self::node()/descendant-or-self::node()/child::para
11268
 * and so will select all para descendant elements of the context
11269
 * node.
11270
 * Similarly, a location step of .. is short for parent::node().
11271
 * For example, ../title is short for parent::node()/child::title
11272
 * and so will select the title children of the parent of the context
11273
 * node.
11274
 */
11275
static void
11276
7.68M
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11277
#ifdef LIBXML_XPTR_LOCS_ENABLED
11278
    int rangeto = 0;
11279
    int op2 = -1;
11280
#endif
11281
11282
7.68M
    SKIP_BLANKS;
11283
7.68M
    if ((CUR == '.') && (NXT(1) == '.')) {
11284
1.54k
  SKIP(2);
11285
1.54k
  SKIP_BLANKS;
11286
1.54k
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11287
1.54k
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11288
7.67M
    } else if (CUR == '.') {
11289
3.15k
  NEXT;
11290
3.15k
  SKIP_BLANKS;
11291
7.67M
    } else {
11292
7.67M
  xmlChar *name = NULL;
11293
7.67M
  xmlChar *prefix = NULL;
11294
7.67M
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11295
7.67M
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11296
7.67M
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11297
7.67M
  int op1;
11298
11299
  /*
11300
   * The modification needed for XPointer change to the production
11301
   */
11302
#ifdef LIBXML_XPTR_LOCS_ENABLED
11303
  if (ctxt->xptr) {
11304
      name = xmlXPathParseNCName(ctxt);
11305
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11306
                op2 = ctxt->comp->last;
11307
    xmlFree(name);
11308
    SKIP_BLANKS;
11309
    if (CUR != '(') {
11310
        XP_ERROR(XPATH_EXPR_ERROR);
11311
    }
11312
    NEXT;
11313
    SKIP_BLANKS;
11314
11315
    xmlXPathCompileExpr(ctxt, 1);
11316
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11317
    CHECK_ERROR;
11318
11319
    SKIP_BLANKS;
11320
    if (CUR != ')') {
11321
        XP_ERROR(XPATH_EXPR_ERROR);
11322
    }
11323
    NEXT;
11324
    rangeto = 1;
11325
    goto eval_predicates;
11326
      }
11327
  }
11328
#endif
11329
7.67M
  if (CUR == '*') {
11330
345k
      axis = AXIS_CHILD;
11331
7.33M
  } else {
11332
7.33M
      if (name == NULL)
11333
7.33M
    name = xmlXPathParseNCName(ctxt);
11334
7.33M
      if (name != NULL) {
11335
7.32M
    axis = xmlXPathIsAxisName(name);
11336
7.32M
    if (axis != 0) {
11337
5.62k
        SKIP_BLANKS;
11338
5.62k
        if ((CUR == ':') && (NXT(1) == ':')) {
11339
5.47k
      SKIP(2);
11340
5.47k
      xmlFree(name);
11341
5.47k
      name = NULL;
11342
5.47k
        } else {
11343
      /* an element name can conflict with an axis one :-\ */
11344
146
      axis = AXIS_CHILD;
11345
146
        }
11346
7.32M
    } else {
11347
7.32M
        axis = AXIS_CHILD;
11348
7.32M
    }
11349
7.32M
      } else if (CUR == '@') {
11350
1.95k
    NEXT;
11351
1.95k
    axis = AXIS_ATTRIBUTE;
11352
1.95k
      } else {
11353
986
    axis = AXIS_CHILD;
11354
986
      }
11355
7.33M
  }
11356
11357
7.67M
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11358
530
            xmlFree(name);
11359
530
            return;
11360
530
        }
11361
11362
7.67M
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11363
7.67M
  if (test == 0)
11364
3.38k
      return;
11365
11366
7.67M
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11367
7.67M
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11368
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11369
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11370
0
      }
11371
0
  }
11372
#ifdef DEBUG_STEP
11373
  xmlGenericError(xmlGenericErrorContext,
11374
    "Basis : computing new set\n");
11375
#endif
11376
11377
#ifdef DEBUG_STEP
11378
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11379
  if (ctxt->value == NULL)
11380
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11381
  else if (ctxt->value->nodesetval == NULL)
11382
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11383
  else
11384
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11385
#endif
11386
11387
#ifdef LIBXML_XPTR_LOCS_ENABLED
11388
eval_predicates:
11389
#endif
11390
7.67M
  op1 = ctxt->comp->last;
11391
7.67M
  ctxt->comp->last = -1;
11392
11393
7.67M
  SKIP_BLANKS;
11394
7.67M
  while (CUR == '[') {
11395
4.70k
      xmlXPathCompPredicate(ctxt, 0);
11396
4.70k
  }
11397
11398
#ifdef LIBXML_XPTR_LOCS_ENABLED
11399
  if (rangeto) {
11400
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11401
  } else
11402
#endif
11403
7.67M
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11404
7.67M
                           test, type, (void *)prefix, (void *)name) == -1) {
11405
79
            xmlFree(prefix);
11406
79
            xmlFree(name);
11407
79
        }
11408
7.67M
    }
11409
#ifdef DEBUG_STEP
11410
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11411
    if (ctxt->value == NULL)
11412
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11413
    else if (ctxt->value->nodesetval == NULL)
11414
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11415
    else
11416
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11417
    ctxt->value->nodesetval);
11418
#endif
11419
7.68M
}
11420
11421
/**
11422
 * xmlXPathCompRelativeLocationPath:
11423
 * @ctxt:  the XPath Parser context
11424
 *
11425
 *  [3]   RelativeLocationPath ::=   Step
11426
 *                     | RelativeLocationPath '/' Step
11427
 *                     | AbbreviatedRelativeLocationPath
11428
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11429
 *
11430
 * Compile a relative location path.
11431
 */
11432
static void
11433
xmlXPathCompRelativeLocationPath
11434
6.48M
(xmlXPathParserContextPtr ctxt) {
11435
6.48M
    SKIP_BLANKS;
11436
6.48M
    if ((CUR == '/') && (NXT(1) == '/')) {
11437
8
  SKIP(2);
11438
8
  SKIP_BLANKS;
11439
8
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11440
8
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11441
6.48M
    } else if (CUR == '/') {
11442
593
      NEXT;
11443
593
  SKIP_BLANKS;
11444
593
    }
11445
6.48M
    xmlXPathCompStep(ctxt);
11446
6.48M
    CHECK_ERROR;
11447
6.48M
    SKIP_BLANKS;
11448
7.67M
    while (CUR == '/') {
11449
1.19M
  if ((CUR == '/') && (NXT(1) == '/')) {
11450
18.9k
      SKIP(2);
11451
18.9k
      SKIP_BLANKS;
11452
18.9k
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11453
18.9k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11454
18.9k
      xmlXPathCompStep(ctxt);
11455
1.17M
  } else if (CUR == '/') {
11456
1.17M
      NEXT;
11457
1.17M
      SKIP_BLANKS;
11458
1.17M
      xmlXPathCompStep(ctxt);
11459
1.17M
  }
11460
1.19M
  SKIP_BLANKS;
11461
1.19M
    }
11462
6.48M
}
11463
11464
/**
11465
 * xmlXPathCompLocationPath:
11466
 * @ctxt:  the XPath Parser context
11467
 *
11468
 *  [1]   LocationPath ::=   RelativeLocationPath
11469
 *                     | AbsoluteLocationPath
11470
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11471
 *                     | AbbreviatedAbsoluteLocationPath
11472
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11473
 *                           '//' RelativeLocationPath
11474
 *
11475
 * Compile a location path
11476
 *
11477
 * // is short for /descendant-or-self::node()/. For example,
11478
 * //para is short for /descendant-or-self::node()/child::para and
11479
 * so will select any para element in the document (even a para element
11480
 * that is a document element will be selected by //para since the
11481
 * document element node is a child of the root node); div//para is
11482
 * short for div/descendant-or-self::node()/child::para and so will
11483
 * select all para descendants of div children.
11484
 */
11485
static void
11486
6.49M
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11487
6.49M
    SKIP_BLANKS;
11488
6.49M
    if (CUR != '/') {
11489
6.47M
        xmlXPathCompRelativeLocationPath(ctxt);
11490
6.47M
    } else {
11491
34.6k
  while (CUR == '/') {
11492
17.8k
      if ((CUR == '/') && (NXT(1) == '/')) {
11493
5.69k
    SKIP(2);
11494
5.69k
    SKIP_BLANKS;
11495
5.69k
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11496
5.69k
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11497
5.69k
    xmlXPathCompRelativeLocationPath(ctxt);
11498
12.1k
      } else if (CUR == '/') {
11499
12.1k
    NEXT;
11500
12.1k
    SKIP_BLANKS;
11501
12.1k
    if ((CUR != 0 ) &&
11502
12.1k
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11503
11.8k
         (CUR == '@') || (CUR == '*')))
11504
3.37k
        xmlXPathCompRelativeLocationPath(ctxt);
11505
12.1k
      }
11506
17.8k
      CHECK_ERROR;
11507
17.8k
  }
11508
17.8k
    }
11509
6.49M
}
11510
11511
/************************************************************************
11512
 *                  *
11513
 *    XPath precompiled expression evaluation     *
11514
 *                  *
11515
 ************************************************************************/
11516
11517
static int
11518
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11519
11520
#ifdef DEBUG_STEP
11521
static void
11522
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11523
        int nbNodes)
11524
{
11525
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11526
    switch (op->value) {
11527
        case AXIS_ANCESTOR:
11528
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11529
            break;
11530
        case AXIS_ANCESTOR_OR_SELF:
11531
            xmlGenericError(xmlGenericErrorContext,
11532
                            "axis 'ancestors-or-self' ");
11533
            break;
11534
        case AXIS_ATTRIBUTE:
11535
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11536
            break;
11537
        case AXIS_CHILD:
11538
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11539
            break;
11540
        case AXIS_DESCENDANT:
11541
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11542
            break;
11543
        case AXIS_DESCENDANT_OR_SELF:
11544
            xmlGenericError(xmlGenericErrorContext,
11545
                            "axis 'descendant-or-self' ");
11546
            break;
11547
        case AXIS_FOLLOWING:
11548
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11549
            break;
11550
        case AXIS_FOLLOWING_SIBLING:
11551
            xmlGenericError(xmlGenericErrorContext,
11552
                            "axis 'following-siblings' ");
11553
            break;
11554
        case AXIS_NAMESPACE:
11555
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11556
            break;
11557
        case AXIS_PARENT:
11558
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11559
            break;
11560
        case AXIS_PRECEDING:
11561
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11562
            break;
11563
        case AXIS_PRECEDING_SIBLING:
11564
            xmlGenericError(xmlGenericErrorContext,
11565
                            "axis 'preceding-sibling' ");
11566
            break;
11567
        case AXIS_SELF:
11568
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11569
            break;
11570
    }
11571
    xmlGenericError(xmlGenericErrorContext,
11572
  " context contains %d nodes\n", nbNodes);
11573
    switch (op->value2) {
11574
        case NODE_TEST_NONE:
11575
            xmlGenericError(xmlGenericErrorContext,
11576
                            "           searching for none !!!\n");
11577
            break;
11578
        case NODE_TEST_TYPE:
11579
            xmlGenericError(xmlGenericErrorContext,
11580
                            "           searching for type %d\n", op->value3);
11581
            break;
11582
        case NODE_TEST_PI:
11583
            xmlGenericError(xmlGenericErrorContext,
11584
                            "           searching for PI !!!\n");
11585
            break;
11586
        case NODE_TEST_ALL:
11587
            xmlGenericError(xmlGenericErrorContext,
11588
                            "           searching for *\n");
11589
            break;
11590
        case NODE_TEST_NS:
11591
            xmlGenericError(xmlGenericErrorContext,
11592
                            "           searching for namespace %s\n",
11593
                            op->value5);
11594
            break;
11595
        case NODE_TEST_NAME:
11596
            xmlGenericError(xmlGenericErrorContext,
11597
                            "           searching for name %s\n", op->value5);
11598
            if (op->value4)
11599
                xmlGenericError(xmlGenericErrorContext,
11600
                                "           with namespace %s\n", op->value4);
11601
            break;
11602
    }
11603
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11604
}
11605
#endif /* DEBUG_STEP */
11606
11607
/**
11608
 * xmlXPathNodeSetFilter:
11609
 * @ctxt:  the XPath Parser context
11610
 * @set: the node set to filter
11611
 * @filterOpIndex: the index of the predicate/filter op
11612
 * @minPos: minimum position in the filtered set (1-based)
11613
 * @maxPos: maximum position in the filtered set (1-based)
11614
 * @hasNsNodes: true if the node set may contain namespace nodes
11615
 *
11616
 * Filter a node set, keeping only nodes for which the predicate expression
11617
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11618
 * filtered result.
11619
 */
11620
static void
11621
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11622
          xmlNodeSetPtr set,
11623
          int filterOpIndex,
11624
                      int minPos, int maxPos,
11625
          int hasNsNodes)
11626
3.55k
{
11627
3.55k
    xmlXPathContextPtr xpctxt;
11628
3.55k
    xmlNodePtr oldnode;
11629
3.55k
    xmlDocPtr olddoc;
11630
3.55k
    xmlXPathStepOpPtr filterOp;
11631
3.55k
    int oldcs, oldpp;
11632
3.55k
    int i, j, pos;
11633
11634
3.55k
    if ((set == NULL) || (set->nodeNr == 0))
11635
12
        return;
11636
11637
    /*
11638
    * Check if the node set contains a sufficient number of nodes for
11639
    * the requested range.
11640
    */
11641
3.54k
    if (set->nodeNr < minPos) {
11642
0
        xmlXPathNodeSetClear(set, hasNsNodes);
11643
0
        return;
11644
0
    }
11645
11646
3.54k
    xpctxt = ctxt->context;
11647
3.54k
    oldnode = xpctxt->node;
11648
3.54k
    olddoc = xpctxt->doc;
11649
3.54k
    oldcs = xpctxt->contextSize;
11650
3.54k
    oldpp = xpctxt->proximityPosition;
11651
3.54k
    filterOp = &ctxt->comp->steps[filterOpIndex];
11652
11653
3.54k
    xpctxt->contextSize = set->nodeNr;
11654
11655
133k
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11656
132k
        xmlNodePtr node = set->nodeTab[i];
11657
132k
        int res;
11658
11659
132k
        xpctxt->node = node;
11660
132k
        xpctxt->proximityPosition = i + 1;
11661
11662
        /*
11663
        * Also set the xpath document in case things like
11664
        * key() are evaluated in the predicate.
11665
        *
11666
        * TODO: Get real doc for namespace nodes.
11667
        */
11668
132k
        if ((node->type != XML_NAMESPACE_DECL) &&
11669
132k
            (node->doc != NULL))
11670
132k
            xpctxt->doc = node->doc;
11671
11672
132k
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11673
11674
132k
        if (ctxt->error != XPATH_EXPRESSION_OK)
11675
65
            break;
11676
132k
        if (res < 0) {
11677
            /* Shouldn't happen */
11678
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11679
0
            break;
11680
0
        }
11681
11682
132k
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11683
121k
            if (i != j) {
11684
132
                set->nodeTab[j] = node;
11685
132
                set->nodeTab[i] = NULL;
11686
132
            }
11687
11688
121k
            j += 1;
11689
121k
        } else {
11690
            /* Remove the entry from the initial node set. */
11691
10.3k
            set->nodeTab[i] = NULL;
11692
10.3k
            if (node->type == XML_NAMESPACE_DECL)
11693
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11694
10.3k
        }
11695
11696
132k
        if (res != 0) {
11697
121k
            if (pos == maxPos) {
11698
2.43k
                i += 1;
11699
2.43k
                break;
11700
2.43k
            }
11701
11702
119k
            pos += 1;
11703
119k
        }
11704
132k
    }
11705
11706
    /* Free remaining nodes. */
11707
3.54k
    if (hasNsNodes) {
11708
258
        for (; i < set->nodeNr; i++) {
11709
177
            xmlNodePtr node = set->nodeTab[i];
11710
177
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11711
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11712
177
        }
11713
81
    }
11714
11715
3.54k
    set->nodeNr = j;
11716
11717
    /* If too many elements were removed, shrink table to preserve memory. */
11718
3.54k
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11719
3.54k
        (set->nodeNr < set->nodeMax / 2)) {
11720
783
        xmlNodePtr *tmp;
11721
783
        int nodeMax = set->nodeNr;
11722
11723
783
        if (nodeMax < XML_NODESET_DEFAULT)
11724
772
            nodeMax = XML_NODESET_DEFAULT;
11725
783
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11726
783
                nodeMax * sizeof(xmlNodePtr));
11727
783
        if (tmp == NULL) {
11728
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11729
783
        } else {
11730
783
            set->nodeTab = tmp;
11731
783
            set->nodeMax = nodeMax;
11732
783
        }
11733
783
    }
11734
11735
3.54k
    xpctxt->node = oldnode;
11736
3.54k
    xpctxt->doc = olddoc;
11737
3.54k
    xpctxt->contextSize = oldcs;
11738
3.54k
    xpctxt->proximityPosition = oldpp;
11739
3.54k
}
11740
11741
#ifdef LIBXML_XPTR_LOCS_ENABLED
11742
/**
11743
 * xmlXPathLocationSetFilter:
11744
 * @ctxt:  the XPath Parser context
11745
 * @locset: the location set to filter
11746
 * @filterOpIndex: the index of the predicate/filter op
11747
 * @minPos: minimum position in the filtered set (1-based)
11748
 * @maxPos: maximum position in the filtered set (1-based)
11749
 *
11750
 * Filter a location set, keeping only nodes for which the predicate
11751
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11752
 * in the filtered result.
11753
 */
11754
static void
11755
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11756
              xmlLocationSetPtr locset,
11757
              int filterOpIndex,
11758
                          int minPos, int maxPos)
11759
{
11760
    xmlXPathContextPtr xpctxt;
11761
    xmlNodePtr oldnode;
11762
    xmlDocPtr olddoc;
11763
    xmlXPathStepOpPtr filterOp;
11764
    int oldcs, oldpp;
11765
    int i, j, pos;
11766
11767
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11768
        return;
11769
11770
    xpctxt = ctxt->context;
11771
    oldnode = xpctxt->node;
11772
    olddoc = xpctxt->doc;
11773
    oldcs = xpctxt->contextSize;
11774
    oldpp = xpctxt->proximityPosition;
11775
    filterOp = &ctxt->comp->steps[filterOpIndex];
11776
11777
    xpctxt->contextSize = locset->locNr;
11778
11779
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11780
        xmlNodePtr contextNode = locset->locTab[i]->user;
11781
        int res;
11782
11783
        xpctxt->node = contextNode;
11784
        xpctxt->proximityPosition = i + 1;
11785
11786
        /*
11787
        * Also set the xpath document in case things like
11788
        * key() are evaluated in the predicate.
11789
        *
11790
        * TODO: Get real doc for namespace nodes.
11791
        */
11792
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11793
            (contextNode->doc != NULL))
11794
            xpctxt->doc = contextNode->doc;
11795
11796
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11797
11798
        if (ctxt->error != XPATH_EXPRESSION_OK)
11799
            break;
11800
        if (res < 0) {
11801
            /* Shouldn't happen */
11802
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11803
            break;
11804
        }
11805
11806
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11807
            if (i != j) {
11808
                locset->locTab[j] = locset->locTab[i];
11809
                locset->locTab[i] = NULL;
11810
            }
11811
11812
            j += 1;
11813
        } else {
11814
            /* Remove the entry from the initial location set. */
11815
            xmlXPathFreeObject(locset->locTab[i]);
11816
            locset->locTab[i] = NULL;
11817
        }
11818
11819
        if (res != 0) {
11820
            if (pos == maxPos) {
11821
                i += 1;
11822
                break;
11823
            }
11824
11825
            pos += 1;
11826
        }
11827
    }
11828
11829
    /* Free remaining nodes. */
11830
    for (; i < locset->locNr; i++)
11831
        xmlXPathFreeObject(locset->locTab[i]);
11832
11833
    locset->locNr = j;
11834
11835
    /* If too many elements were removed, shrink table to preserve memory. */
11836
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11837
        (locset->locNr < locset->locMax / 2)) {
11838
        xmlXPathObjectPtr *tmp;
11839
        int locMax = locset->locNr;
11840
11841
        if (locMax < XML_NODESET_DEFAULT)
11842
            locMax = XML_NODESET_DEFAULT;
11843
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11844
                locMax * sizeof(xmlXPathObjectPtr));
11845
        if (tmp == NULL) {
11846
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11847
        } else {
11848
            locset->locTab = tmp;
11849
            locset->locMax = locMax;
11850
        }
11851
    }
11852
11853
    xpctxt->node = oldnode;
11854
    xpctxt->doc = olddoc;
11855
    xpctxt->contextSize = oldcs;
11856
    xpctxt->proximityPosition = oldpp;
11857
}
11858
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11859
11860
/**
11861
 * xmlXPathCompOpEvalPredicate:
11862
 * @ctxt:  the XPath Parser context
11863
 * @op: the predicate op
11864
 * @set: the node set to filter
11865
 * @minPos: minimum position in the filtered set (1-based)
11866
 * @maxPos: maximum position in the filtered set (1-based)
11867
 * @hasNsNodes: true if the node set may contain namespace nodes
11868
 *
11869
 * Filter a node set, keeping only nodes for which the sequence of predicate
11870
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11871
 * in the filtered result.
11872
 */
11873
static void
11874
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11875
          xmlXPathStepOpPtr op,
11876
          xmlNodeSetPtr set,
11877
                            int minPos, int maxPos,
11878
          int hasNsNodes)
11879
3.47k
{
11880
3.47k
    if (op->ch1 != -1) {
11881
444
  xmlXPathCompExprPtr comp = ctxt->comp;
11882
  /*
11883
  * Process inner predicates first.
11884
  */
11885
444
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11886
0
            xmlGenericError(xmlGenericErrorContext,
11887
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11888
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11889
0
  }
11890
444
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11891
444
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11892
444
        ctxt->context->depth += 1;
11893
444
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11894
444
                                    1, set->nodeNr, hasNsNodes);
11895
444
        ctxt->context->depth -= 1;
11896
444
  CHECK_ERROR;
11897
444
    }
11898
11899
3.46k
    if (op->ch2 != -1)
11900
3.46k
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11901
3.46k
}
11902
11903
static int
11904
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11905
          xmlXPathStepOpPtr op,
11906
          int *maxPos)
11907
2.52k
{
11908
11909
2.52k
    xmlXPathStepOpPtr exprOp;
11910
11911
    /*
11912
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11913
    */
11914
11915
    /*
11916
    * If not -1, then ch1 will point to:
11917
    * 1) For predicates (XPATH_OP_PREDICATE):
11918
    *    - an inner predicate operator
11919
    * 2) For filters (XPATH_OP_FILTER):
11920
    *    - an inner filter operator OR
11921
    *    - an expression selecting the node set.
11922
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11923
    */
11924
2.52k
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11925
0
  return(0);
11926
11927
2.52k
    if (op->ch2 != -1) {
11928
2.52k
  exprOp = &ctxt->comp->steps[op->ch2];
11929
2.52k
    } else
11930
0
  return(0);
11931
11932
2.52k
    if ((exprOp != NULL) &&
11933
2.52k
  (exprOp->op == XPATH_OP_VALUE) &&
11934
2.52k
  (exprOp->value4 != NULL) &&
11935
2.52k
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11936
1.28k
    {
11937
1.28k
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11938
11939
  /*
11940
  * We have a "[n]" predicate here.
11941
  * TODO: Unfortunately this simplistic test here is not
11942
  * able to detect a position() predicate in compound
11943
  * expressions like "[@attr = 'a" and position() = 1],
11944
  * and even not the usage of position() in
11945
  * "[position() = 1]"; thus - obviously - a position-range,
11946
  * like it "[position() < 5]", is also not detected.
11947
  * Maybe we could rewrite the AST to ease the optimization.
11948
  */
11949
11950
1.28k
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11951
913
      *maxPos = (int) floatval;
11952
913
            if (floatval == (double) *maxPos)
11953
913
                return(1);
11954
913
        }
11955
1.28k
    }
11956
1.60k
    return(0);
11957
2.52k
}
11958
11959
static int
11960
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11961
                           xmlXPathStepOpPtr op,
11962
         xmlNodePtr * first, xmlNodePtr * last,
11963
         int toBool)
11964
38.5k
{
11965
11966
38.5k
#define XP_TEST_HIT \
11967
4.68M
    if (hasAxisRange != 0) { \
11968
6
  if (++pos == maxPos) { \
11969
6
      if (addNode(seq, cur) < 0) \
11970
6
          ctxt->error = XPATH_MEMORY_ERROR; \
11971
6
      goto axis_range_end; } \
11972
4.68M
    } else { \
11973
4.68M
  if (addNode(seq, cur) < 0) \
11974
4.68M
      ctxt->error = XPATH_MEMORY_ERROR; \
11975
4.68M
  if (breakOnFirstHit) goto first_hit; }
11976
11977
38.5k
#define XP_TEST_HIT_NS \
11978
38.5k
    if (hasAxisRange != 0) { \
11979
0
  if (++pos == maxPos) { \
11980
0
      hasNsNodes = 1; \
11981
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11982
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11983
0
  goto axis_range_end; } \
11984
86
    } else { \
11985
86
  hasNsNodes = 1; \
11986
86
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11987
86
      ctxt->error = XPATH_MEMORY_ERROR; \
11988
86
  if (breakOnFirstHit) goto first_hit; }
11989
11990
38.5k
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11991
38.5k
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11992
38.5k
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11993
38.5k
    const xmlChar *prefix = op->value4;
11994
38.5k
    const xmlChar *name = op->value5;
11995
38.5k
    const xmlChar *URI = NULL;
11996
11997
#ifdef DEBUG_STEP
11998
    int nbMatches = 0, prevMatches = 0;
11999
#endif
12000
38.5k
    int total = 0, hasNsNodes = 0;
12001
    /* The popped object holding the context nodes */
12002
38.5k
    xmlXPathObjectPtr obj;
12003
    /* The set of context nodes for the node tests */
12004
38.5k
    xmlNodeSetPtr contextSeq;
12005
38.5k
    int contextIdx;
12006
38.5k
    xmlNodePtr contextNode;
12007
    /* The final resulting node set wrt to all context nodes */
12008
38.5k
    xmlNodeSetPtr outSeq;
12009
    /*
12010
    * The temporary resulting node set wrt 1 context node.
12011
    * Used to feed predicate evaluation.
12012
    */
12013
38.5k
    xmlNodeSetPtr seq;
12014
38.5k
    xmlNodePtr cur;
12015
    /* First predicate operator */
12016
38.5k
    xmlXPathStepOpPtr predOp;
12017
38.5k
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12018
38.5k
    int hasPredicateRange, hasAxisRange, pos;
12019
38.5k
    int breakOnFirstHit;
12020
12021
38.5k
    xmlXPathTraversalFunction next = NULL;
12022
38.5k
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12023
38.5k
    xmlXPathNodeSetMergeFunction mergeAndClear;
12024
38.5k
    xmlNodePtr oldContextNode;
12025
38.5k
    xmlXPathContextPtr xpctxt = ctxt->context;
12026
12027
12028
38.5k
    CHECK_TYPE0(XPATH_NODESET);
12029
38.5k
    obj = valuePop(ctxt);
12030
    /*
12031
    * Setup namespaces.
12032
    */
12033
38.5k
    if (prefix != NULL) {
12034
4.32k
        URI = xmlXPathNsLookup(xpctxt, prefix);
12035
4.32k
        if (URI == NULL) {
12036
65
      xmlXPathReleaseObject(xpctxt, obj);
12037
65
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12038
0
  }
12039
4.32k
    }
12040
    /*
12041
    * Setup axis.
12042
    *
12043
    * MAYBE FUTURE TODO: merging optimizations:
12044
    * - If the nodes to be traversed wrt to the initial nodes and
12045
    *   the current axis cannot overlap, then we could avoid searching
12046
    *   for duplicates during the merge.
12047
    *   But the question is how/when to evaluate if they cannot overlap.
12048
    *   Example: if we know that for two initial nodes, the one is
12049
    *   not in the ancestor-or-self axis of the other, then we could safely
12050
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12051
    *   the descendant-or-self axis.
12052
    */
12053
38.5k
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12054
38.5k
    switch (axis) {
12055
0
        case AXIS_ANCESTOR:
12056
0
            first = NULL;
12057
0
            next = xmlXPathNextAncestor;
12058
0
            break;
12059
2
        case AXIS_ANCESTOR_OR_SELF:
12060
2
            first = NULL;
12061
2
            next = xmlXPathNextAncestorOrSelf;
12062
2
            break;
12063
1.28k
        case AXIS_ATTRIBUTE:
12064
1.28k
            first = NULL;
12065
1.28k
      last = NULL;
12066
1.28k
            next = xmlXPathNextAttribute;
12067
1.28k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12068
1.28k
            break;
12069
22.1k
        case AXIS_CHILD:
12070
22.1k
      last = NULL;
12071
22.1k
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12072
22.1k
    (type == NODE_TYPE_NODE))
12073
14.8k
      {
12074
    /*
12075
    * Optimization if an element node type is 'element'.
12076
    */
12077
14.8k
    next = xmlXPathNextChildElement;
12078
14.8k
      } else
12079
7.27k
    next = xmlXPathNextChild;
12080
22.1k
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12081
22.1k
            break;
12082
5.06k
        case AXIS_DESCENDANT:
12083
5.06k
      last = NULL;
12084
5.06k
            next = xmlXPathNextDescendant;
12085
5.06k
            break;
12086
1.47k
        case AXIS_DESCENDANT_OR_SELF:
12087
1.47k
      last = NULL;
12088
1.47k
            next = xmlXPathNextDescendantOrSelf;
12089
1.47k
            break;
12090
0
        case AXIS_FOLLOWING:
12091
0
      last = NULL;
12092
0
            next = xmlXPathNextFollowing;
12093
0
            break;
12094
0
        case AXIS_FOLLOWING_SIBLING:
12095
0
      last = NULL;
12096
0
            next = xmlXPathNextFollowingSibling;
12097
0
            break;
12098
396
        case AXIS_NAMESPACE:
12099
396
            first = NULL;
12100
396
      last = NULL;
12101
396
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12102
396
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12103
396
            break;
12104
6.40k
        case AXIS_PARENT:
12105
6.40k
            first = NULL;
12106
6.40k
            next = xmlXPathNextParent;
12107
6.40k
            break;
12108
1.62k
        case AXIS_PRECEDING:
12109
1.62k
            first = NULL;
12110
1.62k
            next = xmlXPathNextPrecedingInternal;
12111
1.62k
            break;
12112
118
        case AXIS_PRECEDING_SIBLING:
12113
118
            first = NULL;
12114
118
            next = xmlXPathNextPrecedingSibling;
12115
118
            break;
12116
2
        case AXIS_SELF:
12117
2
            first = NULL;
12118
2
      last = NULL;
12119
2
            next = xmlXPathNextSelf;
12120
2
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12121
2
            break;
12122
38.5k
    }
12123
12124
#ifdef DEBUG_STEP
12125
    xmlXPathDebugDumpStepAxis(op,
12126
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12127
#endif
12128
12129
38.5k
    if (next == NULL) {
12130
0
  xmlXPathReleaseObject(xpctxt, obj);
12131
0
        return(0);
12132
0
    }
12133
38.5k
    contextSeq = obj->nodesetval;
12134
38.5k
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12135
4.26k
  xmlXPathReleaseObject(xpctxt, obj);
12136
4.26k
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12137
4.26k
        return(0);
12138
4.26k
    }
12139
    /*
12140
    * Predicate optimization ---------------------------------------------
12141
    * If this step has a last predicate, which contains a position(),
12142
    * then we'll optimize (although not exactly "position()", but only
12143
    * the  short-hand form, i.e., "[n]".
12144
    *
12145
    * Example - expression "/foo[parent::bar][1]":
12146
    *
12147
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12148
    *   ROOT                               -- op->ch1
12149
    *   PREDICATE                          -- op->ch2 (predOp)
12150
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12151
    *       SORT
12152
    *         COLLECT  'parent' 'name' 'node' bar
12153
    *           NODE
12154
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12155
    *
12156
    */
12157
34.2k
    maxPos = 0;
12158
34.2k
    predOp = NULL;
12159
34.2k
    hasPredicateRange = 0;
12160
34.2k
    hasAxisRange = 0;
12161
34.2k
    if (op->ch2 != -1) {
12162
  /*
12163
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12164
  */
12165
2.52k
  predOp = &ctxt->comp->steps[op->ch2];
12166
2.52k
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12167
913
      if (predOp->ch1 != -1) {
12168
    /*
12169
    * Use the next inner predicate operator.
12170
    */
12171
195
    predOp = &ctxt->comp->steps[predOp->ch1];
12172
195
    hasPredicateRange = 1;
12173
718
      } else {
12174
    /*
12175
    * There's no other predicate than the [n] predicate.
12176
    */
12177
718
    predOp = NULL;
12178
718
    hasAxisRange = 1;
12179
718
      }
12180
913
  }
12181
2.52k
    }
12182
34.2k
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12183
    /*
12184
    * Axis traversal -----------------------------------------------------
12185
    */
12186
    /*
12187
     * 2.3 Node Tests
12188
     *  - For the attribute axis, the principal node type is attribute.
12189
     *  - For the namespace axis, the principal node type is namespace.
12190
     *  - For other axes, the principal node type is element.
12191
     *
12192
     * A node test * is true for any node of the
12193
     * principal node type. For example, child::* will
12194
     * select all element children of the context node
12195
     */
12196
34.2k
    oldContextNode = xpctxt->node;
12197
34.2k
    addNode = xmlXPathNodeSetAddUnique;
12198
34.2k
    outSeq = NULL;
12199
34.2k
    seq = NULL;
12200
34.2k
    contextNode = NULL;
12201
34.2k
    contextIdx = 0;
12202
12203
12204
452k
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12205
452k
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12206
418k
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12207
12208
418k
  if (seq == NULL) {
12209
34.6k
      seq = xmlXPathNodeSetCreate(NULL);
12210
34.6k
      if (seq == NULL) {
12211
                /* TODO: Propagate memory error. */
12212
0
    total = 0;
12213
0
    goto error;
12214
0
      }
12215
34.6k
  }
12216
  /*
12217
  * Traverse the axis and test the nodes.
12218
  */
12219
418k
  pos = 0;
12220
418k
  cur = NULL;
12221
418k
  hasNsNodes = 0;
12222
5.41M
        do {
12223
5.41M
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12224
15
                goto error;
12225
12226
5.41M
            cur = next(ctxt, cur);
12227
5.41M
            if (cur == NULL)
12228
418k
                break;
12229
12230
      /*
12231
      * QUESTION TODO: What does the "first" and "last" stuff do?
12232
      */
12233
4.99M
            if ((first != NULL) && (*first != NULL)) {
12234
494
    if (*first == cur)
12235
0
        break;
12236
494
    if (((total % 256) == 0) &&
12237
494
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12238
494
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12239
#else
12240
        (xmlXPathCmpNodes(*first, cur) >= 0))
12241
#endif
12242
0
    {
12243
0
        break;
12244
0
    }
12245
494
      }
12246
4.99M
      if ((last != NULL) && (*last != NULL)) {
12247
0
    if (*last == cur)
12248
0
        break;
12249
0
    if (((total % 256) == 0) &&
12250
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12251
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12252
#else
12253
        (xmlXPathCmpNodes(cur, *last) >= 0))
12254
#endif
12255
0
    {
12256
0
        break;
12257
0
    }
12258
0
      }
12259
12260
4.99M
            total++;
12261
12262
#ifdef DEBUG_STEP
12263
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12264
#endif
12265
12266
4.99M
      switch (test) {
12267
0
                case NODE_TEST_NONE:
12268
0
        total = 0;
12269
0
                    STRANGE
12270
0
        goto error;
12271
4.58M
                case NODE_TEST_TYPE:
12272
4.58M
        if (type == NODE_TYPE_NODE) {
12273
4.55M
      switch (cur->type) {
12274
305k
          case XML_DOCUMENT_NODE:
12275
305k
          case XML_HTML_DOCUMENT_NODE:
12276
2.47M
          case XML_ELEMENT_NODE:
12277
2.47M
          case XML_ATTRIBUTE_NODE:
12278
2.47M
          case XML_PI_NODE:
12279
2.47M
          case XML_COMMENT_NODE:
12280
2.47M
          case XML_CDATA_SECTION_NODE:
12281
4.55M
          case XML_TEXT_NODE:
12282
4.55M
        XP_TEST_HIT
12283
4.55M
        break;
12284
4.55M
          case XML_NAMESPACE_DECL: {
12285
0
        if (axis == AXIS_NAMESPACE) {
12286
0
            XP_TEST_HIT_NS
12287
0
        } else {
12288
0
                              hasNsNodes = 1;
12289
0
            XP_TEST_HIT
12290
0
        }
12291
0
        break;
12292
0
                            }
12293
0
          default:
12294
0
        break;
12295
4.55M
      }
12296
4.55M
        } else if (cur->type == (xmlElementType) type) {
12297
12.4k
      if (cur->type == XML_NAMESPACE_DECL)
12298
0
          XP_TEST_HIT_NS
12299
12.4k
      else
12300
12.4k
          XP_TEST_HIT
12301
13.1k
        } else if ((type == NODE_TYPE_TEXT) &&
12302
13.1k
       (cur->type == XML_CDATA_SECTION_NODE))
12303
188
        {
12304
188
      XP_TEST_HIT
12305
188
        }
12306
4.58M
        break;
12307
4.58M
                case NODE_TEST_PI:
12308
0
                    if ((cur->type == XML_PI_NODE) &&
12309
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12310
0
        {
12311
0
      XP_TEST_HIT
12312
0
                    }
12313
0
                    break;
12314
148k
                case NODE_TEST_ALL:
12315
148k
                    if (axis == AXIS_ATTRIBUTE) {
12316
50
                        if (cur->type == XML_ATTRIBUTE_NODE)
12317
50
      {
12318
50
                            if (prefix == NULL)
12319
50
          {
12320
50
        XP_TEST_HIT
12321
50
                            } else if ((cur->ns != NULL) &&
12322
0
        (xmlStrEqual(URI, cur->ns->href)))
12323
0
          {
12324
0
        XP_TEST_HIT
12325
0
                            }
12326
50
                        }
12327
148k
                    } else if (axis == AXIS_NAMESPACE) {
12328
86
                        if (cur->type == XML_NAMESPACE_DECL)
12329
86
      {
12330
86
          XP_TEST_HIT_NS
12331
86
                        }
12332
148k
                    } else {
12333
148k
                        if (cur->type == XML_ELEMENT_NODE) {
12334
115k
                            if (prefix == NULL)
12335
109k
          {
12336
109k
        XP_TEST_HIT
12337
12338
109k
                            } else if ((cur->ns != NULL) &&
12339
5.96k
        (xmlStrEqual(URI, cur->ns->href)))
12340
2.29k
          {
12341
2.29k
        XP_TEST_HIT
12342
2.29k
                            }
12343
115k
                        }
12344
148k
                    }
12345
148k
                    break;
12346
148k
                case NODE_TEST_NS:{
12347
0
                        TODO;
12348
0
                        break;
12349
148k
                    }
12350
265k
                case NODE_TEST_NAME:
12351
265k
                    if (axis == AXIS_ATTRIBUTE) {
12352
2.46k
                        if (cur->type != XML_ATTRIBUTE_NODE)
12353
0
          break;
12354
263k
        } else if (axis == AXIS_NAMESPACE) {
12355
0
                        if (cur->type != XML_NAMESPACE_DECL)
12356
0
          break;
12357
263k
        } else {
12358
263k
            if (cur->type != XML_ELEMENT_NODE)
12359
179k
          break;
12360
263k
        }
12361
86.4k
                    switch (cur->type) {
12362
83.9k
                        case XML_ELEMENT_NODE:
12363
83.9k
                            if (xmlStrEqual(name, cur->name)) {
12364
4.23k
                                if (prefix == NULL) {
12365
519
                                    if (cur->ns == NULL)
12366
231
            {
12367
231
          XP_TEST_HIT
12368
231
                                    }
12369
3.71k
                                } else {
12370
3.71k
                                    if ((cur->ns != NULL) &&
12371
3.71k
                                        (xmlStrEqual(URI, cur->ns->href)))
12372
1.85k
            {
12373
1.85k
          XP_TEST_HIT
12374
1.85k
                                    }
12375
3.71k
                                }
12376
4.23k
                            }
12377
83.9k
                            break;
12378
83.9k
                        case XML_ATTRIBUTE_NODE:{
12379
2.46k
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12380
12381
2.46k
                                if (xmlStrEqual(name, attr->name)) {
12382
351
                                    if (prefix == NULL) {
12383
351
                                        if ((attr->ns == NULL) ||
12384
351
                                            (attr->ns->prefix == NULL))
12385
351
          {
12386
351
              XP_TEST_HIT
12387
351
                                        }
12388
351
                                    } else {
12389
0
                                        if ((attr->ns != NULL) &&
12390
0
                                            (xmlStrEqual(URI,
12391
0
                attr->ns->href)))
12392
0
          {
12393
0
              XP_TEST_HIT
12394
0
                                        }
12395
0
                                    }
12396
351
                                }
12397
2.46k
                                break;
12398
2.46k
                            }
12399
2.46k
                        case XML_NAMESPACE_DECL:
12400
0
                            if (cur->type == XML_NAMESPACE_DECL) {
12401
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
12402
12403
0
                                if ((ns->prefix != NULL) && (name != NULL)
12404
0
                                    && (xmlStrEqual(ns->prefix, name)))
12405
0
        {
12406
0
            XP_TEST_HIT_NS
12407
0
                                }
12408
0
                            }
12409
0
                            break;
12410
0
                        default:
12411
0
                            break;
12412
86.4k
                    }
12413
86.4k
                    break;
12414
4.99M
      } /* switch(test) */
12415
4.99M
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12416
12417
418k
  goto apply_predicates;
12418
12419
418k
axis_range_end: /* ----------------------------------------------------- */
12420
  /*
12421
  * We have a "/foo[n]", and position() = n was reached.
12422
  * Note that we can have as well "/foo/::parent::foo[1]", so
12423
  * a duplicate-aware merge is still needed.
12424
  * Merge with the result.
12425
  */
12426
6
  if (outSeq == NULL) {
12427
3
      outSeq = seq;
12428
3
      seq = NULL;
12429
3
  } else
12430
            /* TODO: Check memory error. */
12431
3
      outSeq = mergeAndClear(outSeq, seq);
12432
  /*
12433
  * Break if only a true/false result was requested.
12434
  */
12435
6
  if (toBool)
12436
0
      break;
12437
6
  continue;
12438
12439
6
first_hit: /* ---------------------------------------------------------- */
12440
  /*
12441
  * Break if only a true/false result was requested and
12442
  * no predicates existed and a node test succeeded.
12443
  */
12444
4
  if (outSeq == NULL) {
12445
4
      outSeq = seq;
12446
4
      seq = NULL;
12447
4
  } else
12448
            /* TODO: Check memory error. */
12449
0
      outSeq = mergeAndClear(outSeq, seq);
12450
4
  break;
12451
12452
#ifdef DEBUG_STEP
12453
  if (seq != NULL)
12454
      nbMatches += seq->nodeNr;
12455
#endif
12456
12457
418k
apply_predicates: /* --------------------------------------------------- */
12458
418k
        if (ctxt->error != XPATH_EXPRESSION_OK)
12459
0
      goto error;
12460
12461
        /*
12462
  * Apply predicates.
12463
  */
12464
418k
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12465
      /*
12466
      * E.g. when we have a "/foo[some expression][n]".
12467
      */
12468
      /*
12469
      * QUESTION TODO: The old predicate evaluation took into
12470
      *  account location-sets.
12471
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12472
      *  Do we expect such a set here?
12473
      *  All what I learned now from the evaluation semantics
12474
      *  does not indicate that a location-set will be processed
12475
      *  here, so this looks OK.
12476
      */
12477
      /*
12478
      * Iterate over all predicates, starting with the outermost
12479
      * predicate.
12480
      * TODO: Problem: we cannot execute the inner predicates first
12481
      *  since we cannot go back *up* the operator tree!
12482
      *  Options we have:
12483
      *  1) Use of recursive functions (like is it currently done
12484
      *     via xmlXPathCompOpEval())
12485
      *  2) Add a predicate evaluation information stack to the
12486
      *     context struct
12487
      *  3) Change the way the operators are linked; we need a
12488
      *     "parent" field on xmlXPathStepOp
12489
      *
12490
      * For the moment, I'll try to solve this with a recursive
12491
      * function: xmlXPathCompOpEvalPredicate().
12492
      */
12493
3.02k
      if (hasPredicateRange != 0)
12494
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12495
0
              hasNsNodes);
12496
3.02k
      else
12497
3.02k
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12498
3.02k
              hasNsNodes);
12499
12500
3.02k
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12501
49
    total = 0;
12502
49
    goto error;
12503
49
      }
12504
3.02k
        }
12505
12506
418k
        if (seq->nodeNr > 0) {
12507
      /*
12508
      * Add to result set.
12509
      */
12510
272k
      if (outSeq == NULL) {
12511
15.4k
    outSeq = seq;
12512
15.4k
    seq = NULL;
12513
256k
      } else {
12514
                /* TODO: Check memory error. */
12515
256k
    outSeq = mergeAndClear(outSeq, seq);
12516
256k
      }
12517
12518
272k
            if (toBool)
12519
0
                break;
12520
272k
  }
12521
418k
    }
12522
12523
34.2k
error:
12524
34.2k
    if ((obj->boolval) && (obj->user != NULL)) {
12525
  /*
12526
  * QUESTION TODO: What does this do and why?
12527
  * TODO: Do we have to do this also for the "error"
12528
  * cleanup further down?
12529
  */
12530
0
  ctxt->value->boolval = 1;
12531
0
  ctxt->value->user = obj->user;
12532
0
  obj->user = NULL;
12533
0
  obj->boolval = 0;
12534
0
    }
12535
34.2k
    xmlXPathReleaseObject(xpctxt, obj);
12536
12537
    /*
12538
    * Ensure we return at least an empty set.
12539
    */
12540
34.2k
    if (outSeq == NULL) {
12541
18.7k
  if ((seq != NULL) && (seq->nodeNr == 0))
12542
18.7k
      outSeq = seq;
12543
9
  else
12544
            /* TODO: Check memory error. */
12545
9
      outSeq = xmlXPathNodeSetCreate(NULL);
12546
18.7k
    }
12547
34.2k
    if ((seq != NULL) && (seq != outSeq)) {
12548
436
   xmlXPathFreeNodeSet(seq);
12549
436
    }
12550
    /*
12551
    * Hand over the result. Better to push the set also in
12552
    * case of errors.
12553
    */
12554
34.2k
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12555
    /*
12556
    * Reset the context node.
12557
    */
12558
34.2k
    xpctxt->node = oldContextNode;
12559
    /*
12560
    * When traversing the namespace axis in "toBool" mode, it's
12561
    * possible that tmpNsList wasn't freed.
12562
    */
12563
34.2k
    if (xpctxt->tmpNsList != NULL) {
12564
0
        xmlFree(xpctxt->tmpNsList);
12565
0
        xpctxt->tmpNsList = NULL;
12566
0
    }
12567
12568
#ifdef DEBUG_STEP
12569
    xmlGenericError(xmlGenericErrorContext,
12570
  "\nExamined %d nodes, found %d nodes at that step\n",
12571
  total, nbMatches);
12572
#endif
12573
12574
34.2k
    return(total);
12575
34.2k
}
12576
12577
static int
12578
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12579
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12580
12581
/**
12582
 * xmlXPathCompOpEvalFirst:
12583
 * @ctxt:  the XPath parser context with the compiled expression
12584
 * @op:  an XPath compiled operation
12585
 * @first:  the first elem found so far
12586
 *
12587
 * Evaluate the Precompiled XPath operation searching only the first
12588
 * element in document order
12589
 *
12590
 * Returns the number of examined objects.
12591
 */
12592
static int
12593
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12594
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12595
85
{
12596
85
    int total = 0, cur;
12597
85
    xmlXPathCompExprPtr comp;
12598
85
    xmlXPathObjectPtr arg1, arg2;
12599
12600
85
    CHECK_ERROR0;
12601
85
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12602
0
        return(0);
12603
85
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12604
85
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12605
85
    ctxt->context->depth += 1;
12606
85
    comp = ctxt->comp;
12607
85
    switch (op->op) {
12608
0
        case XPATH_OP_END:
12609
0
            break;
12610
19
        case XPATH_OP_UNION:
12611
19
            total =
12612
19
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12613
19
                                        first);
12614
19
      CHECK_ERROR0;
12615
13
            if ((ctxt->value != NULL)
12616
13
                && (ctxt->value->type == XPATH_NODESET)
12617
13
                && (ctxt->value->nodesetval != NULL)
12618
13
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12619
                /*
12620
                 * limit tree traversing to first node in the result
12621
                 */
12622
    /*
12623
    * OPTIMIZE TODO: This implicitly sorts
12624
    *  the result, even if not needed. E.g. if the argument
12625
    *  of the count() function, no sorting is needed.
12626
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12627
    *  already sorted?
12628
    */
12629
13
    if (ctxt->value->nodesetval->nodeNr > 1)
12630
13
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12631
13
                *first = ctxt->value->nodesetval->nodeTab[0];
12632
13
            }
12633
13
            cur =
12634
13
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12635
13
                                        first);
12636
13
      CHECK_ERROR0;
12637
12638
13
            arg2 = valuePop(ctxt);
12639
13
            arg1 = valuePop(ctxt);
12640
13
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12641
13
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12642
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12643
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12644
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12645
0
            }
12646
13
            if ((ctxt->context->opLimit != 0) &&
12647
13
                (((arg1->nodesetval != NULL) &&
12648
13
                  (xmlXPathCheckOpLimit(ctxt,
12649
13
                                        arg1->nodesetval->nodeNr) < 0)) ||
12650
13
                 ((arg2->nodesetval != NULL) &&
12651
12
                  (xmlXPathCheckOpLimit(ctxt,
12652
12
                                        arg2->nodesetval->nodeNr) < 0)))) {
12653
1
          xmlXPathReleaseObject(ctxt->context, arg1);
12654
1
          xmlXPathReleaseObject(ctxt->context, arg2);
12655
1
                break;
12656
1
            }
12657
12658
            /* TODO: Check memory error. */
12659
12
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12660
12
                                                    arg2->nodesetval);
12661
12
            valuePush(ctxt, arg1);
12662
12
      xmlXPathReleaseObject(ctxt->context, arg2);
12663
            /* optimizer */
12664
12
      if (total > cur)
12665
0
    xmlXPathCompSwap(op);
12666
12
            total += cur;
12667
12
            break;
12668
0
        case XPATH_OP_ROOT:
12669
0
            xmlXPathRoot(ctxt);
12670
0
            break;
12671
0
        case XPATH_OP_NODE:
12672
0
            if (op->ch1 != -1)
12673
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12674
0
      CHECK_ERROR0;
12675
0
            if (op->ch2 != -1)
12676
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12677
0
      CHECK_ERROR0;
12678
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12679
0
    ctxt->context->node));
12680
0
            break;
12681
14
        case XPATH_OP_COLLECT:{
12682
14
                if (op->ch1 == -1)
12683
0
                    break;
12684
12685
14
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12686
14
    CHECK_ERROR0;
12687
12688
13
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12689
13
                break;
12690
14
            }
12691
0
        case XPATH_OP_VALUE:
12692
0
            valuePush(ctxt,
12693
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12694
0
      (xmlXPathObjectPtr) op->value4));
12695
0
            break;
12696
14
        case XPATH_OP_SORT:
12697
14
            if (op->ch1 != -1)
12698
14
                total +=
12699
14
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12700
14
                                            first);
12701
14
      CHECK_ERROR0;
12702
12
            if ((ctxt->value != NULL)
12703
12
                && (ctxt->value->type == XPATH_NODESET)
12704
12
                && (ctxt->value->nodesetval != NULL)
12705
12
    && (ctxt->value->nodesetval->nodeNr > 1))
12706
12
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12707
12
            break;
12708
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12709
25
  case XPATH_OP_FILTER:
12710
25
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12711
25
            break;
12712
0
#endif
12713
13
        default:
12714
13
            total += xmlXPathCompOpEval(ctxt, op);
12715
13
            break;
12716
85
    }
12717
12718
76
    ctxt->context->depth -= 1;
12719
76
    return(total);
12720
85
}
12721
12722
/**
12723
 * xmlXPathCompOpEvalLast:
12724
 * @ctxt:  the XPath parser context with the compiled expression
12725
 * @op:  an XPath compiled operation
12726
 * @last:  the last elem found so far
12727
 *
12728
 * Evaluate the Precompiled XPath operation searching only the last
12729
 * element in document order
12730
 *
12731
 * Returns the number of nodes traversed
12732
 */
12733
static int
12734
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12735
                       xmlNodePtr * last)
12736
8
{
12737
8
    int total = 0, cur;
12738
8
    xmlXPathCompExprPtr comp;
12739
8
    xmlXPathObjectPtr arg1, arg2;
12740
12741
8
    CHECK_ERROR0;
12742
8
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12743
0
        return(0);
12744
8
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12745
8
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12746
8
    ctxt->context->depth += 1;
12747
8
    comp = ctxt->comp;
12748
8
    switch (op->op) {
12749
0
        case XPATH_OP_END:
12750
0
            break;
12751
0
        case XPATH_OP_UNION:
12752
0
            total =
12753
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12754
0
      CHECK_ERROR0;
12755
0
            if ((ctxt->value != NULL)
12756
0
                && (ctxt->value->type == XPATH_NODESET)
12757
0
                && (ctxt->value->nodesetval != NULL)
12758
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12759
                /*
12760
                 * limit tree traversing to first node in the result
12761
                 */
12762
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12763
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12764
0
                *last =
12765
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12766
0
                                                     nodesetval->nodeNr -
12767
0
                                                     1];
12768
0
            }
12769
0
            cur =
12770
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12771
0
      CHECK_ERROR0;
12772
0
            if ((ctxt->value != NULL)
12773
0
                && (ctxt->value->type == XPATH_NODESET)
12774
0
                && (ctxt->value->nodesetval != NULL)
12775
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12776
0
            }
12777
12778
0
            arg2 = valuePop(ctxt);
12779
0
            arg1 = valuePop(ctxt);
12780
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12781
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12782
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12783
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12784
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12785
0
            }
12786
0
            if ((ctxt->context->opLimit != 0) &&
12787
0
                (((arg1->nodesetval != NULL) &&
12788
0
                  (xmlXPathCheckOpLimit(ctxt,
12789
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12790
0
                 ((arg2->nodesetval != NULL) &&
12791
0
                  (xmlXPathCheckOpLimit(ctxt,
12792
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12793
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12794
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12795
0
                break;
12796
0
            }
12797
12798
            /* TODO: Check memory error. */
12799
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12800
0
                                                    arg2->nodesetval);
12801
0
            valuePush(ctxt, arg1);
12802
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12803
            /* optimizer */
12804
0
      if (total > cur)
12805
0
    xmlXPathCompSwap(op);
12806
0
            total += cur;
12807
0
            break;
12808
0
        case XPATH_OP_ROOT:
12809
0
            xmlXPathRoot(ctxt);
12810
0
            break;
12811
0
        case XPATH_OP_NODE:
12812
0
            if (op->ch1 != -1)
12813
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12814
0
      CHECK_ERROR0;
12815
0
            if (op->ch2 != -1)
12816
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12817
0
      CHECK_ERROR0;
12818
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12819
0
    ctxt->context->node));
12820
0
            break;
12821
4
        case XPATH_OP_COLLECT:{
12822
4
                if (op->ch1 == -1)
12823
0
                    break;
12824
12825
4
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12826
4
    CHECK_ERROR0;
12827
12828
4
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12829
4
                break;
12830
4
            }
12831
0
        case XPATH_OP_VALUE:
12832
0
            valuePush(ctxt,
12833
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12834
0
      (xmlXPathObjectPtr) op->value4));
12835
0
            break;
12836
4
        case XPATH_OP_SORT:
12837
4
            if (op->ch1 != -1)
12838
4
                total +=
12839
4
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12840
4
                                           last);
12841
4
      CHECK_ERROR0;
12842
4
            if ((ctxt->value != NULL)
12843
4
                && (ctxt->value->type == XPATH_NODESET)
12844
4
                && (ctxt->value->nodesetval != NULL)
12845
4
    && (ctxt->value->nodesetval->nodeNr > 1))
12846
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12847
4
            break;
12848
0
        default:
12849
0
            total += xmlXPathCompOpEval(ctxt, op);
12850
0
            break;
12851
8
    }
12852
12853
8
    ctxt->context->depth -= 1;
12854
8
    return (total);
12855
8
}
12856
12857
#ifdef XP_OPTIMIZED_FILTER_FIRST
12858
static int
12859
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12860
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12861
25
{
12862
25
    int total = 0;
12863
25
    xmlXPathCompExprPtr comp;
12864
25
    xmlNodeSetPtr set;
12865
12866
25
    CHECK_ERROR0;
12867
25
    comp = ctxt->comp;
12868
    /*
12869
    * Optimization for ()[last()] selection i.e. the last elem
12870
    */
12871
25
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12872
25
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12873
25
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12874
22
  int f = comp->steps[op->ch2].ch1;
12875
12876
22
  if ((f != -1) &&
12877
22
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12878
22
      (comp->steps[f].value5 == NULL) &&
12879
22
      (comp->steps[f].value == 0) &&
12880
22
      (comp->steps[f].value4 != NULL) &&
12881
22
      (xmlStrEqual
12882
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
12883
0
      xmlNodePtr last = NULL;
12884
12885
0
      total +=
12886
0
    xmlXPathCompOpEvalLast(ctxt,
12887
0
        &comp->steps[op->ch1],
12888
0
        &last);
12889
0
      CHECK_ERROR0;
12890
      /*
12891
      * The nodeset should be in document order,
12892
      * Keep only the last value
12893
      */
12894
0
      if ((ctxt->value != NULL) &&
12895
0
    (ctxt->value->type == XPATH_NODESET) &&
12896
0
    (ctxt->value->nodesetval != NULL) &&
12897
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12898
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
12899
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12900
0
    *first = *(ctxt->value->nodesetval->nodeTab);
12901
0
      }
12902
0
      return (total);
12903
0
  }
12904
22
    }
12905
12906
25
    if (op->ch1 != -1)
12907
25
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12908
25
    CHECK_ERROR0;
12909
10
    if (op->ch2 == -1)
12910
0
  return (total);
12911
10
    if (ctxt->value == NULL)
12912
0
  return (total);
12913
12914
#ifdef LIBXML_XPTR_LOCS_ENABLED
12915
    /*
12916
    * Hum are we filtering the result of an XPointer expression
12917
    */
12918
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12919
        xmlLocationSetPtr locset = ctxt->value->user;
12920
12921
        if (locset != NULL) {
12922
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12923
            if (locset->locNr > 0)
12924
                *first = (xmlNodePtr) locset->locTab[0]->user;
12925
        }
12926
12927
  return (total);
12928
    }
12929
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12930
12931
10
    CHECK_TYPE0(XPATH_NODESET);
12932
10
    set = ctxt->value->nodesetval;
12933
10
    if (set != NULL) {
12934
10
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12935
10
        if (set->nodeNr > 0)
12936
0
            *first = set->nodeTab[0];
12937
10
    }
12938
12939
10
    return (total);
12940
10
}
12941
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12942
12943
/**
12944
 * xmlXPathCompOpEval:
12945
 * @ctxt:  the XPath parser context with the compiled expression
12946
 * @op:  an XPath compiled operation
12947
 *
12948
 * Evaluate the Precompiled XPath operation
12949
 * Returns the number of nodes traversed
12950
 */
12951
static int
12952
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12953
352k
{
12954
352k
    int total = 0;
12955
352k
    int equal, ret;
12956
352k
    xmlXPathCompExprPtr comp;
12957
352k
    xmlXPathObjectPtr arg1, arg2;
12958
12959
352k
    CHECK_ERROR0;
12960
352k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12961
711
        return(0);
12962
352k
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12963
352k
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12964
352k
    ctxt->context->depth += 1;
12965
352k
    comp = ctxt->comp;
12966
352k
    switch (op->op) {
12967
0
        case XPATH_OP_END:
12968
0
            break;
12969
119
        case XPATH_OP_AND:
12970
119
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12971
119
      CHECK_ERROR0;
12972
118
            xmlXPathBooleanFunction(ctxt, 1);
12973
118
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12974
0
                break;
12975
118
            arg2 = valuePop(ctxt);
12976
118
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12977
118
      if (ctxt->error) {
12978
0
    xmlXPathFreeObject(arg2);
12979
0
    break;
12980
0
      }
12981
118
            xmlXPathBooleanFunction(ctxt, 1);
12982
118
            if (ctxt->value != NULL)
12983
118
                ctxt->value->boolval &= arg2->boolval;
12984
118
      xmlXPathReleaseObject(ctxt->context, arg2);
12985
118
            break;
12986
1.73k
        case XPATH_OP_OR:
12987
1.73k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12988
1.73k
      CHECK_ERROR0;
12989
1.73k
            xmlXPathBooleanFunction(ctxt, 1);
12990
1.73k
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12991
1.73k
                break;
12992
0
            arg2 = valuePop(ctxt);
12993
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12994
0
      if (ctxt->error) {
12995
0
    xmlXPathFreeObject(arg2);
12996
0
    break;
12997
0
      }
12998
0
            xmlXPathBooleanFunction(ctxt, 1);
12999
0
            if (ctxt->value != NULL)
13000
0
                ctxt->value->boolval |= arg2->boolval;
13001
0
      xmlXPathReleaseObject(ctxt->context, arg2);
13002
0
            break;
13003
2.04k
        case XPATH_OP_EQUAL:
13004
2.04k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13005
2.04k
      CHECK_ERROR0;
13006
1.52k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13007
1.52k
      CHECK_ERROR0;
13008
1.45k
      if (op->value)
13009
1.25k
    equal = xmlXPathEqualValues(ctxt);
13010
198
      else
13011
198
    equal = xmlXPathNotEqualValues(ctxt);
13012
1.45k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13013
1.45k
            break;
13014
4.65k
        case XPATH_OP_CMP:
13015
4.65k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13016
4.65k
      CHECK_ERROR0;
13017
2.24k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13018
2.24k
      CHECK_ERROR0;
13019
2.23k
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13020
2.23k
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13021
2.23k
            break;
13022
3.11k
        case XPATH_OP_PLUS:
13023
3.11k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13024
3.11k
      CHECK_ERROR0;
13025
2.95k
            if (op->ch2 != -1) {
13026
1.76k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13027
1.76k
      }
13028
2.95k
      CHECK_ERROR0;
13029
2.83k
            if (op->value == 0)
13030
482
                xmlXPathSubValues(ctxt);
13031
2.35k
            else if (op->value == 1)
13032
1.16k
                xmlXPathAddValues(ctxt);
13033
1.18k
            else if (op->value == 2)
13034
1.17k
                xmlXPathValueFlipSign(ctxt);
13035
15
            else if (op->value == 3) {
13036
15
                CAST_TO_NUMBER;
13037
15
                CHECK_TYPE0(XPATH_NUMBER);
13038
15
            }
13039
2.83k
            break;
13040
5.96k
        case XPATH_OP_MULT:
13041
5.96k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13042
5.96k
      CHECK_ERROR0;
13043
3.46k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13044
3.46k
      CHECK_ERROR0;
13045
3.42k
            if (op->value == 0)
13046
3.29k
                xmlXPathMultValues(ctxt);
13047
126
            else if (op->value == 1)
13048
13
                xmlXPathDivValues(ctxt);
13049
113
            else if (op->value == 2)
13050
113
                xmlXPathModValues(ctxt);
13051
3.42k
            break;
13052
12.3k
        case XPATH_OP_UNION:
13053
12.3k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13054
12.3k
      CHECK_ERROR0;
13055
7.08k
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13056
7.08k
      CHECK_ERROR0;
13057
13058
6.85k
            arg2 = valuePop(ctxt);
13059
6.85k
            arg1 = valuePop(ctxt);
13060
6.85k
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13061
6.85k
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13062
304
          xmlXPathReleaseObject(ctxt->context, arg1);
13063
304
          xmlXPathReleaseObject(ctxt->context, arg2);
13064
304
                XP_ERROR0(XPATH_INVALID_TYPE);
13065
0
            }
13066
6.55k
            if ((ctxt->context->opLimit != 0) &&
13067
6.55k
                (((arg1->nodesetval != NULL) &&
13068
6.55k
                  (xmlXPathCheckOpLimit(ctxt,
13069
6.05k
                                        arg1->nodesetval->nodeNr) < 0)) ||
13070
6.55k
                 ((arg2->nodesetval != NULL) &&
13071
6.55k
                  (xmlXPathCheckOpLimit(ctxt,
13072
5.83k
                                        arg2->nodesetval->nodeNr) < 0)))) {
13073
1
          xmlXPathReleaseObject(ctxt->context, arg1);
13074
1
          xmlXPathReleaseObject(ctxt->context, arg2);
13075
1
                break;
13076
1
            }
13077
13078
6.55k
      if ((arg1->nodesetval == NULL) ||
13079
6.55k
    ((arg2->nodesetval != NULL) &&
13080
6.05k
     (arg2->nodesetval->nodeNr != 0)))
13081
2.59k
      {
13082
                /* TODO: Check memory error. */
13083
2.59k
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13084
2.59k
              arg2->nodesetval);
13085
2.59k
      }
13086
13087
6.55k
            valuePush(ctxt, arg1);
13088
6.55k
      xmlXPathReleaseObject(ctxt->context, arg2);
13089
6.55k
            break;
13090
8.98k
        case XPATH_OP_ROOT:
13091
8.98k
            xmlXPathRoot(ctxt);
13092
8.98k
            break;
13093
117k
        case XPATH_OP_NODE:
13094
117k
            if (op->ch1 != -1)
13095
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13096
117k
      CHECK_ERROR0;
13097
117k
            if (op->ch2 != -1)
13098
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13099
117k
      CHECK_ERROR0;
13100
117k
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13101
117k
    ctxt->context->node));
13102
117k
            break;
13103
41.6k
        case XPATH_OP_COLLECT:{
13104
41.6k
                if (op->ch1 == -1)
13105
0
                    break;
13106
13107
41.6k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13108
41.6k
    CHECK_ERROR0;
13109
13110
38.5k
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13111
38.5k
                break;
13112
41.6k
            }
13113
14.6k
        case XPATH_OP_VALUE:
13114
14.6k
            valuePush(ctxt,
13115
14.6k
                      xmlXPathCacheObjectCopy(ctxt->context,
13116
14.6k
      (xmlXPathObjectPtr) op->value4));
13117
14.6k
            break;
13118
0
        case XPATH_OP_VARIABLE:{
13119
0
    xmlXPathObjectPtr val;
13120
13121
0
                if (op->ch1 != -1)
13122
0
                    total +=
13123
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13124
0
                if (op->value5 == NULL) {
13125
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13126
0
        if (val == NULL)
13127
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13128
0
                    valuePush(ctxt, val);
13129
0
    } else {
13130
0
                    const xmlChar *URI;
13131
13132
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13133
0
                    if (URI == NULL) {
13134
0
                        xmlGenericError(xmlGenericErrorContext,
13135
0
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13136
0
                                    (char *) op->value4, (char *)op->value5);
13137
0
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13138
0
                        break;
13139
0
                    }
13140
0
        val = xmlXPathVariableLookupNS(ctxt->context,
13141
0
                                                       op->value4, URI);
13142
0
        if (val == NULL)
13143
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13144
0
                    valuePush(ctxt, val);
13145
0
                }
13146
0
                break;
13147
0
            }
13148
60.8k
        case XPATH_OP_FUNCTION:{
13149
60.8k
                xmlXPathFunction func;
13150
60.8k
                const xmlChar *oldFunc, *oldFuncURI;
13151
60.8k
    int i;
13152
60.8k
                int frame;
13153
13154
60.8k
                frame = xmlXPathSetFrame(ctxt);
13155
60.8k
                if (op->ch1 != -1) {
13156
19.1k
                    total +=
13157
19.1k
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13158
19.1k
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13159
656
                        xmlXPathPopFrame(ctxt, frame);
13160
656
                        break;
13161
656
                    }
13162
19.1k
                }
13163
60.2k
    if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13164
0
        xmlGenericError(xmlGenericErrorContext,
13165
0
          "xmlXPathCompOpEval: parameter error\n");
13166
0
        ctxt->error = XPATH_INVALID_OPERAND;
13167
0
                    xmlXPathPopFrame(ctxt, frame);
13168
0
        break;
13169
0
    }
13170
94.9k
    for (i = 0; i < op->value; i++) {
13171
34.7k
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13172
0
      xmlGenericError(xmlGenericErrorContext,
13173
0
        "xmlXPathCompOpEval: parameter error\n");
13174
0
      ctxt->error = XPATH_INVALID_OPERAND;
13175
0
                        xmlXPathPopFrame(ctxt, frame);
13176
0
      break;
13177
0
        }
13178
34.7k
                }
13179
60.2k
                if (op->cache != NULL)
13180
56.2k
                    func = op->cache;
13181
3.96k
                else {
13182
3.96k
                    const xmlChar *URI = NULL;
13183
13184
3.96k
                    if (op->value5 == NULL)
13185
3.78k
                        func =
13186
3.78k
                            xmlXPathFunctionLookup(ctxt->context,
13187
3.78k
                                                   op->value4);
13188
182
                    else {
13189
182
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13190
182
                        if (URI == NULL) {
13191
37
                            xmlGenericError(xmlGenericErrorContext,
13192
37
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13193
37
                                    (char *)op->value4, (char *)op->value5);
13194
37
                            xmlXPathPopFrame(ctxt, frame);
13195
37
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13196
37
                            break;
13197
37
                        }
13198
145
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13199
145
                                                        op->value4, URI);
13200
145
                    }
13201
3.92k
                    if (func == NULL) {
13202
530
                        xmlGenericError(xmlGenericErrorContext,
13203
530
                                "xmlXPathCompOpEval: function %s not found\n",
13204
530
                                        (char *)op->value4);
13205
530
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13206
0
                    }
13207
3.39k
                    op->cache = func;
13208
3.39k
                    op->cacheURI = (void *) URI;
13209
3.39k
                }
13210
59.6k
                oldFunc = ctxt->context->function;
13211
59.6k
                oldFuncURI = ctxt->context->functionURI;
13212
59.6k
                ctxt->context->function = op->value4;
13213
59.6k
                ctxt->context->functionURI = op->cacheURI;
13214
59.6k
                func(ctxt, op->value);
13215
59.6k
                ctxt->context->function = oldFunc;
13216
59.6k
                ctxt->context->functionURI = oldFuncURI;
13217
59.6k
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13218
59.6k
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13219
59.6k
                    XP_ERROR0(XPATH_STACK_ERROR);
13220
59.6k
                xmlXPathPopFrame(ctxt, frame);
13221
59.6k
                break;
13222
59.6k
            }
13223
35.4k
        case XPATH_OP_ARG:
13224
35.4k
            if (op->ch1 != -1) {
13225
16.3k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13226
16.3k
          CHECK_ERROR0;
13227
16.3k
            }
13228
35.4k
            if (op->ch2 != -1) {
13229
35.4k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13230
35.4k
          CHECK_ERROR0;
13231
35.4k
      }
13232
34.7k
            break;
13233
34.7k
        case XPATH_OP_PREDICATE:
13234
703
        case XPATH_OP_FILTER:{
13235
703
                xmlNodeSetPtr set;
13236
13237
                /*
13238
                 * Optimization for ()[1] selection i.e. the first elem
13239
                 */
13240
703
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13241
703
#ifdef XP_OPTIMIZED_FILTER_FIRST
13242
        /*
13243
        * FILTER TODO: Can we assume that the inner processing
13244
        *  will result in an ordered list if we have an
13245
        *  XPATH_OP_FILTER?
13246
        *  What about an additional field or flag on
13247
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13248
        *  to assume anything, so it would be more robust and
13249
        *  easier to optimize.
13250
        */
13251
703
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13252
703
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13253
#else
13254
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13255
#endif
13256
703
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13257
259
                    xmlXPathObjectPtr val;
13258
13259
259
                    val = comp->steps[op->ch2].value4;
13260
259
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13261
259
                        (val->floatval == 1.0)) {
13262
39
                        xmlNodePtr first = NULL;
13263
13264
39
                        total +=
13265
39
                            xmlXPathCompOpEvalFirst(ctxt,
13266
39
                                                    &comp->steps[op->ch1],
13267
39
                                                    &first);
13268
39
      CHECK_ERROR0;
13269
                        /*
13270
                         * The nodeset should be in document order,
13271
                         * Keep only the first value
13272
                         */
13273
22
                        if ((ctxt->value != NULL) &&
13274
22
                            (ctxt->value->type == XPATH_NODESET) &&
13275
22
                            (ctxt->value->nodesetval != NULL) &&
13276
22
                            (ctxt->value->nodesetval->nodeNr > 1))
13277
12
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13278
12
                                                        1, 1);
13279
22
                        break;
13280
39
                    }
13281
259
                }
13282
                /*
13283
                 * Optimization for ()[last()] selection i.e. the last elem
13284
                 */
13285
664
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13286
664
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13287
664
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13288
247
                    int f = comp->steps[op->ch2].ch1;
13289
13290
247
                    if ((f != -1) &&
13291
247
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13292
247
                        (comp->steps[f].value5 == NULL) &&
13293
247
                        (comp->steps[f].value == 0) &&
13294
247
                        (comp->steps[f].value4 != NULL) &&
13295
247
                        (xmlStrEqual
13296
21
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13297
4
                        xmlNodePtr last = NULL;
13298
13299
4
                        total +=
13300
4
                            xmlXPathCompOpEvalLast(ctxt,
13301
4
                                                   &comp->steps[op->ch1],
13302
4
                                                   &last);
13303
4
      CHECK_ERROR0;
13304
                        /*
13305
                         * The nodeset should be in document order,
13306
                         * Keep only the last value
13307
                         */
13308
4
                        if ((ctxt->value != NULL) &&
13309
4
                            (ctxt->value->type == XPATH_NODESET) &&
13310
4
                            (ctxt->value->nodesetval != NULL) &&
13311
4
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13312
4
                            (ctxt->value->nodesetval->nodeNr > 1))
13313
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13314
4
                        break;
13315
4
                    }
13316
247
                }
13317
    /*
13318
    * Process inner predicates first.
13319
    * Example "index[parent::book][1]":
13320
    * ...
13321
    *   PREDICATE   <-- we are here "[1]"
13322
    *     PREDICATE <-- process "[parent::book]" first
13323
    *       SORT
13324
    *         COLLECT  'parent' 'name' 'node' book
13325
    *           NODE
13326
    *     ELEM Object is a number : 1
13327
    */
13328
660
                if (op->ch1 != -1)
13329
660
                    total +=
13330
660
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13331
660
    CHECK_ERROR0;
13332
390
                if (op->ch2 == -1)
13333
0
                    break;
13334
390
                if (ctxt->value == NULL)
13335
0
                    break;
13336
13337
#ifdef LIBXML_XPTR_LOCS_ENABLED
13338
                /*
13339
                 * Hum are we filtering the result of an XPointer expression
13340
                 */
13341
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13342
                    xmlLocationSetPtr locset = ctxt->value->user;
13343
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13344
                                              1, locset->locNr);
13345
                    break;
13346
                }
13347
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13348
13349
390
                CHECK_TYPE0(XPATH_NODESET);
13350
119
                set = ctxt->value->nodesetval;
13351
119
                if (set != NULL)
13352
81
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13353
81
                                          1, set->nodeNr, 1);
13354
119
                break;
13355
390
            }
13356
42.1k
        case XPATH_OP_SORT:
13357
42.1k
            if (op->ch1 != -1)
13358
42.1k
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13359
42.1k
      CHECK_ERROR0;
13360
38.8k
            if ((ctxt->value != NULL) &&
13361
38.8k
                (ctxt->value->type == XPATH_NODESET) &&
13362
38.8k
                (ctxt->value->nodesetval != NULL) &&
13363
38.8k
    (ctxt->value->nodesetval->nodeNr > 1))
13364
736
      {
13365
736
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13366
736
      }
13367
38.8k
            break;
13368
#ifdef LIBXML_XPTR_LOCS_ENABLED
13369
        case XPATH_OP_RANGETO:{
13370
                xmlXPathObjectPtr range;
13371
                xmlXPathObjectPtr res, obj;
13372
                xmlXPathObjectPtr tmp;
13373
                xmlLocationSetPtr newlocset = NULL;
13374
        xmlLocationSetPtr oldlocset;
13375
                xmlNodeSetPtr oldset;
13376
                xmlNodePtr oldnode = ctxt->context->node;
13377
                int oldcs = ctxt->context->contextSize;
13378
                int oldpp = ctxt->context->proximityPosition;
13379
                int i, j;
13380
13381
                if (op->ch1 != -1) {
13382
                    total +=
13383
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13384
                    CHECK_ERROR0;
13385
                }
13386
                if (ctxt->value == NULL) {
13387
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13388
                }
13389
                if (op->ch2 == -1)
13390
                    break;
13391
13392
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13393
                    /*
13394
                     * Extract the old locset, and then evaluate the result of the
13395
                     * expression for all the element in the locset. use it to grow
13396
                     * up a new locset.
13397
                     */
13398
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13399
13400
                    if ((ctxt->value->user == NULL) ||
13401
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13402
                        break;
13403
13404
                    obj = valuePop(ctxt);
13405
                    oldlocset = obj->user;
13406
13407
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13408
13409
                    for (i = 0; i < oldlocset->locNr; i++) {
13410
                        /*
13411
                         * Run the evaluation with a node list made of a
13412
                         * single item in the nodelocset.
13413
                         */
13414
                        ctxt->context->node = oldlocset->locTab[i]->user;
13415
                        ctxt->context->contextSize = oldlocset->locNr;
13416
                        ctxt->context->proximityPosition = i + 1;
13417
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13418
          ctxt->context->node);
13419
                        valuePush(ctxt, tmp);
13420
13421
                        if (op->ch2 != -1)
13422
                            total +=
13423
                                xmlXPathCompOpEval(ctxt,
13424
                                                   &comp->steps[op->ch2]);
13425
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13426
                            xmlXPtrFreeLocationSet(newlocset);
13427
                            goto rangeto_error;
13428
      }
13429
13430
                        res = valuePop(ctxt);
13431
      if (res->type == XPATH_LOCATIONSET) {
13432
          xmlLocationSetPtr rloc =
13433
              (xmlLocationSetPtr)res->user;
13434
          for (j=0; j<rloc->locNr; j++) {
13435
              range = xmlXPtrNewRange(
13436
          oldlocset->locTab[i]->user,
13437
          oldlocset->locTab[i]->index,
13438
          rloc->locTab[j]->user2,
13439
          rloc->locTab[j]->index2);
13440
        if (range != NULL) {
13441
            xmlXPtrLocationSetAdd(newlocset, range);
13442
        }
13443
          }
13444
      } else {
13445
          range = xmlXPtrNewRangeNodeObject(
13446
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13447
                            if (range != NULL) {
13448
                                xmlXPtrLocationSetAdd(newlocset,range);
13449
          }
13450
                        }
13451
13452
                        /*
13453
                         * Cleanup
13454
                         */
13455
                        if (res != NULL) {
13456
          xmlXPathReleaseObject(ctxt->context, res);
13457
      }
13458
                        if (ctxt->value == tmp) {
13459
                            res = valuePop(ctxt);
13460
          xmlXPathReleaseObject(ctxt->context, res);
13461
                        }
13462
                    }
13463
    } else {  /* Not a location set */
13464
                    CHECK_TYPE0(XPATH_NODESET);
13465
                    obj = valuePop(ctxt);
13466
                    oldset = obj->nodesetval;
13467
13468
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13469
13470
                    if (oldset != NULL) {
13471
                        for (i = 0; i < oldset->nodeNr; i++) {
13472
                            /*
13473
                             * Run the evaluation with a node list made of a single item
13474
                             * in the nodeset.
13475
                             */
13476
                            ctxt->context->node = oldset->nodeTab[i];
13477
          /*
13478
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13479
          */
13480
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13481
        ctxt->context->node);
13482
                            valuePush(ctxt, tmp);
13483
13484
                            if (op->ch2 != -1)
13485
                                total +=
13486
                                    xmlXPathCompOpEval(ctxt,
13487
                                                   &comp->steps[op->ch2]);
13488
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13489
                                xmlXPtrFreeLocationSet(newlocset);
13490
                                goto rangeto_error;
13491
          }
13492
13493
                            res = valuePop(ctxt);
13494
                            range =
13495
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13496
                                                      res);
13497
                            if (range != NULL) {
13498
                                xmlXPtrLocationSetAdd(newlocset, range);
13499
                            }
13500
13501
                            /*
13502
                             * Cleanup
13503
                             */
13504
                            if (res != NULL) {
13505
        xmlXPathReleaseObject(ctxt->context, res);
13506
          }
13507
                            if (ctxt->value == tmp) {
13508
                                res = valuePop(ctxt);
13509
        xmlXPathReleaseObject(ctxt->context, res);
13510
                            }
13511
                        }
13512
                    }
13513
                }
13514
13515
                /*
13516
                 * The result is used as the new evaluation set.
13517
                 */
13518
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13519
rangeto_error:
13520
    xmlXPathReleaseObject(ctxt->context, obj);
13521
                ctxt->context->node = oldnode;
13522
                ctxt->context->contextSize = oldcs;
13523
                ctxt->context->proximityPosition = oldpp;
13524
                break;
13525
            }
13526
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13527
0
        default:
13528
0
            xmlGenericError(xmlGenericErrorContext,
13529
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13530
0
            ctxt->error = XPATH_INVALID_OPERAND;
13531
0
            break;
13532
352k
    }
13533
13534
332k
    ctxt->context->depth -= 1;
13535
332k
    return (total);
13536
352k
}
13537
13538
/**
13539
 * xmlXPathCompOpEvalToBoolean:
13540
 * @ctxt:  the XPath parser context
13541
 *
13542
 * Evaluates if the expression evaluates to true.
13543
 *
13544
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13545
 */
13546
static int
13547
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13548
          xmlXPathStepOpPtr op,
13549
          int isPredicate)
13550
132k
{
13551
132k
    xmlXPathObjectPtr resObj = NULL;
13552
13553
132k
start:
13554
132k
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13555
0
        return(0);
13556
    /* comp = ctxt->comp; */
13557
132k
    switch (op->op) {
13558
0
        case XPATH_OP_END:
13559
0
            return (0);
13560
248
  case XPATH_OP_VALUE:
13561
248
      resObj = (xmlXPathObjectPtr) op->value4;
13562
248
      if (isPredicate)
13563
248
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13564
0
      return(xmlXPathCastToBoolean(resObj));
13565
118
  case XPATH_OP_SORT:
13566
      /*
13567
      * We don't need sorting for boolean results. Skip this one.
13568
      */
13569
118
            if (op->ch1 != -1) {
13570
118
    op = &ctxt->comp->steps[op->ch1];
13571
118
    goto start;
13572
118
      }
13573
0
      return(0);
13574
7
  case XPATH_OP_COLLECT:
13575
7
      if (op->ch1 == -1)
13576
0
    return(0);
13577
13578
7
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13579
7
      if (ctxt->error != XPATH_EXPRESSION_OK)
13580
0
    return(-1);
13581
13582
7
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13583
7
      if (ctxt->error != XPATH_EXPRESSION_OK)
13584
2
    return(-1);
13585
13586
5
      resObj = valuePop(ctxt);
13587
5
      if (resObj == NULL)
13588
0
    return(-1);
13589
5
      break;
13590
131k
  default:
13591
      /*
13592
      * Fallback to call xmlXPathCompOpEval().
13593
      */
13594
131k
      xmlXPathCompOpEval(ctxt, op);
13595
131k
      if (ctxt->error != XPATH_EXPRESSION_OK)
13596
63
    return(-1);
13597
13598
131k
      resObj = valuePop(ctxt);
13599
131k
      if (resObj == NULL)
13600
0
    return(-1);
13601
131k
      break;
13602
132k
    }
13603
13604
131k
    if (resObj) {
13605
131k
  int res;
13606
13607
131k
  if (resObj->type == XPATH_BOOLEAN) {
13608
3.84k
      res = resObj->boolval;
13609
127k
  } else if (isPredicate) {
13610
      /*
13611
      * For predicates a result of type "number" is handled
13612
      * differently:
13613
      * SPEC XPath 1.0:
13614
      * "If the result is a number, the result will be converted
13615
      *  to true if the number is equal to the context position
13616
      *  and will be converted to false otherwise;"
13617
      */
13618
127k
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13619
127k
  } else {
13620
5
      res = xmlXPathCastToBoolean(resObj);
13621
5
  }
13622
131k
  xmlXPathReleaseObject(ctxt->context, resObj);
13623
131k
  return(res);
13624
131k
    }
13625
13626
0
    return(0);
13627
131k
}
13628
13629
#ifdef XPATH_STREAMING
13630
/**
13631
 * xmlXPathRunStreamEval:
13632
 * @ctxt:  the XPath parser context with the compiled expression
13633
 *
13634
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13635
 */
13636
static int
13637
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13638
          xmlXPathObjectPtr *resultSeq, int toBool)
13639
11.4k
{
13640
11.4k
    int max_depth, min_depth;
13641
11.4k
    int from_root;
13642
11.4k
    int ret, depth;
13643
11.4k
    int eval_all_nodes;
13644
11.4k
    xmlNodePtr cur = NULL, limit = NULL;
13645
11.4k
    xmlStreamCtxtPtr patstream = NULL;
13646
13647
11.4k
    if ((ctxt == NULL) || (comp == NULL))
13648
0
        return(-1);
13649
11.4k
    max_depth = xmlPatternMaxDepth(comp);
13650
11.4k
    if (max_depth == -1)
13651
0
        return(-1);
13652
11.4k
    if (max_depth == -2)
13653
3
        max_depth = 10000;
13654
11.4k
    min_depth = xmlPatternMinDepth(comp);
13655
11.4k
    if (min_depth == -1)
13656
0
        return(-1);
13657
11.4k
    from_root = xmlPatternFromRoot(comp);
13658
11.4k
    if (from_root < 0)
13659
0
        return(-1);
13660
#if 0
13661
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13662
#endif
13663
13664
11.4k
    if (! toBool) {
13665
11.4k
  if (resultSeq == NULL)
13666
0
      return(-1);
13667
11.4k
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13668
11.4k
  if (*resultSeq == NULL)
13669
0
      return(-1);
13670
11.4k
    }
13671
13672
    /*
13673
     * handle the special cases of "/" amd "." being matched
13674
     */
13675
11.4k
    if (min_depth == 0) {
13676
3.20k
  if (from_root) {
13677
      /* Select "/" */
13678
0
      if (toBool)
13679
0
    return(1);
13680
            /* TODO: Check memory error. */
13681
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13682
0
                         (xmlNodePtr) ctxt->doc);
13683
3.20k
  } else {
13684
      /* Select "self::node()" */
13685
3.20k
      if (toBool)
13686
0
    return(1);
13687
            /* TODO: Check memory error. */
13688
3.20k
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13689
3.20k
  }
13690
3.20k
    }
13691
11.4k
    if (max_depth == 0) {
13692
3.09k
  return(0);
13693
3.09k
    }
13694
13695
8.35k
    if (from_root) {
13696
11
        cur = (xmlNodePtr)ctxt->doc;
13697
8.34k
    } else if (ctxt->node != NULL) {
13698
8.34k
        switch (ctxt->node->type) {
13699
3.44k
            case XML_ELEMENT_NODE:
13700
3.44k
            case XML_DOCUMENT_NODE:
13701
3.44k
            case XML_DOCUMENT_FRAG_NODE:
13702
3.44k
            case XML_HTML_DOCUMENT_NODE:
13703
3.44k
          cur = ctxt->node;
13704
3.44k
    break;
13705
0
            case XML_ATTRIBUTE_NODE:
13706
4.90k
            case XML_TEXT_NODE:
13707
4.90k
            case XML_CDATA_SECTION_NODE:
13708
4.90k
            case XML_ENTITY_REF_NODE:
13709
4.90k
            case XML_ENTITY_NODE:
13710
4.90k
            case XML_PI_NODE:
13711
4.90k
            case XML_COMMENT_NODE:
13712
4.90k
            case XML_NOTATION_NODE:
13713
4.90k
            case XML_DTD_NODE:
13714
4.90k
            case XML_DOCUMENT_TYPE_NODE:
13715
4.90k
            case XML_ELEMENT_DECL:
13716
4.90k
            case XML_ATTRIBUTE_DECL:
13717
4.90k
            case XML_ENTITY_DECL:
13718
4.90k
            case XML_NAMESPACE_DECL:
13719
4.90k
            case XML_XINCLUDE_START:
13720
4.90k
            case XML_XINCLUDE_END:
13721
4.90k
    break;
13722
8.34k
  }
13723
8.34k
  limit = cur;
13724
8.34k
    }
13725
8.35k
    if (cur == NULL) {
13726
4.90k
        return(0);
13727
4.90k
    }
13728
13729
3.45k
    patstream = xmlPatternGetStreamCtxt(comp);
13730
3.45k
    if (patstream == NULL) {
13731
  /*
13732
  * QUESTION TODO: Is this an error?
13733
  */
13734
0
  return(0);
13735
0
    }
13736
13737
3.45k
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13738
13739
3.45k
    if (from_root) {
13740
11
  ret = xmlStreamPush(patstream, NULL, NULL);
13741
11
  if (ret < 0) {
13742
11
  } else if (ret == 1) {
13743
0
      if (toBool)
13744
0
    goto return_1;
13745
            /* TODO: Check memory error. */
13746
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13747
0
  }
13748
11
    }
13749
3.45k
    depth = 0;
13750
3.45k
    goto scan_children;
13751
11.5k
next_node:
13752
16.1k
    do {
13753
16.1k
        if (ctxt->opLimit != 0) {
13754
16.1k
            if (ctxt->opCount >= ctxt->opLimit) {
13755
149
                xmlGenericError(xmlGenericErrorContext,
13756
149
                        "XPath operation limit exceeded\n");
13757
149
                xmlFreeStreamCtxt(patstream);
13758
149
                return(-1);
13759
149
            }
13760
16.0k
            ctxt->opCount++;
13761
16.0k
        }
13762
13763
16.0k
  switch (cur->type) {
13764
5.22k
      case XML_ELEMENT_NODE:
13765
14.8k
      case XML_TEXT_NODE:
13766
15.0k
      case XML_CDATA_SECTION_NODE:
13767
15.7k
      case XML_COMMENT_NODE:
13768
16.0k
      case XML_PI_NODE:
13769
16.0k
    if (cur->type == XML_ELEMENT_NODE) {
13770
5.22k
        ret = xmlStreamPush(patstream, cur->name,
13771
5.22k
        (cur->ns ? cur->ns->href : NULL));
13772
10.7k
    } else if (eval_all_nodes)
13773
666
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13774
10.1k
    else
13775
10.1k
        break;
13776
13777
5.89k
    if (ret < 0) {
13778
        /* NOP. */
13779
5.89k
    } else if (ret == 1) {
13780
0
        if (toBool)
13781
0
      goto return_1;
13782
0
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13783
0
            < 0) {
13784
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13785
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13786
0
        }
13787
0
    }
13788
5.89k
    if ((cur->children == NULL) || (depth >= max_depth)) {
13789
5.07k
        ret = xmlStreamPop(patstream);
13790
5.07k
        while (cur->next != NULL) {
13791
4.98k
      cur = cur->next;
13792
4.98k
      if ((cur->type != XML_ENTITY_DECL) &&
13793
4.98k
          (cur->type != XML_DTD_NODE))
13794
4.98k
          goto next_node;
13795
4.98k
        }
13796
5.07k
    }
13797
908
      default:
13798
908
    break;
13799
16.0k
  }
13800
13801
14.4k
scan_children:
13802
14.4k
  if (cur->type == XML_NAMESPACE_DECL) break;
13803
14.4k
  if ((cur->children != NULL) && (depth < max_depth)) {
13804
      /*
13805
       * Do not descend on entities declarations
13806
       */
13807
3.81k
      if (cur->children->type != XML_ENTITY_DECL) {
13808
3.81k
    cur = cur->children;
13809
3.81k
    depth++;
13810
    /*
13811
     * Skip DTDs
13812
     */
13813
3.81k
    if (cur->type != XML_DTD_NODE)
13814
3.81k
        continue;
13815
3.81k
      }
13816
3.81k
  }
13817
13818
10.6k
  if (cur == limit)
13819
458
      break;
13820
13821
10.2k
  while (cur->next != NULL) {
13822
6.56k
      cur = cur->next;
13823
6.56k
      if ((cur->type != XML_ENTITY_DECL) &&
13824
6.56k
    (cur->type != XML_DTD_NODE))
13825
6.56k
    goto next_node;
13826
6.56k
  }
13827
13828
3.66k
  do {
13829
3.66k
      cur = cur->parent;
13830
3.66k
      depth--;
13831
3.66k
      if ((cur == NULL) || (cur == limit) ||
13832
3.66k
                (cur->type == XML_DOCUMENT_NODE))
13833
2.84k
          goto done;
13834
818
      if (cur->type == XML_ELEMENT_NODE) {
13835
818
    ret = xmlStreamPop(patstream);
13836
818
      } else if ((eval_all_nodes) &&
13837
0
    ((cur->type == XML_TEXT_NODE) ||
13838
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13839
0
     (cur->type == XML_COMMENT_NODE) ||
13840
0
     (cur->type == XML_PI_NODE)))
13841
0
      {
13842
0
    ret = xmlStreamPop(patstream);
13843
0
      }
13844
818
      if (cur->next != NULL) {
13845
807
    cur = cur->next;
13846
807
    break;
13847
807
      }
13848
818
  } while (cur != NULL);
13849
13850
4.62k
    } while ((cur != NULL) && (depth >= 0));
13851
13852
3.30k
done:
13853
13854
3.30k
    if (patstream)
13855
3.30k
  xmlFreeStreamCtxt(patstream);
13856
3.30k
    return(0);
13857
13858
0
return_1:
13859
0
    if (patstream)
13860
0
  xmlFreeStreamCtxt(patstream);
13861
0
    return(1);
13862
11.5k
}
13863
#endif /* XPATH_STREAMING */
13864
13865
/**
13866
 * xmlXPathRunEval:
13867
 * @ctxt:  the XPath parser context with the compiled expression
13868
 * @toBool:  evaluate to a boolean result
13869
 *
13870
 * Evaluate the Precompiled XPath expression in the given context.
13871
 */
13872
static int
13873
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13874
31.0k
{
13875
31.0k
    xmlXPathCompExprPtr comp;
13876
31.0k
    int oldDepth;
13877
13878
31.0k
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13879
0
  return(-1);
13880
13881
31.0k
    if (ctxt->valueTab == NULL) {
13882
  /* Allocate the value stack */
13883
2
  ctxt->valueTab = (xmlXPathObjectPtr *)
13884
2
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13885
2
  if (ctxt->valueTab == NULL) {
13886
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13887
0
      return(-1);
13888
0
  }
13889
2
  ctxt->valueNr = 0;
13890
2
  ctxt->valueMax = 10;
13891
2
  ctxt->value = NULL;
13892
2
        ctxt->valueFrame = 0;
13893
2
    }
13894
31.0k
#ifdef XPATH_STREAMING
13895
31.0k
    if (ctxt->comp->stream) {
13896
11.4k
  int res;
13897
13898
11.4k
  if (toBool) {
13899
      /*
13900
      * Evaluation to boolean result.
13901
      */
13902
0
      res = xmlXPathRunStreamEval(ctxt->context,
13903
0
    ctxt->comp->stream, NULL, 1);
13904
0
      if (res != -1)
13905
0
    return(res);
13906
11.4k
  } else {
13907
11.4k
      xmlXPathObjectPtr resObj = NULL;
13908
13909
      /*
13910
      * Evaluation to a sequence.
13911
      */
13912
11.4k
      res = xmlXPathRunStreamEval(ctxt->context,
13913
11.4k
    ctxt->comp->stream, &resObj, 0);
13914
13915
11.4k
      if ((res != -1) && (resObj != NULL)) {
13916
11.2k
    valuePush(ctxt, resObj);
13917
11.2k
    return(0);
13918
11.2k
      }
13919
149
      if (resObj != NULL)
13920
149
    xmlXPathReleaseObject(ctxt->context, resObj);
13921
149
  }
13922
  /*
13923
  * QUESTION TODO: This falls back to normal XPath evaluation
13924
  * if res == -1. Is this intended?
13925
  */
13926
11.4k
    }
13927
19.7k
#endif
13928
19.7k
    comp = ctxt->comp;
13929
19.7k
    if (comp->last < 0) {
13930
149
  xmlGenericError(xmlGenericErrorContext,
13931
149
      "xmlXPathRunEval: last is less than zero\n");
13932
149
  return(-1);
13933
149
    }
13934
19.5k
    oldDepth = ctxt->context->depth;
13935
19.5k
    if (toBool)
13936
5
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13937
5
      &comp->steps[comp->last], 0));
13938
19.5k
    else
13939
19.5k
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13940
19.5k
    ctxt->context->depth = oldDepth;
13941
13942
19.5k
    return(0);
13943
19.5k
}
13944
13945
/************************************************************************
13946
 *                  *
13947
 *      Public interfaces       *
13948
 *                  *
13949
 ************************************************************************/
13950
13951
/**
13952
 * xmlXPathEvalPredicate:
13953
 * @ctxt:  the XPath context
13954
 * @res:  the Predicate Expression evaluation result
13955
 *
13956
 * Evaluate a predicate result for the current node.
13957
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13958
 * the result to a boolean. If the result is a number, the result will
13959
 * be converted to true if the number is equal to the position of the
13960
 * context node in the context node list (as returned by the position
13961
 * function) and will be converted to false otherwise; if the result
13962
 * is not a number, then the result will be converted as if by a call
13963
 * to the boolean function.
13964
 *
13965
 * Returns 1 if predicate is true, 0 otherwise
13966
 */
13967
int
13968
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13969
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13970
0
    switch (res->type) {
13971
0
        case XPATH_BOOLEAN:
13972
0
      return(res->boolval);
13973
0
        case XPATH_NUMBER:
13974
0
      return(res->floatval == ctxt->proximityPosition);
13975
0
        case XPATH_NODESET:
13976
0
        case XPATH_XSLT_TREE:
13977
0
      if (res->nodesetval == NULL)
13978
0
    return(0);
13979
0
      return(res->nodesetval->nodeNr != 0);
13980
0
        case XPATH_STRING:
13981
0
      return((res->stringval != NULL) &&
13982
0
             (xmlStrlen(res->stringval) != 0));
13983
0
        default:
13984
0
      STRANGE
13985
0
    }
13986
0
    return(0);
13987
0
}
13988
13989
/**
13990
 * xmlXPathEvaluatePredicateResult:
13991
 * @ctxt:  the XPath Parser context
13992
 * @res:  the Predicate Expression evaluation result
13993
 *
13994
 * Evaluate a predicate result for the current node.
13995
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13996
 * the result to a boolean. If the result is a number, the result will
13997
 * be converted to true if the number is equal to the position of the
13998
 * context node in the context node list (as returned by the position
13999
 * function) and will be converted to false otherwise; if the result
14000
 * is not a number, then the result will be converted as if by a call
14001
 * to the boolean function.
14002
 *
14003
 * Returns 1 if predicate is true, 0 otherwise
14004
 */
14005
int
14006
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14007
128k
                                xmlXPathObjectPtr res) {
14008
128k
    if ((ctxt == NULL) || (res == NULL)) return(0);
14009
128k
    switch (res->type) {
14010
0
        case XPATH_BOOLEAN:
14011
0
      return(res->boolval);
14012
41.6k
        case XPATH_NUMBER:
14013
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14014
      return((res->floatval == ctxt->context->proximityPosition) &&
14015
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14016
#else
14017
41.6k
      return(res->floatval == ctxt->context->proximityPosition);
14018
0
#endif
14019
85.3k
        case XPATH_NODESET:
14020
85.3k
        case XPATH_XSLT_TREE:
14021
85.3k
      if (res->nodesetval == NULL)
14022
0
    return(0);
14023
85.3k
      return(res->nodesetval->nodeNr != 0);
14024
1.21k
        case XPATH_STRING:
14025
1.21k
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14026
#ifdef LIBXML_XPTR_LOCS_ENABLED
14027
  case XPATH_LOCATIONSET:{
14028
      xmlLocationSetPtr ptr = res->user;
14029
      if (ptr == NULL)
14030
          return(0);
14031
      return (ptr->locNr != 0);
14032
      }
14033
#endif
14034
0
        default:
14035
0
      STRANGE
14036
128k
    }
14037
0
    return(0);
14038
128k
}
14039
14040
#ifdef XPATH_STREAMING
14041
/**
14042
 * xmlXPathTryStreamCompile:
14043
 * @ctxt: an XPath context
14044
 * @str:  the XPath expression
14045
 *
14046
 * Try to compile the XPath expression as a streamable subset.
14047
 *
14048
 * Returns the compiled expression or NULL if failed to compile.
14049
 */
14050
static xmlXPathCompExprPtr
14051
47.7k
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14052
    /*
14053
     * Optimization: use streaming patterns when the XPath expression can
14054
     * be compiled to a stream lookup
14055
     */
14056
47.7k
    xmlPatternPtr stream;
14057
47.7k
    xmlXPathCompExprPtr comp;
14058
47.7k
    xmlDictPtr dict = NULL;
14059
47.7k
    const xmlChar **namespaces = NULL;
14060
47.7k
    xmlNsPtr ns;
14061
47.7k
    int i, j;
14062
14063
47.7k
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14064
47.7k
        (!xmlStrchr(str, '@'))) {
14065
33.6k
  const xmlChar *tmp;
14066
14067
  /*
14068
   * We don't try to handle expressions using the verbose axis
14069
   * specifiers ("::"), just the simplified form at this point.
14070
   * Additionally, if there is no list of namespaces available and
14071
   *  there's a ":" in the expression, indicating a prefixed QName,
14072
   *  then we won't try to compile either. xmlPatterncompile() needs
14073
   *  to have a list of namespaces at compilation time in order to
14074
   *  compile prefixed name tests.
14075
   */
14076
33.6k
  tmp = xmlStrchr(str, ':');
14077
33.6k
  if ((tmp != NULL) &&
14078
33.6k
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14079
1.70k
      return(NULL);
14080
14081
31.9k
  if (ctxt != NULL) {
14082
31.9k
      dict = ctxt->dict;
14083
31.9k
      if (ctxt->nsNr > 0) {
14084
11.7k
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14085
11.7k
    if (namespaces == NULL) {
14086
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14087
0
        return(NULL);
14088
0
    }
14089
128k
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14090
117k
        ns = ctxt->namespaces[j];
14091
117k
        namespaces[i++] = ns->href;
14092
117k
        namespaces[i++] = ns->prefix;
14093
117k
    }
14094
11.7k
    namespaces[i++] = NULL;
14095
11.7k
    namespaces[i] = NULL;
14096
11.7k
      }
14097
31.9k
  }
14098
14099
31.9k
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14100
31.9k
  if (namespaces != NULL) {
14101
11.7k
      xmlFree((xmlChar **)namespaces);
14102
11.7k
  }
14103
31.9k
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14104
11.6k
      comp = xmlXPathNewCompExpr();
14105
11.6k
      if (comp == NULL) {
14106
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14107
0
    return(NULL);
14108
0
      }
14109
11.6k
      comp->stream = stream;
14110
11.6k
      comp->dict = dict;
14111
11.6k
      if (comp->dict)
14112
8.49k
    xmlDictReference(comp->dict);
14113
11.6k
      return(comp);
14114
11.6k
  }
14115
20.2k
  xmlFreePattern(stream);
14116
20.2k
    }
14117
34.3k
    return(NULL);
14118
47.7k
}
14119
#endif /* XPATH_STREAMING */
14120
14121
static void
14122
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14123
                           xmlXPathStepOpPtr op)
14124
2.92M
{
14125
2.92M
    xmlXPathCompExprPtr comp = pctxt->comp;
14126
2.92M
    xmlXPathContextPtr ctxt;
14127
14128
    /*
14129
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14130
    * internal representation.
14131
    */
14132
14133
2.92M
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14134
2.92M
        (op->ch1 != -1) &&
14135
2.92M
        (op->ch2 == -1 /* no predicate */))
14136
965k
    {
14137
965k
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14138
14139
965k
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14140
965k
            ((xmlXPathAxisVal) prevop->value ==
14141
9.51k
                AXIS_DESCENDANT_OR_SELF) &&
14142
965k
            (prevop->ch2 == -1) &&
14143
965k
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14144
965k
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14145
2.76k
        {
14146
            /*
14147
            * This is a "descendant-or-self::node()" without predicates.
14148
            * Try to eliminate it.
14149
            */
14150
14151
2.76k
            switch ((xmlXPathAxisVal) op->value) {
14152
1.51k
                case AXIS_CHILD:
14153
1.51k
                case AXIS_DESCENDANT:
14154
                    /*
14155
                    * Convert "descendant-or-self::node()/child::" or
14156
                    * "descendant-or-self::node()/descendant::" to
14157
                    * "descendant::"
14158
                    */
14159
1.51k
                    op->ch1   = prevop->ch1;
14160
1.51k
                    op->value = AXIS_DESCENDANT;
14161
1.51k
                    break;
14162
0
                case AXIS_SELF:
14163
0
                case AXIS_DESCENDANT_OR_SELF:
14164
                    /*
14165
                    * Convert "descendant-or-self::node()/self::" or
14166
                    * "descendant-or-self::node()/descendant-or-self::" to
14167
                    * to "descendant-or-self::"
14168
                    */
14169
0
                    op->ch1   = prevop->ch1;
14170
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
14171
0
                    break;
14172
1.24k
                default:
14173
1.24k
                    break;
14174
2.76k
            }
14175
2.76k
  }
14176
965k
    }
14177
14178
    /* OP_VALUE has invalid ch1. */
14179
2.92M
    if (op->op == XPATH_OP_VALUE)
14180
5.95k
        return;
14181
14182
    /* Recurse */
14183
2.91M
    ctxt = pctxt->context;
14184
2.91M
    if (ctxt != NULL) {
14185
2.91M
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14186
7.18k
            return;
14187
2.91M
        ctxt->depth += 1;
14188
2.91M
    }
14189
2.91M
    if (op->ch1 != -1)
14190
1.94M
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14191
2.91M
    if (op->ch2 != -1)
14192
971k
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14193
2.91M
    if (ctxt != NULL)
14194
2.91M
        ctxt->depth -= 1;
14195
2.91M
}
14196
14197
/**
14198
 * xmlXPathCtxtCompile:
14199
 * @ctxt: an XPath context
14200
 * @str:  the XPath expression
14201
 *
14202
 * Compile an XPath expression
14203
 *
14204
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14205
 *         the caller has to free the object.
14206
 */
14207
xmlXPathCompExprPtr
14208
47.6k
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14209
47.6k
    xmlXPathParserContextPtr pctxt;
14210
47.6k
    xmlXPathCompExprPtr comp;
14211
47.6k
    int oldDepth = 0;
14212
14213
47.6k
#ifdef XPATH_STREAMING
14214
47.6k
    comp = xmlXPathTryStreamCompile(ctxt, str);
14215
47.6k
    if (comp != NULL)
14216
11.6k
        return(comp);
14217
35.9k
#endif
14218
14219
35.9k
    xmlInitParser();
14220
14221
35.9k
    pctxt = xmlXPathNewParserContext(str, ctxt);
14222
35.9k
    if (pctxt == NULL)
14223
0
        return NULL;
14224
35.9k
    if (ctxt != NULL)
14225
35.9k
        oldDepth = ctxt->depth;
14226
35.9k
    xmlXPathCompileExpr(pctxt, 1);
14227
35.9k
    if (ctxt != NULL)
14228
35.9k
        ctxt->depth = oldDepth;
14229
14230
35.9k
    if( pctxt->error != XPATH_EXPRESSION_OK )
14231
12.7k
    {
14232
12.7k
        xmlXPathFreeParserContext(pctxt);
14233
12.7k
        return(NULL);
14234
12.7k
    }
14235
14236
23.2k
    if (*pctxt->cur != 0) {
14237
  /*
14238
   * aleksey: in some cases this line prints *second* error message
14239
   * (see bug #78858) and probably this should be fixed.
14240
   * However, we are not sure that all error messages are printed
14241
   * out in other places. It's not critical so we leave it as-is for now
14242
   */
14243
10.1k
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14244
10.1k
  comp = NULL;
14245
13.0k
    } else {
14246
13.0k
  comp = pctxt->comp;
14247
13.0k
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14248
7.28k
            if (ctxt != NULL)
14249
7.28k
                oldDepth = ctxt->depth;
14250
7.28k
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14251
7.28k
            if (ctxt != NULL)
14252
7.28k
                ctxt->depth = oldDepth;
14253
7.28k
  }
14254
13.0k
  pctxt->comp = NULL;
14255
13.0k
    }
14256
23.2k
    xmlXPathFreeParserContext(pctxt);
14257
14258
23.2k
    if (comp != NULL) {
14259
13.0k
  comp->expr = xmlStrdup(str);
14260
#ifdef DEBUG_EVAL_COUNTS
14261
  comp->string = xmlStrdup(str);
14262
  comp->nb = 0;
14263
#endif
14264
13.0k
    }
14265
23.2k
    return(comp);
14266
35.9k
}
14267
14268
/**
14269
 * xmlXPathCompile:
14270
 * @str:  the XPath expression
14271
 *
14272
 * Compile an XPath expression
14273
 *
14274
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14275
 *         the caller has to free the object.
14276
 */
14277
xmlXPathCompExprPtr
14278
0
xmlXPathCompile(const xmlChar *str) {
14279
0
    return(xmlXPathCtxtCompile(NULL, str));
14280
0
}
14281
14282
/**
14283
 * xmlXPathCompiledEvalInternal:
14284
 * @comp:  the compiled XPath expression
14285
 * @ctxt:  the XPath context
14286
 * @resObj: the resulting XPath object or NULL
14287
 * @toBool: 1 if only a boolean result is requested
14288
 *
14289
 * Evaluate the Precompiled XPath expression in the given context.
14290
 * The caller has to free @resObj.
14291
 *
14292
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14293
 *         the caller has to free the object.
14294
 */
14295
static int
14296
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14297
           xmlXPathContextPtr ctxt,
14298
           xmlXPathObjectPtr *resObjPtr,
14299
           int toBool)
14300
49.7k
{
14301
49.7k
    xmlXPathParserContextPtr pctxt;
14302
49.7k
    xmlXPathObjectPtr resObj;
14303
#ifndef LIBXML_THREAD_ENABLED
14304
    static int reentance = 0;
14305
#endif
14306
49.7k
    int res;
14307
14308
49.7k
    CHECK_CTXT_NEG(ctxt)
14309
14310
49.7k
    if (comp == NULL)
14311
18.7k
  return(-1);
14312
31.0k
    xmlInitParser();
14313
14314
#ifndef LIBXML_THREAD_ENABLED
14315
    reentance++;
14316
    if (reentance > 1)
14317
  xmlXPathDisableOptimizer = 1;
14318
#endif
14319
14320
#ifdef DEBUG_EVAL_COUNTS
14321
    comp->nb++;
14322
    if ((comp->string != NULL) && (comp->nb > 100)) {
14323
  fprintf(stderr, "100 x %s\n", comp->string);
14324
  comp->nb = 0;
14325
    }
14326
#endif
14327
31.0k
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14328
31.0k
    res = xmlXPathRunEval(pctxt, toBool);
14329
14330
31.0k
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14331
3.32k
        resObj = NULL;
14332
27.6k
    } else {
14333
27.6k
        resObj = valuePop(pctxt);
14334
27.6k
        if (resObj == NULL) {
14335
154
            if (!toBool)
14336
149
                xmlGenericError(xmlGenericErrorContext,
14337
149
                    "xmlXPathCompiledEval: No result on the stack.\n");
14338
27.5k
        } else if (pctxt->valueNr > 0) {
14339
0
            xmlGenericError(xmlGenericErrorContext,
14340
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14341
0
                pctxt->valueNr);
14342
0
        }
14343
27.6k
    }
14344
14345
31.0k
    if (resObjPtr)
14346
31.0k
        *resObjPtr = resObj;
14347
5
    else
14348
5
        xmlXPathReleaseObject(ctxt, resObj);
14349
14350
31.0k
    pctxt->comp = NULL;
14351
31.0k
    xmlXPathFreeParserContext(pctxt);
14352
#ifndef LIBXML_THREAD_ENABLED
14353
    reentance--;
14354
#endif
14355
14356
31.0k
    return(res);
14357
49.7k
}
14358
14359
/**
14360
 * xmlXPathCompiledEval:
14361
 * @comp:  the compiled XPath expression
14362
 * @ctx:  the XPath context
14363
 *
14364
 * Evaluate the Precompiled XPath expression in the given context.
14365
 *
14366
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14367
 *         the caller has to free the object.
14368
 */
14369
xmlXPathObjectPtr
14370
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14371
49.7k
{
14372
49.7k
    xmlXPathObjectPtr res = NULL;
14373
14374
49.7k
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14375
49.7k
    return(res);
14376
49.7k
}
14377
14378
/**
14379
 * xmlXPathCompiledEvalToBoolean:
14380
 * @comp:  the compiled XPath expression
14381
 * @ctxt:  the XPath context
14382
 *
14383
 * Applies the XPath boolean() function on the result of the given
14384
 * compiled expression.
14385
 *
14386
 * Returns 1 if the expression evaluated to true, 0 if to false and
14387
 *         -1 in API and internal errors.
14388
 */
14389
int
14390
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14391
            xmlXPathContextPtr ctxt)
14392
5
{
14393
5
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14394
5
}
14395
14396
/**
14397
 * xmlXPathEvalExpr:
14398
 * @ctxt:  the XPath Parser context
14399
 *
14400
 * Parse and evaluate an XPath expression in the given context,
14401
 * then push the result on the context stack
14402
 */
14403
void
14404
44
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14405
44
#ifdef XPATH_STREAMING
14406
44
    xmlXPathCompExprPtr comp;
14407
44
#endif
14408
44
    int oldDepth = 0;
14409
14410
44
    if (ctxt == NULL) return;
14411
14412
44
#ifdef XPATH_STREAMING
14413
44
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14414
44
    if (comp != NULL) {
14415
0
        if (ctxt->comp != NULL)
14416
0
      xmlXPathFreeCompExpr(ctxt->comp);
14417
0
        ctxt->comp = comp;
14418
0
    } else
14419
44
#endif
14420
44
    {
14421
44
        if (ctxt->context != NULL)
14422
44
            oldDepth = ctxt->context->depth;
14423
44
  xmlXPathCompileExpr(ctxt, 1);
14424
44
        if (ctxt->context != NULL)
14425
44
            ctxt->context->depth = oldDepth;
14426
44
        CHECK_ERROR;
14427
14428
        /* Check for trailing characters. */
14429
8
        if (*ctxt->cur != 0)
14430
8
            XP_ERROR(XPATH_EXPR_ERROR);
14431
14432
8
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14433
8
            if (ctxt->context != NULL)
14434
8
                oldDepth = ctxt->context->depth;
14435
8
      xmlXPathOptimizeExpression(ctxt,
14436
8
    &ctxt->comp->steps[ctxt->comp->last]);
14437
8
            if (ctxt->context != NULL)
14438
8
                ctxt->context->depth = oldDepth;
14439
8
        }
14440
8
    }
14441
14442
8
    xmlXPathRunEval(ctxt, 0);
14443
8
}
14444
14445
/**
14446
 * xmlXPathEval:
14447
 * @str:  the XPath expression
14448
 * @ctx:  the XPath context
14449
 *
14450
 * Evaluate the XPath Location Path in the given context.
14451
 *
14452
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14453
 *         the caller has to free the object.
14454
 */
14455
xmlXPathObjectPtr
14456
38
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14457
38
    xmlXPathParserContextPtr ctxt;
14458
38
    xmlXPathObjectPtr res;
14459
14460
38
    CHECK_CTXT(ctx)
14461
14462
38
    xmlInitParser();
14463
14464
38
    ctxt = xmlXPathNewParserContext(str, ctx);
14465
38
    if (ctxt == NULL)
14466
0
        return NULL;
14467
38
    xmlXPathEvalExpr(ctxt);
14468
14469
38
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14470
36
  res = NULL;
14471
36
    } else {
14472
2
  res = valuePop(ctxt);
14473
2
        if (res == NULL) {
14474
0
            xmlGenericError(xmlGenericErrorContext,
14475
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14476
2
        } else if (ctxt->valueNr > 0) {
14477
0
            xmlGenericError(xmlGenericErrorContext,
14478
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14479
0
                ctxt->valueNr);
14480
0
        }
14481
2
    }
14482
14483
38
    xmlXPathFreeParserContext(ctxt);
14484
38
    return(res);
14485
38
}
14486
14487
/**
14488
 * xmlXPathSetContextNode:
14489
 * @node: the node to to use as the context node
14490
 * @ctx:  the XPath context
14491
 *
14492
 * Sets 'node' as the context node. The node must be in the same
14493
 * document as that associated with the context.
14494
 *
14495
 * Returns -1 in case of error or 0 if successful
14496
 */
14497
int
14498
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14499
0
    if ((node == NULL) || (ctx == NULL))
14500
0
        return(-1);
14501
14502
0
    if (node->doc == ctx->doc) {
14503
0
        ctx->node = node;
14504
0
  return(0);
14505
0
    }
14506
0
    return(-1);
14507
0
}
14508
14509
/**
14510
 * xmlXPathNodeEval:
14511
 * @node: the node to to use as the context node
14512
 * @str:  the XPath expression
14513
 * @ctx:  the XPath context
14514
 *
14515
 * Evaluate the XPath Location Path in the given context. The node 'node'
14516
 * is set as the context node. The context node is not restored.
14517
 *
14518
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14519
 *         the caller has to free the object.
14520
 */
14521
xmlXPathObjectPtr
14522
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14523
0
    if (str == NULL)
14524
0
        return(NULL);
14525
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14526
0
        return(NULL);
14527
0
    return(xmlXPathEval(str, ctx));
14528
0
}
14529
14530
/**
14531
 * xmlXPathEvalExpression:
14532
 * @str:  the XPath expression
14533
 * @ctxt:  the XPath context
14534
 *
14535
 * Alias for xmlXPathEval().
14536
 *
14537
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14538
 *         the caller has to free the object.
14539
 */
14540
xmlXPathObjectPtr
14541
36
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14542
36
    return(xmlXPathEval(str, ctxt));
14543
36
}
14544
14545
/************************************************************************
14546
 *                  *
14547
 *  Extra functions not pertaining to the XPath spec    *
14548
 *                  *
14549
 ************************************************************************/
14550
/**
14551
 * xmlXPathEscapeUriFunction:
14552
 * @ctxt:  the XPath Parser context
14553
 * @nargs:  the number of arguments
14554
 *
14555
 * Implement the escape-uri() XPath function
14556
 *    string escape-uri(string $str, bool $escape-reserved)
14557
 *
14558
 * This function applies the URI escaping rules defined in section 2 of [RFC
14559
 * 2396] to the string supplied as $uri-part, which typically represents all
14560
 * or part of a URI. The effect of the function is to replace any special
14561
 * character in the string by an escape sequence of the form %xx%yy...,
14562
 * where xxyy... is the hexadecimal representation of the octets used to
14563
 * represent the character in UTF-8.
14564
 *
14565
 * The set of characters that are escaped depends on the setting of the
14566
 * boolean argument $escape-reserved.
14567
 *
14568
 * If $escape-reserved is true, all characters are escaped other than lower
14569
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14570
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14571
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14572
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14573
 * A-F).
14574
 *
14575
 * If $escape-reserved is false, the behavior differs in that characters
14576
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14577
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14578
 *
14579
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14580
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14581
 * compared using string comparison functions, this function must always use
14582
 * the upper-case letters A-F.
14583
 *
14584
 * Generally, $escape-reserved should be set to true when escaping a string
14585
 * that is to form a single part of a URI, and to false when escaping an
14586
 * entire URI or URI reference.
14587
 *
14588
 * In the case of non-ascii characters, the string is encoded according to
14589
 * utf-8 and then converted according to RFC 2396.
14590
 *
14591
 * Examples
14592
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14593
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14594
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14595
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14596
 *
14597
 */
14598
static void
14599
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14600
0
    xmlXPathObjectPtr str;
14601
0
    int escape_reserved;
14602
0
    xmlBufPtr target;
14603
0
    xmlChar *cptr;
14604
0
    xmlChar escape[4];
14605
14606
0
    CHECK_ARITY(2);
14607
14608
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14609
14610
0
    CAST_TO_STRING;
14611
0
    str = valuePop(ctxt);
14612
14613
0
    target = xmlBufCreate();
14614
14615
0
    escape[0] = '%';
14616
0
    escape[3] = 0;
14617
14618
0
    if (target) {
14619
0
  for (cptr = str->stringval; *cptr; cptr++) {
14620
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14621
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14622
0
    (*cptr >= '0' && *cptr <= '9') ||
14623
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14624
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14625
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14626
0
    (*cptr == '%' &&
14627
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14628
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14629
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14630
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14631
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14632
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14633
0
    (!escape_reserved &&
14634
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14635
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14636
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14637
0
      *cptr == ','))) {
14638
0
    xmlBufAdd(target, cptr, 1);
14639
0
      } else {
14640
0
    if ((*cptr >> 4) < 10)
14641
0
        escape[1] = '0' + (*cptr >> 4);
14642
0
    else
14643
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14644
0
    if ((*cptr & 0xF) < 10)
14645
0
        escape[2] = '0' + (*cptr & 0xF);
14646
0
    else
14647
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14648
14649
0
    xmlBufAdd(target, &escape[0], 3);
14650
0
      }
14651
0
  }
14652
0
    }
14653
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14654
0
  xmlBufContent(target)));
14655
0
    xmlBufFree(target);
14656
0
    xmlXPathReleaseObject(ctxt->context, str);
14657
0
}
14658
14659
/**
14660
 * xmlXPathRegisterAllFunctions:
14661
 * @ctxt:  the XPath context
14662
 *
14663
 * Registers all default XPath functions in this context
14664
 */
14665
void
14666
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14667
117
{
14668
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14669
117
                         xmlXPathBooleanFunction);
14670
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14671
117
                         xmlXPathCeilingFunction);
14672
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14673
117
                         xmlXPathCountFunction);
14674
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14675
117
                         xmlXPathConcatFunction);
14676
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14677
117
                         xmlXPathContainsFunction);
14678
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14679
117
                         xmlXPathIdFunction);
14680
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14681
117
                         xmlXPathFalseFunction);
14682
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14683
117
                         xmlXPathFloorFunction);
14684
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14685
117
                         xmlXPathLastFunction);
14686
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14687
117
                         xmlXPathLangFunction);
14688
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14689
117
                         xmlXPathLocalNameFunction);
14690
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14691
117
                         xmlXPathNotFunction);
14692
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14693
117
                         xmlXPathNameFunction);
14694
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14695
117
                         xmlXPathNamespaceURIFunction);
14696
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14697
117
                         xmlXPathNormalizeFunction);
14698
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14699
117
                         xmlXPathNumberFunction);
14700
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14701
117
                         xmlXPathPositionFunction);
14702
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14703
117
                         xmlXPathRoundFunction);
14704
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14705
117
                         xmlXPathStringFunction);
14706
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14707
117
                         xmlXPathStringLengthFunction);
14708
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14709
117
                         xmlXPathStartsWithFunction);
14710
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14711
117
                         xmlXPathSubstringFunction);
14712
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14713
117
                         xmlXPathSubstringBeforeFunction);
14714
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14715
117
                         xmlXPathSubstringAfterFunction);
14716
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14717
117
                         xmlXPathSumFunction);
14718
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14719
117
                         xmlXPathTrueFunction);
14720
117
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14721
117
                         xmlXPathTranslateFunction);
14722
14723
117
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14724
117
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14725
117
                         xmlXPathEscapeUriFunction);
14726
117
}
14727
14728
#endif /* LIBXML_XPATH_ENABLED */