Coverage Report

Created: 2024-02-04 06:19

/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/xpath.h>
35
#include <libxml/xpathInternals.h>
36
#include <libxml/parserInternals.h>
37
#include <libxml/hash.h>
38
#ifdef LIBXML_XPTR_LOCS_ENABLED
39
#include <libxml/xpointer.h>
40
#endif
41
#ifdef LIBXML_DEBUG_ENABLED
42
#include <libxml/debugXML.h>
43
#endif
44
#include <libxml/xmlerror.h>
45
#include <libxml/threads.h>
46
#ifdef LIBXML_PATTERN_ENABLED
47
#include <libxml/pattern.h>
48
#endif
49
50
#include "private/buf.h"
51
#include "private/error.h"
52
#include "private/xpath.h"
53
54
/* Disabled for now */
55
#if 0
56
#ifdef LIBXML_PATTERN_ENABLED
57
#define XPATH_STREAMING
58
#endif
59
#endif
60
61
/**
62
 * WITH_TIM_SORT:
63
 *
64
 * Use the Timsort algorithm provided in timsort.h to sort
65
 * nodeset as this is a great improvement over the old Shell sort
66
 * used in xmlXPathNodeSetSort()
67
 */
68
#define WITH_TIM_SORT
69
70
/*
71
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
72
* If defined, this will use xmlXPathCmpNodesExt() instead of
73
* xmlXPathCmpNodes(). The new function is optimized comparison of
74
* non-element nodes; actually it will speed up comparison only if
75
* xmlXPathOrderDocElems() was called in order to index the elements of
76
* a tree in document order; Libxslt does such an indexing, thus it will
77
* benefit from this optimization.
78
*/
79
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
80
81
/*
82
* XP_OPTIMIZED_FILTER_FIRST:
83
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
84
* in a way, that it stop evaluation at the first node.
85
*/
86
#define XP_OPTIMIZED_FILTER_FIRST
87
88
/*
89
 * XPATH_MAX_STEPS:
90
 * when compiling an XPath expression we arbitrary limit the maximum
91
 * number of step operation in the compiled expression. 1000000 is
92
 * an insanely large value which should never be reached under normal
93
 * circumstances
94
 */
95
0
#define XPATH_MAX_STEPS 1000000
96
97
/*
98
 * XPATH_MAX_STACK_DEPTH:
99
 * when evaluating an XPath expression we arbitrary limit the maximum
100
 * number of object allowed to be pushed on the stack. 1000000 is
101
 * an insanely large value which should never be reached under normal
102
 * circumstances
103
 */
104
0
#define XPATH_MAX_STACK_DEPTH 1000000
105
106
/*
107
 * XPATH_MAX_NODESET_LENGTH:
108
 * when evaluating an XPath expression nodesets are created and we
109
 * arbitrary limit the maximum length of those node set. 10000000 is
110
 * an insanely large value which should never be reached under normal
111
 * circumstances, one would first need to construct an in memory tree
112
 * with more than 10 millions nodes.
113
 */
114
0
#define XPATH_MAX_NODESET_LENGTH 10000000
115
116
/*
117
 * XPATH_MAX_RECRUSION_DEPTH:
118
 * Maximum amount of nested functions calls when parsing or evaluating
119
 * expressions
120
 */
121
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
122
0
#define XPATH_MAX_RECURSION_DEPTH 500
123
#elif defined(_WIN32)
124
/* Windows typically limits stack size to 1MB. */
125
#define XPATH_MAX_RECURSION_DEPTH 1000
126
#else
127
#define XPATH_MAX_RECURSION_DEPTH 5000
128
#endif
129
130
/*
131
 * TODO:
132
 * There are a few spots where some tests are done which depend upon ascii
133
 * data.  These should be enhanced for full UTF8 support (see particularly
134
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
135
 */
136
137
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
138
139
/************************************************************************
140
 *                  *
141
 *      Floating point stuff        *
142
 *                  *
143
 ************************************************************************/
144
145
double xmlXPathNAN = 0.0;
146
double xmlXPathPINF = 0.0;
147
double xmlXPathNINF = 0.0;
148
149
/**
150
 * xmlXPathInit:
151
 *
152
 * DEPRECATED: Alias for xmlInitParser.
153
 */
154
void
155
0
xmlXPathInit(void) {
156
0
    xmlInitParser();
157
0
}
158
159
/**
160
 * xmlInitXPathInternal:
161
 *
162
 * Initialize the XPath environment
163
 */
164
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
165
void
166
2
xmlInitXPathInternal(void) {
167
2
#if defined(NAN) && defined(INFINITY)
168
2
    xmlXPathNAN = NAN;
169
2
    xmlXPathPINF = INFINITY;
170
2
    xmlXPathNINF = -INFINITY;
171
#else
172
    /* MSVC doesn't allow division by zero in constant expressions. */
173
    double zero = 0.0;
174
    xmlXPathNAN = 0.0 / zero;
175
    xmlXPathPINF = 1.0 / zero;
176
    xmlXPathNINF = -xmlXPathPINF;
177
#endif
178
2
}
179
180
/**
181
 * xmlXPathIsNaN:
182
 * @val:  a double value
183
 *
184
 * Checks whether a double is a NaN.
185
 *
186
 * Returns 1 if the value is a NaN, 0 otherwise
187
 */
188
int
189
12
xmlXPathIsNaN(double val) {
190
12
#ifdef isnan
191
12
    return isnan(val);
192
#else
193
    return !(val == val);
194
#endif
195
12
}
196
197
/**
198
 * xmlXPathIsInf:
199
 * @val:  a double value
200
 *
201
 * Checks whether a double is an infinity.
202
 *
203
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
204
 */
205
int
206
0
xmlXPathIsInf(double val) {
207
0
#ifdef isinf
208
0
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
209
#else
210
    if (val >= xmlXPathPINF)
211
        return 1;
212
    if (val <= -xmlXPathPINF)
213
        return -1;
214
    return 0;
215
#endif
216
0
}
217
218
#endif /* SCHEMAS or XPATH */
219
220
#ifdef LIBXML_XPATH_ENABLED
221
222
/*
223
 * TODO: when compatibility allows remove all "fake node libxslt" strings
224
 *       the test should just be name[0] = ' '
225
 */
226
227
static xmlNs xmlXPathXMLNamespaceStruct = {
228
    NULL,
229
    XML_NAMESPACE_DECL,
230
    XML_XML_NAMESPACE,
231
    BAD_CAST "xml",
232
    NULL,
233
    NULL
234
};
235
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
236
#ifndef LIBXML_THREAD_ENABLED
237
/*
238
 * Optimizer is disabled only when threaded apps are detected while
239
 * the library ain't compiled for thread safety.
240
 */
241
static int xmlXPathDisableOptimizer = 0;
242
#endif
243
244
static void
245
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
246
247
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
248
/**
249
 * xmlXPathCmpNodesExt:
250
 * @node1:  the first node
251
 * @node2:  the second node
252
 *
253
 * Compare two nodes w.r.t document order.
254
 * This one is optimized for handling of non-element nodes.
255
 *
256
 * Returns -2 in case of error 1 if first point < second point, 0 if
257
 *         it's the same node, -1 otherwise
258
 */
259
static int
260
0
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
261
0
    int depth1, depth2;
262
0
    int misc = 0, precedence1 = 0, precedence2 = 0;
263
0
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
264
0
    xmlNodePtr cur, root;
265
0
    ptrdiff_t l1, l2;
266
267
0
    if ((node1 == NULL) || (node2 == NULL))
268
0
  return(-2);
269
270
0
    if (node1 == node2)
271
0
  return(0);
272
273
    /*
274
     * a couple of optimizations which will avoid computations in most cases
275
     */
276
0
    switch (node1->type) {
277
0
  case XML_ELEMENT_NODE:
278
0
      if (node2->type == XML_ELEMENT_NODE) {
279
0
    if ((0 > (ptrdiff_t) node1->content) &&
280
0
        (0 > (ptrdiff_t) node2->content) &&
281
0
        (node1->doc == node2->doc))
282
0
    {
283
0
        l1 = -((ptrdiff_t) node1->content);
284
0
        l2 = -((ptrdiff_t) node2->content);
285
0
        if (l1 < l2)
286
0
      return(1);
287
0
        if (l1 > l2)
288
0
      return(-1);
289
0
    } else
290
0
        goto turtle_comparison;
291
0
      }
292
0
      break;
293
0
  case XML_ATTRIBUTE_NODE:
294
0
      precedence1 = 1; /* element is owner */
295
0
      miscNode1 = node1;
296
0
      node1 = node1->parent;
297
0
      misc = 1;
298
0
      break;
299
0
  case XML_TEXT_NODE:
300
0
  case XML_CDATA_SECTION_NODE:
301
0
  case XML_COMMENT_NODE:
302
0
  case XML_PI_NODE: {
303
0
      miscNode1 = node1;
304
      /*
305
      * Find nearest element node.
306
      */
307
0
      if (node1->prev != NULL) {
308
0
    do {
309
0
        node1 = node1->prev;
310
0
        if (node1->type == XML_ELEMENT_NODE) {
311
0
      precedence1 = 3; /* element in prev-sibl axis */
312
0
      break;
313
0
        }
314
0
        if (node1->prev == NULL) {
315
0
      precedence1 = 2; /* element is parent */
316
      /*
317
      * URGENT TODO: Are there any cases, where the
318
      * parent of such a node is not an element node?
319
      */
320
0
      node1 = node1->parent;
321
0
      break;
322
0
        }
323
0
    } while (1);
324
0
      } else {
325
0
    precedence1 = 2; /* element is parent */
326
0
    node1 = node1->parent;
327
0
      }
328
0
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
329
0
    (0 <= (ptrdiff_t) node1->content)) {
330
    /*
331
    * Fallback for whatever case.
332
    */
333
0
    node1 = miscNode1;
334
0
    precedence1 = 0;
335
0
      } else
336
0
    misc = 1;
337
0
  }
338
0
      break;
339
0
  case XML_NAMESPACE_DECL:
340
      /*
341
      * TODO: why do we return 1 for namespace nodes?
342
      */
343
0
      return(1);
344
0
  default:
345
0
      break;
346
0
    }
347
0
    switch (node2->type) {
348
0
  case XML_ELEMENT_NODE:
349
0
      break;
350
0
  case XML_ATTRIBUTE_NODE:
351
0
      precedence2 = 1; /* element is owner */
352
0
      miscNode2 = node2;
353
0
      node2 = node2->parent;
354
0
      misc = 1;
355
0
      break;
356
0
  case XML_TEXT_NODE:
357
0
  case XML_CDATA_SECTION_NODE:
358
0
  case XML_COMMENT_NODE:
359
0
  case XML_PI_NODE: {
360
0
      miscNode2 = node2;
361
0
      if (node2->prev != NULL) {
362
0
    do {
363
0
        node2 = node2->prev;
364
0
        if (node2->type == XML_ELEMENT_NODE) {
365
0
      precedence2 = 3; /* element in prev-sibl axis */
366
0
      break;
367
0
        }
368
0
        if (node2->prev == NULL) {
369
0
      precedence2 = 2; /* element is parent */
370
0
      node2 = node2->parent;
371
0
      break;
372
0
        }
373
0
    } while (1);
374
0
      } else {
375
0
    precedence2 = 2; /* element is parent */
376
0
    node2 = node2->parent;
377
0
      }
378
0
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
379
0
    (0 <= (ptrdiff_t) node2->content))
380
0
      {
381
0
    node2 = miscNode2;
382
0
    precedence2 = 0;
383
0
      } else
384
0
    misc = 1;
385
0
  }
386
0
      break;
387
0
  case XML_NAMESPACE_DECL:
388
0
      return(1);
389
0
  default:
390
0
      break;
391
0
    }
392
0
    if (misc) {
393
0
  if (node1 == node2) {
394
0
      if (precedence1 == precedence2) {
395
    /*
396
    * The ugly case; but normally there aren't many
397
    * adjacent non-element nodes around.
398
    */
399
0
    cur = miscNode2->prev;
400
0
    while (cur != NULL) {
401
0
        if (cur == miscNode1)
402
0
      return(1);
403
0
        if (cur->type == XML_ELEMENT_NODE)
404
0
      return(-1);
405
0
        cur = cur->prev;
406
0
    }
407
0
    return (-1);
408
0
      } else {
409
    /*
410
    * Evaluate based on higher precedence wrt to the element.
411
    * TODO: This assumes attributes are sorted before content.
412
    *   Is this 100% correct?
413
    */
414
0
    if (precedence1 < precedence2)
415
0
        return(1);
416
0
    else
417
0
        return(-1);
418
0
      }
419
0
  }
420
  /*
421
  * Special case: One of the helper-elements is contained by the other.
422
  * <foo>
423
  *   <node2>
424
  *     <node1>Text-1(precedence1 == 2)</node1>
425
  *   </node2>
426
  *   Text-6(precedence2 == 3)
427
  * </foo>
428
  */
429
0
  if ((precedence2 == 3) && (precedence1 > 1)) {
430
0
      cur = node1->parent;
431
0
      while (cur) {
432
0
    if (cur == node2)
433
0
        return(1);
434
0
    cur = cur->parent;
435
0
      }
436
0
  }
437
0
  if ((precedence1 == 3) && (precedence2 > 1)) {
438
0
      cur = node2->parent;
439
0
      while (cur) {
440
0
    if (cur == node1)
441
0
        return(-1);
442
0
    cur = cur->parent;
443
0
      }
444
0
  }
445
0
    }
446
447
    /*
448
     * Speedup using document order if available.
449
     */
450
0
    if ((node1->type == XML_ELEMENT_NODE) &&
451
0
  (node2->type == XML_ELEMENT_NODE) &&
452
0
  (0 > (ptrdiff_t) node1->content) &&
453
0
  (0 > (ptrdiff_t) node2->content) &&
454
0
  (node1->doc == node2->doc)) {
455
456
0
  l1 = -((ptrdiff_t) node1->content);
457
0
  l2 = -((ptrdiff_t) node2->content);
458
0
  if (l1 < l2)
459
0
      return(1);
460
0
  if (l1 > l2)
461
0
      return(-1);
462
0
    }
463
464
0
turtle_comparison:
465
466
0
    if (node1 == node2->prev)
467
0
  return(1);
468
0
    if (node1 == node2->next)
469
0
  return(-1);
470
    /*
471
     * compute depth to root
472
     */
473
0
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
474
0
  if (cur->parent == node1)
475
0
      return(1);
476
0
  depth2++;
477
0
    }
478
0
    root = cur;
479
0
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
480
0
  if (cur->parent == node2)
481
0
      return(-1);
482
0
  depth1++;
483
0
    }
484
    /*
485
     * Distinct document (or distinct entities :-( ) case.
486
     */
487
0
    if (root != cur) {
488
0
  return(-2);
489
0
    }
490
    /*
491
     * get the nearest common ancestor.
492
     */
493
0
    while (depth1 > depth2) {
494
0
  depth1--;
495
0
  node1 = node1->parent;
496
0
    }
497
0
    while (depth2 > depth1) {
498
0
  depth2--;
499
0
  node2 = node2->parent;
500
0
    }
501
0
    while (node1->parent != node2->parent) {
502
0
  node1 = node1->parent;
503
0
  node2 = node2->parent;
504
  /* should not happen but just in case ... */
505
0
  if ((node1 == NULL) || (node2 == NULL))
506
0
      return(-2);
507
0
    }
508
    /*
509
     * Find who's first.
510
     */
511
0
    if (node1 == node2->prev)
512
0
  return(1);
513
0
    if (node1 == node2->next)
514
0
  return(-1);
515
    /*
516
     * Speedup using document order if available.
517
     */
518
0
    if ((node1->type == XML_ELEMENT_NODE) &&
519
0
  (node2->type == XML_ELEMENT_NODE) &&
520
0
  (0 > (ptrdiff_t) node1->content) &&
521
0
  (0 > (ptrdiff_t) node2->content) &&
522
0
  (node1->doc == node2->doc)) {
523
524
0
  l1 = -((ptrdiff_t) node1->content);
525
0
  l2 = -((ptrdiff_t) node2->content);
526
0
  if (l1 < l2)
527
0
      return(1);
528
0
  if (l1 > l2)
529
0
      return(-1);
530
0
    }
531
532
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
533
0
  if (cur == node2)
534
0
      return(1);
535
0
    return(-1); /* assume there is no sibling list corruption */
536
0
}
537
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
538
539
/*
540
 * Wrapper for the Timsort algorithm from timsort.h
541
 */
542
#ifdef WITH_TIM_SORT
543
#define SORT_NAME libxml_domnode
544
0
#define SORT_TYPE xmlNodePtr
545
/**
546
 * wrap_cmp:
547
 * @x: a node
548
 * @y: another node
549
 *
550
 * Comparison function for the Timsort implementation
551
 *
552
 * Returns -2 in case of error -1 if first point < second point, 0 if
553
 *         it's the same node, +1 otherwise
554
 */
555
static
556
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
557
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
558
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
559
0
    {
560
0
        int res = xmlXPathCmpNodesExt(x, y);
561
0
        return res == -2 ? res : -res;
562
0
    }
563
#else
564
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
565
    {
566
        int res = xmlXPathCmpNodes(x, y);
567
        return res == -2 ? res : -res;
568
    }
569
#endif
570
0
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
571
#include "timsort.h"
572
#endif /* WITH_TIM_SORT */
573
574
/************************************************************************
575
 *                  *
576
 *      Error handling routines       *
577
 *                  *
578
 ************************************************************************/
579
580
/**
581
 * XP_ERRORNULL:
582
 * @X:  the error code
583
 *
584
 * Macro to raise an XPath error and return NULL.
585
 */
586
#define XP_ERRORNULL(X)             \
587
0
    { xmlXPathErr(ctxt, X); return(NULL); }
588
589
/*
590
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
591
 */
592
static const char* const xmlXPathErrorMessages[] = {
593
    "Ok\n",
594
    "Number encoding\n",
595
    "Unfinished literal\n",
596
    "Start of literal\n",
597
    "Expected $ for variable reference\n",
598
    "Undefined variable\n",
599
    "Invalid predicate\n",
600
    "Invalid expression\n",
601
    "Missing closing curly brace\n",
602
    "Unregistered function\n",
603
    "Invalid operand\n",
604
    "Invalid type\n",
605
    "Invalid number of arguments\n",
606
    "Invalid context size\n",
607
    "Invalid context position\n",
608
    "Memory allocation error\n",
609
    "Syntax error\n",
610
    "Resource error\n",
611
    "Sub resource error\n",
612
    "Undefined namespace prefix\n",
613
    "Encoding error\n",
614
    "Char out of XML range\n",
615
    "Invalid or incomplete context\n",
616
    "Stack usage error\n",
617
    "Forbidden variable\n",
618
    "Operation limit exceeded\n",
619
    "Recursion limit exceeded\n",
620
    "?? Unknown error ??\n" /* Must be last in the list! */
621
};
622
0
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
623
0
       sizeof(xmlXPathErrorMessages[0])) - 1)
624
/**
625
 * xmlXPathErrMemory:
626
 * @ctxt:  an XPath context
627
 * @extra:  extra information
628
 *
629
 * Handle a memory allocation failure.
630
 */
631
void
632
xmlXPathErrMemory(xmlXPathContextPtr ctxt)
633
0
{
634
0
    if (ctxt == NULL)
635
0
        return;
636
0
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
637
0
                        &ctxt->lastError);
638
0
}
639
640
/**
641
 * xmlXPathPErrMemory:
642
 * @ctxt:  an XPath parser context
643
 * @extra:  extra information
644
 *
645
 * Handle a memory allocation failure.
646
 */
647
void
648
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
649
0
{
650
0
    if (ctxt == NULL)
651
0
        return;
652
0
    ctxt->error = XPATH_MEMORY_ERROR;
653
0
    xmlXPathErrMemory(ctxt->context);
654
0
}
655
656
/**
657
 * xmlXPathErr:
658
 * @ctxt:  a XPath parser context
659
 * @error:  the error code
660
 *
661
 * Handle an XPath error
662
 */
663
void
664
xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
665
0
{
666
0
    xmlStructuredErrorFunc schannel = NULL;
667
0
    xmlGenericErrorFunc channel = NULL;
668
0
    void *data = NULL;
669
0
    xmlNodePtr node = NULL;
670
0
    int res;
671
672
0
    if (ctxt == NULL)
673
0
        return;
674
0
    if ((code < 0) || (code > MAXERRNO))
675
0
  code = MAXERRNO;
676
    /* Only report the first error */
677
0
    if (ctxt->error != 0)
678
0
        return;
679
680
0
    ctxt->error = code;
681
682
0
    if (ctxt->context != NULL) {
683
0
        xmlErrorPtr err = &ctxt->context->lastError;
684
685
        /* Don't overwrite memory error. */
686
0
        if (err->code == XML_ERR_NO_MEMORY)
687
0
            return;
688
689
        /* cleanup current last error */
690
0
        xmlResetError(err);
691
692
0
        err->domain = XML_FROM_XPATH;
693
0
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
694
0
        err->level = XML_ERR_ERROR;
695
0
        if (ctxt->base != NULL) {
696
0
            err->str1 = (char *) xmlStrdup(ctxt->base);
697
0
            if (err->str1 == NULL) {
698
0
                xmlXPathPErrMemory(ctxt);
699
0
                return;
700
0
            }
701
0
        }
702
0
        err->int1 = ctxt->cur - ctxt->base;
703
0
        err->node = ctxt->context->debugNode;
704
705
0
        schannel = ctxt->context->error;
706
0
        data = ctxt->context->userData;
707
0
        node = ctxt->context->debugNode;
708
0
    }
709
710
0
    if (schannel == NULL) {
711
0
        channel = xmlGenericError;
712
0
        data = xmlGenericErrorContext;
713
0
    }
714
715
0
    res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
716
0
                          code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
717
0
                          XML_ERR_ERROR, NULL, 0,
718
0
                          (const char *) ctxt->base, NULL, NULL,
719
0
                          ctxt->cur - ctxt->base, 0,
720
0
                          "%s", xmlXPathErrorMessages[code]);
721
0
    if (res < 0)
722
0
        xmlXPathPErrMemory(ctxt);
723
0
}
724
725
/**
726
 * xmlXPatherror:
727
 * @ctxt:  the XPath Parser context
728
 * @file:  the file name
729
 * @line:  the line number
730
 * @no:  the error number
731
 *
732
 * Formats an error message.
733
 */
734
void
735
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
736
0
              int line ATTRIBUTE_UNUSED, int no) {
737
0
    xmlXPathErr(ctxt, no);
738
0
}
739
740
/**
741
 * xmlXPathCheckOpLimit:
742
 * @ctxt:  the XPath Parser context
743
 * @opCount:  the number of operations to be added
744
 *
745
 * Adds opCount to the running total of operations and returns -1 if the
746
 * operation limit is exceeded. Returns 0 otherwise.
747
 */
748
static int
749
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
750
0
    xmlXPathContextPtr xpctxt = ctxt->context;
751
752
0
    if ((opCount > xpctxt->opLimit) ||
753
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
754
0
        xpctxt->opCount = xpctxt->opLimit;
755
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
756
0
        return(-1);
757
0
    }
758
759
0
    xpctxt->opCount += opCount;
760
0
    return(0);
761
0
}
762
763
#define OP_LIMIT_EXCEEDED(ctxt, n) \
764
0
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
765
766
/************************************************************************
767
 *                  *
768
 *      Parser Types          *
769
 *                  *
770
 ************************************************************************/
771
772
/*
773
 * Types are private:
774
 */
775
776
typedef enum {
777
    XPATH_OP_END=0,
778
    XPATH_OP_AND,
779
    XPATH_OP_OR,
780
    XPATH_OP_EQUAL,
781
    XPATH_OP_CMP,
782
    XPATH_OP_PLUS,
783
    XPATH_OP_MULT,
784
    XPATH_OP_UNION,
785
    XPATH_OP_ROOT,
786
    XPATH_OP_NODE,
787
    XPATH_OP_COLLECT,
788
    XPATH_OP_VALUE, /* 11 */
789
    XPATH_OP_VARIABLE,
790
    XPATH_OP_FUNCTION,
791
    XPATH_OP_ARG,
792
    XPATH_OP_PREDICATE,
793
    XPATH_OP_FILTER, /* 16 */
794
    XPATH_OP_SORT /* 17 */
795
#ifdef LIBXML_XPTR_LOCS_ENABLED
796
    ,XPATH_OP_RANGETO
797
#endif
798
} xmlXPathOp;
799
800
typedef enum {
801
    AXIS_ANCESTOR = 1,
802
    AXIS_ANCESTOR_OR_SELF,
803
    AXIS_ATTRIBUTE,
804
    AXIS_CHILD,
805
    AXIS_DESCENDANT,
806
    AXIS_DESCENDANT_OR_SELF,
807
    AXIS_FOLLOWING,
808
    AXIS_FOLLOWING_SIBLING,
809
    AXIS_NAMESPACE,
810
    AXIS_PARENT,
811
    AXIS_PRECEDING,
812
    AXIS_PRECEDING_SIBLING,
813
    AXIS_SELF
814
} xmlXPathAxisVal;
815
816
typedef enum {
817
    NODE_TEST_NONE = 0,
818
    NODE_TEST_TYPE = 1,
819
    NODE_TEST_PI = 2,
820
    NODE_TEST_ALL = 3,
821
    NODE_TEST_NS = 4,
822
    NODE_TEST_NAME = 5
823
} xmlXPathTestVal;
824
825
typedef enum {
826
    NODE_TYPE_NODE = 0,
827
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
828
    NODE_TYPE_TEXT = XML_TEXT_NODE,
829
    NODE_TYPE_PI = XML_PI_NODE
830
} xmlXPathTypeVal;
831
832
typedef struct _xmlXPathStepOp xmlXPathStepOp;
833
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
834
struct _xmlXPathStepOp {
835
    xmlXPathOp op;    /* The identifier of the operation */
836
    int ch1;      /* First child */
837
    int ch2;      /* Second child */
838
    int value;
839
    int value2;
840
    int value3;
841
    void *value4;
842
    void *value5;
843
    xmlXPathFunction cache;
844
    void *cacheURI;
845
};
846
847
struct _xmlXPathCompExpr {
848
    int nbStep;     /* Number of steps in this expression */
849
    int maxStep;    /* Maximum number of steps allocated */
850
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
851
    int last;     /* index of last step in expression */
852
    xmlChar *expr;    /* the expression being computed */
853
    xmlDictPtr dict;    /* the dictionary to use if any */
854
#ifdef XPATH_STREAMING
855
    xmlPatternPtr stream;
856
#endif
857
};
858
859
/************************************************************************
860
 *                  *
861
 *      Forward declarations        *
862
 *                  *
863
 ************************************************************************/
864
865
static void
866
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
867
static int
868
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
869
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
870
static int
871
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
872
          xmlXPathStepOpPtr op,
873
          int isPredicate);
874
static void
875
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
876
877
/************************************************************************
878
 *                  *
879
 *      Parser Type functions       *
880
 *                  *
881
 ************************************************************************/
882
883
/**
884
 * xmlXPathNewCompExpr:
885
 *
886
 * Create a new Xpath component
887
 *
888
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
889
 */
890
static xmlXPathCompExprPtr
891
0
xmlXPathNewCompExpr(void) {
892
0
    xmlXPathCompExprPtr cur;
893
894
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
895
0
    if (cur == NULL)
896
0
  return(NULL);
897
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
898
0
    cur->maxStep = 10;
899
0
    cur->nbStep = 0;
900
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
901
0
                                     sizeof(xmlXPathStepOp));
902
0
    if (cur->steps == NULL) {
903
0
  xmlFree(cur);
904
0
  return(NULL);
905
0
    }
906
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
907
0
    cur->last = -1;
908
0
    return(cur);
909
0
}
910
911
/**
912
 * xmlXPathFreeCompExpr:
913
 * @comp:  an XPATH comp
914
 *
915
 * Free up the memory allocated by @comp
916
 */
917
void
918
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
919
0
{
920
0
    xmlXPathStepOpPtr op;
921
0
    int i;
922
923
0
    if (comp == NULL)
924
0
        return;
925
0
    if (comp->dict == NULL) {
926
0
  for (i = 0; i < comp->nbStep; i++) {
927
0
      op = &comp->steps[i];
928
0
      if (op->value4 != NULL) {
929
0
    if (op->op == XPATH_OP_VALUE)
930
0
        xmlXPathFreeObject(op->value4);
931
0
    else
932
0
        xmlFree(op->value4);
933
0
      }
934
0
      if (op->value5 != NULL)
935
0
    xmlFree(op->value5);
936
0
  }
937
0
    } else {
938
0
  for (i = 0; i < comp->nbStep; i++) {
939
0
      op = &comp->steps[i];
940
0
      if (op->value4 != NULL) {
941
0
    if (op->op == XPATH_OP_VALUE)
942
0
        xmlXPathFreeObject(op->value4);
943
0
      }
944
0
  }
945
0
        xmlDictFree(comp->dict);
946
0
    }
947
0
    if (comp->steps != NULL) {
948
0
        xmlFree(comp->steps);
949
0
    }
950
#ifdef XPATH_STREAMING
951
    if (comp->stream != NULL) {
952
        xmlFreePatternList(comp->stream);
953
    }
954
#endif
955
0
    if (comp->expr != NULL) {
956
0
        xmlFree(comp->expr);
957
0
    }
958
959
0
    xmlFree(comp);
960
0
}
961
962
/**
963
 * xmlXPathCompExprAdd:
964
 * @comp:  the compiled expression
965
 * @ch1: first child index
966
 * @ch2: second child index
967
 * @op:  an op
968
 * @value:  the first int value
969
 * @value2:  the second int value
970
 * @value3:  the third int value
971
 * @value4:  the first string value
972
 * @value5:  the second string value
973
 *
974
 * Add a step to an XPath Compiled Expression
975
 *
976
 * Returns -1 in case of failure, the index otherwise
977
 */
978
static int
979
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
980
   xmlXPathOp op, int value,
981
0
   int value2, int value3, void *value4, void *value5) {
982
0
    xmlXPathCompExprPtr comp = ctxt->comp;
983
0
    if (comp->nbStep >= comp->maxStep) {
984
0
  xmlXPathStepOp *real;
985
986
0
        if (comp->maxStep >= XPATH_MAX_STEPS) {
987
0
      xmlXPathPErrMemory(ctxt);
988
0
      return(-1);
989
0
        }
990
0
  comp->maxStep *= 2;
991
0
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
992
0
                          comp->maxStep * sizeof(xmlXPathStepOp));
993
0
  if (real == NULL) {
994
0
      comp->maxStep /= 2;
995
0
      xmlXPathPErrMemory(ctxt);
996
0
      return(-1);
997
0
  }
998
0
  comp->steps = real;
999
0
    }
1000
0
    comp->last = comp->nbStep;
1001
0
    comp->steps[comp->nbStep].ch1 = ch1;
1002
0
    comp->steps[comp->nbStep].ch2 = ch2;
1003
0
    comp->steps[comp->nbStep].op = op;
1004
0
    comp->steps[comp->nbStep].value = value;
1005
0
    comp->steps[comp->nbStep].value2 = value2;
1006
0
    comp->steps[comp->nbStep].value3 = value3;
1007
0
    if ((comp->dict != NULL) &&
1008
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1009
0
   (op == XPATH_OP_COLLECT))) {
1010
0
        if (value4 != NULL) {
1011
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1012
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1013
0
      xmlFree(value4);
1014
0
  } else
1015
0
      comp->steps[comp->nbStep].value4 = NULL;
1016
0
        if (value5 != NULL) {
1017
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1018
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1019
0
      xmlFree(value5);
1020
0
  } else
1021
0
      comp->steps[comp->nbStep].value5 = NULL;
1022
0
    } else {
1023
0
  comp->steps[comp->nbStep].value4 = value4;
1024
0
  comp->steps[comp->nbStep].value5 = value5;
1025
0
    }
1026
0
    comp->steps[comp->nbStep].cache = NULL;
1027
0
    return(comp->nbStep++);
1028
0
}
1029
1030
/**
1031
 * xmlXPathCompSwap:
1032
 * @comp:  the compiled expression
1033
 * @op: operation index
1034
 *
1035
 * Swaps 2 operations in the compiled expression
1036
 */
1037
static void
1038
0
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1039
0
    int tmp;
1040
1041
#ifndef LIBXML_THREAD_ENABLED
1042
    /*
1043
     * Since this manipulates possibly shared variables, this is
1044
     * disabled if one detects that the library is used in a multithreaded
1045
     * application
1046
     */
1047
    if (xmlXPathDisableOptimizer)
1048
  return;
1049
#endif
1050
1051
0
    tmp = op->ch1;
1052
0
    op->ch1 = op->ch2;
1053
0
    op->ch2 = tmp;
1054
0
}
1055
1056
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1057
0
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1058
0
                  (op), (val), (val2), (val3), (val4), (val5))
1059
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1060
0
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1061
0
                  (op), (val), (val2), (val3), (val4), (val5))
1062
1063
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1064
0
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1065
1066
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1067
0
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1068
1069
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1070
0
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1071
0
      (val), (val2), 0 ,NULL ,NULL)
1072
1073
/************************************************************************
1074
 *                  *
1075
 *    XPath object cache structures       *
1076
 *                  *
1077
 ************************************************************************/
1078
1079
/* #define XP_DEFAULT_CACHE_ON */
1080
1081
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1082
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1083
struct _xmlXPathContextCache {
1084
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1085
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1086
    int numNodeset;
1087
    int maxNodeset;
1088
    int numMisc;
1089
    int maxMisc;
1090
};
1091
1092
/************************************************************************
1093
 *                  *
1094
 *    Debugging related functions       *
1095
 *                  *
1096
 ************************************************************************/
1097
1098
#ifdef LIBXML_DEBUG_ENABLED
1099
static void
1100
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1101
    int i;
1102
    char shift[100];
1103
1104
    for (i = 0;((i < depth) && (i < 25));i++)
1105
        shift[2 * i] = shift[2 * i + 1] = ' ';
1106
    shift[2 * i] = shift[2 * i + 1] = 0;
1107
    if (cur == NULL) {
1108
  fprintf(output, "%s", shift);
1109
  fprintf(output, "Node is NULL !\n");
1110
  return;
1111
1112
    }
1113
1114
    if ((cur->type == XML_DOCUMENT_NODE) ||
1115
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1116
  fprintf(output, "%s", shift);
1117
  fprintf(output, " /\n");
1118
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1119
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1120
    else
1121
  xmlDebugDumpOneNode(output, cur, depth);
1122
}
1123
static void
1124
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1125
    xmlNodePtr tmp;
1126
    int i;
1127
    char shift[100];
1128
1129
    for (i = 0;((i < depth) && (i < 25));i++)
1130
        shift[2 * i] = shift[2 * i + 1] = ' ';
1131
    shift[2 * i] = shift[2 * i + 1] = 0;
1132
    if (cur == NULL) {
1133
  fprintf(output, "%s", shift);
1134
  fprintf(output, "Node is NULL !\n");
1135
  return;
1136
1137
    }
1138
1139
    while (cur != NULL) {
1140
  tmp = cur;
1141
  cur = cur->next;
1142
  xmlDebugDumpOneNode(output, tmp, depth);
1143
    }
1144
}
1145
1146
static void
1147
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1148
    int i;
1149
    char shift[100];
1150
1151
    for (i = 0;((i < depth) && (i < 25));i++)
1152
        shift[2 * i] = shift[2 * i + 1] = ' ';
1153
    shift[2 * i] = shift[2 * i + 1] = 0;
1154
1155
    if (cur == NULL) {
1156
  fprintf(output, "%s", shift);
1157
  fprintf(output, "NodeSet is NULL !\n");
1158
  return;
1159
1160
    }
1161
1162
    if (cur != NULL) {
1163
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1164
  for (i = 0;i < cur->nodeNr;i++) {
1165
      fprintf(output, "%s", shift);
1166
      fprintf(output, "%d", i + 1);
1167
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1168
  }
1169
    }
1170
}
1171
1172
static void
1173
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1174
    int i;
1175
    char shift[100];
1176
1177
    for (i = 0;((i < depth) && (i < 25));i++)
1178
        shift[2 * i] = shift[2 * i + 1] = ' ';
1179
    shift[2 * i] = shift[2 * i + 1] = 0;
1180
1181
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1182
  fprintf(output, "%s", shift);
1183
  fprintf(output, "Value Tree is NULL !\n");
1184
  return;
1185
1186
    }
1187
1188
    fprintf(output, "%s", shift);
1189
    fprintf(output, "%d", i + 1);
1190
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1191
}
1192
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1193
static void
1194
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1195
    int i;
1196
    char shift[100];
1197
1198
    for (i = 0;((i < depth) && (i < 25));i++)
1199
        shift[2 * i] = shift[2 * i + 1] = ' ';
1200
    shift[2 * i] = shift[2 * i + 1] = 0;
1201
1202
    if (cur == NULL) {
1203
  fprintf(output, "%s", shift);
1204
  fprintf(output, "LocationSet is NULL !\n");
1205
  return;
1206
1207
    }
1208
1209
    for (i = 0;i < cur->locNr;i++) {
1210
  fprintf(output, "%s", shift);
1211
        fprintf(output, "%d : ", i + 1);
1212
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1213
    }
1214
}
1215
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1216
1217
/**
1218
 * xmlXPathDebugDumpObject:
1219
 * @output:  the FILE * to dump the output
1220
 * @cur:  the object to inspect
1221
 * @depth:  indentation level
1222
 *
1223
 * Dump the content of the object for debugging purposes
1224
 */
1225
void
1226
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1227
    int i;
1228
    char shift[100];
1229
1230
    if (output == NULL) return;
1231
1232
    for (i = 0;((i < depth) && (i < 25));i++)
1233
        shift[2 * i] = shift[2 * i + 1] = ' ';
1234
    shift[2 * i] = shift[2 * i + 1] = 0;
1235
1236
1237
    fprintf(output, "%s", shift);
1238
1239
    if (cur == NULL) {
1240
        fprintf(output, "Object is empty (NULL)\n");
1241
  return;
1242
    }
1243
    switch(cur->type) {
1244
        case XPATH_UNDEFINED:
1245
      fprintf(output, "Object is uninitialized\n");
1246
      break;
1247
        case XPATH_NODESET:
1248
      fprintf(output, "Object is a Node Set :\n");
1249
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1250
      break;
1251
  case XPATH_XSLT_TREE:
1252
      fprintf(output, "Object is an XSLT value tree :\n");
1253
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1254
      break;
1255
        case XPATH_BOOLEAN:
1256
      fprintf(output, "Object is a Boolean : ");
1257
      if (cur->boolval) fprintf(output, "true\n");
1258
      else fprintf(output, "false\n");
1259
      break;
1260
        case XPATH_NUMBER:
1261
      switch (xmlXPathIsInf(cur->floatval)) {
1262
      case 1:
1263
    fprintf(output, "Object is a number : Infinity\n");
1264
    break;
1265
      case -1:
1266
    fprintf(output, "Object is a number : -Infinity\n");
1267
    break;
1268
      default:
1269
    if (xmlXPathIsNaN(cur->floatval)) {
1270
        fprintf(output, "Object is a number : NaN\n");
1271
    } else if (cur->floatval == 0) {
1272
                    /* Omit sign for negative zero. */
1273
        fprintf(output, "Object is a number : 0\n");
1274
    } else {
1275
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1276
    }
1277
      }
1278
      break;
1279
        case XPATH_STRING:
1280
      fprintf(output, "Object is a string : ");
1281
      xmlDebugDumpString(output, cur->stringval);
1282
      fprintf(output, "\n");
1283
      break;
1284
#ifdef LIBXML_XPTR_LOCS_ENABLED
1285
  case XPATH_POINT:
1286
      fprintf(output, "Object is a point : index %d in node", cur->index);
1287
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1288
      fprintf(output, "\n");
1289
      break;
1290
  case XPATH_RANGE:
1291
      if ((cur->user2 == NULL) ||
1292
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1293
    fprintf(output, "Object is a collapsed range :\n");
1294
    fprintf(output, "%s", shift);
1295
    if (cur->index >= 0)
1296
        fprintf(output, "index %d in ", cur->index);
1297
    fprintf(output, "node\n");
1298
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1299
                    depth + 1);
1300
      } else  {
1301
    fprintf(output, "Object is a range :\n");
1302
    fprintf(output, "%s", shift);
1303
    fprintf(output, "From ");
1304
    if (cur->index >= 0)
1305
        fprintf(output, "index %d in ", cur->index);
1306
    fprintf(output, "node\n");
1307
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1308
                    depth + 1);
1309
    fprintf(output, "%s", shift);
1310
    fprintf(output, "To ");
1311
    if (cur->index2 >= 0)
1312
        fprintf(output, "index %d in ", cur->index2);
1313
    fprintf(output, "node\n");
1314
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1315
                    depth + 1);
1316
    fprintf(output, "\n");
1317
      }
1318
      break;
1319
  case XPATH_LOCATIONSET:
1320
      fprintf(output, "Object is a Location Set:\n");
1321
      xmlXPathDebugDumpLocationSet(output,
1322
        (xmlLocationSetPtr) cur->user, depth);
1323
      break;
1324
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1325
  case XPATH_USERS:
1326
      fprintf(output, "Object is user defined\n");
1327
      break;
1328
    }
1329
}
1330
1331
static void
1332
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1333
                       xmlXPathStepOpPtr op, int depth) {
1334
    int i;
1335
    char shift[100];
1336
1337
    for (i = 0;((i < depth) && (i < 25));i++)
1338
        shift[2 * i] = shift[2 * i + 1] = ' ';
1339
    shift[2 * i] = shift[2 * i + 1] = 0;
1340
1341
    fprintf(output, "%s", shift);
1342
    if (op == NULL) {
1343
  fprintf(output, "Step is NULL\n");
1344
  return;
1345
    }
1346
    switch (op->op) {
1347
        case XPATH_OP_END:
1348
      fprintf(output, "END"); break;
1349
        case XPATH_OP_AND:
1350
      fprintf(output, "AND"); break;
1351
        case XPATH_OP_OR:
1352
      fprintf(output, "OR"); break;
1353
        case XPATH_OP_EQUAL:
1354
       if (op->value)
1355
     fprintf(output, "EQUAL =");
1356
       else
1357
     fprintf(output, "EQUAL !=");
1358
       break;
1359
        case XPATH_OP_CMP:
1360
       if (op->value)
1361
     fprintf(output, "CMP <");
1362
       else
1363
     fprintf(output, "CMP >");
1364
       if (!op->value2)
1365
     fprintf(output, "=");
1366
       break;
1367
        case XPATH_OP_PLUS:
1368
       if (op->value == 0)
1369
     fprintf(output, "PLUS -");
1370
       else if (op->value == 1)
1371
     fprintf(output, "PLUS +");
1372
       else if (op->value == 2)
1373
     fprintf(output, "PLUS unary -");
1374
       else if (op->value == 3)
1375
     fprintf(output, "PLUS unary - -");
1376
       break;
1377
        case XPATH_OP_MULT:
1378
       if (op->value == 0)
1379
     fprintf(output, "MULT *");
1380
       else if (op->value == 1)
1381
     fprintf(output, "MULT div");
1382
       else
1383
     fprintf(output, "MULT mod");
1384
       break;
1385
        case XPATH_OP_UNION:
1386
       fprintf(output, "UNION"); break;
1387
        case XPATH_OP_ROOT:
1388
       fprintf(output, "ROOT"); break;
1389
        case XPATH_OP_NODE:
1390
       fprintf(output, "NODE"); break;
1391
        case XPATH_OP_SORT:
1392
       fprintf(output, "SORT"); break;
1393
        case XPATH_OP_COLLECT: {
1394
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1395
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1396
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1397
      const xmlChar *prefix = op->value4;
1398
      const xmlChar *name = op->value5;
1399
1400
      fprintf(output, "COLLECT ");
1401
      switch (axis) {
1402
    case AXIS_ANCESTOR:
1403
        fprintf(output, " 'ancestors' "); break;
1404
    case AXIS_ANCESTOR_OR_SELF:
1405
        fprintf(output, " 'ancestors-or-self' "); break;
1406
    case AXIS_ATTRIBUTE:
1407
        fprintf(output, " 'attributes' "); break;
1408
    case AXIS_CHILD:
1409
        fprintf(output, " 'child' "); break;
1410
    case AXIS_DESCENDANT:
1411
        fprintf(output, " 'descendant' "); break;
1412
    case AXIS_DESCENDANT_OR_SELF:
1413
        fprintf(output, " 'descendant-or-self' "); break;
1414
    case AXIS_FOLLOWING:
1415
        fprintf(output, " 'following' "); break;
1416
    case AXIS_FOLLOWING_SIBLING:
1417
        fprintf(output, " 'following-siblings' "); break;
1418
    case AXIS_NAMESPACE:
1419
        fprintf(output, " 'namespace' "); break;
1420
    case AXIS_PARENT:
1421
        fprintf(output, " 'parent' "); break;
1422
    case AXIS_PRECEDING:
1423
        fprintf(output, " 'preceding' "); break;
1424
    case AXIS_PRECEDING_SIBLING:
1425
        fprintf(output, " 'preceding-sibling' "); break;
1426
    case AXIS_SELF:
1427
        fprintf(output, " 'self' "); break;
1428
      }
1429
      switch (test) {
1430
                case NODE_TEST_NONE:
1431
        fprintf(output, "'none' "); break;
1432
                case NODE_TEST_TYPE:
1433
        fprintf(output, "'type' "); break;
1434
                case NODE_TEST_PI:
1435
        fprintf(output, "'PI' "); break;
1436
                case NODE_TEST_ALL:
1437
        fprintf(output, "'all' "); break;
1438
                case NODE_TEST_NS:
1439
        fprintf(output, "'namespace' "); break;
1440
                case NODE_TEST_NAME:
1441
        fprintf(output, "'name' "); break;
1442
      }
1443
      switch (type) {
1444
                case NODE_TYPE_NODE:
1445
        fprintf(output, "'node' "); break;
1446
                case NODE_TYPE_COMMENT:
1447
        fprintf(output, "'comment' "); break;
1448
                case NODE_TYPE_TEXT:
1449
        fprintf(output, "'text' "); break;
1450
                case NODE_TYPE_PI:
1451
        fprintf(output, "'PI' "); break;
1452
      }
1453
      if (prefix != NULL)
1454
    fprintf(output, "%s:", prefix);
1455
      if (name != NULL)
1456
    fprintf(output, "%s", (const char *) name);
1457
      break;
1458
1459
        }
1460
  case XPATH_OP_VALUE: {
1461
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1462
1463
      fprintf(output, "ELEM ");
1464
      xmlXPathDebugDumpObject(output, object, 0);
1465
      goto finish;
1466
  }
1467
  case XPATH_OP_VARIABLE: {
1468
      const xmlChar *prefix = op->value5;
1469
      const xmlChar *name = op->value4;
1470
1471
      if (prefix != NULL)
1472
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1473
      else
1474
    fprintf(output, "VARIABLE %s", name);
1475
      break;
1476
  }
1477
  case XPATH_OP_FUNCTION: {
1478
      int nbargs = op->value;
1479
      const xmlChar *prefix = op->value5;
1480
      const xmlChar *name = op->value4;
1481
1482
      if (prefix != NULL)
1483
    fprintf(output, "FUNCTION %s:%s(%d args)",
1484
      prefix, name, nbargs);
1485
      else
1486
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1487
      break;
1488
  }
1489
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1490
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1491
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1492
#ifdef LIBXML_XPTR_LOCS_ENABLED
1493
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1494
#endif
1495
  default:
1496
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1497
    }
1498
    fprintf(output, "\n");
1499
finish:
1500
    if (op->ch1 >= 0)
1501
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1502
    if (op->ch2 >= 0)
1503
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1504
}
1505
1506
/**
1507
 * xmlXPathDebugDumpCompExpr:
1508
 * @output:  the FILE * for the output
1509
 * @comp:  the precompiled XPath expression
1510
 * @depth:  the indentation level.
1511
 *
1512
 * Dumps the tree of the compiled XPath expression.
1513
 */
1514
void
1515
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1516
                    int depth) {
1517
    int i;
1518
    char shift[100];
1519
1520
    if ((output == NULL) || (comp == NULL)) return;
1521
1522
    for (i = 0;((i < depth) && (i < 25));i++)
1523
        shift[2 * i] = shift[2 * i + 1] = ' ';
1524
    shift[2 * i] = shift[2 * i + 1] = 0;
1525
1526
    fprintf(output, "%s", shift);
1527
1528
#ifdef XPATH_STREAMING
1529
    if (comp->stream) {
1530
        fprintf(output, "Streaming Expression\n");
1531
    } else
1532
#endif
1533
    {
1534
        fprintf(output, "Compiled Expression : %d elements\n",
1535
                comp->nbStep);
1536
        i = comp->last;
1537
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1538
    }
1539
}
1540
1541
#endif /* LIBXML_DEBUG_ENABLED */
1542
1543
/************************************************************************
1544
 *                  *
1545
 *      XPath object caching        *
1546
 *                  *
1547
 ************************************************************************/
1548
1549
/**
1550
 * xmlXPathNewCache:
1551
 *
1552
 * Create a new object cache
1553
 *
1554
 * Returns the xmlXPathCache just allocated.
1555
 */
1556
static xmlXPathContextCachePtr
1557
xmlXPathNewCache(void)
1558
0
{
1559
0
    xmlXPathContextCachePtr ret;
1560
1561
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1562
0
    if (ret == NULL)
1563
0
  return(NULL);
1564
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1565
0
    ret->maxNodeset = 100;
1566
0
    ret->maxMisc = 100;
1567
0
    return(ret);
1568
0
}
1569
1570
static void
1571
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1572
0
{
1573
0
    while (list != NULL) {
1574
0
        xmlXPathObjectPtr next;
1575
1576
0
        next = (void *) list->stringval;
1577
1578
0
  if (list->nodesetval != NULL) {
1579
0
      if (list->nodesetval->nodeTab != NULL)
1580
0
    xmlFree(list->nodesetval->nodeTab);
1581
0
      xmlFree(list->nodesetval);
1582
0
  }
1583
0
  xmlFree(list);
1584
1585
0
        list = next;
1586
0
    }
1587
0
}
1588
1589
static void
1590
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1591
0
{
1592
0
    if (cache == NULL)
1593
0
  return;
1594
0
    if (cache->nodesetObjs)
1595
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1596
0
    if (cache->miscObjs)
1597
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1598
0
    xmlFree(cache);
1599
0
}
1600
1601
/**
1602
 * xmlXPathContextSetCache:
1603
 *
1604
 * @ctxt:  the XPath context
1605
 * @active: enables/disables (creates/frees) the cache
1606
 * @value: a value with semantics dependent on @options
1607
 * @options: options (currently only the value 0 is used)
1608
 *
1609
 * Creates/frees an object cache on the XPath context.
1610
 * If activates XPath objects (xmlXPathObject) will be cached internally
1611
 * to be reused.
1612
 * @options:
1613
 *   0: This will set the XPath object caching:
1614
 *      @value:
1615
 *        This will set the maximum number of XPath objects
1616
 *        to be cached per slot
1617
 *        There are two slots for node-set and misc objects.
1618
 *        Use <0 for the default number (100).
1619
 *   Other values for @options have currently no effect.
1620
 *
1621
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1622
 */
1623
int
1624
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1625
      int active,
1626
      int value,
1627
      int options)
1628
0
{
1629
0
    if (ctxt == NULL)
1630
0
  return(-1);
1631
0
    if (active) {
1632
0
  xmlXPathContextCachePtr cache;
1633
1634
0
  if (ctxt->cache == NULL) {
1635
0
      ctxt->cache = xmlXPathNewCache();
1636
0
      if (ctxt->cache == NULL) {
1637
0
                xmlXPathErrMemory(ctxt);
1638
0
    return(-1);
1639
0
            }
1640
0
  }
1641
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1642
0
  if (options == 0) {
1643
0
      if (value < 0)
1644
0
    value = 100;
1645
0
      cache->maxNodeset = value;
1646
0
      cache->maxMisc = value;
1647
0
  }
1648
0
    } else if (ctxt->cache != NULL) {
1649
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1650
0
  ctxt->cache = NULL;
1651
0
    }
1652
0
    return(0);
1653
0
}
1654
1655
/**
1656
 * xmlXPathCacheWrapNodeSet:
1657
 * @pctxt: the XPath context
1658
 * @val:  the NodePtr value
1659
 *
1660
 * This is the cached version of xmlXPathWrapNodeSet().
1661
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1662
 *
1663
 * Returns the created or reused object.
1664
 *
1665
 * In case of error the node set is destroyed and NULL is returned.
1666
 */
1667
static xmlXPathObjectPtr
1668
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1669
0
{
1670
0
    xmlXPathObjectPtr ret;
1671
0
    xmlXPathContextPtr ctxt = pctxt->context;
1672
1673
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1674
0
  xmlXPathContextCachePtr cache =
1675
0
      (xmlXPathContextCachePtr) ctxt->cache;
1676
1677
0
  if (cache->miscObjs != NULL) {
1678
0
      ret = cache->miscObjs;
1679
0
            cache->miscObjs = (void *) ret->stringval;
1680
0
            cache->numMisc -= 1;
1681
0
            ret->stringval = NULL;
1682
0
      ret->type = XPATH_NODESET;
1683
0
      ret->nodesetval = val;
1684
0
      return(ret);
1685
0
  }
1686
0
    }
1687
1688
0
    ret = xmlXPathWrapNodeSet(val);
1689
0
    if (ret == NULL)
1690
0
        xmlXPathPErrMemory(pctxt);
1691
0
    return(ret);
1692
0
}
1693
1694
/**
1695
 * xmlXPathCacheWrapString:
1696
 * @pctxt the XPath context
1697
 * @val:  the xmlChar * value
1698
 *
1699
 * This is the cached version of xmlXPathWrapString().
1700
 * Wraps the @val string into an XPath object.
1701
 *
1702
 * Returns the created or reused object.
1703
 */
1704
static xmlXPathObjectPtr
1705
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1706
0
{
1707
0
    xmlXPathObjectPtr ret;
1708
0
    xmlXPathContextPtr ctxt = pctxt->context;
1709
1710
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1711
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1712
1713
0
  if (cache->miscObjs != NULL) {
1714
0
      ret = cache->miscObjs;
1715
0
            cache->miscObjs = (void *) ret->stringval;
1716
0
            cache->numMisc -= 1;
1717
0
      ret->type = XPATH_STRING;
1718
0
      ret->stringval = val;
1719
0
      return(ret);
1720
0
  }
1721
0
    }
1722
1723
0
    ret = xmlXPathWrapString(val);
1724
0
    if (ret == NULL)
1725
0
        xmlXPathPErrMemory(pctxt);
1726
0
    return(ret);
1727
0
}
1728
1729
/**
1730
 * xmlXPathCacheNewNodeSet:
1731
 * @pctxt the XPath context
1732
 * @val:  the NodePtr value
1733
 *
1734
 * This is the cached version of xmlXPathNewNodeSet().
1735
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1736
 * it with the single Node @val
1737
 *
1738
 * Returns the created or reused object.
1739
 */
1740
static xmlXPathObjectPtr
1741
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1742
0
{
1743
0
    xmlXPathObjectPtr ret;
1744
0
    xmlXPathContextPtr ctxt = pctxt->context;
1745
1746
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1747
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1748
1749
0
  if (cache->nodesetObjs != NULL) {
1750
      /*
1751
      * Use the nodeset-cache.
1752
      */
1753
0
      ret = cache->nodesetObjs;
1754
0
            cache->nodesetObjs = (void *) ret->stringval;
1755
0
            cache->numNodeset -= 1;
1756
0
            ret->stringval = NULL;
1757
0
      ret->type = XPATH_NODESET;
1758
0
      ret->boolval = 0;
1759
0
      if (val) {
1760
0
    if ((ret->nodesetval->nodeMax == 0) ||
1761
0
        (val->type == XML_NAMESPACE_DECL))
1762
0
    {
1763
0
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1764
0
                        xmlXPathPErrMemory(pctxt);
1765
0
    } else {
1766
0
        ret->nodesetval->nodeTab[0] = val;
1767
0
        ret->nodesetval->nodeNr = 1;
1768
0
    }
1769
0
      }
1770
0
      return(ret);
1771
0
  } else if (cache->miscObjs != NULL) {
1772
0
            xmlNodeSetPtr set;
1773
      /*
1774
      * Fallback to misc-cache.
1775
      */
1776
1777
0
      set = xmlXPathNodeSetCreate(val);
1778
0
      if (set == NULL) {
1779
0
                xmlXPathPErrMemory(pctxt);
1780
0
    return(NULL);
1781
0
      }
1782
1783
0
      ret = cache->miscObjs;
1784
0
            cache->miscObjs = (void *) ret->stringval;
1785
0
            cache->numMisc -= 1;
1786
0
            ret->stringval = NULL;
1787
0
      ret->type = XPATH_NODESET;
1788
0
      ret->boolval = 0;
1789
0
      ret->nodesetval = set;
1790
0
      return(ret);
1791
0
  }
1792
0
    }
1793
0
    ret = xmlXPathNewNodeSet(val);
1794
0
    if (ret == NULL)
1795
0
        xmlXPathPErrMemory(pctxt);
1796
0
    return(ret);
1797
0
}
1798
1799
/**
1800
 * xmlXPathCacheNewString:
1801
 * @pctxt the XPath context
1802
 * @val:  the xmlChar * value
1803
 *
1804
 * This is the cached version of xmlXPathNewString().
1805
 * Acquire an xmlXPathObjectPtr of type string and of value @val
1806
 *
1807
 * Returns the created or reused object.
1808
 */
1809
static xmlXPathObjectPtr
1810
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1811
0
{
1812
0
    xmlXPathObjectPtr ret;
1813
0
    xmlXPathContextPtr ctxt = pctxt->context;
1814
1815
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1816
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1817
1818
0
  if (cache->miscObjs != NULL) {
1819
0
            xmlChar *copy;
1820
1821
0
            if (val == NULL)
1822
0
                val = BAD_CAST "";
1823
0
            copy = xmlStrdup(val);
1824
0
            if (copy == NULL) {
1825
0
                xmlXPathPErrMemory(pctxt);
1826
0
                return(NULL);
1827
0
            }
1828
1829
0
      ret = cache->miscObjs;
1830
0
            cache->miscObjs = (void *) ret->stringval;
1831
0
            cache->numMisc -= 1;
1832
0
      ret->type = XPATH_STRING;
1833
0
            ret->stringval = copy;
1834
0
      return(ret);
1835
0
  }
1836
0
    }
1837
1838
0
    ret = xmlXPathNewString(val);
1839
0
    if (ret == NULL)
1840
0
        xmlXPathPErrMemory(pctxt);
1841
0
    return(ret);
1842
0
}
1843
1844
/**
1845
 * xmlXPathCacheNewCString:
1846
 * @pctxt the XPath context
1847
 * @val:  the char * value
1848
 *
1849
 * This is the cached version of xmlXPathNewCString().
1850
 * Acquire an xmlXPathObjectPtr of type string and of value @val
1851
 *
1852
 * Returns the created or reused object.
1853
 */
1854
static xmlXPathObjectPtr
1855
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1856
0
{
1857
0
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1858
0
}
1859
1860
/**
1861
 * xmlXPathCacheNewBoolean:
1862
 * @pctxt the XPath context
1863
 * @val:  the boolean value
1864
 *
1865
 * This is the cached version of xmlXPathNewBoolean().
1866
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1867
 *
1868
 * Returns the created or reused object.
1869
 */
1870
static xmlXPathObjectPtr
1871
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1872
0
{
1873
0
    xmlXPathObjectPtr ret;
1874
0
    xmlXPathContextPtr ctxt = pctxt->context;
1875
1876
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1877
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1878
1879
0
  if (cache->miscObjs != NULL) {
1880
0
      ret = cache->miscObjs;
1881
0
            cache->miscObjs = (void *) ret->stringval;
1882
0
            cache->numMisc -= 1;
1883
0
            ret->stringval = NULL;
1884
0
      ret->type = XPATH_BOOLEAN;
1885
0
      ret->boolval = (val != 0);
1886
0
      return(ret);
1887
0
  }
1888
0
    }
1889
1890
0
    ret = xmlXPathNewBoolean(val);
1891
0
    if (ret == NULL)
1892
0
        xmlXPathPErrMemory(pctxt);
1893
0
    return(ret);
1894
0
}
1895
1896
/**
1897
 * xmlXPathCacheNewFloat:
1898
 * @pctxt the XPath context
1899
 * @val:  the double value
1900
 *
1901
 * This is the cached version of xmlXPathNewFloat().
1902
 * Acquires an xmlXPathObjectPtr of type double and of value @val
1903
 *
1904
 * Returns the created or reused object.
1905
 */
1906
static xmlXPathObjectPtr
1907
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1908
0
{
1909
0
    xmlXPathObjectPtr ret;
1910
0
    xmlXPathContextPtr ctxt = pctxt->context;
1911
1912
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1913
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1914
1915
0
  if (cache->miscObjs != NULL) {
1916
0
      ret = cache->miscObjs;
1917
0
            cache->miscObjs = (void *) ret->stringval;
1918
0
            cache->numMisc -= 1;
1919
0
            ret->stringval = NULL;
1920
0
      ret->type = XPATH_NUMBER;
1921
0
      ret->floatval = val;
1922
0
      return(ret);
1923
0
  }
1924
0
    }
1925
1926
0
    ret = xmlXPathNewFloat(val);
1927
0
    if (ret == NULL)
1928
0
        xmlXPathPErrMemory(pctxt);
1929
0
    return(ret);
1930
0
}
1931
1932
/**
1933
 * xmlXPathCacheObjectCopy:
1934
 * @pctxt the XPath context
1935
 * @val:  the original object
1936
 *
1937
 * This is the cached version of xmlXPathObjectCopy().
1938
 * Acquire a copy of a given object
1939
 *
1940
 * Returns a created or reused created object.
1941
 */
1942
static xmlXPathObjectPtr
1943
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1944
0
{
1945
0
    xmlXPathObjectPtr ret;
1946
0
    xmlXPathContextPtr ctxt = pctxt->context;
1947
1948
0
    if (val == NULL)
1949
0
  return(NULL);
1950
1951
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1952
0
  switch (val->type) {
1953
0
            case XPATH_NODESET: {
1954
0
                xmlNodeSetPtr set;
1955
1956
0
                set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1957
0
                if (set == NULL) {
1958
0
                    xmlXPathPErrMemory(pctxt);
1959
0
                    return(NULL);
1960
0
                }
1961
0
                return(xmlXPathCacheWrapNodeSet(pctxt, set));
1962
0
            }
1963
0
      case XPATH_STRING:
1964
0
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1965
0
      case XPATH_BOOLEAN:
1966
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1967
0
      case XPATH_NUMBER:
1968
0
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1969
0
      default:
1970
0
    break;
1971
0
  }
1972
0
    }
1973
0
    ret = xmlXPathObjectCopy(val);
1974
0
    if (ret == NULL)
1975
0
        xmlXPathPErrMemory(pctxt);
1976
0
    return(ret);
1977
0
}
1978
1979
/************************************************************************
1980
 *                  *
1981
 *    Parser stacks related functions and macros    *
1982
 *                  *
1983
 ************************************************************************/
1984
1985
/**
1986
 * xmlXPathCastToNumberInternal:
1987
 * @ctxt:  parser context
1988
 * @val:  an XPath object
1989
 *
1990
 * Converts an XPath object to its number value
1991
 *
1992
 * Returns the number value
1993
 */
1994
static double
1995
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1996
0
                             xmlXPathObjectPtr val) {
1997
0
    double ret = 0.0;
1998
1999
0
    if (val == NULL)
2000
0
  return(xmlXPathNAN);
2001
0
    switch (val->type) {
2002
0
    case XPATH_UNDEFINED:
2003
0
  ret = xmlXPathNAN;
2004
0
  break;
2005
0
    case XPATH_NODESET:
2006
0
    case XPATH_XSLT_TREE: {
2007
0
        xmlChar *str;
2008
2009
0
  str = xmlXPathCastNodeSetToString(val->nodesetval);
2010
0
        if (str == NULL) {
2011
0
            xmlXPathPErrMemory(ctxt);
2012
0
            ret = xmlXPathNAN;
2013
0
        } else {
2014
0
      ret = xmlXPathCastStringToNumber(str);
2015
0
            xmlFree(str);
2016
0
        }
2017
0
  break;
2018
0
    }
2019
0
    case XPATH_STRING:
2020
0
  ret = xmlXPathCastStringToNumber(val->stringval);
2021
0
  break;
2022
0
    case XPATH_NUMBER:
2023
0
  ret = val->floatval;
2024
0
  break;
2025
0
    case XPATH_BOOLEAN:
2026
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
2027
0
  break;
2028
0
    case XPATH_USERS:
2029
#ifdef LIBXML_XPTR_LOCS_ENABLED
2030
    case XPATH_POINT:
2031
    case XPATH_RANGE:
2032
    case XPATH_LOCATIONSET:
2033
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2034
  /* TODO */
2035
0
  ret = xmlXPathNAN;
2036
0
  break;
2037
0
    }
2038
0
    return(ret);
2039
0
}
2040
2041
/**
2042
 * valuePop:
2043
 * @ctxt: an XPath evaluation context
2044
 *
2045
 * Pops the top XPath object from the value stack
2046
 *
2047
 * Returns the XPath object just removed
2048
 */
2049
xmlXPathObjectPtr
2050
valuePop(xmlXPathParserContextPtr ctxt)
2051
0
{
2052
0
    xmlXPathObjectPtr ret;
2053
2054
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2055
0
        return (NULL);
2056
2057
0
    ctxt->valueNr--;
2058
0
    if (ctxt->valueNr > 0)
2059
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2060
0
    else
2061
0
        ctxt->value = NULL;
2062
0
    ret = ctxt->valueTab[ctxt->valueNr];
2063
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
2064
0
    return (ret);
2065
0
}
2066
/**
2067
 * valuePush:
2068
 * @ctxt:  an XPath evaluation context
2069
 * @value:  the XPath object
2070
 *
2071
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2072
 * a memory error is recorded in the parser context.
2073
 *
2074
 * Returns the number of items on the value stack, or -1 in case of error.
2075
 *
2076
 * The object is destroyed in case of error.
2077
 */
2078
int
2079
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2080
0
{
2081
0
    if (ctxt == NULL) return(-1);
2082
0
    if (value == NULL) {
2083
        /*
2084
         * A NULL value typically indicates that a memory allocation failed.
2085
         */
2086
0
        xmlXPathPErrMemory(ctxt);
2087
0
        return(-1);
2088
0
    }
2089
0
    if (ctxt->valueNr >= ctxt->valueMax) {
2090
0
        xmlXPathObjectPtr *tmp;
2091
2092
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2093
0
            xmlXPathPErrMemory(ctxt);
2094
0
            xmlXPathFreeObject(value);
2095
0
            return (-1);
2096
0
        }
2097
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2098
0
                                             2 * ctxt->valueMax *
2099
0
                                             sizeof(ctxt->valueTab[0]));
2100
0
        if (tmp == NULL) {
2101
0
            xmlXPathPErrMemory(ctxt);
2102
0
            xmlXPathFreeObject(value);
2103
0
            return (-1);
2104
0
        }
2105
0
        ctxt->valueMax *= 2;
2106
0
  ctxt->valueTab = tmp;
2107
0
    }
2108
0
    ctxt->valueTab[ctxt->valueNr] = value;
2109
0
    ctxt->value = value;
2110
0
    return (ctxt->valueNr++);
2111
0
}
2112
2113
/**
2114
 * xmlXPathPopBoolean:
2115
 * @ctxt:  an XPath parser context
2116
 *
2117
 * Pops a boolean from the stack, handling conversion if needed.
2118
 * Check error with #xmlXPathCheckError.
2119
 *
2120
 * Returns the boolean
2121
 */
2122
int
2123
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2124
0
    xmlXPathObjectPtr obj;
2125
0
    int ret;
2126
2127
0
    obj = valuePop(ctxt);
2128
0
    if (obj == NULL) {
2129
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2130
0
  return(0);
2131
0
    }
2132
0
    if (obj->type != XPATH_BOOLEAN)
2133
0
  ret = xmlXPathCastToBoolean(obj);
2134
0
    else
2135
0
        ret = obj->boolval;
2136
0
    xmlXPathReleaseObject(ctxt->context, obj);
2137
0
    return(ret);
2138
0
}
2139
2140
/**
2141
 * xmlXPathPopNumber:
2142
 * @ctxt:  an XPath parser context
2143
 *
2144
 * Pops a number from the stack, handling conversion if needed.
2145
 * Check error with #xmlXPathCheckError.
2146
 *
2147
 * Returns the number
2148
 */
2149
double
2150
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2151
0
    xmlXPathObjectPtr obj;
2152
0
    double ret;
2153
2154
0
    obj = valuePop(ctxt);
2155
0
    if (obj == NULL) {
2156
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2157
0
  return(0);
2158
0
    }
2159
0
    if (obj->type != XPATH_NUMBER)
2160
0
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2161
0
    else
2162
0
        ret = obj->floatval;
2163
0
    xmlXPathReleaseObject(ctxt->context, obj);
2164
0
    return(ret);
2165
0
}
2166
2167
/**
2168
 * xmlXPathPopString:
2169
 * @ctxt:  an XPath parser context
2170
 *
2171
 * Pops a string from the stack, handling conversion if needed.
2172
 * Check error with #xmlXPathCheckError.
2173
 *
2174
 * Returns the string
2175
 */
2176
xmlChar *
2177
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2178
0
    xmlXPathObjectPtr obj;
2179
0
    xmlChar * ret;
2180
2181
0
    obj = valuePop(ctxt);
2182
0
    if (obj == NULL) {
2183
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2184
0
  return(NULL);
2185
0
    }
2186
0
    ret = xmlXPathCastToString(obj);
2187
0
    if (ret == NULL)
2188
0
        xmlXPathPErrMemory(ctxt);
2189
0
    xmlXPathReleaseObject(ctxt->context, obj);
2190
0
    return(ret);
2191
0
}
2192
2193
/**
2194
 * xmlXPathPopNodeSet:
2195
 * @ctxt:  an XPath parser context
2196
 *
2197
 * Pops a node-set from the stack, handling conversion if needed.
2198
 * Check error with #xmlXPathCheckError.
2199
 *
2200
 * Returns the node-set
2201
 */
2202
xmlNodeSetPtr
2203
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2204
0
    xmlXPathObjectPtr obj;
2205
0
    xmlNodeSetPtr ret;
2206
2207
0
    if (ctxt == NULL) return(NULL);
2208
0
    if (ctxt->value == NULL) {
2209
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2210
0
  return(NULL);
2211
0
    }
2212
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2213
0
  xmlXPathSetTypeError(ctxt);
2214
0
  return(NULL);
2215
0
    }
2216
0
    obj = valuePop(ctxt);
2217
0
    ret = obj->nodesetval;
2218
#if 0
2219
    /* to fix memory leak of not clearing obj->user */
2220
    if (obj->boolval && obj->user != NULL)
2221
        xmlFreeNodeList((xmlNodePtr) obj->user);
2222
#endif
2223
0
    obj->nodesetval = NULL;
2224
0
    xmlXPathReleaseObject(ctxt->context, obj);
2225
0
    return(ret);
2226
0
}
2227
2228
/**
2229
 * xmlXPathPopExternal:
2230
 * @ctxt:  an XPath parser context
2231
 *
2232
 * Pops an external object from the stack, handling conversion if needed.
2233
 * Check error with #xmlXPathCheckError.
2234
 *
2235
 * Returns the object
2236
 */
2237
void *
2238
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2239
0
    xmlXPathObjectPtr obj;
2240
0
    void * ret;
2241
2242
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2243
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2244
0
  return(NULL);
2245
0
    }
2246
0
    if (ctxt->value->type != XPATH_USERS) {
2247
0
  xmlXPathSetTypeError(ctxt);
2248
0
  return(NULL);
2249
0
    }
2250
0
    obj = valuePop(ctxt);
2251
0
    ret = obj->user;
2252
0
    obj->user = NULL;
2253
0
    xmlXPathReleaseObject(ctxt->context, obj);
2254
0
    return(ret);
2255
0
}
2256
2257
/*
2258
 * Macros for accessing the content. Those should be used only by the parser,
2259
 * and not exported.
2260
 *
2261
 * Dirty macros, i.e. one need to make assumption on the context to use them
2262
 *
2263
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2264
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2265
 *           in ISO-Latin or UTF-8.
2266
 *           This should be used internally by the parser
2267
 *           only to compare to ASCII values otherwise it would break when
2268
 *           running with UTF-8 encoding.
2269
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2270
 *           to compare on ASCII based substring.
2271
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2272
 *           strings within the parser.
2273
 *   CURRENT Returns the current char value, with the full decoding of
2274
 *           UTF-8 if we are using this mode. It returns an int.
2275
 *   NEXT    Skip to the next character, this does the proper decoding
2276
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2277
 *           It returns the pointer to the current xmlChar.
2278
 */
2279
2280
0
#define CUR (*ctxt->cur)
2281
0
#define SKIP(val) ctxt->cur += (val)
2282
0
#define NXT(val) ctxt->cur[(val)]
2283
0
#define CUR_PTR ctxt->cur
2284
0
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2285
2286
#define COPY_BUF(l,b,i,v)                                              \
2287
0
    if (l == 1) b[i++] = v;                                            \
2288
0
    else i += xmlCopyChar(l,&b[i],v)
2289
2290
0
#define NEXTL(l)  ctxt->cur += l
2291
2292
#define SKIP_BLANKS             \
2293
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2294
2295
#define CURRENT (*ctxt->cur)
2296
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2297
2298
2299
#ifndef DBL_DIG
2300
#define DBL_DIG 16
2301
#endif
2302
#ifndef DBL_EPSILON
2303
#define DBL_EPSILON 1E-9
2304
#endif
2305
2306
0
#define UPPER_DOUBLE 1E9
2307
0
#define LOWER_DOUBLE 1E-5
2308
#define LOWER_DOUBLE_EXP 5
2309
2310
#define INTEGER_DIGITS DBL_DIG
2311
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2312
0
#define EXPONENT_DIGITS (3 + 2)
2313
2314
/**
2315
 * xmlXPathFormatNumber:
2316
 * @number:     number to format
2317
 * @buffer:     output buffer
2318
 * @buffersize: size of output buffer
2319
 *
2320
 * Convert the number into a string representation.
2321
 */
2322
static void
2323
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2324
0
{
2325
0
    switch (xmlXPathIsInf(number)) {
2326
0
    case 1:
2327
0
  if (buffersize > (int)sizeof("Infinity"))
2328
0
      snprintf(buffer, buffersize, "Infinity");
2329
0
  break;
2330
0
    case -1:
2331
0
  if (buffersize > (int)sizeof("-Infinity"))
2332
0
      snprintf(buffer, buffersize, "-Infinity");
2333
0
  break;
2334
0
    default:
2335
0
  if (xmlXPathIsNaN(number)) {
2336
0
      if (buffersize > (int)sizeof("NaN"))
2337
0
    snprintf(buffer, buffersize, "NaN");
2338
0
  } else if (number == 0) {
2339
            /* Omit sign for negative zero. */
2340
0
      snprintf(buffer, buffersize, "0");
2341
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2342
0
                   (number == (int) number)) {
2343
0
      char work[30];
2344
0
      char *ptr, *cur;
2345
0
      int value = (int) number;
2346
2347
0
            ptr = &buffer[0];
2348
0
      if (value == 0) {
2349
0
    *ptr++ = '0';
2350
0
      } else {
2351
0
    snprintf(work, 29, "%d", value);
2352
0
    cur = &work[0];
2353
0
    while ((*cur) && (ptr - buffer < buffersize)) {
2354
0
        *ptr++ = *cur++;
2355
0
    }
2356
0
      }
2357
0
      if (ptr - buffer < buffersize) {
2358
0
    *ptr = 0;
2359
0
      } else if (buffersize > 0) {
2360
0
    ptr--;
2361
0
    *ptr = 0;
2362
0
      }
2363
0
  } else {
2364
      /*
2365
        For the dimension of work,
2366
            DBL_DIG is number of significant digits
2367
      EXPONENT is only needed for "scientific notation"
2368
            3 is sign, decimal point, and terminating zero
2369
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2370
        Note that this dimension is slightly (a few characters)
2371
        larger than actually necessary.
2372
      */
2373
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2374
0
      int integer_place, fraction_place;
2375
0
      char *ptr;
2376
0
      char *after_fraction;
2377
0
      double absolute_value;
2378
0
      int size;
2379
2380
0
      absolute_value = fabs(number);
2381
2382
      /*
2383
       * First choose format - scientific or regular floating point.
2384
       * In either case, result is in work, and after_fraction points
2385
       * just past the fractional part.
2386
      */
2387
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
2388
0
      (absolute_value < LOWER_DOUBLE)) &&
2389
0
     (absolute_value != 0.0) ) {
2390
    /* Use scientific notation */
2391
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2392
0
    fraction_place = DBL_DIG - 1;
2393
0
    size = snprintf(work, sizeof(work),"%*.*e",
2394
0
       integer_place, fraction_place, number);
2395
0
    while ((size > 0) && (work[size] != 'e')) size--;
2396
2397
0
      }
2398
0
      else {
2399
    /* Use regular notation */
2400
0
    if (absolute_value > 0.0) {
2401
0
        integer_place = (int)log10(absolute_value);
2402
0
        if (integer_place > 0)
2403
0
            fraction_place = DBL_DIG - integer_place - 1;
2404
0
        else
2405
0
            fraction_place = DBL_DIG - integer_place;
2406
0
    } else {
2407
0
        fraction_place = 1;
2408
0
    }
2409
0
    size = snprintf(work, sizeof(work), "%0.*f",
2410
0
        fraction_place, number);
2411
0
      }
2412
2413
      /* Remove leading spaces sometimes inserted by snprintf */
2414
0
      while (work[0] == ' ') {
2415
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2416
0
    size--;
2417
0
      }
2418
2419
      /* Remove fractional trailing zeroes */
2420
0
      after_fraction = work + size;
2421
0
      ptr = after_fraction;
2422
0
      while (*(--ptr) == '0')
2423
0
    ;
2424
0
      if (*ptr != '.')
2425
0
          ptr++;
2426
0
      while ((*ptr++ = *after_fraction++) != 0);
2427
2428
      /* Finally copy result back to caller */
2429
0
      size = strlen(work) + 1;
2430
0
      if (size > buffersize) {
2431
0
    work[buffersize - 1] = 0;
2432
0
    size = buffersize;
2433
0
      }
2434
0
      memmove(buffer, work, size);
2435
0
  }
2436
0
  break;
2437
0
    }
2438
0
}
2439
2440
2441
/************************************************************************
2442
 *                  *
2443
 *      Routines to handle NodeSets     *
2444
 *                  *
2445
 ************************************************************************/
2446
2447
/**
2448
 * xmlXPathOrderDocElems:
2449
 * @doc:  an input document
2450
 *
2451
 * Call this routine to speed up XPath computation on static documents.
2452
 * This stamps all the element nodes with the document order
2453
 * Like for line information, the order is kept in the element->content
2454
 * field, the value stored is actually - the node number (starting at -1)
2455
 * to be able to differentiate from line numbers.
2456
 *
2457
 * Returns the number of elements found in the document or -1 in case
2458
 *    of error.
2459
 */
2460
long
2461
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
2462
0
    ptrdiff_t count = 0;
2463
0
    xmlNodePtr cur;
2464
2465
0
    if (doc == NULL)
2466
0
  return(-1);
2467
0
    cur = doc->children;
2468
0
    while (cur != NULL) {
2469
0
  if (cur->type == XML_ELEMENT_NODE) {
2470
0
      cur->content = (void *) (-(++count));
2471
0
      if (cur->children != NULL) {
2472
0
    cur = cur->children;
2473
0
    continue;
2474
0
      }
2475
0
  }
2476
0
  if (cur->next != NULL) {
2477
0
      cur = cur->next;
2478
0
      continue;
2479
0
  }
2480
0
  do {
2481
0
      cur = cur->parent;
2482
0
      if (cur == NULL)
2483
0
    break;
2484
0
      if (cur == (xmlNodePtr) doc) {
2485
0
    cur = NULL;
2486
0
    break;
2487
0
      }
2488
0
      if (cur->next != NULL) {
2489
0
    cur = cur->next;
2490
0
    break;
2491
0
      }
2492
0
  } while (cur != NULL);
2493
0
    }
2494
0
    return(count);
2495
0
}
2496
2497
/**
2498
 * xmlXPathCmpNodes:
2499
 * @node1:  the first node
2500
 * @node2:  the second node
2501
 *
2502
 * Compare two nodes w.r.t document order
2503
 *
2504
 * Returns -2 in case of error 1 if first point < second point, 0 if
2505
 *         it's the same node, -1 otherwise
2506
 */
2507
int
2508
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2509
0
    int depth1, depth2;
2510
0
    int attr1 = 0, attr2 = 0;
2511
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2512
0
    xmlNodePtr cur, root;
2513
2514
0
    if ((node1 == NULL) || (node2 == NULL))
2515
0
  return(-2);
2516
    /*
2517
     * a couple of optimizations which will avoid computations in most cases
2518
     */
2519
0
    if (node1 == node2)   /* trivial case */
2520
0
  return(0);
2521
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2522
0
  attr1 = 1;
2523
0
  attrNode1 = node1;
2524
0
  node1 = node1->parent;
2525
0
    }
2526
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2527
0
  attr2 = 1;
2528
0
  attrNode2 = node2;
2529
0
  node2 = node2->parent;
2530
0
    }
2531
0
    if (node1 == node2) {
2532
0
  if (attr1 == attr2) {
2533
      /* not required, but we keep attributes in order */
2534
0
      if (attr1 != 0) {
2535
0
          cur = attrNode2->prev;
2536
0
    while (cur != NULL) {
2537
0
        if (cur == attrNode1)
2538
0
            return (1);
2539
0
        cur = cur->prev;
2540
0
    }
2541
0
    return (-1);
2542
0
      }
2543
0
      return(0);
2544
0
  }
2545
0
  if (attr2 == 1)
2546
0
      return(1);
2547
0
  return(-1);
2548
0
    }
2549
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2550
0
        (node2->type == XML_NAMESPACE_DECL))
2551
0
  return(1);
2552
0
    if (node1 == node2->prev)
2553
0
  return(1);
2554
0
    if (node1 == node2->next)
2555
0
  return(-1);
2556
2557
    /*
2558
     * Speedup using document order if available.
2559
     */
2560
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2561
0
  (node2->type == XML_ELEMENT_NODE) &&
2562
0
  (0 > (ptrdiff_t) node1->content) &&
2563
0
  (0 > (ptrdiff_t) node2->content) &&
2564
0
  (node1->doc == node2->doc)) {
2565
0
  ptrdiff_t l1, l2;
2566
2567
0
  l1 = -((ptrdiff_t) node1->content);
2568
0
  l2 = -((ptrdiff_t) node2->content);
2569
0
  if (l1 < l2)
2570
0
      return(1);
2571
0
  if (l1 > l2)
2572
0
      return(-1);
2573
0
    }
2574
2575
    /*
2576
     * compute depth to root
2577
     */
2578
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2579
0
  if (cur->parent == node1)
2580
0
      return(1);
2581
0
  depth2++;
2582
0
    }
2583
0
    root = cur;
2584
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2585
0
  if (cur->parent == node2)
2586
0
      return(-1);
2587
0
  depth1++;
2588
0
    }
2589
    /*
2590
     * Distinct document (or distinct entities :-( ) case.
2591
     */
2592
0
    if (root != cur) {
2593
0
  return(-2);
2594
0
    }
2595
    /*
2596
     * get the nearest common ancestor.
2597
     */
2598
0
    while (depth1 > depth2) {
2599
0
  depth1--;
2600
0
  node1 = node1->parent;
2601
0
    }
2602
0
    while (depth2 > depth1) {
2603
0
  depth2--;
2604
0
  node2 = node2->parent;
2605
0
    }
2606
0
    while (node1->parent != node2->parent) {
2607
0
  node1 = node1->parent;
2608
0
  node2 = node2->parent;
2609
  /* should not happen but just in case ... */
2610
0
  if ((node1 == NULL) || (node2 == NULL))
2611
0
      return(-2);
2612
0
    }
2613
    /*
2614
     * Find who's first.
2615
     */
2616
0
    if (node1 == node2->prev)
2617
0
  return(1);
2618
0
    if (node1 == node2->next)
2619
0
  return(-1);
2620
    /*
2621
     * Speedup using document order if available.
2622
     */
2623
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2624
0
  (node2->type == XML_ELEMENT_NODE) &&
2625
0
  (0 > (ptrdiff_t) node1->content) &&
2626
0
  (0 > (ptrdiff_t) node2->content) &&
2627
0
  (node1->doc == node2->doc)) {
2628
0
  ptrdiff_t l1, l2;
2629
2630
0
  l1 = -((ptrdiff_t) node1->content);
2631
0
  l2 = -((ptrdiff_t) node2->content);
2632
0
  if (l1 < l2)
2633
0
      return(1);
2634
0
  if (l1 > l2)
2635
0
      return(-1);
2636
0
    }
2637
2638
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2639
0
  if (cur == node2)
2640
0
      return(1);
2641
0
    return(-1); /* assume there is no sibling list corruption */
2642
0
}
2643
2644
/**
2645
 * xmlXPathNodeSetSort:
2646
 * @set:  the node set
2647
 *
2648
 * Sort the node set in document order
2649
 */
2650
void
2651
0
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2652
#ifndef WITH_TIM_SORT
2653
    int i, j, incr, len;
2654
    xmlNodePtr tmp;
2655
#endif
2656
2657
0
    if (set == NULL)
2658
0
  return;
2659
2660
#ifndef WITH_TIM_SORT
2661
    /*
2662
     * Use the old Shell's sort implementation to sort the node-set
2663
     * Timsort ought to be quite faster
2664
     */
2665
    len = set->nodeNr;
2666
    for (incr = len / 2; incr > 0; incr /= 2) {
2667
  for (i = incr; i < len; i++) {
2668
      j = i - incr;
2669
      while (j >= 0) {
2670
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2671
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
2672
      set->nodeTab[j + incr]) == -1)
2673
#else
2674
    if (xmlXPathCmpNodes(set->nodeTab[j],
2675
      set->nodeTab[j + incr]) == -1)
2676
#endif
2677
    {
2678
        tmp = set->nodeTab[j];
2679
        set->nodeTab[j] = set->nodeTab[j + incr];
2680
        set->nodeTab[j + incr] = tmp;
2681
        j -= incr;
2682
    } else
2683
        break;
2684
      }
2685
  }
2686
    }
2687
#else /* WITH_TIM_SORT */
2688
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2689
0
#endif /* WITH_TIM_SORT */
2690
0
}
2691
2692
0
#define XML_NODESET_DEFAULT 10
2693
/**
2694
 * xmlXPathNodeSetDupNs:
2695
 * @node:  the parent node of the namespace XPath node
2696
 * @ns:  the libxml namespace declaration node.
2697
 *
2698
 * Namespace node in libxml don't match the XPath semantic. In a node set
2699
 * the namespace nodes are duplicated and the next pointer is set to the
2700
 * parent node in the XPath semantic.
2701
 *
2702
 * Returns the newly created object.
2703
 */
2704
static xmlNodePtr
2705
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2706
0
    xmlNsPtr cur;
2707
2708
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2709
0
  return(NULL);
2710
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2711
0
  return((xmlNodePtr) ns);
2712
2713
    /*
2714
     * Allocate a new Namespace and fill the fields.
2715
     */
2716
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2717
0
    if (cur == NULL)
2718
0
  return(NULL);
2719
0
    memset(cur, 0, sizeof(xmlNs));
2720
0
    cur->type = XML_NAMESPACE_DECL;
2721
0
    if (ns->href != NULL) {
2722
0
  cur->href = xmlStrdup(ns->href);
2723
0
        if (cur->href == NULL) {
2724
0
            xmlFree(cur);
2725
0
            return(NULL);
2726
0
        }
2727
0
    }
2728
0
    if (ns->prefix != NULL) {
2729
0
  cur->prefix = xmlStrdup(ns->prefix);
2730
0
        if (cur->prefix == NULL) {
2731
0
            xmlFree((xmlChar *) cur->href);
2732
0
            xmlFree(cur);
2733
0
            return(NULL);
2734
0
        }
2735
0
    }
2736
0
    cur->next = (xmlNsPtr) node;
2737
0
    return((xmlNodePtr) cur);
2738
0
}
2739
2740
/**
2741
 * xmlXPathNodeSetFreeNs:
2742
 * @ns:  the XPath namespace node found in a nodeset.
2743
 *
2744
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2745
 * the namespace nodes are duplicated and the next pointer is set to the
2746
 * parent node in the XPath semantic. Check if such a node needs to be freed
2747
 */
2748
void
2749
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2750
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2751
0
  return;
2752
2753
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2754
0
  if (ns->href != NULL)
2755
0
      xmlFree((xmlChar *)ns->href);
2756
0
  if (ns->prefix != NULL)
2757
0
      xmlFree((xmlChar *)ns->prefix);
2758
0
  xmlFree(ns);
2759
0
    }
2760
0
}
2761
2762
/**
2763
 * xmlXPathNodeSetCreate:
2764
 * @val:  an initial xmlNodePtr, or NULL
2765
 *
2766
 * Create a new xmlNodeSetPtr of type double and of value @val
2767
 *
2768
 * Returns the newly created object.
2769
 */
2770
xmlNodeSetPtr
2771
0
xmlXPathNodeSetCreate(xmlNodePtr val) {
2772
0
    xmlNodeSetPtr ret;
2773
2774
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2775
0
    if (ret == NULL)
2776
0
  return(NULL);
2777
0
    memset(ret, 0 , sizeof(xmlNodeSet));
2778
0
    if (val != NULL) {
2779
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2780
0
               sizeof(xmlNodePtr));
2781
0
  if (ret->nodeTab == NULL) {
2782
0
      xmlFree(ret);
2783
0
      return(NULL);
2784
0
  }
2785
0
  memset(ret->nodeTab, 0 ,
2786
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2787
0
        ret->nodeMax = XML_NODESET_DEFAULT;
2788
0
  if (val->type == XML_NAMESPACE_DECL) {
2789
0
      xmlNsPtr ns = (xmlNsPtr) val;
2790
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2791
2792
0
            if (nsNode == NULL) {
2793
0
                xmlXPathFreeNodeSet(ret);
2794
0
                return(NULL);
2795
0
            }
2796
0
      ret->nodeTab[ret->nodeNr++] = nsNode;
2797
0
  } else
2798
0
      ret->nodeTab[ret->nodeNr++] = val;
2799
0
    }
2800
0
    return(ret);
2801
0
}
2802
2803
/**
2804
 * xmlXPathNodeSetContains:
2805
 * @cur:  the node-set
2806
 * @val:  the node
2807
 *
2808
 * checks whether @cur contains @val
2809
 *
2810
 * Returns true (1) if @cur contains @val, false (0) otherwise
2811
 */
2812
int
2813
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2814
0
    int i;
2815
2816
0
    if ((cur == NULL) || (val == NULL)) return(0);
2817
0
    if (val->type == XML_NAMESPACE_DECL) {
2818
0
  for (i = 0; i < cur->nodeNr; i++) {
2819
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2820
0
    xmlNsPtr ns1, ns2;
2821
2822
0
    ns1 = (xmlNsPtr) val;
2823
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2824
0
    if (ns1 == ns2)
2825
0
        return(1);
2826
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2827
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2828
0
        return(1);
2829
0
      }
2830
0
  }
2831
0
    } else {
2832
0
  for (i = 0; i < cur->nodeNr; i++) {
2833
0
      if (cur->nodeTab[i] == val)
2834
0
    return(1);
2835
0
  }
2836
0
    }
2837
0
    return(0);
2838
0
}
2839
2840
/**
2841
 * xmlXPathNodeSetAddNs:
2842
 * @cur:  the initial node set
2843
 * @node:  the hosting node
2844
 * @ns:  a the namespace node
2845
 *
2846
 * add a new namespace node to an existing NodeSet
2847
 *
2848
 * Returns 0 in case of success and -1 in case of error
2849
 */
2850
int
2851
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2852
0
    int i;
2853
0
    xmlNodePtr nsNode;
2854
2855
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2856
0
        (ns->type != XML_NAMESPACE_DECL) ||
2857
0
  (node->type != XML_ELEMENT_NODE))
2858
0
  return(-1);
2859
2860
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2861
    /*
2862
     * prevent duplicates
2863
     */
2864
0
    for (i = 0;i < cur->nodeNr;i++) {
2865
0
        if ((cur->nodeTab[i] != NULL) &&
2866
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2867
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2868
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2869
0
      return(0);
2870
0
    }
2871
2872
    /*
2873
     * grow the nodeTab if needed
2874
     */
2875
0
    if (cur->nodeMax == 0) {
2876
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2877
0
               sizeof(xmlNodePtr));
2878
0
  if (cur->nodeTab == NULL)
2879
0
      return(-1);
2880
0
  memset(cur->nodeTab, 0 ,
2881
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2882
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2883
0
    } else if (cur->nodeNr == cur->nodeMax) {
2884
0
        xmlNodePtr *temp;
2885
2886
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2887
0
            return(-1);
2888
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2889
0
              sizeof(xmlNodePtr));
2890
0
  if (temp == NULL)
2891
0
      return(-1);
2892
0
        cur->nodeMax *= 2;
2893
0
  cur->nodeTab = temp;
2894
0
    }
2895
0
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2896
0
    if(nsNode == NULL)
2897
0
        return(-1);
2898
0
    cur->nodeTab[cur->nodeNr++] = nsNode;
2899
0
    return(0);
2900
0
}
2901
2902
/**
2903
 * xmlXPathNodeSetAdd:
2904
 * @cur:  the initial node set
2905
 * @val:  a new xmlNodePtr
2906
 *
2907
 * add a new xmlNodePtr to an existing NodeSet
2908
 *
2909
 * Returns 0 in case of success, and -1 in case of error
2910
 */
2911
int
2912
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2913
0
    int i;
2914
2915
0
    if ((cur == NULL) || (val == NULL)) return(-1);
2916
2917
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2918
    /*
2919
     * prevent duplicates
2920
     */
2921
0
    for (i = 0;i < cur->nodeNr;i++)
2922
0
        if (cur->nodeTab[i] == val) return(0);
2923
2924
    /*
2925
     * grow the nodeTab if needed
2926
     */
2927
0
    if (cur->nodeMax == 0) {
2928
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2929
0
               sizeof(xmlNodePtr));
2930
0
  if (cur->nodeTab == NULL)
2931
0
      return(-1);
2932
0
  memset(cur->nodeTab, 0 ,
2933
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2934
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2935
0
    } else if (cur->nodeNr == cur->nodeMax) {
2936
0
        xmlNodePtr *temp;
2937
2938
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2939
0
            return(-1);
2940
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2941
0
              sizeof(xmlNodePtr));
2942
0
  if (temp == NULL)
2943
0
      return(-1);
2944
0
        cur->nodeMax *= 2;
2945
0
  cur->nodeTab = temp;
2946
0
    }
2947
0
    if (val->type == XML_NAMESPACE_DECL) {
2948
0
  xmlNsPtr ns = (xmlNsPtr) val;
2949
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2950
2951
0
        if (nsNode == NULL)
2952
0
            return(-1);
2953
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2954
0
    } else
2955
0
  cur->nodeTab[cur->nodeNr++] = val;
2956
0
    return(0);
2957
0
}
2958
2959
/**
2960
 * xmlXPathNodeSetAddUnique:
2961
 * @cur:  the initial node set
2962
 * @val:  a new xmlNodePtr
2963
 *
2964
 * add a new xmlNodePtr to an existing NodeSet, optimized version
2965
 * when we are sure the node is not already in the set.
2966
 *
2967
 * Returns 0 in case of success and -1 in case of failure
2968
 */
2969
int
2970
0
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2971
0
    if ((cur == NULL) || (val == NULL)) return(-1);
2972
2973
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2974
    /*
2975
     * grow the nodeTab if needed
2976
     */
2977
0
    if (cur->nodeMax == 0) {
2978
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2979
0
               sizeof(xmlNodePtr));
2980
0
  if (cur->nodeTab == NULL)
2981
0
      return(-1);
2982
0
  memset(cur->nodeTab, 0 ,
2983
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2984
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2985
0
    } else if (cur->nodeNr == cur->nodeMax) {
2986
0
        xmlNodePtr *temp;
2987
2988
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2989
0
            return(-1);
2990
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2991
0
              sizeof(xmlNodePtr));
2992
0
  if (temp == NULL)
2993
0
      return(-1);
2994
0
  cur->nodeTab = temp;
2995
0
        cur->nodeMax *= 2;
2996
0
    }
2997
0
    if (val->type == XML_NAMESPACE_DECL) {
2998
0
  xmlNsPtr ns = (xmlNsPtr) val;
2999
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3000
3001
0
        if (nsNode == NULL)
3002
0
            return(-1);
3003
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
3004
0
    } else
3005
0
  cur->nodeTab[cur->nodeNr++] = val;
3006
0
    return(0);
3007
0
}
3008
3009
/**
3010
 * xmlXPathNodeSetMerge:
3011
 * @val1:  the first NodeSet or NULL
3012
 * @val2:  the second NodeSet
3013
 *
3014
 * Merges two nodesets, all nodes from @val2 are added to @val1
3015
 * if @val1 is NULL, a new set is created and copied from @val2
3016
 *
3017
 * Returns @val1 once extended or NULL in case of error.
3018
 *
3019
 * Frees @val1 in case of error.
3020
 */
3021
xmlNodeSetPtr
3022
0
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3023
0
    int i, j, initNr, skip;
3024
0
    xmlNodePtr n1, n2;
3025
3026
0
    if (val1 == NULL) {
3027
0
  val1 = xmlXPathNodeSetCreate(NULL);
3028
0
        if (val1 == NULL)
3029
0
            return (NULL);
3030
0
    }
3031
0
    if (val2 == NULL)
3032
0
        return(val1);
3033
3034
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3035
0
    initNr = val1->nodeNr;
3036
3037
0
    for (i = 0;i < val2->nodeNr;i++) {
3038
0
  n2 = val2->nodeTab[i];
3039
  /*
3040
   * check against duplicates
3041
   */
3042
0
  skip = 0;
3043
0
  for (j = 0; j < initNr; j++) {
3044
0
      n1 = val1->nodeTab[j];
3045
0
      if (n1 == n2) {
3046
0
    skip = 1;
3047
0
    break;
3048
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3049
0
           (n2->type == XML_NAMESPACE_DECL)) {
3050
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3051
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3052
0
      ((xmlNsPtr) n2)->prefix)))
3053
0
    {
3054
0
        skip = 1;
3055
0
        break;
3056
0
    }
3057
0
      }
3058
0
  }
3059
0
  if (skip)
3060
0
      continue;
3061
3062
  /*
3063
   * grow the nodeTab if needed
3064
   */
3065
0
  if (val1->nodeMax == 0) {
3066
0
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3067
0
                sizeof(xmlNodePtr));
3068
0
      if (val1->nodeTab == NULL)
3069
0
    goto error;
3070
0
      memset(val1->nodeTab, 0 ,
3071
0
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3072
0
      val1->nodeMax = XML_NODESET_DEFAULT;
3073
0
  } else if (val1->nodeNr == val1->nodeMax) {
3074
0
      xmlNodePtr *temp;
3075
3076
0
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3077
0
                goto error;
3078
0
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3079
0
               sizeof(xmlNodePtr));
3080
0
      if (temp == NULL)
3081
0
    goto error;
3082
0
      val1->nodeTab = temp;
3083
0
      val1->nodeMax *= 2;
3084
0
  }
3085
0
  if (n2->type == XML_NAMESPACE_DECL) {
3086
0
      xmlNsPtr ns = (xmlNsPtr) n2;
3087
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3088
3089
0
            if (nsNode == NULL)
3090
0
                goto error;
3091
0
      val1->nodeTab[val1->nodeNr++] = nsNode;
3092
0
  } else
3093
0
      val1->nodeTab[val1->nodeNr++] = n2;
3094
0
    }
3095
3096
0
    return(val1);
3097
3098
0
error:
3099
0
    xmlXPathFreeNodeSet(val1);
3100
0
    return(NULL);
3101
0
}
3102
3103
3104
/**
3105
 * xmlXPathNodeSetMergeAndClear:
3106
 * @set1:  the first NodeSet or NULL
3107
 * @set2:  the second NodeSet
3108
 *
3109
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3110
 * Checks for duplicate nodes. Clears set2.
3111
 *
3112
 * Returns @set1 once extended or NULL in case of error.
3113
 *
3114
 * Frees @set1 in case of error.
3115
 */
3116
static xmlNodeSetPtr
3117
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3118
0
{
3119
0
    {
3120
0
  int i, j, initNbSet1;
3121
0
  xmlNodePtr n1, n2;
3122
3123
0
  initNbSet1 = set1->nodeNr;
3124
0
  for (i = 0;i < set2->nodeNr;i++) {
3125
0
      n2 = set2->nodeTab[i];
3126
      /*
3127
      * Skip duplicates.
3128
      */
3129
0
      for (j = 0; j < initNbSet1; j++) {
3130
0
    n1 = set1->nodeTab[j];
3131
0
    if (n1 == n2) {
3132
0
        goto skip_node;
3133
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3134
0
        (n2->type == XML_NAMESPACE_DECL))
3135
0
    {
3136
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3137
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3138
0
      ((xmlNsPtr) n2)->prefix)))
3139
0
        {
3140
      /*
3141
      * Free the namespace node.
3142
      */
3143
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3144
0
      goto skip_node;
3145
0
        }
3146
0
    }
3147
0
      }
3148
      /*
3149
      * grow the nodeTab if needed
3150
      */
3151
0
      if (set1->nodeMax == 0) {
3152
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3153
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3154
0
    if (set1->nodeTab == NULL)
3155
0
        goto error;
3156
0
    memset(set1->nodeTab, 0,
3157
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3158
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3159
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3160
0
    xmlNodePtr *temp;
3161
3162
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3163
0
                    goto error;
3164
0
    temp = (xmlNodePtr *) xmlRealloc(
3165
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3166
0
    if (temp == NULL)
3167
0
        goto error;
3168
0
    set1->nodeTab = temp;
3169
0
    set1->nodeMax *= 2;
3170
0
      }
3171
0
      set1->nodeTab[set1->nodeNr++] = n2;
3172
0
skip_node:
3173
0
            set2->nodeTab[i] = NULL;
3174
0
  }
3175
0
    }
3176
0
    set2->nodeNr = 0;
3177
0
    return(set1);
3178
3179
0
error:
3180
0
    xmlXPathFreeNodeSet(set1);
3181
0
    xmlXPathNodeSetClear(set2, 1);
3182
0
    return(NULL);
3183
0
}
3184
3185
/**
3186
 * xmlXPathNodeSetMergeAndClearNoDupls:
3187
 * @set1:  the first NodeSet or NULL
3188
 * @set2:  the second NodeSet
3189
 *
3190
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3191
 * Doesn't check for duplicate nodes. Clears set2.
3192
 *
3193
 * Returns @set1 once extended or NULL in case of error.
3194
 *
3195
 * Frees @set1 in case of error.
3196
 */
3197
static xmlNodeSetPtr
3198
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3199
0
{
3200
0
    {
3201
0
  int i;
3202
0
  xmlNodePtr n2;
3203
3204
0
  for (i = 0;i < set2->nodeNr;i++) {
3205
0
      n2 = set2->nodeTab[i];
3206
0
      if (set1->nodeMax == 0) {
3207
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3208
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3209
0
    if (set1->nodeTab == NULL)
3210
0
        goto error;
3211
0
    memset(set1->nodeTab, 0,
3212
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3213
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3214
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3215
0
    xmlNodePtr *temp;
3216
3217
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3218
0
                    goto error;
3219
0
    temp = (xmlNodePtr *) xmlRealloc(
3220
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3221
0
    if (temp == NULL)
3222
0
        goto error;
3223
0
    set1->nodeTab = temp;
3224
0
    set1->nodeMax *= 2;
3225
0
      }
3226
0
      set1->nodeTab[set1->nodeNr++] = n2;
3227
0
            set2->nodeTab[i] = NULL;
3228
0
  }
3229
0
    }
3230
0
    set2->nodeNr = 0;
3231
0
    return(set1);
3232
3233
0
error:
3234
0
    xmlXPathFreeNodeSet(set1);
3235
0
    xmlXPathNodeSetClear(set2, 1);
3236
0
    return(NULL);
3237
0
}
3238
3239
/**
3240
 * xmlXPathNodeSetDel:
3241
 * @cur:  the initial node set
3242
 * @val:  an xmlNodePtr
3243
 *
3244
 * Removes an xmlNodePtr from an existing NodeSet
3245
 */
3246
void
3247
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3248
0
    int i;
3249
3250
0
    if (cur == NULL) return;
3251
0
    if (val == NULL) return;
3252
3253
    /*
3254
     * find node in nodeTab
3255
     */
3256
0
    for (i = 0;i < cur->nodeNr;i++)
3257
0
        if (cur->nodeTab[i] == val) break;
3258
3259
0
    if (i >= cur->nodeNr) { /* not found */
3260
0
        return;
3261
0
    }
3262
0
    if ((cur->nodeTab[i] != NULL) &&
3263
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3264
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3265
0
    cur->nodeNr--;
3266
0
    for (;i < cur->nodeNr;i++)
3267
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
3268
0
    cur->nodeTab[cur->nodeNr] = NULL;
3269
0
}
3270
3271
/**
3272
 * xmlXPathNodeSetRemove:
3273
 * @cur:  the initial node set
3274
 * @val:  the index to remove
3275
 *
3276
 * Removes an entry from an existing NodeSet list.
3277
 */
3278
void
3279
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3280
0
    if (cur == NULL) return;
3281
0
    if (val >= cur->nodeNr) return;
3282
0
    if ((cur->nodeTab[val] != NULL) &&
3283
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3284
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3285
0
    cur->nodeNr--;
3286
0
    for (;val < cur->nodeNr;val++)
3287
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
3288
0
    cur->nodeTab[cur->nodeNr] = NULL;
3289
0
}
3290
3291
/**
3292
 * xmlXPathFreeNodeSet:
3293
 * @obj:  the xmlNodeSetPtr to free
3294
 *
3295
 * Free the NodeSet compound (not the actual nodes !).
3296
 */
3297
void
3298
0
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3299
0
    if (obj == NULL) return;
3300
0
    if (obj->nodeTab != NULL) {
3301
0
  int i;
3302
3303
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3304
0
  for (i = 0;i < obj->nodeNr;i++)
3305
0
      if ((obj->nodeTab[i] != NULL) &&
3306
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3307
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3308
0
  xmlFree(obj->nodeTab);
3309
0
    }
3310
0
    xmlFree(obj);
3311
0
}
3312
3313
/**
3314
 * xmlXPathNodeSetClearFromPos:
3315
 * @set: the node set to be cleared
3316
 * @pos: the start position to clear from
3317
 *
3318
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3319
 * are feed) starting with the entry at @pos, but does *not* free the list
3320
 * itself. Sets the length of the list to @pos.
3321
 */
3322
static void
3323
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3324
0
{
3325
0
    if ((set == NULL) || (pos >= set->nodeNr))
3326
0
  return;
3327
0
    else if ((hasNsNodes)) {
3328
0
  int i;
3329
0
  xmlNodePtr node;
3330
3331
0
  for (i = pos; i < set->nodeNr; i++) {
3332
0
      node = set->nodeTab[i];
3333
0
      if ((node != NULL) &&
3334
0
    (node->type == XML_NAMESPACE_DECL))
3335
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3336
0
  }
3337
0
    }
3338
0
    set->nodeNr = pos;
3339
0
}
3340
3341
/**
3342
 * xmlXPathNodeSetClear:
3343
 * @set:  the node set to clear
3344
 *
3345
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3346
 * are feed), but does *not* free the list itself. Sets the length of the
3347
 * list to 0.
3348
 */
3349
static void
3350
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3351
0
{
3352
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3353
0
}
3354
3355
/**
3356
 * xmlXPathNodeSetKeepLast:
3357
 * @set: the node set to be cleared
3358
 *
3359
 * Move the last node to the first position and clear temporary XPath objects
3360
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3361
 * to 1.
3362
 */
3363
static void
3364
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3365
0
{
3366
0
    int i;
3367
0
    xmlNodePtr node;
3368
3369
0
    if ((set == NULL) || (set->nodeNr <= 1))
3370
0
  return;
3371
0
    for (i = 0; i < set->nodeNr - 1; i++) {
3372
0
        node = set->nodeTab[i];
3373
0
        if ((node != NULL) &&
3374
0
            (node->type == XML_NAMESPACE_DECL))
3375
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3376
0
    }
3377
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3378
0
    set->nodeNr = 1;
3379
0
}
3380
3381
/**
3382
 * xmlXPathNewNodeSet:
3383
 * @val:  the NodePtr value
3384
 *
3385
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3386
 * it with the single Node @val
3387
 *
3388
 * Returns the newly created object.
3389
 */
3390
xmlXPathObjectPtr
3391
0
xmlXPathNewNodeSet(xmlNodePtr val) {
3392
0
    xmlXPathObjectPtr ret;
3393
3394
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3395
0
    if (ret == NULL)
3396
0
  return(NULL);
3397
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3398
0
    ret->type = XPATH_NODESET;
3399
0
    ret->boolval = 0;
3400
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3401
0
    if (ret->nodesetval == NULL) {
3402
0
        xmlFree(ret);
3403
0
        return(NULL);
3404
0
    }
3405
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3406
0
    return(ret);
3407
0
}
3408
3409
/**
3410
 * xmlXPathNewValueTree:
3411
 * @val:  the NodePtr value
3412
 *
3413
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3414
 * it with the tree root @val
3415
 *
3416
 * Returns the newly created object.
3417
 */
3418
xmlXPathObjectPtr
3419
0
xmlXPathNewValueTree(xmlNodePtr val) {
3420
0
    xmlXPathObjectPtr ret;
3421
3422
0
    ret = xmlXPathNewNodeSet(val);
3423
0
    if (ret == NULL)
3424
0
  return(NULL);
3425
0
    ret->type = XPATH_XSLT_TREE;
3426
3427
0
    return(ret);
3428
0
}
3429
3430
/**
3431
 * xmlXPathNewNodeSetList:
3432
 * @val:  an existing NodeSet
3433
 *
3434
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3435
 * it with the Nodeset @val
3436
 *
3437
 * Returns the newly created object.
3438
 */
3439
xmlXPathObjectPtr
3440
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3441
0
{
3442
0
    xmlXPathObjectPtr ret;
3443
3444
0
    if (val == NULL)
3445
0
        ret = NULL;
3446
0
    else if (val->nodeTab == NULL)
3447
0
        ret = xmlXPathNewNodeSet(NULL);
3448
0
    else {
3449
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3450
0
        if (ret) {
3451
0
            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3452
0
            if (ret->nodesetval == NULL) {
3453
0
                xmlFree(ret);
3454
0
                return(NULL);
3455
0
            }
3456
0
        }
3457
0
    }
3458
3459
0
    return (ret);
3460
0
}
3461
3462
/**
3463
 * xmlXPathWrapNodeSet:
3464
 * @val:  the NodePtr value
3465
 *
3466
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3467
 *
3468
 * Returns the newly created object.
3469
 *
3470
 * In case of error the node set is destroyed and NULL is returned.
3471
 */
3472
xmlXPathObjectPtr
3473
0
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3474
0
    xmlXPathObjectPtr ret;
3475
3476
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3477
0
    if (ret == NULL) {
3478
0
        xmlXPathFreeNodeSet(val);
3479
0
  return(NULL);
3480
0
    }
3481
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3482
0
    ret->type = XPATH_NODESET;
3483
0
    ret->nodesetval = val;
3484
0
    return(ret);
3485
0
}
3486
3487
/**
3488
 * xmlXPathFreeNodeSetList:
3489
 * @obj:  an existing NodeSetList object
3490
 *
3491
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3492
 * the list contrary to xmlXPathFreeObject().
3493
 */
3494
void
3495
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3496
0
    if (obj == NULL) return;
3497
0
    xmlFree(obj);
3498
0
}
3499
3500
/**
3501
 * xmlXPathDifference:
3502
 * @nodes1:  a node-set
3503
 * @nodes2:  a node-set
3504
 *
3505
 * Implements the EXSLT - Sets difference() function:
3506
 *    node-set set:difference (node-set, node-set)
3507
 *
3508
 * Returns the difference between the two node sets, or nodes1 if
3509
 *         nodes2 is empty
3510
 */
3511
xmlNodeSetPtr
3512
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3513
0
    xmlNodeSetPtr ret;
3514
0
    int i, l1;
3515
0
    xmlNodePtr cur;
3516
3517
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3518
0
  return(nodes1);
3519
3520
0
    ret = xmlXPathNodeSetCreate(NULL);
3521
0
    if (ret == NULL)
3522
0
        return(NULL);
3523
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3524
0
  return(ret);
3525
3526
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3527
3528
0
    for (i = 0; i < l1; i++) {
3529
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3530
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3531
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3532
0
                xmlXPathFreeNodeSet(ret);
3533
0
          return(NULL);
3534
0
            }
3535
0
  }
3536
0
    }
3537
0
    return(ret);
3538
0
}
3539
3540
/**
3541
 * xmlXPathIntersection:
3542
 * @nodes1:  a node-set
3543
 * @nodes2:  a node-set
3544
 *
3545
 * Implements the EXSLT - Sets intersection() function:
3546
 *    node-set set:intersection (node-set, node-set)
3547
 *
3548
 * Returns a node set comprising the nodes that are within both the
3549
 *         node sets passed as arguments
3550
 */
3551
xmlNodeSetPtr
3552
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3553
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3554
0
    int i, l1;
3555
0
    xmlNodePtr cur;
3556
3557
0
    if (ret == NULL)
3558
0
        return(ret);
3559
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3560
0
  return(ret);
3561
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3562
0
  return(ret);
3563
3564
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3565
3566
0
    for (i = 0; i < l1; i++) {
3567
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3568
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3569
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3570
0
                xmlXPathFreeNodeSet(ret);
3571
0
          return(NULL);
3572
0
            }
3573
0
  }
3574
0
    }
3575
0
    return(ret);
3576
0
}
3577
3578
/**
3579
 * xmlXPathDistinctSorted:
3580
 * @nodes:  a node-set, sorted by document order
3581
 *
3582
 * Implements the EXSLT - Sets distinct() function:
3583
 *    node-set set:distinct (node-set)
3584
 *
3585
 * Returns a subset of the nodes contained in @nodes, or @nodes if
3586
 *         it is empty
3587
 */
3588
xmlNodeSetPtr
3589
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3590
0
    xmlNodeSetPtr ret;
3591
0
    xmlHashTablePtr hash;
3592
0
    int i, l;
3593
0
    xmlChar * strval;
3594
0
    xmlNodePtr cur;
3595
3596
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3597
0
  return(nodes);
3598
3599
0
    ret = xmlXPathNodeSetCreate(NULL);
3600
0
    if (ret == NULL)
3601
0
        return(ret);
3602
0
    l = xmlXPathNodeSetGetLength(nodes);
3603
0
    hash = xmlHashCreate (l);
3604
0
    for (i = 0; i < l; i++) {
3605
0
  cur = xmlXPathNodeSetItem(nodes, i);
3606
0
  strval = xmlXPathCastNodeToString(cur);
3607
0
  if (xmlHashLookup(hash, strval) == NULL) {
3608
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3609
0
                xmlFree(strval);
3610
0
                goto error;
3611
0
            }
3612
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3613
0
          goto error;
3614
0
  } else {
3615
0
      xmlFree(strval);
3616
0
  }
3617
0
    }
3618
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3619
0
    return(ret);
3620
3621
0
error:
3622
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3623
0
    xmlXPathFreeNodeSet(ret);
3624
0
    return(NULL);
3625
0
}
3626
3627
/**
3628
 * xmlXPathDistinct:
3629
 * @nodes:  a node-set
3630
 *
3631
 * Implements the EXSLT - Sets distinct() function:
3632
 *    node-set set:distinct (node-set)
3633
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3634
 * is called with the sorted node-set
3635
 *
3636
 * Returns a subset of the nodes contained in @nodes, or @nodes if
3637
 *         it is empty
3638
 */
3639
xmlNodeSetPtr
3640
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
3641
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3642
0
  return(nodes);
3643
3644
0
    xmlXPathNodeSetSort(nodes);
3645
0
    return(xmlXPathDistinctSorted(nodes));
3646
0
}
3647
3648
/**
3649
 * xmlXPathHasSameNodes:
3650
 * @nodes1:  a node-set
3651
 * @nodes2:  a node-set
3652
 *
3653
 * Implements the EXSLT - Sets has-same-nodes function:
3654
 *    boolean set:has-same-node(node-set, node-set)
3655
 *
3656
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3657
 *         otherwise
3658
 */
3659
int
3660
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3661
0
    int i, l;
3662
0
    xmlNodePtr cur;
3663
3664
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3665
0
  xmlXPathNodeSetIsEmpty(nodes2))
3666
0
  return(0);
3667
3668
0
    l = xmlXPathNodeSetGetLength(nodes1);
3669
0
    for (i = 0; i < l; i++) {
3670
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3671
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3672
0
      return(1);
3673
0
    }
3674
0
    return(0);
3675
0
}
3676
3677
/**
3678
 * xmlXPathNodeLeadingSorted:
3679
 * @nodes: a node-set, sorted by document order
3680
 * @node: a node
3681
 *
3682
 * Implements the EXSLT - Sets leading() function:
3683
 *    node-set set:leading (node-set, node-set)
3684
 *
3685
 * Returns the nodes in @nodes that precede @node in document order,
3686
 *         @nodes if @node is NULL or an empty node-set if @nodes
3687
 *         doesn't contain @node
3688
 */
3689
xmlNodeSetPtr
3690
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3691
0
    int i, l;
3692
0
    xmlNodePtr cur;
3693
0
    xmlNodeSetPtr ret;
3694
3695
0
    if (node == NULL)
3696
0
  return(nodes);
3697
3698
0
    ret = xmlXPathNodeSetCreate(NULL);
3699
0
    if (ret == NULL)
3700
0
        return(ret);
3701
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3702
0
  (!xmlXPathNodeSetContains(nodes, node)))
3703
0
  return(ret);
3704
3705
0
    l = xmlXPathNodeSetGetLength(nodes);
3706
0
    for (i = 0; i < l; i++) {
3707
0
  cur = xmlXPathNodeSetItem(nodes, i);
3708
0
  if (cur == node)
3709
0
      break;
3710
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3711
0
            xmlXPathFreeNodeSet(ret);
3712
0
      return(NULL);
3713
0
        }
3714
0
    }
3715
0
    return(ret);
3716
0
}
3717
3718
/**
3719
 * xmlXPathNodeLeading:
3720
 * @nodes:  a node-set
3721
 * @node:  a node
3722
 *
3723
 * Implements the EXSLT - Sets leading() function:
3724
 *    node-set set:leading (node-set, node-set)
3725
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3726
 * is called.
3727
 *
3728
 * Returns the nodes in @nodes that precede @node in document order,
3729
 *         @nodes if @node is NULL or an empty node-set if @nodes
3730
 *         doesn't contain @node
3731
 */
3732
xmlNodeSetPtr
3733
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3734
0
    xmlXPathNodeSetSort(nodes);
3735
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3736
0
}
3737
3738
/**
3739
 * xmlXPathLeadingSorted:
3740
 * @nodes1:  a node-set, sorted by document order
3741
 * @nodes2:  a node-set, sorted by document order
3742
 *
3743
 * Implements the EXSLT - Sets leading() function:
3744
 *    node-set set:leading (node-set, node-set)
3745
 *
3746
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3747
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3748
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3749
 */
3750
xmlNodeSetPtr
3751
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3752
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3753
0
  return(nodes1);
3754
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3755
0
             xmlXPathNodeSetItem(nodes2, 1)));
3756
0
}
3757
3758
/**
3759
 * xmlXPathLeading:
3760
 * @nodes1:  a node-set
3761
 * @nodes2:  a node-set
3762
 *
3763
 * Implements the EXSLT - Sets leading() function:
3764
 *    node-set set:leading (node-set, node-set)
3765
 * @nodes1 and @nodes2 are sorted by document order, then
3766
 * #exslSetsLeadingSorted is called.
3767
 *
3768
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3769
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3770
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3771
 */
3772
xmlNodeSetPtr
3773
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3774
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3775
0
  return(nodes1);
3776
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3777
0
  return(xmlXPathNodeSetCreate(NULL));
3778
0
    xmlXPathNodeSetSort(nodes1);
3779
0
    xmlXPathNodeSetSort(nodes2);
3780
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3781
0
             xmlXPathNodeSetItem(nodes2, 1)));
3782
0
}
3783
3784
/**
3785
 * xmlXPathNodeTrailingSorted:
3786
 * @nodes: a node-set, sorted by document order
3787
 * @node: a node
3788
 *
3789
 * Implements the EXSLT - Sets trailing() function:
3790
 *    node-set set:trailing (node-set, node-set)
3791
 *
3792
 * Returns the nodes in @nodes that follow @node in document order,
3793
 *         @nodes if @node is NULL or an empty node-set if @nodes
3794
 *         doesn't contain @node
3795
 */
3796
xmlNodeSetPtr
3797
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3798
0
    int i, l;
3799
0
    xmlNodePtr cur;
3800
0
    xmlNodeSetPtr ret;
3801
3802
0
    if (node == NULL)
3803
0
  return(nodes);
3804
3805
0
    ret = xmlXPathNodeSetCreate(NULL);
3806
0
    if (ret == NULL)
3807
0
        return(ret);
3808
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3809
0
  (!xmlXPathNodeSetContains(nodes, node)))
3810
0
  return(ret);
3811
3812
0
    l = xmlXPathNodeSetGetLength(nodes);
3813
0
    for (i = l - 1; i >= 0; i--) {
3814
0
  cur = xmlXPathNodeSetItem(nodes, i);
3815
0
  if (cur == node)
3816
0
      break;
3817
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3818
0
            xmlXPathFreeNodeSet(ret);
3819
0
      return(NULL);
3820
0
        }
3821
0
    }
3822
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3823
0
    return(ret);
3824
0
}
3825
3826
/**
3827
 * xmlXPathNodeTrailing:
3828
 * @nodes:  a node-set
3829
 * @node:  a node
3830
 *
3831
 * Implements the EXSLT - Sets trailing() function:
3832
 *    node-set set:trailing (node-set, node-set)
3833
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3834
 * is called.
3835
 *
3836
 * Returns the nodes in @nodes that follow @node in document order,
3837
 *         @nodes if @node is NULL or an empty node-set if @nodes
3838
 *         doesn't contain @node
3839
 */
3840
xmlNodeSetPtr
3841
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3842
0
    xmlXPathNodeSetSort(nodes);
3843
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3844
0
}
3845
3846
/**
3847
 * xmlXPathTrailingSorted:
3848
 * @nodes1:  a node-set, sorted by document order
3849
 * @nodes2:  a node-set, sorted by document order
3850
 *
3851
 * Implements the EXSLT - Sets trailing() function:
3852
 *    node-set set:trailing (node-set, node-set)
3853
 *
3854
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3855
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3856
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3857
 */
3858
xmlNodeSetPtr
3859
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3860
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3861
0
  return(nodes1);
3862
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3863
0
              xmlXPathNodeSetItem(nodes2, 0)));
3864
0
}
3865
3866
/**
3867
 * xmlXPathTrailing:
3868
 * @nodes1:  a node-set
3869
 * @nodes2:  a node-set
3870
 *
3871
 * Implements the EXSLT - Sets trailing() function:
3872
 *    node-set set:trailing (node-set, node-set)
3873
 * @nodes1 and @nodes2 are sorted by document order, then
3874
 * #xmlXPathTrailingSorted is called.
3875
 *
3876
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3877
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3878
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3879
 */
3880
xmlNodeSetPtr
3881
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3882
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3883
0
  return(nodes1);
3884
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3885
0
  return(xmlXPathNodeSetCreate(NULL));
3886
0
    xmlXPathNodeSetSort(nodes1);
3887
0
    xmlXPathNodeSetSort(nodes2);
3888
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3889
0
              xmlXPathNodeSetItem(nodes2, 0)));
3890
0
}
3891
3892
/************************************************************************
3893
 *                  *
3894
 *    Routines to handle extra functions      *
3895
 *                  *
3896
 ************************************************************************/
3897
3898
/**
3899
 * xmlXPathRegisterFunc:
3900
 * @ctxt:  the XPath context
3901
 * @name:  the function name
3902
 * @f:  the function implementation or NULL
3903
 *
3904
 * Register a new function. If @f is NULL it unregisters the function
3905
 *
3906
 * Returns 0 in case of success, -1 in case of error
3907
 */
3908
int
3909
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3910
0
         xmlXPathFunction f) {
3911
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3912
0
}
3913
3914
/**
3915
 * xmlXPathRegisterFuncNS:
3916
 * @ctxt:  the XPath context
3917
 * @name:  the function name
3918
 * @ns_uri:  the function namespace URI
3919
 * @f:  the function implementation or NULL
3920
 *
3921
 * Register a new function. If @f is NULL it unregisters the function
3922
 *
3923
 * Returns 0 in case of success, -1 in case of error
3924
 */
3925
int
3926
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3927
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
3928
0
    int ret;
3929
3930
0
    if (ctxt == NULL)
3931
0
  return(-1);
3932
0
    if (name == NULL)
3933
0
  return(-1);
3934
3935
0
    if (ctxt->funcHash == NULL)
3936
0
  ctxt->funcHash = xmlHashCreate(0);
3937
0
    if (ctxt->funcHash == NULL) {
3938
0
        xmlXPathErrMemory(ctxt);
3939
0
  return(-1);
3940
0
    }
3941
0
    if (f == NULL)
3942
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3943
0
XML_IGNORE_FPTR_CAST_WARNINGS
3944
0
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3945
0
XML_POP_WARNINGS
3946
0
    if (ret < 0) {
3947
0
        xmlXPathErrMemory(ctxt);
3948
0
        return(-1);
3949
0
    }
3950
3951
0
    return(0);
3952
0
}
3953
3954
/**
3955
 * xmlXPathRegisterFuncLookup:
3956
 * @ctxt:  the XPath context
3957
 * @f:  the lookup function
3958
 * @funcCtxt:  the lookup data
3959
 *
3960
 * Registers an external mechanism to do function lookup.
3961
 */
3962
void
3963
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3964
          xmlXPathFuncLookupFunc f,
3965
0
          void *funcCtxt) {
3966
0
    if (ctxt == NULL)
3967
0
  return;
3968
0
    ctxt->funcLookupFunc = f;
3969
0
    ctxt->funcLookupData = funcCtxt;
3970
0
}
3971
3972
/**
3973
 * xmlXPathFunctionLookup:
3974
 * @ctxt:  the XPath context
3975
 * @name:  the function name
3976
 *
3977
 * Search in the Function array of the context for the given
3978
 * function.
3979
 *
3980
 * Returns the xmlXPathFunction or NULL if not found
3981
 */
3982
xmlXPathFunction
3983
0
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3984
0
    if (ctxt == NULL)
3985
0
  return (NULL);
3986
3987
0
    if (ctxt->funcLookupFunc != NULL) {
3988
0
  xmlXPathFunction ret;
3989
0
  xmlXPathFuncLookupFunc f;
3990
3991
0
  f = ctxt->funcLookupFunc;
3992
0
  ret = f(ctxt->funcLookupData, name, NULL);
3993
0
  if (ret != NULL)
3994
0
      return(ret);
3995
0
    }
3996
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3997
0
}
3998
3999
/**
4000
 * xmlXPathFunctionLookupNS:
4001
 * @ctxt:  the XPath context
4002
 * @name:  the function name
4003
 * @ns_uri:  the function namespace URI
4004
 *
4005
 * Search in the Function array of the context for the given
4006
 * function.
4007
 *
4008
 * Returns the xmlXPathFunction or NULL if not found
4009
 */
4010
xmlXPathFunction
4011
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4012
0
       const xmlChar *ns_uri) {
4013
0
    xmlXPathFunction ret;
4014
4015
0
    if (ctxt == NULL)
4016
0
  return(NULL);
4017
0
    if (name == NULL)
4018
0
  return(NULL);
4019
4020
0
    if (ctxt->funcLookupFunc != NULL) {
4021
0
  xmlXPathFuncLookupFunc f;
4022
4023
0
  f = ctxt->funcLookupFunc;
4024
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
4025
0
  if (ret != NULL)
4026
0
      return(ret);
4027
0
    }
4028
4029
0
    if (ctxt->funcHash == NULL)
4030
0
  return(NULL);
4031
4032
0
XML_IGNORE_FPTR_CAST_WARNINGS
4033
0
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4034
0
XML_POP_WARNINGS
4035
0
    return(ret);
4036
0
}
4037
4038
/**
4039
 * xmlXPathRegisteredFuncsCleanup:
4040
 * @ctxt:  the XPath context
4041
 *
4042
 * Cleanup the XPath context data associated to registered functions
4043
 */
4044
void
4045
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4046
0
    if (ctxt == NULL)
4047
0
  return;
4048
4049
0
    xmlHashFree(ctxt->funcHash, NULL);
4050
0
    ctxt->funcHash = NULL;
4051
0
}
4052
4053
/************************************************************************
4054
 *                  *
4055
 *      Routines to handle Variables      *
4056
 *                  *
4057
 ************************************************************************/
4058
4059
/**
4060
 * xmlXPathRegisterVariable:
4061
 * @ctxt:  the XPath context
4062
 * @name:  the variable name
4063
 * @value:  the variable value or NULL
4064
 *
4065
 * Register a new variable value. If @value is NULL it unregisters
4066
 * the variable
4067
 *
4068
 * Returns 0 in case of success, -1 in case of error
4069
 */
4070
int
4071
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4072
0
       xmlXPathObjectPtr value) {
4073
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4074
0
}
4075
4076
/**
4077
 * xmlXPathRegisterVariableNS:
4078
 * @ctxt:  the XPath context
4079
 * @name:  the variable name
4080
 * @ns_uri:  the variable namespace URI
4081
 * @value:  the variable value or NULL
4082
 *
4083
 * Register a new variable value. If @value is NULL it unregisters
4084
 * the variable
4085
 *
4086
 * Returns 0 in case of success, -1 in case of error
4087
 */
4088
int
4089
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4090
         const xmlChar *ns_uri,
4091
0
         xmlXPathObjectPtr value) {
4092
0
    if (ctxt == NULL)
4093
0
  return(-1);
4094
0
    if (name == NULL)
4095
0
  return(-1);
4096
4097
0
    if (ctxt->varHash == NULL)
4098
0
  ctxt->varHash = xmlHashCreate(0);
4099
0
    if (ctxt->varHash == NULL)
4100
0
  return(-1);
4101
0
    if (value == NULL)
4102
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4103
0
                             xmlXPathFreeObjectEntry));
4104
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4105
0
             (void *) value, xmlXPathFreeObjectEntry));
4106
0
}
4107
4108
/**
4109
 * xmlXPathRegisterVariableLookup:
4110
 * @ctxt:  the XPath context
4111
 * @f:  the lookup function
4112
 * @data:  the lookup data
4113
 *
4114
 * register an external mechanism to do variable lookup
4115
 */
4116
void
4117
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4118
0
   xmlXPathVariableLookupFunc f, void *data) {
4119
0
    if (ctxt == NULL)
4120
0
  return;
4121
0
    ctxt->varLookupFunc = f;
4122
0
    ctxt->varLookupData = data;
4123
0
}
4124
4125
/**
4126
 * xmlXPathVariableLookup:
4127
 * @ctxt:  the XPath context
4128
 * @name:  the variable name
4129
 *
4130
 * Search in the Variable array of the context for the given
4131
 * variable value.
4132
 *
4133
 * Returns a copy of the value or NULL if not found
4134
 */
4135
xmlXPathObjectPtr
4136
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4137
0
    if (ctxt == NULL)
4138
0
  return(NULL);
4139
4140
0
    if (ctxt->varLookupFunc != NULL) {
4141
0
  xmlXPathObjectPtr ret;
4142
4143
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4144
0
          (ctxt->varLookupData, name, NULL);
4145
0
  return(ret);
4146
0
    }
4147
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4148
0
}
4149
4150
/**
4151
 * xmlXPathVariableLookupNS:
4152
 * @ctxt:  the XPath context
4153
 * @name:  the variable name
4154
 * @ns_uri:  the variable namespace URI
4155
 *
4156
 * Search in the Variable array of the context for the given
4157
 * variable value.
4158
 *
4159
 * Returns the a copy of the value or NULL if not found
4160
 */
4161
xmlXPathObjectPtr
4162
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4163
0
       const xmlChar *ns_uri) {
4164
0
    if (ctxt == NULL)
4165
0
  return(NULL);
4166
4167
0
    if (ctxt->varLookupFunc != NULL) {
4168
0
  xmlXPathObjectPtr ret;
4169
4170
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4171
0
          (ctxt->varLookupData, name, ns_uri);
4172
0
  if (ret != NULL) return(ret);
4173
0
    }
4174
4175
0
    if (ctxt->varHash == NULL)
4176
0
  return(NULL);
4177
0
    if (name == NULL)
4178
0
  return(NULL);
4179
4180
0
    return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4181
0
}
4182
4183
/**
4184
 * xmlXPathRegisteredVariablesCleanup:
4185
 * @ctxt:  the XPath context
4186
 *
4187
 * Cleanup the XPath context data associated to registered variables
4188
 */
4189
void
4190
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4191
0
    if (ctxt == NULL)
4192
0
  return;
4193
4194
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4195
0
    ctxt->varHash = NULL;
4196
0
}
4197
4198
/**
4199
 * xmlXPathRegisterNs:
4200
 * @ctxt:  the XPath context
4201
 * @prefix:  the namespace prefix cannot be NULL or empty string
4202
 * @ns_uri:  the namespace name
4203
 *
4204
 * Register a new namespace. If @ns_uri is NULL it unregisters
4205
 * the namespace
4206
 *
4207
 * Returns 0 in case of success, -1 in case of error
4208
 */
4209
int
4210
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4211
0
         const xmlChar *ns_uri) {
4212
0
    xmlChar *copy;
4213
4214
0
    if (ctxt == NULL)
4215
0
  return(-1);
4216
0
    if (prefix == NULL)
4217
0
  return(-1);
4218
0
    if (prefix[0] == 0)
4219
0
  return(-1);
4220
4221
0
    if (ctxt->nsHash == NULL)
4222
0
  ctxt->nsHash = xmlHashCreate(10);
4223
0
    if (ctxt->nsHash == NULL) {
4224
0
        xmlXPathErrMemory(ctxt);
4225
0
  return(-1);
4226
0
    }
4227
0
    if (ns_uri == NULL)
4228
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4229
0
                            xmlHashDefaultDeallocator));
4230
4231
0
    copy = xmlStrdup(ns_uri);
4232
0
    if (copy == NULL) {
4233
0
        xmlXPathErrMemory(ctxt);
4234
0
        return(-1);
4235
0
    }
4236
0
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4237
0
                           xmlHashDefaultDeallocator) < 0) {
4238
0
        xmlXPathErrMemory(ctxt);
4239
0
        xmlFree(copy);
4240
0
        return(-1);
4241
0
    }
4242
4243
0
    return(0);
4244
0
}
4245
4246
/**
4247
 * xmlXPathNsLookup:
4248
 * @ctxt:  the XPath context
4249
 * @prefix:  the namespace prefix value
4250
 *
4251
 * Search in the namespace declaration array of the context for the given
4252
 * namespace name associated to the given prefix
4253
 *
4254
 * Returns the value or NULL if not found
4255
 */
4256
const xmlChar *
4257
0
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4258
0
    if (ctxt == NULL)
4259
0
  return(NULL);
4260
0
    if (prefix == NULL)
4261
0
  return(NULL);
4262
4263
0
#ifdef XML_XML_NAMESPACE
4264
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4265
0
  return(XML_XML_NAMESPACE);
4266
0
#endif
4267
4268
0
    if (ctxt->namespaces != NULL) {
4269
0
  int i;
4270
4271
0
  for (i = 0;i < ctxt->nsNr;i++) {
4272
0
      if ((ctxt->namespaces[i] != NULL) &&
4273
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4274
0
    return(ctxt->namespaces[i]->href);
4275
0
  }
4276
0
    }
4277
4278
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4279
0
}
4280
4281
/**
4282
 * xmlXPathRegisteredNsCleanup:
4283
 * @ctxt:  the XPath context
4284
 *
4285
 * Cleanup the XPath context data associated to registered variables
4286
 */
4287
void
4288
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4289
0
    if (ctxt == NULL)
4290
0
  return;
4291
4292
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4293
0
    ctxt->nsHash = NULL;
4294
0
}
4295
4296
/************************************************************************
4297
 *                  *
4298
 *      Routines to handle Values     *
4299
 *                  *
4300
 ************************************************************************/
4301
4302
/* Allocations are terrible, one needs to optimize all this !!! */
4303
4304
/**
4305
 * xmlXPathNewFloat:
4306
 * @val:  the double value
4307
 *
4308
 * Create a new xmlXPathObjectPtr of type double and of value @val
4309
 *
4310
 * Returns the newly created object.
4311
 */
4312
xmlXPathObjectPtr
4313
0
xmlXPathNewFloat(double val) {
4314
0
    xmlXPathObjectPtr ret;
4315
4316
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4317
0
    if (ret == NULL)
4318
0
  return(NULL);
4319
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4320
0
    ret->type = XPATH_NUMBER;
4321
0
    ret->floatval = val;
4322
0
    return(ret);
4323
0
}
4324
4325
/**
4326
 * xmlXPathNewBoolean:
4327
 * @val:  the boolean value
4328
 *
4329
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4330
 *
4331
 * Returns the newly created object.
4332
 */
4333
xmlXPathObjectPtr
4334
0
xmlXPathNewBoolean(int val) {
4335
0
    xmlXPathObjectPtr ret;
4336
4337
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4338
0
    if (ret == NULL)
4339
0
  return(NULL);
4340
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4341
0
    ret->type = XPATH_BOOLEAN;
4342
0
    ret->boolval = (val != 0);
4343
0
    return(ret);
4344
0
}
4345
4346
/**
4347
 * xmlXPathNewString:
4348
 * @val:  the xmlChar * value
4349
 *
4350
 * Create a new xmlXPathObjectPtr of type string and of value @val
4351
 *
4352
 * Returns the newly created object.
4353
 */
4354
xmlXPathObjectPtr
4355
0
xmlXPathNewString(const xmlChar *val) {
4356
0
    xmlXPathObjectPtr ret;
4357
4358
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4359
0
    if (ret == NULL)
4360
0
  return(NULL);
4361
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4362
0
    ret->type = XPATH_STRING;
4363
0
    if (val == NULL)
4364
0
        val = BAD_CAST "";
4365
0
    ret->stringval = xmlStrdup(val);
4366
0
    if (ret->stringval == NULL) {
4367
0
        xmlFree(ret);
4368
0
        return(NULL);
4369
0
    }
4370
0
    return(ret);
4371
0
}
4372
4373
/**
4374
 * xmlXPathWrapString:
4375
 * @val:  the xmlChar * value
4376
 *
4377
 * Wraps the @val string into an XPath object.
4378
 *
4379
 * Returns the newly created object.
4380
 *
4381
 * Frees @val in case of error.
4382
 */
4383
xmlXPathObjectPtr
4384
0
xmlXPathWrapString (xmlChar *val) {
4385
0
    xmlXPathObjectPtr ret;
4386
4387
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4388
0
    if (ret == NULL) {
4389
0
        xmlFree(val);
4390
0
  return(NULL);
4391
0
    }
4392
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4393
0
    ret->type = XPATH_STRING;
4394
0
    ret->stringval = val;
4395
0
    return(ret);
4396
0
}
4397
4398
/**
4399
 * xmlXPathNewCString:
4400
 * @val:  the char * value
4401
 *
4402
 * Create a new xmlXPathObjectPtr of type string and of value @val
4403
 *
4404
 * Returns the newly created object.
4405
 */
4406
xmlXPathObjectPtr
4407
0
xmlXPathNewCString(const char *val) {
4408
0
    return(xmlXPathNewString(BAD_CAST val));
4409
0
}
4410
4411
/**
4412
 * xmlXPathWrapCString:
4413
 * @val:  the char * value
4414
 *
4415
 * Wraps a string into an XPath object.
4416
 *
4417
 * Returns the newly created object.
4418
 */
4419
xmlXPathObjectPtr
4420
0
xmlXPathWrapCString (char * val) {
4421
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4422
0
}
4423
4424
/**
4425
 * xmlXPathWrapExternal:
4426
 * @val:  the user data
4427
 *
4428
 * Wraps the @val data into an XPath object.
4429
 *
4430
 * Returns the newly created object.
4431
 */
4432
xmlXPathObjectPtr
4433
0
xmlXPathWrapExternal (void *val) {
4434
0
    xmlXPathObjectPtr ret;
4435
4436
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4437
0
    if (ret == NULL)
4438
0
  return(NULL);
4439
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4440
0
    ret->type = XPATH_USERS;
4441
0
    ret->user = val;
4442
0
    return(ret);
4443
0
}
4444
4445
/**
4446
 * xmlXPathObjectCopy:
4447
 * @val:  the original object
4448
 *
4449
 * allocate a new copy of a given object
4450
 *
4451
 * Returns the newly created object.
4452
 */
4453
xmlXPathObjectPtr
4454
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4455
0
    xmlXPathObjectPtr ret;
4456
4457
0
    if (val == NULL)
4458
0
  return(NULL);
4459
4460
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4461
0
    if (ret == NULL)
4462
0
  return(NULL);
4463
0
    memcpy(ret, val , sizeof(xmlXPathObject));
4464
0
    switch (val->type) {
4465
0
  case XPATH_BOOLEAN:
4466
0
  case XPATH_NUMBER:
4467
#ifdef LIBXML_XPTR_LOCS_ENABLED
4468
  case XPATH_POINT:
4469
  case XPATH_RANGE:
4470
#endif /* LIBXML_XPTR_LOCS_ENABLED */
4471
0
      break;
4472
0
  case XPATH_STRING:
4473
0
      ret->stringval = xmlStrdup(val->stringval);
4474
0
            if (ret->stringval == NULL) {
4475
0
                xmlFree(ret);
4476
0
                return(NULL);
4477
0
            }
4478
0
      break;
4479
0
  case XPATH_XSLT_TREE:
4480
#if 0
4481
/*
4482
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4483
  this previous handling is no longer correct, and can cause some serious
4484
  problems (ref. bug 145547)
4485
*/
4486
      if ((val->nodesetval != NULL) &&
4487
    (val->nodesetval->nodeTab != NULL)) {
4488
    xmlNodePtr cur, tmp;
4489
    xmlDocPtr top;
4490
4491
    ret->boolval = 1;
4492
    top =  xmlNewDoc(NULL);
4493
    top->name = (char *)
4494
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
4495
    ret->user = top;
4496
    if (top != NULL) {
4497
        top->doc = top;
4498
        cur = val->nodesetval->nodeTab[0]->children;
4499
        while (cur != NULL) {
4500
      tmp = xmlDocCopyNode(cur, top, 1);
4501
      xmlAddChild((xmlNodePtr) top, tmp);
4502
      cur = cur->next;
4503
        }
4504
    }
4505
4506
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4507
      } else
4508
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4509
      /* Deallocate the copied tree value */
4510
      break;
4511
#endif
4512
0
  case XPATH_NODESET:
4513
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4514
0
            if (ret->nodesetval == NULL) {
4515
0
                xmlFree(ret);
4516
0
                return(NULL);
4517
0
            }
4518
      /* Do not deallocate the copied tree value */
4519
0
      ret->boolval = 0;
4520
0
      break;
4521
#ifdef LIBXML_XPTR_LOCS_ENABLED
4522
  case XPATH_LOCATIONSET:
4523
  {
4524
      xmlLocationSetPtr loc = val->user;
4525
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4526
      break;
4527
  }
4528
#endif
4529
0
        case XPATH_USERS:
4530
0
      ret->user = val->user;
4531
0
      break;
4532
0
        default:
4533
0
            xmlFree(ret);
4534
0
            ret = NULL;
4535
0
      break;
4536
0
    }
4537
0
    return(ret);
4538
0
}
4539
4540
/**
4541
 * xmlXPathFreeObject:
4542
 * @obj:  the object to free
4543
 *
4544
 * Free up an xmlXPathObjectPtr object.
4545
 */
4546
void
4547
0
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4548
0
    if (obj == NULL) return;
4549
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4550
0
        if (obj->nodesetval != NULL)
4551
0
            xmlXPathFreeNodeSet(obj->nodesetval);
4552
#ifdef LIBXML_XPTR_LOCS_ENABLED
4553
    } else if (obj->type == XPATH_LOCATIONSET) {
4554
  if (obj->user != NULL)
4555
      xmlXPtrFreeLocationSet(obj->user);
4556
#endif
4557
0
    } else if (obj->type == XPATH_STRING) {
4558
0
  if (obj->stringval != NULL)
4559
0
      xmlFree(obj->stringval);
4560
0
    }
4561
0
    xmlFree(obj);
4562
0
}
4563
4564
static void
4565
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4566
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4567
0
}
4568
4569
/**
4570
 * xmlXPathReleaseObject:
4571
 * @obj:  the xmlXPathObjectPtr to free or to cache
4572
 *
4573
 * Depending on the state of the cache this frees the given
4574
 * XPath object or stores it in the cache.
4575
 */
4576
static void
4577
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4578
0
{
4579
0
    if (obj == NULL)
4580
0
  return;
4581
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4582
0
   xmlXPathFreeObject(obj);
4583
0
    } else {
4584
0
  xmlXPathContextCachePtr cache =
4585
0
      (xmlXPathContextCachePtr) ctxt->cache;
4586
4587
0
  switch (obj->type) {
4588
0
      case XPATH_NODESET:
4589
0
      case XPATH_XSLT_TREE:
4590
0
    if (obj->nodesetval != NULL) {
4591
0
        if ((obj->nodesetval->nodeMax <= 40) &&
4592
0
      (cache->numNodeset < cache->maxNodeset)) {
4593
0
                        obj->stringval = (void *) cache->nodesetObjs;
4594
0
                        cache->nodesetObjs = obj;
4595
0
                        cache->numNodeset += 1;
4596
0
      goto obj_cached;
4597
0
        } else {
4598
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4599
0
      obj->nodesetval = NULL;
4600
0
        }
4601
0
    }
4602
0
    break;
4603
0
      case XPATH_STRING:
4604
0
    if (obj->stringval != NULL)
4605
0
        xmlFree(obj->stringval);
4606
0
                obj->stringval = NULL;
4607
0
    break;
4608
0
      case XPATH_BOOLEAN:
4609
0
      case XPATH_NUMBER:
4610
0
    break;
4611
#ifdef LIBXML_XPTR_LOCS_ENABLED
4612
      case XPATH_LOCATIONSET:
4613
    if (obj->user != NULL) {
4614
        xmlXPtrFreeLocationSet(obj->user);
4615
    }
4616
    goto free_obj;
4617
#endif
4618
0
      default:
4619
0
    goto free_obj;
4620
0
  }
4621
4622
  /*
4623
  * Fallback to adding to the misc-objects slot.
4624
  */
4625
0
        if (cache->numMisc >= cache->maxMisc)
4626
0
      goto free_obj;
4627
0
        obj->stringval = (void *) cache->miscObjs;
4628
0
        cache->miscObjs = obj;
4629
0
        cache->numMisc += 1;
4630
4631
0
obj_cached:
4632
0
        obj->boolval = 0;
4633
0
  if (obj->nodesetval != NULL) {
4634
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
4635
4636
      /*
4637
      * Due to those nasty ns-nodes, we need to traverse
4638
      * the list and free the ns-nodes.
4639
      */
4640
0
      if (tmpset->nodeNr > 0) {
4641
0
    int i;
4642
0
    xmlNodePtr node;
4643
4644
0
    for (i = 0; i < tmpset->nodeNr; i++) {
4645
0
        node = tmpset->nodeTab[i];
4646
0
        if ((node != NULL) &&
4647
0
      (node->type == XML_NAMESPACE_DECL))
4648
0
        {
4649
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4650
0
        }
4651
0
    }
4652
0
      }
4653
0
      tmpset->nodeNr = 0;
4654
0
        }
4655
4656
0
  return;
4657
4658
0
free_obj:
4659
  /*
4660
  * Cache is full; free the object.
4661
  */
4662
0
  if (obj->nodesetval != NULL)
4663
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4664
0
  xmlFree(obj);
4665
0
    }
4666
0
    return;
4667
0
}
4668
4669
4670
/************************************************************************
4671
 *                  *
4672
 *      Type Casting Routines       *
4673
 *                  *
4674
 ************************************************************************/
4675
4676
/**
4677
 * xmlXPathCastBooleanToString:
4678
 * @val:  a boolean
4679
 *
4680
 * Converts a boolean to its string value.
4681
 *
4682
 * Returns a newly allocated string.
4683
 */
4684
xmlChar *
4685
0
xmlXPathCastBooleanToString (int val) {
4686
0
    xmlChar *ret;
4687
0
    if (val)
4688
0
  ret = xmlStrdup((const xmlChar *) "true");
4689
0
    else
4690
0
  ret = xmlStrdup((const xmlChar *) "false");
4691
0
    return(ret);
4692
0
}
4693
4694
/**
4695
 * xmlXPathCastNumberToString:
4696
 * @val:  a number
4697
 *
4698
 * Converts a number to its string value.
4699
 *
4700
 * Returns a newly allocated string.
4701
 */
4702
xmlChar *
4703
0
xmlXPathCastNumberToString (double val) {
4704
0
    xmlChar *ret;
4705
0
    switch (xmlXPathIsInf(val)) {
4706
0
    case 1:
4707
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
4708
0
  break;
4709
0
    case -1:
4710
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4711
0
  break;
4712
0
    default:
4713
0
  if (xmlXPathIsNaN(val)) {
4714
0
      ret = xmlStrdup((const xmlChar *) "NaN");
4715
0
  } else if (val == 0) {
4716
            /* Omit sign for negative zero. */
4717
0
      ret = xmlStrdup((const xmlChar *) "0");
4718
0
  } else {
4719
      /* could be improved */
4720
0
      char buf[100];
4721
0
      xmlXPathFormatNumber(val, buf, 99);
4722
0
      buf[99] = 0;
4723
0
      ret = xmlStrdup((const xmlChar *) buf);
4724
0
  }
4725
0
    }
4726
0
    return(ret);
4727
0
}
4728
4729
/**
4730
 * xmlXPathCastNodeToString:
4731
 * @node:  a node
4732
 *
4733
 * Converts a node to its string value.
4734
 *
4735
 * Returns a newly allocated string.
4736
 */
4737
xmlChar *
4738
0
xmlXPathCastNodeToString (xmlNodePtr node) {
4739
0
    return(xmlNodeGetContent(node));
4740
0
}
4741
4742
/**
4743
 * xmlXPathCastNodeSetToString:
4744
 * @ns:  a node-set
4745
 *
4746
 * Converts a node-set to its string value.
4747
 *
4748
 * Returns a newly allocated string.
4749
 */
4750
xmlChar *
4751
0
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4752
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4753
0
  return(xmlStrdup((const xmlChar *) ""));
4754
4755
0
    if (ns->nodeNr > 1)
4756
0
  xmlXPathNodeSetSort(ns);
4757
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4758
0
}
4759
4760
/**
4761
 * xmlXPathCastToString:
4762
 * @val:  an XPath object
4763
 *
4764
 * Converts an existing object to its string() equivalent
4765
 *
4766
 * Returns the allocated string value of the object, NULL in case of error.
4767
 *         It's up to the caller to free the string memory with xmlFree().
4768
 */
4769
xmlChar *
4770
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
4771
0
    xmlChar *ret = NULL;
4772
4773
0
    if (val == NULL)
4774
0
  return(xmlStrdup((const xmlChar *) ""));
4775
0
    switch (val->type) {
4776
0
  case XPATH_UNDEFINED:
4777
0
      ret = xmlStrdup((const xmlChar *) "");
4778
0
      break;
4779
0
        case XPATH_NODESET:
4780
0
        case XPATH_XSLT_TREE:
4781
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4782
0
      break;
4783
0
  case XPATH_STRING:
4784
0
      return(xmlStrdup(val->stringval));
4785
0
        case XPATH_BOOLEAN:
4786
0
      ret = xmlXPathCastBooleanToString(val->boolval);
4787
0
      break;
4788
0
  case XPATH_NUMBER: {
4789
0
      ret = xmlXPathCastNumberToString(val->floatval);
4790
0
      break;
4791
0
  }
4792
0
  case XPATH_USERS:
4793
#ifdef LIBXML_XPTR_LOCS_ENABLED
4794
  case XPATH_POINT:
4795
  case XPATH_RANGE:
4796
  case XPATH_LOCATIONSET:
4797
#endif /* LIBXML_XPTR_LOCS_ENABLED */
4798
      /* TODO */
4799
0
      ret = xmlStrdup((const xmlChar *) "");
4800
0
      break;
4801
0
    }
4802
0
    return(ret);
4803
0
}
4804
4805
/**
4806
 * xmlXPathConvertString:
4807
 * @val:  an XPath object
4808
 *
4809
 * Converts an existing object to its string() equivalent
4810
 *
4811
 * Returns the new object, the old one is freed (or the operation
4812
 *         is done directly on @val)
4813
 */
4814
xmlXPathObjectPtr
4815
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
4816
0
    xmlChar *res = NULL;
4817
4818
0
    if (val == NULL)
4819
0
  return(xmlXPathNewCString(""));
4820
4821
0
    switch (val->type) {
4822
0
    case XPATH_UNDEFINED:
4823
0
  break;
4824
0
    case XPATH_NODESET:
4825
0
    case XPATH_XSLT_TREE:
4826
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4827
0
  break;
4828
0
    case XPATH_STRING:
4829
0
  return(val);
4830
0
    case XPATH_BOOLEAN:
4831
0
  res = xmlXPathCastBooleanToString(val->boolval);
4832
0
  break;
4833
0
    case XPATH_NUMBER:
4834
0
  res = xmlXPathCastNumberToString(val->floatval);
4835
0
  break;
4836
0
    case XPATH_USERS:
4837
#ifdef LIBXML_XPTR_LOCS_ENABLED
4838
    case XPATH_POINT:
4839
    case XPATH_RANGE:
4840
    case XPATH_LOCATIONSET:
4841
#endif /* LIBXML_XPTR_LOCS_ENABLED */
4842
  /* TODO */
4843
0
  break;
4844
0
    }
4845
0
    xmlXPathFreeObject(val);
4846
0
    if (res == NULL)
4847
0
  return(xmlXPathNewCString(""));
4848
0
    return(xmlXPathWrapString(res));
4849
0
}
4850
4851
/**
4852
 * xmlXPathCastBooleanToNumber:
4853
 * @val:  a boolean
4854
 *
4855
 * Converts a boolean to its number value
4856
 *
4857
 * Returns the number value
4858
 */
4859
double
4860
0
xmlXPathCastBooleanToNumber(int val) {
4861
0
    if (val)
4862
0
  return(1.0);
4863
0
    return(0.0);
4864
0
}
4865
4866
/**
4867
 * xmlXPathCastStringToNumber:
4868
 * @val:  a string
4869
 *
4870
 * Converts a string to its number value
4871
 *
4872
 * Returns the number value
4873
 */
4874
double
4875
0
xmlXPathCastStringToNumber(const xmlChar * val) {
4876
0
    return(xmlXPathStringEvalNumber(val));
4877
0
}
4878
4879
/**
4880
 * xmlXPathNodeToNumberInternal:
4881
 * @node:  a node
4882
 *
4883
 * Converts a node to its number value
4884
 *
4885
 * Returns the number value
4886
 */
4887
static double
4888
0
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4889
0
    xmlChar *strval;
4890
0
    double ret;
4891
4892
0
    if (node == NULL)
4893
0
  return(xmlXPathNAN);
4894
0
    strval = xmlXPathCastNodeToString(node);
4895
0
    if (strval == NULL) {
4896
0
        xmlXPathPErrMemory(ctxt);
4897
0
  return(xmlXPathNAN);
4898
0
    }
4899
0
    ret = xmlXPathCastStringToNumber(strval);
4900
0
    xmlFree(strval);
4901
4902
0
    return(ret);
4903
0
}
4904
4905
/**
4906
 * xmlXPathCastNodeToNumber:
4907
 * @node:  a node
4908
 *
4909
 * Converts a node to its number value
4910
 *
4911
 * Returns the number value
4912
 */
4913
double
4914
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
4915
0
    return(xmlXPathNodeToNumberInternal(NULL, node));
4916
0
}
4917
4918
/**
4919
 * xmlXPathCastNodeSetToNumber:
4920
 * @ns:  a node-set
4921
 *
4922
 * Converts a node-set to its number value
4923
 *
4924
 * Returns the number value
4925
 */
4926
double
4927
0
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4928
0
    xmlChar *str;
4929
0
    double ret;
4930
4931
0
    if (ns == NULL)
4932
0
  return(xmlXPathNAN);
4933
0
    str = xmlXPathCastNodeSetToString(ns);
4934
0
    ret = xmlXPathCastStringToNumber(str);
4935
0
    xmlFree(str);
4936
0
    return(ret);
4937
0
}
4938
4939
/**
4940
 * xmlXPathCastToNumber:
4941
 * @val:  an XPath object
4942
 *
4943
 * Converts an XPath object to its number value
4944
 *
4945
 * Returns the number value
4946
 */
4947
double
4948
0
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4949
0
    return(xmlXPathCastToNumberInternal(NULL, val));
4950
0
}
4951
4952
/**
4953
 * xmlXPathConvertNumber:
4954
 * @val:  an XPath object
4955
 *
4956
 * Converts an existing object to its number() equivalent
4957
 *
4958
 * Returns the new object, the old one is freed (or the operation
4959
 *         is done directly on @val)
4960
 */
4961
xmlXPathObjectPtr
4962
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4963
0
    xmlXPathObjectPtr ret;
4964
4965
0
    if (val == NULL)
4966
0
  return(xmlXPathNewFloat(0.0));
4967
0
    if (val->type == XPATH_NUMBER)
4968
0
  return(val);
4969
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4970
0
    xmlXPathFreeObject(val);
4971
0
    return(ret);
4972
0
}
4973
4974
/**
4975
 * xmlXPathCastNumberToBoolean:
4976
 * @val:  a number
4977
 *
4978
 * Converts a number to its boolean value
4979
 *
4980
 * Returns the boolean value
4981
 */
4982
int
4983
0
xmlXPathCastNumberToBoolean (double val) {
4984
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
4985
0
   return(0);
4986
0
     return(1);
4987
0
}
4988
4989
/**
4990
 * xmlXPathCastStringToBoolean:
4991
 * @val:  a string
4992
 *
4993
 * Converts a string to its boolean value
4994
 *
4995
 * Returns the boolean value
4996
 */
4997
int
4998
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
4999
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
5000
0
  return(0);
5001
0
    return(1);
5002
0
}
5003
5004
/**
5005
 * xmlXPathCastNodeSetToBoolean:
5006
 * @ns:  a node-set
5007
 *
5008
 * Converts a node-set to its boolean value
5009
 *
5010
 * Returns the boolean value
5011
 */
5012
int
5013
0
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5014
0
    if ((ns == NULL) || (ns->nodeNr == 0))
5015
0
  return(0);
5016
0
    return(1);
5017
0
}
5018
5019
/**
5020
 * xmlXPathCastToBoolean:
5021
 * @val:  an XPath object
5022
 *
5023
 * Converts an XPath object to its boolean value
5024
 *
5025
 * Returns the boolean value
5026
 */
5027
int
5028
0
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5029
0
    int ret = 0;
5030
5031
0
    if (val == NULL)
5032
0
  return(0);
5033
0
    switch (val->type) {
5034
0
    case XPATH_UNDEFINED:
5035
0
  ret = 0;
5036
0
  break;
5037
0
    case XPATH_NODESET:
5038
0
    case XPATH_XSLT_TREE:
5039
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5040
0
  break;
5041
0
    case XPATH_STRING:
5042
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
5043
0
  break;
5044
0
    case XPATH_NUMBER:
5045
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
5046
0
  break;
5047
0
    case XPATH_BOOLEAN:
5048
0
  ret = val->boolval;
5049
0
  break;
5050
0
    case XPATH_USERS:
5051
#ifdef LIBXML_XPTR_LOCS_ENABLED
5052
    case XPATH_POINT:
5053
    case XPATH_RANGE:
5054
    case XPATH_LOCATIONSET:
5055
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5056
  /* TODO */
5057
0
  ret = 0;
5058
0
  break;
5059
0
    }
5060
0
    return(ret);
5061
0
}
5062
5063
5064
/**
5065
 * xmlXPathConvertBoolean:
5066
 * @val:  an XPath object
5067
 *
5068
 * Converts an existing object to its boolean() equivalent
5069
 *
5070
 * Returns the new object, the old one is freed (or the operation
5071
 *         is done directly on @val)
5072
 */
5073
xmlXPathObjectPtr
5074
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5075
0
    xmlXPathObjectPtr ret;
5076
5077
0
    if (val == NULL)
5078
0
  return(xmlXPathNewBoolean(0));
5079
0
    if (val->type == XPATH_BOOLEAN)
5080
0
  return(val);
5081
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5082
0
    xmlXPathFreeObject(val);
5083
0
    return(ret);
5084
0
}
5085
5086
/************************************************************************
5087
 *                  *
5088
 *    Routines to handle XPath contexts     *
5089
 *                  *
5090
 ************************************************************************/
5091
5092
/**
5093
 * xmlXPathNewContext:
5094
 * @doc:  the XML document
5095
 *
5096
 * Create a new xmlXPathContext
5097
 *
5098
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5099
 */
5100
xmlXPathContextPtr
5101
0
xmlXPathNewContext(xmlDocPtr doc) {
5102
0
    xmlXPathContextPtr ret;
5103
5104
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5105
0
    if (ret == NULL)
5106
0
  return(NULL);
5107
0
    memset(ret, 0 , sizeof(xmlXPathContext));
5108
0
    ret->doc = doc;
5109
0
    ret->node = NULL;
5110
5111
0
    ret->varHash = NULL;
5112
5113
0
    ret->nb_types = 0;
5114
0
    ret->max_types = 0;
5115
0
    ret->types = NULL;
5116
5117
0
    ret->nb_axis = 0;
5118
0
    ret->max_axis = 0;
5119
0
    ret->axis = NULL;
5120
5121
0
    ret->nsHash = NULL;
5122
0
    ret->user = NULL;
5123
5124
0
    ret->contextSize = -1;
5125
0
    ret->proximityPosition = -1;
5126
5127
#ifdef XP_DEFAULT_CACHE_ON
5128
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5129
  xmlXPathFreeContext(ret);
5130
  return(NULL);
5131
    }
5132
#endif
5133
5134
0
    xmlXPathRegisterAllFunctions(ret);
5135
5136
0
    if (ret->lastError.code != XML_ERR_OK) {
5137
0
  xmlXPathFreeContext(ret);
5138
0
  return(NULL);
5139
0
    }
5140
5141
0
    return(ret);
5142
0
}
5143
5144
/**
5145
 * xmlXPathFreeContext:
5146
 * @ctxt:  the context to free
5147
 *
5148
 * Free up an xmlXPathContext
5149
 */
5150
void
5151
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5152
0
    if (ctxt == NULL) return;
5153
5154
0
    if (ctxt->cache != NULL)
5155
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5156
0
    xmlXPathRegisteredNsCleanup(ctxt);
5157
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
5158
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
5159
0
    xmlResetError(&ctxt->lastError);
5160
0
    xmlFree(ctxt);
5161
0
}
5162
5163
/**
5164
 * xmlXPathSetErrorHandler:
5165
 * @ctxt:  the XPath context
5166
 * @handler:  error handler
5167
 * @data:  user data which will be passed to the handler
5168
 *
5169
 * Register a callback function that will be called on errors and
5170
 * warnings. If handler is NULL, the error handler will be deactivated.
5171
 *
5172
 * Available since 2.13.0.
5173
 */
5174
void
5175
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
5176
0
                        xmlStructuredErrorFunc handler, void *data) {
5177
0
    if (ctxt == NULL)
5178
0
        return;
5179
5180
0
    ctxt->error = handler;
5181
0
    ctxt->userData = data;
5182
0
}
5183
5184
/************************************************************************
5185
 *                  *
5186
 *    Routines to handle XPath parser contexts    *
5187
 *                  *
5188
 ************************************************************************/
5189
5190
/**
5191
 * xmlXPathNewParserContext:
5192
 * @str:  the XPath expression
5193
 * @ctxt:  the XPath context
5194
 *
5195
 * Create a new xmlXPathParserContext
5196
 *
5197
 * Returns the xmlXPathParserContext just allocated.
5198
 */
5199
xmlXPathParserContextPtr
5200
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5201
0
    xmlXPathParserContextPtr ret;
5202
5203
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5204
0
    if (ret == NULL) {
5205
0
        xmlXPathErrMemory(ctxt);
5206
0
  return(NULL);
5207
0
    }
5208
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
5209
0
    ret->cur = ret->base = str;
5210
0
    ret->context = ctxt;
5211
5212
0
    ret->comp = xmlXPathNewCompExpr();
5213
0
    if (ret->comp == NULL) {
5214
0
        xmlXPathErrMemory(ctxt);
5215
0
  xmlFree(ret->valueTab);
5216
0
  xmlFree(ret);
5217
0
  return(NULL);
5218
0
    }
5219
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5220
0
        ret->comp->dict = ctxt->dict;
5221
0
  xmlDictReference(ret->comp->dict);
5222
0
    }
5223
5224
0
    return(ret);
5225
0
}
5226
5227
/**
5228
 * xmlXPathCompParserContext:
5229
 * @comp:  the XPath compiled expression
5230
 * @ctxt:  the XPath context
5231
 *
5232
 * Create a new xmlXPathParserContext when processing a compiled expression
5233
 *
5234
 * Returns the xmlXPathParserContext just allocated.
5235
 */
5236
static xmlXPathParserContextPtr
5237
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5238
0
    xmlXPathParserContextPtr ret;
5239
5240
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5241
0
    if (ret == NULL) {
5242
0
        xmlXPathErrMemory(ctxt);
5243
0
  return(NULL);
5244
0
    }
5245
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
5246
5247
    /* Allocate the value stack */
5248
0
    ret->valueTab = (xmlXPathObjectPtr *)
5249
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5250
0
    if (ret->valueTab == NULL) {
5251
0
  xmlFree(ret);
5252
0
  xmlXPathErrMemory(ctxt);
5253
0
  return(NULL);
5254
0
    }
5255
0
    ret->valueNr = 0;
5256
0
    ret->valueMax = 10;
5257
0
    ret->value = NULL;
5258
5259
0
    ret->context = ctxt;
5260
0
    ret->comp = comp;
5261
5262
0
    return(ret);
5263
0
}
5264
5265
/**
5266
 * xmlXPathFreeParserContext:
5267
 * @ctxt:  the context to free
5268
 *
5269
 * Free up an xmlXPathParserContext
5270
 */
5271
void
5272
0
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5273
0
    int i;
5274
5275
0
    if (ctxt->valueTab != NULL) {
5276
0
        for (i = 0; i < ctxt->valueNr; i++) {
5277
0
            if (ctxt->context)
5278
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5279
0
            else
5280
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
5281
0
        }
5282
0
        xmlFree(ctxt->valueTab);
5283
0
    }
5284
0
    if (ctxt->comp != NULL) {
5285
#ifdef XPATH_STREAMING
5286
  if (ctxt->comp->stream != NULL) {
5287
      xmlFreePatternList(ctxt->comp->stream);
5288
      ctxt->comp->stream = NULL;
5289
  }
5290
#endif
5291
0
  xmlXPathFreeCompExpr(ctxt->comp);
5292
0
    }
5293
0
    xmlFree(ctxt);
5294
0
}
5295
5296
/************************************************************************
5297
 *                  *
5298
 *    The implicit core function library      *
5299
 *                  *
5300
 ************************************************************************/
5301
5302
/**
5303
 * xmlXPathNodeValHash:
5304
 * @node:  a node pointer
5305
 *
5306
 * Function computing the beginning of the string value of the node,
5307
 * used to speed up comparisons
5308
 *
5309
 * Returns an int usable as a hash
5310
 */
5311
static unsigned int
5312
0
xmlXPathNodeValHash(xmlNodePtr node) {
5313
0
    int len = 2;
5314
0
    const xmlChar * string = NULL;
5315
0
    xmlNodePtr tmp = NULL;
5316
0
    unsigned int ret = 0;
5317
5318
0
    if (node == NULL)
5319
0
  return(0);
5320
5321
0
    if (node->type == XML_DOCUMENT_NODE) {
5322
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
5323
0
  if (tmp == NULL)
5324
0
      node = node->children;
5325
0
  else
5326
0
      node = tmp;
5327
5328
0
  if (node == NULL)
5329
0
      return(0);
5330
0
    }
5331
5332
0
    switch (node->type) {
5333
0
  case XML_COMMENT_NODE:
5334
0
  case XML_PI_NODE:
5335
0
  case XML_CDATA_SECTION_NODE:
5336
0
  case XML_TEXT_NODE:
5337
0
      string = node->content;
5338
0
      if (string == NULL)
5339
0
    return(0);
5340
0
      if (string[0] == 0)
5341
0
    return(0);
5342
0
      return(string[0] + (string[1] << 8));
5343
0
  case XML_NAMESPACE_DECL:
5344
0
      string = ((xmlNsPtr)node)->href;
5345
0
      if (string == NULL)
5346
0
    return(0);
5347
0
      if (string[0] == 0)
5348
0
    return(0);
5349
0
      return(string[0] + (string[1] << 8));
5350
0
  case XML_ATTRIBUTE_NODE:
5351
0
      tmp = ((xmlAttrPtr) node)->children;
5352
0
      break;
5353
0
  case XML_ELEMENT_NODE:
5354
0
      tmp = node->children;
5355
0
      break;
5356
0
  default:
5357
0
      return(0);
5358
0
    }
5359
0
    while (tmp != NULL) {
5360
0
  switch (tmp->type) {
5361
0
      case XML_CDATA_SECTION_NODE:
5362
0
      case XML_TEXT_NODE:
5363
0
    string = tmp->content;
5364
0
    break;
5365
0
      default:
5366
0
                string = NULL;
5367
0
    break;
5368
0
  }
5369
0
  if ((string != NULL) && (string[0] != 0)) {
5370
0
      if (len == 1) {
5371
0
    return(ret + (string[0] << 8));
5372
0
      }
5373
0
      if (string[1] == 0) {
5374
0
    len = 1;
5375
0
    ret = string[0];
5376
0
      } else {
5377
0
    return(string[0] + (string[1] << 8));
5378
0
      }
5379
0
  }
5380
  /*
5381
   * Skip to next node
5382
   */
5383
0
        if ((tmp->children != NULL) &&
5384
0
            (tmp->type != XML_DTD_NODE) &&
5385
0
            (tmp->type != XML_ENTITY_REF_NODE) &&
5386
0
            (tmp->children->type != XML_ENTITY_DECL)) {
5387
0
            tmp = tmp->children;
5388
0
            continue;
5389
0
  }
5390
0
  if (tmp == node)
5391
0
      break;
5392
5393
0
  if (tmp->next != NULL) {
5394
0
      tmp = tmp->next;
5395
0
      continue;
5396
0
  }
5397
5398
0
  do {
5399
0
      tmp = tmp->parent;
5400
0
      if (tmp == NULL)
5401
0
    break;
5402
0
      if (tmp == node) {
5403
0
    tmp = NULL;
5404
0
    break;
5405
0
      }
5406
0
      if (tmp->next != NULL) {
5407
0
    tmp = tmp->next;
5408
0
    break;
5409
0
      }
5410
0
  } while (tmp != NULL);
5411
0
    }
5412
0
    return(ret);
5413
0
}
5414
5415
/**
5416
 * xmlXPathStringHash:
5417
 * @string:  a string
5418
 *
5419
 * Function computing the beginning of the string value of the node,
5420
 * used to speed up comparisons
5421
 *
5422
 * Returns an int usable as a hash
5423
 */
5424
static unsigned int
5425
0
xmlXPathStringHash(const xmlChar * string) {
5426
0
    if (string == NULL)
5427
0
  return(0);
5428
0
    if (string[0] == 0)
5429
0
  return(0);
5430
0
    return(string[0] + (string[1] << 8));
5431
0
}
5432
5433
/**
5434
 * xmlXPathCompareNodeSetFloat:
5435
 * @ctxt:  the XPath Parser context
5436
 * @inf:  less than (1) or greater than (0)
5437
 * @strict:  is the comparison strict
5438
 * @arg:  the node set
5439
 * @f:  the value
5440
 *
5441
 * Implement the compare operation between a nodeset and a number
5442
 *     @ns < @val    (1, 1, ...
5443
 *     @ns <= @val   (1, 0, ...
5444
 *     @ns > @val    (0, 1, ...
5445
 *     @ns >= @val   (0, 0, ...
5446
 *
5447
 * If one object to be compared is a node-set and the other is a number,
5448
 * then the comparison will be true if and only if there is a node in the
5449
 * node-set such that the result of performing the comparison on the number
5450
 * to be compared and on the result of converting the string-value of that
5451
 * node to a number using the number function is true.
5452
 *
5453
 * Returns 0 or 1 depending on the results of the test.
5454
 */
5455
static int
5456
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5457
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5458
0
    int i, ret = 0;
5459
0
    xmlNodeSetPtr ns;
5460
0
    xmlChar *str2;
5461
5462
0
    if ((f == NULL) || (arg == NULL) ||
5463
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5464
0
  xmlXPathReleaseObject(ctxt->context, arg);
5465
0
  xmlXPathReleaseObject(ctxt->context, f);
5466
0
        return(0);
5467
0
    }
5468
0
    ns = arg->nodesetval;
5469
0
    if (ns != NULL) {
5470
0
  for (i = 0;i < ns->nodeNr;i++) {
5471
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5472
0
       if (str2 != NULL) {
5473
0
     valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5474
0
     xmlFree(str2);
5475
0
     xmlXPathNumberFunction(ctxt, 1);
5476
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5477
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5478
0
     if (ret)
5479
0
         break;
5480
0
       } else {
5481
0
                 xmlXPathPErrMemory(ctxt);
5482
0
             }
5483
0
  }
5484
0
    }
5485
0
    xmlXPathReleaseObject(ctxt->context, arg);
5486
0
    xmlXPathReleaseObject(ctxt->context, f);
5487
0
    return(ret);
5488
0
}
5489
5490
/**
5491
 * xmlXPathCompareNodeSetString:
5492
 * @ctxt:  the XPath Parser context
5493
 * @inf:  less than (1) or greater than (0)
5494
 * @strict:  is the comparison strict
5495
 * @arg:  the node set
5496
 * @s:  the value
5497
 *
5498
 * Implement the compare operation between a nodeset and a string
5499
 *     @ns < @val    (1, 1, ...
5500
 *     @ns <= @val   (1, 0, ...
5501
 *     @ns > @val    (0, 1, ...
5502
 *     @ns >= @val   (0, 0, ...
5503
 *
5504
 * If one object to be compared is a node-set and the other is a string,
5505
 * then the comparison will be true if and only if there is a node in
5506
 * the node-set such that the result of performing the comparison on the
5507
 * string-value of the node and the other string is true.
5508
 *
5509
 * Returns 0 or 1 depending on the results of the test.
5510
 */
5511
static int
5512
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5513
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5514
0
    int i, ret = 0;
5515
0
    xmlNodeSetPtr ns;
5516
0
    xmlChar *str2;
5517
5518
0
    if ((s == NULL) || (arg == NULL) ||
5519
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5520
0
  xmlXPathReleaseObject(ctxt->context, arg);
5521
0
  xmlXPathReleaseObject(ctxt->context, s);
5522
0
        return(0);
5523
0
    }
5524
0
    ns = arg->nodesetval;
5525
0
    if (ns != NULL) {
5526
0
  for (i = 0;i < ns->nodeNr;i++) {
5527
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5528
0
       if (str2 != NULL) {
5529
0
     valuePush(ctxt,
5530
0
         xmlXPathCacheNewString(ctxt, str2));
5531
0
     xmlFree(str2);
5532
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5533
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5534
0
     if (ret)
5535
0
         break;
5536
0
       } else {
5537
0
                 xmlXPathPErrMemory(ctxt);
5538
0
             }
5539
0
  }
5540
0
    }
5541
0
    xmlXPathReleaseObject(ctxt->context, arg);
5542
0
    xmlXPathReleaseObject(ctxt->context, s);
5543
0
    return(ret);
5544
0
}
5545
5546
/**
5547
 * xmlXPathCompareNodeSets:
5548
 * @inf:  less than (1) or greater than (0)
5549
 * @strict:  is the comparison strict
5550
 * @arg1:  the first node set object
5551
 * @arg2:  the second node set object
5552
 *
5553
 * Implement the compare operation on nodesets:
5554
 *
5555
 * If both objects to be compared are node-sets, then the comparison
5556
 * will be true if and only if there is a node in the first node-set
5557
 * and a node in the second node-set such that the result of performing
5558
 * the comparison on the string-values of the two nodes is true.
5559
 * ....
5560
 * When neither object to be compared is a node-set and the operator
5561
 * is <=, <, >= or >, then the objects are compared by converting both
5562
 * objects to numbers and comparing the numbers according to IEEE 754.
5563
 * ....
5564
 * The number function converts its argument to a number as follows:
5565
 *  - a string that consists of optional whitespace followed by an
5566
 *    optional minus sign followed by a Number followed by whitespace
5567
 *    is converted to the IEEE 754 number that is nearest (according
5568
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5569
 *    represented by the string; any other string is converted to NaN
5570
 *
5571
 * Conclusion all nodes need to be converted first to their string value
5572
 * and then the comparison must be done when possible
5573
 */
5574
static int
5575
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5576
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5577
0
    int i, j, init = 0;
5578
0
    double val1;
5579
0
    double *values2;
5580
0
    int ret = 0;
5581
0
    xmlNodeSetPtr ns1;
5582
0
    xmlNodeSetPtr ns2;
5583
5584
0
    if ((arg1 == NULL) ||
5585
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5586
0
  xmlXPathFreeObject(arg2);
5587
0
        return(0);
5588
0
    }
5589
0
    if ((arg2 == NULL) ||
5590
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5591
0
  xmlXPathFreeObject(arg1);
5592
0
  xmlXPathFreeObject(arg2);
5593
0
        return(0);
5594
0
    }
5595
5596
0
    ns1 = arg1->nodesetval;
5597
0
    ns2 = arg2->nodesetval;
5598
5599
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5600
0
  xmlXPathFreeObject(arg1);
5601
0
  xmlXPathFreeObject(arg2);
5602
0
  return(0);
5603
0
    }
5604
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5605
0
  xmlXPathFreeObject(arg1);
5606
0
  xmlXPathFreeObject(arg2);
5607
0
  return(0);
5608
0
    }
5609
5610
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5611
0
    if (values2 == NULL) {
5612
0
        xmlXPathPErrMemory(ctxt);
5613
0
  xmlXPathFreeObject(arg1);
5614
0
  xmlXPathFreeObject(arg2);
5615
0
  return(0);
5616
0
    }
5617
0
    for (i = 0;i < ns1->nodeNr;i++) {
5618
0
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5619
0
  if (xmlXPathIsNaN(val1))
5620
0
      continue;
5621
0
  for (j = 0;j < ns2->nodeNr;j++) {
5622
0
      if (init == 0) {
5623
0
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5624
0
                                                          ns2->nodeTab[j]);
5625
0
      }
5626
0
      if (xmlXPathIsNaN(values2[j]))
5627
0
    continue;
5628
0
      if (inf && strict)
5629
0
    ret = (val1 < values2[j]);
5630
0
      else if (inf && !strict)
5631
0
    ret = (val1 <= values2[j]);
5632
0
      else if (!inf && strict)
5633
0
    ret = (val1 > values2[j]);
5634
0
      else if (!inf && !strict)
5635
0
    ret = (val1 >= values2[j]);
5636
0
      if (ret)
5637
0
    break;
5638
0
  }
5639
0
  if (ret)
5640
0
      break;
5641
0
  init = 1;
5642
0
    }
5643
0
    xmlFree(values2);
5644
0
    xmlXPathFreeObject(arg1);
5645
0
    xmlXPathFreeObject(arg2);
5646
0
    return(ret);
5647
0
}
5648
5649
/**
5650
 * xmlXPathCompareNodeSetValue:
5651
 * @ctxt:  the XPath Parser context
5652
 * @inf:  less than (1) or greater than (0)
5653
 * @strict:  is the comparison strict
5654
 * @arg:  the node set
5655
 * @val:  the value
5656
 *
5657
 * Implement the compare operation between a nodeset and a value
5658
 *     @ns < @val    (1, 1, ...
5659
 *     @ns <= @val   (1, 0, ...
5660
 *     @ns > @val    (0, 1, ...
5661
 *     @ns >= @val   (0, 0, ...
5662
 *
5663
 * If one object to be compared is a node-set and the other is a boolean,
5664
 * then the comparison will be true if and only if the result of performing
5665
 * the comparison on the boolean and on the result of converting
5666
 * the node-set to a boolean using the boolean function is true.
5667
 *
5668
 * Returns 0 or 1 depending on the results of the test.
5669
 */
5670
static int
5671
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5672
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5673
0
    if ((val == NULL) || (arg == NULL) ||
5674
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5675
0
        return(0);
5676
5677
0
    switch(val->type) {
5678
0
        case XPATH_NUMBER:
5679
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5680
0
        case XPATH_NODESET:
5681
0
        case XPATH_XSLT_TREE:
5682
0
      return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5683
0
        case XPATH_STRING:
5684
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5685
0
        case XPATH_BOOLEAN:
5686
0
      valuePush(ctxt, arg);
5687
0
      xmlXPathBooleanFunction(ctxt, 1);
5688
0
      valuePush(ctxt, val);
5689
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
5690
0
  default:
5691
0
            xmlXPathReleaseObject(ctxt->context, arg);
5692
0
            xmlXPathReleaseObject(ctxt->context, val);
5693
0
            XP_ERROR0(XPATH_INVALID_TYPE);
5694
0
    }
5695
0
    return(0);
5696
0
}
5697
5698
/**
5699
 * xmlXPathEqualNodeSetString:
5700
 * @arg:  the nodeset object argument
5701
 * @str:  the string to compare to.
5702
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
5703
 *
5704
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5705
 * If one object to be compared is a node-set and the other is a string,
5706
 * then the comparison will be true if and only if there is a node in
5707
 * the node-set such that the result of performing the comparison on the
5708
 * string-value of the node and the other string is true.
5709
 *
5710
 * Returns 0 or 1 depending on the results of the test.
5711
 */
5712
static int
5713
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5714
                           xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5715
0
{
5716
0
    int i;
5717
0
    xmlNodeSetPtr ns;
5718
0
    xmlChar *str2;
5719
0
    unsigned int hash;
5720
5721
0
    if ((str == NULL) || (arg == NULL) ||
5722
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5723
0
        return (0);
5724
0
    ns = arg->nodesetval;
5725
    /*
5726
     * A NULL nodeset compared with a string is always false
5727
     * (since there is no node equal, and no node not equal)
5728
     */
5729
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5730
0
        return (0);
5731
0
    hash = xmlXPathStringHash(str);
5732
0
    for (i = 0; i < ns->nodeNr; i++) {
5733
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5734
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5735
0
            if (str2 == NULL) {
5736
0
                xmlXPathPErrMemory(ctxt);
5737
0
                return(0);
5738
0
            }
5739
0
            if (xmlStrEqual(str, str2)) {
5740
0
                xmlFree(str2);
5741
0
    if (neq)
5742
0
        continue;
5743
0
                return (1);
5744
0
            } else if (neq) {
5745
0
    xmlFree(str2);
5746
0
    return (1);
5747
0
      }
5748
0
            xmlFree(str2);
5749
0
        } else if (neq)
5750
0
      return (1);
5751
0
    }
5752
0
    return (0);
5753
0
}
5754
5755
/**
5756
 * xmlXPathEqualNodeSetFloat:
5757
 * @arg:  the nodeset object argument
5758
 * @f:  the float to compare to
5759
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
5760
 *
5761
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5762
 * If one object to be compared is a node-set and the other is a number,
5763
 * then the comparison will be true if and only if there is a node in
5764
 * the node-set such that the result of performing the comparison on the
5765
 * number to be compared and on the result of converting the string-value
5766
 * of that node to a number using the number function is true.
5767
 *
5768
 * Returns 0 or 1 depending on the results of the test.
5769
 */
5770
static int
5771
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5772
0
    xmlXPathObjectPtr arg, double f, int neq) {
5773
0
  int i, ret=0;
5774
0
  xmlNodeSetPtr ns;
5775
0
  xmlChar *str2;
5776
0
  xmlXPathObjectPtr val;
5777
0
  double v;
5778
5779
0
    if ((arg == NULL) ||
5780
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5781
0
        return(0);
5782
5783
0
    ns = arg->nodesetval;
5784
0
    if (ns != NULL) {
5785
0
  for (i=0;i<ns->nodeNr;i++) {
5786
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5787
0
      if (str2 != NULL) {
5788
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5789
0
    xmlFree(str2);
5790
0
    xmlXPathNumberFunction(ctxt, 1);
5791
0
                CHECK_ERROR0;
5792
0
    val = valuePop(ctxt);
5793
0
    v = val->floatval;
5794
0
    xmlXPathReleaseObject(ctxt->context, val);
5795
0
    if (!xmlXPathIsNaN(v)) {
5796
0
        if ((!neq) && (v==f)) {
5797
0
      ret = 1;
5798
0
      break;
5799
0
        } else if ((neq) && (v!=f)) {
5800
0
      ret = 1;
5801
0
      break;
5802
0
        }
5803
0
    } else { /* NaN is unequal to any value */
5804
0
        if (neq)
5805
0
      ret = 1;
5806
0
    }
5807
0
      } else {
5808
0
                xmlXPathPErrMemory(ctxt);
5809
0
            }
5810
0
  }
5811
0
    }
5812
5813
0
    return(ret);
5814
0
}
5815
5816
5817
/**
5818
 * xmlXPathEqualNodeSets:
5819
 * @arg1:  first nodeset object argument
5820
 * @arg2:  second nodeset object argument
5821
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
5822
 *
5823
 * Implement the equal / not equal operation on XPath nodesets:
5824
 * @arg1 == @arg2  or  @arg1 != @arg2
5825
 * If both objects to be compared are node-sets, then the comparison
5826
 * will be true if and only if there is a node in the first node-set and
5827
 * a node in the second node-set such that the result of performing the
5828
 * comparison on the string-values of the two nodes is true.
5829
 *
5830
 * (needless to say, this is a costly operation)
5831
 *
5832
 * Returns 0 or 1 depending on the results of the test.
5833
 */
5834
static int
5835
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5836
0
                      xmlXPathObjectPtr arg2, int neq) {
5837
0
    int i, j;
5838
0
    unsigned int *hashs1;
5839
0
    unsigned int *hashs2;
5840
0
    xmlChar **values1;
5841
0
    xmlChar **values2;
5842
0
    int ret = 0;
5843
0
    xmlNodeSetPtr ns1;
5844
0
    xmlNodeSetPtr ns2;
5845
5846
0
    if ((arg1 == NULL) ||
5847
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5848
0
        return(0);
5849
0
    if ((arg2 == NULL) ||
5850
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5851
0
        return(0);
5852
5853
0
    ns1 = arg1->nodesetval;
5854
0
    ns2 = arg2->nodesetval;
5855
5856
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5857
0
  return(0);
5858
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5859
0
  return(0);
5860
5861
    /*
5862
     * for equal, check if there is a node pertaining to both sets
5863
     */
5864
0
    if (neq == 0)
5865
0
  for (i = 0;i < ns1->nodeNr;i++)
5866
0
      for (j = 0;j < ns2->nodeNr;j++)
5867
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5868
0
        return(1);
5869
5870
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5871
0
    if (values1 == NULL) {
5872
0
        xmlXPathPErrMemory(ctxt);
5873
0
  return(0);
5874
0
    }
5875
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5876
0
    if (hashs1 == NULL) {
5877
0
        xmlXPathPErrMemory(ctxt);
5878
0
  xmlFree(values1);
5879
0
  return(0);
5880
0
    }
5881
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5882
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5883
0
    if (values2 == NULL) {
5884
0
        xmlXPathPErrMemory(ctxt);
5885
0
  xmlFree(hashs1);
5886
0
  xmlFree(values1);
5887
0
  return(0);
5888
0
    }
5889
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5890
0
    if (hashs2 == NULL) {
5891
0
        xmlXPathPErrMemory(ctxt);
5892
0
  xmlFree(hashs1);
5893
0
  xmlFree(values1);
5894
0
  xmlFree(values2);
5895
0
  return(0);
5896
0
    }
5897
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5898
0
    for (i = 0;i < ns1->nodeNr;i++) {
5899
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5900
0
  for (j = 0;j < ns2->nodeNr;j++) {
5901
0
      if (i == 0)
5902
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5903
0
      if (hashs1[i] != hashs2[j]) {
5904
0
    if (neq) {
5905
0
        ret = 1;
5906
0
        break;
5907
0
    }
5908
0
      }
5909
0
      else {
5910
0
    if (values1[i] == NULL) {
5911
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5912
0
                    if (values1[i] == NULL)
5913
0
                        xmlXPathPErrMemory(ctxt);
5914
0
                }
5915
0
    if (values2[j] == NULL) {
5916
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5917
0
                    if (values2[j] == NULL)
5918
0
                        xmlXPathPErrMemory(ctxt);
5919
0
                }
5920
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5921
0
    if (ret)
5922
0
        break;
5923
0
      }
5924
0
  }
5925
0
  if (ret)
5926
0
      break;
5927
0
    }
5928
0
    for (i = 0;i < ns1->nodeNr;i++)
5929
0
  if (values1[i] != NULL)
5930
0
      xmlFree(values1[i]);
5931
0
    for (j = 0;j < ns2->nodeNr;j++)
5932
0
  if (values2[j] != NULL)
5933
0
      xmlFree(values2[j]);
5934
0
    xmlFree(values1);
5935
0
    xmlFree(values2);
5936
0
    xmlFree(hashs1);
5937
0
    xmlFree(hashs2);
5938
0
    return(ret);
5939
0
}
5940
5941
static int
5942
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5943
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5944
0
    int ret = 0;
5945
    /*
5946
     *At this point we are assured neither arg1 nor arg2
5947
     *is a nodeset, so we can just pick the appropriate routine.
5948
     */
5949
0
    switch (arg1->type) {
5950
0
        case XPATH_UNDEFINED:
5951
0
      break;
5952
0
        case XPATH_BOOLEAN:
5953
0
      switch (arg2->type) {
5954
0
          case XPATH_UNDEFINED:
5955
0
        break;
5956
0
    case XPATH_BOOLEAN:
5957
0
        ret = (arg1->boolval == arg2->boolval);
5958
0
        break;
5959
0
    case XPATH_NUMBER:
5960
0
        ret = (arg1->boolval ==
5961
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
5962
0
        break;
5963
0
    case XPATH_STRING:
5964
0
        if ((arg2->stringval == NULL) ||
5965
0
      (arg2->stringval[0] == 0)) ret = 0;
5966
0
        else
5967
0
      ret = 1;
5968
0
        ret = (arg1->boolval == ret);
5969
0
        break;
5970
0
    case XPATH_USERS:
5971
#ifdef LIBXML_XPTR_LOCS_ENABLED
5972
    case XPATH_POINT:
5973
    case XPATH_RANGE:
5974
    case XPATH_LOCATIONSET:
5975
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5976
        /* TODO */
5977
0
        break;
5978
0
    case XPATH_NODESET:
5979
0
    case XPATH_XSLT_TREE:
5980
0
        break;
5981
0
      }
5982
0
      break;
5983
0
        case XPATH_NUMBER:
5984
0
      switch (arg2->type) {
5985
0
          case XPATH_UNDEFINED:
5986
0
        break;
5987
0
    case XPATH_BOOLEAN:
5988
0
        ret = (arg2->boolval==
5989
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
5990
0
        break;
5991
0
    case XPATH_STRING:
5992
0
        valuePush(ctxt, arg2);
5993
0
        xmlXPathNumberFunction(ctxt, 1);
5994
0
        arg2 = valuePop(ctxt);
5995
0
                    if (ctxt->error)
5996
0
                        break;
5997
                    /* Falls through. */
5998
0
    case XPATH_NUMBER:
5999
        /* Hand check NaN and Infinity equalities */
6000
0
        if (xmlXPathIsNaN(arg1->floatval) ||
6001
0
          xmlXPathIsNaN(arg2->floatval)) {
6002
0
            ret = 0;
6003
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6004
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
6005
0
          ret = 1;
6006
0
      else
6007
0
          ret = 0;
6008
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6009
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
6010
0
          ret = 1;
6011
0
      else
6012
0
          ret = 0;
6013
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6014
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
6015
0
          ret = 1;
6016
0
      else
6017
0
          ret = 0;
6018
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6019
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
6020
0
          ret = 1;
6021
0
      else
6022
0
          ret = 0;
6023
0
        } else {
6024
0
            ret = (arg1->floatval == arg2->floatval);
6025
0
        }
6026
0
        break;
6027
0
    case XPATH_USERS:
6028
#ifdef LIBXML_XPTR_LOCS_ENABLED
6029
    case XPATH_POINT:
6030
    case XPATH_RANGE:
6031
    case XPATH_LOCATIONSET:
6032
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6033
        /* TODO */
6034
0
        break;
6035
0
    case XPATH_NODESET:
6036
0
    case XPATH_XSLT_TREE:
6037
0
        break;
6038
0
      }
6039
0
      break;
6040
0
        case XPATH_STRING:
6041
0
      switch (arg2->type) {
6042
0
          case XPATH_UNDEFINED:
6043
0
        break;
6044
0
    case XPATH_BOOLEAN:
6045
0
        if ((arg1->stringval == NULL) ||
6046
0
      (arg1->stringval[0] == 0)) ret = 0;
6047
0
        else
6048
0
      ret = 1;
6049
0
        ret = (arg2->boolval == ret);
6050
0
        break;
6051
0
    case XPATH_STRING:
6052
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6053
0
        break;
6054
0
    case XPATH_NUMBER:
6055
0
        valuePush(ctxt, arg1);
6056
0
        xmlXPathNumberFunction(ctxt, 1);
6057
0
        arg1 = valuePop(ctxt);
6058
0
                    if (ctxt->error)
6059
0
                        break;
6060
        /* Hand check NaN and Infinity equalities */
6061
0
        if (xmlXPathIsNaN(arg1->floatval) ||
6062
0
          xmlXPathIsNaN(arg2->floatval)) {
6063
0
            ret = 0;
6064
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6065
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
6066
0
          ret = 1;
6067
0
      else
6068
0
          ret = 0;
6069
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6070
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
6071
0
          ret = 1;
6072
0
      else
6073
0
          ret = 0;
6074
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6075
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
6076
0
          ret = 1;
6077
0
      else
6078
0
          ret = 0;
6079
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6080
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
6081
0
          ret = 1;
6082
0
      else
6083
0
          ret = 0;
6084
0
        } else {
6085
0
            ret = (arg1->floatval == arg2->floatval);
6086
0
        }
6087
0
        break;
6088
0
    case XPATH_USERS:
6089
#ifdef LIBXML_XPTR_LOCS_ENABLED
6090
    case XPATH_POINT:
6091
    case XPATH_RANGE:
6092
    case XPATH_LOCATIONSET:
6093
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6094
        /* TODO */
6095
0
        break;
6096
0
    case XPATH_NODESET:
6097
0
    case XPATH_XSLT_TREE:
6098
0
        break;
6099
0
      }
6100
0
      break;
6101
0
        case XPATH_USERS:
6102
#ifdef LIBXML_XPTR_LOCS_ENABLED
6103
  case XPATH_POINT:
6104
  case XPATH_RANGE:
6105
  case XPATH_LOCATIONSET:
6106
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6107
      /* TODO */
6108
0
      break;
6109
0
  case XPATH_NODESET:
6110
0
  case XPATH_XSLT_TREE:
6111
0
      break;
6112
0
    }
6113
0
    xmlXPathReleaseObject(ctxt->context, arg1);
6114
0
    xmlXPathReleaseObject(ctxt->context, arg2);
6115
0
    return(ret);
6116
0
}
6117
6118
/**
6119
 * xmlXPathEqualValues:
6120
 * @ctxt:  the XPath Parser context
6121
 *
6122
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6123
 *
6124
 * Returns 0 or 1 depending on the results of the test.
6125
 */
6126
int
6127
0
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6128
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
6129
0
    int ret = 0;
6130
6131
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6132
0
    arg2 = valuePop(ctxt);
6133
0
    arg1 = valuePop(ctxt);
6134
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6135
0
  if (arg1 != NULL)
6136
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6137
0
  else
6138
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6139
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6140
0
    }
6141
6142
0
    if (arg1 == arg2) {
6143
0
  xmlXPathFreeObject(arg1);
6144
0
        return(1);
6145
0
    }
6146
6147
    /*
6148
     *If either argument is a nodeset, it's a 'special case'
6149
     */
6150
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6151
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6152
  /*
6153
   *Hack it to assure arg1 is the nodeset
6154
   */
6155
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6156
0
    argtmp = arg2;
6157
0
    arg2 = arg1;
6158
0
    arg1 = argtmp;
6159
0
  }
6160
0
  switch (arg2->type) {
6161
0
      case XPATH_UNDEFINED:
6162
0
    break;
6163
0
      case XPATH_NODESET:
6164
0
      case XPATH_XSLT_TREE:
6165
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
6166
0
    break;
6167
0
      case XPATH_BOOLEAN:
6168
0
    if ((arg1->nodesetval == NULL) ||
6169
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
6170
0
    else
6171
0
        ret = 1;
6172
0
    ret = (ret == arg2->boolval);
6173
0
    break;
6174
0
      case XPATH_NUMBER:
6175
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6176
0
    break;
6177
0
      case XPATH_STRING:
6178
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6179
0
                                                 arg2->stringval, 0);
6180
0
    break;
6181
0
      case XPATH_USERS:
6182
#ifdef LIBXML_XPTR_LOCS_ENABLED
6183
      case XPATH_POINT:
6184
      case XPATH_RANGE:
6185
      case XPATH_LOCATIONSET:
6186
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6187
    /* TODO */
6188
0
    break;
6189
0
  }
6190
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6191
0
  xmlXPathReleaseObject(ctxt->context, arg2);
6192
0
  return(ret);
6193
0
    }
6194
6195
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6196
0
}
6197
6198
/**
6199
 * xmlXPathNotEqualValues:
6200
 * @ctxt:  the XPath Parser context
6201
 *
6202
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6203
 *
6204
 * Returns 0 or 1 depending on the results of the test.
6205
 */
6206
int
6207
0
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6208
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
6209
0
    int ret = 0;
6210
6211
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6212
0
    arg2 = valuePop(ctxt);
6213
0
    arg1 = valuePop(ctxt);
6214
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6215
0
  if (arg1 != NULL)
6216
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6217
0
  else
6218
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6219
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6220
0
    }
6221
6222
0
    if (arg1 == arg2) {
6223
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6224
0
        return(0);
6225
0
    }
6226
6227
    /*
6228
     *If either argument is a nodeset, it's a 'special case'
6229
     */
6230
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6231
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6232
  /*
6233
   *Hack it to assure arg1 is the nodeset
6234
   */
6235
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6236
0
    argtmp = arg2;
6237
0
    arg2 = arg1;
6238
0
    arg1 = argtmp;
6239
0
  }
6240
0
  switch (arg2->type) {
6241
0
      case XPATH_UNDEFINED:
6242
0
    break;
6243
0
      case XPATH_NODESET:
6244
0
      case XPATH_XSLT_TREE:
6245
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6246
0
    break;
6247
0
      case XPATH_BOOLEAN:
6248
0
    if ((arg1->nodesetval == NULL) ||
6249
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
6250
0
    else
6251
0
        ret = 1;
6252
0
    ret = (ret != arg2->boolval);
6253
0
    break;
6254
0
      case XPATH_NUMBER:
6255
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6256
0
    break;
6257
0
      case XPATH_STRING:
6258
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6259
0
                                                 arg2->stringval, 1);
6260
0
    break;
6261
0
      case XPATH_USERS:
6262
#ifdef LIBXML_XPTR_LOCS_ENABLED
6263
      case XPATH_POINT:
6264
      case XPATH_RANGE:
6265
      case XPATH_LOCATIONSET:
6266
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6267
    /* TODO */
6268
0
    break;
6269
0
  }
6270
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6271
0
  xmlXPathReleaseObject(ctxt->context, arg2);
6272
0
  return(ret);
6273
0
    }
6274
6275
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6276
0
}
6277
6278
/**
6279
 * xmlXPathCompareValues:
6280
 * @ctxt:  the XPath Parser context
6281
 * @inf:  less than (1) or greater than (0)
6282
 * @strict:  is the comparison strict
6283
 *
6284
 * Implement the compare operation on XPath objects:
6285
 *     @arg1 < @arg2    (1, 1, ...
6286
 *     @arg1 <= @arg2   (1, 0, ...
6287
 *     @arg1 > @arg2    (0, 1, ...
6288
 *     @arg1 >= @arg2   (0, 0, ...
6289
 *
6290
 * When neither object to be compared is a node-set and the operator is
6291
 * <=, <, >=, >, then the objects are compared by converted both objects
6292
 * to numbers and comparing the numbers according to IEEE 754. The <
6293
 * comparison will be true if and only if the first number is less than the
6294
 * second number. The <= comparison will be true if and only if the first
6295
 * number is less than or equal to the second number. The > comparison
6296
 * will be true if and only if the first number is greater than the second
6297
 * number. The >= comparison will be true if and only if the first number
6298
 * is greater than or equal to the second number.
6299
 *
6300
 * Returns 1 if the comparison succeeded, 0 if it failed
6301
 */
6302
int
6303
0
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6304
0
    int ret = 0, arg1i = 0, arg2i = 0;
6305
0
    xmlXPathObjectPtr arg1, arg2;
6306
6307
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6308
0
    arg2 = valuePop(ctxt);
6309
0
    arg1 = valuePop(ctxt);
6310
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6311
0
  if (arg1 != NULL)
6312
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6313
0
  else
6314
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6315
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6316
0
    }
6317
6318
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6319
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6320
  /*
6321
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6322
   * are not freed from within this routine; they will be freed from the
6323
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6324
   */
6325
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6326
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6327
0
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6328
0
  } else {
6329
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6330
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6331
0
                                arg1, arg2);
6332
0
      } else {
6333
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6334
0
                                arg2, arg1);
6335
0
      }
6336
0
  }
6337
0
  return(ret);
6338
0
    }
6339
6340
0
    if (arg1->type != XPATH_NUMBER) {
6341
0
  valuePush(ctxt, arg1);
6342
0
  xmlXPathNumberFunction(ctxt, 1);
6343
0
  arg1 = valuePop(ctxt);
6344
0
    }
6345
0
    if (arg2->type != XPATH_NUMBER) {
6346
0
  valuePush(ctxt, arg2);
6347
0
  xmlXPathNumberFunction(ctxt, 1);
6348
0
  arg2 = valuePop(ctxt);
6349
0
    }
6350
0
    if (ctxt->error)
6351
0
        goto error;
6352
    /*
6353
     * Add tests for infinity and nan
6354
     * => feedback on 3.4 for Inf and NaN
6355
     */
6356
    /* Hand check NaN and Infinity comparisons */
6357
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6358
0
  ret=0;
6359
0
    } else {
6360
0
  arg1i=xmlXPathIsInf(arg1->floatval);
6361
0
  arg2i=xmlXPathIsInf(arg2->floatval);
6362
0
  if (inf && strict) {
6363
0
      if ((arg1i == -1 && arg2i != -1) ||
6364
0
    (arg2i == 1 && arg1i != 1)) {
6365
0
    ret = 1;
6366
0
      } else if (arg1i == 0 && arg2i == 0) {
6367
0
    ret = (arg1->floatval < arg2->floatval);
6368
0
      } else {
6369
0
    ret = 0;
6370
0
      }
6371
0
  }
6372
0
  else if (inf && !strict) {
6373
0
      if (arg1i == -1 || arg2i == 1) {
6374
0
    ret = 1;
6375
0
      } else if (arg1i == 0 && arg2i == 0) {
6376
0
    ret = (arg1->floatval <= arg2->floatval);
6377
0
      } else {
6378
0
    ret = 0;
6379
0
      }
6380
0
  }
6381
0
  else if (!inf && strict) {
6382
0
      if ((arg1i == 1 && arg2i != 1) ||
6383
0
    (arg2i == -1 && arg1i != -1)) {
6384
0
    ret = 1;
6385
0
      } else if (arg1i == 0 && arg2i == 0) {
6386
0
    ret = (arg1->floatval > arg2->floatval);
6387
0
      } else {
6388
0
    ret = 0;
6389
0
      }
6390
0
  }
6391
0
  else if (!inf && !strict) {
6392
0
      if (arg1i == 1 || arg2i == -1) {
6393
0
    ret = 1;
6394
0
      } else if (arg1i == 0 && arg2i == 0) {
6395
0
    ret = (arg1->floatval >= arg2->floatval);
6396
0
      } else {
6397
0
    ret = 0;
6398
0
      }
6399
0
  }
6400
0
    }
6401
0
error:
6402
0
    xmlXPathReleaseObject(ctxt->context, arg1);
6403
0
    xmlXPathReleaseObject(ctxt->context, arg2);
6404
0
    return(ret);
6405
0
}
6406
6407
/**
6408
 * xmlXPathValueFlipSign:
6409
 * @ctxt:  the XPath Parser context
6410
 *
6411
 * Implement the unary - operation on an XPath object
6412
 * The numeric operators convert their operands to numbers as if
6413
 * by calling the number function.
6414
 */
6415
void
6416
0
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6417
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6418
0
    CAST_TO_NUMBER;
6419
0
    CHECK_TYPE(XPATH_NUMBER);
6420
0
    ctxt->value->floatval = -ctxt->value->floatval;
6421
0
}
6422
6423
/**
6424
 * xmlXPathAddValues:
6425
 * @ctxt:  the XPath Parser context
6426
 *
6427
 * Implement the add operation on XPath objects:
6428
 * The numeric operators convert their operands to numbers as if
6429
 * by calling the number function.
6430
 */
6431
void
6432
0
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6433
0
    xmlXPathObjectPtr arg;
6434
0
    double val;
6435
6436
0
    arg = valuePop(ctxt);
6437
0
    if (arg == NULL)
6438
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6439
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6440
0
    xmlXPathReleaseObject(ctxt->context, arg);
6441
0
    CAST_TO_NUMBER;
6442
0
    CHECK_TYPE(XPATH_NUMBER);
6443
0
    ctxt->value->floatval += val;
6444
0
}
6445
6446
/**
6447
 * xmlXPathSubValues:
6448
 * @ctxt:  the XPath Parser context
6449
 *
6450
 * Implement the subtraction operation on XPath objects:
6451
 * The numeric operators convert their operands to numbers as if
6452
 * by calling the number function.
6453
 */
6454
void
6455
0
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6456
0
    xmlXPathObjectPtr arg;
6457
0
    double val;
6458
6459
0
    arg = valuePop(ctxt);
6460
0
    if (arg == NULL)
6461
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6462
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6463
0
    xmlXPathReleaseObject(ctxt->context, arg);
6464
0
    CAST_TO_NUMBER;
6465
0
    CHECK_TYPE(XPATH_NUMBER);
6466
0
    ctxt->value->floatval -= val;
6467
0
}
6468
6469
/**
6470
 * xmlXPathMultValues:
6471
 * @ctxt:  the XPath Parser context
6472
 *
6473
 * Implement the multiply operation on XPath objects:
6474
 * The numeric operators convert their operands to numbers as if
6475
 * by calling the number function.
6476
 */
6477
void
6478
0
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6479
0
    xmlXPathObjectPtr arg;
6480
0
    double val;
6481
6482
0
    arg = valuePop(ctxt);
6483
0
    if (arg == NULL)
6484
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6485
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6486
0
    xmlXPathReleaseObject(ctxt->context, arg);
6487
0
    CAST_TO_NUMBER;
6488
0
    CHECK_TYPE(XPATH_NUMBER);
6489
0
    ctxt->value->floatval *= val;
6490
0
}
6491
6492
/**
6493
 * xmlXPathDivValues:
6494
 * @ctxt:  the XPath Parser context
6495
 *
6496
 * Implement the div operation on XPath objects @arg1 / @arg2:
6497
 * The numeric operators convert their operands to numbers as if
6498
 * by calling the number function.
6499
 */
6500
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6501
void
6502
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6503
0
    xmlXPathObjectPtr arg;
6504
0
    double val;
6505
6506
0
    arg = valuePop(ctxt);
6507
0
    if (arg == NULL)
6508
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6509
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6510
0
    xmlXPathReleaseObject(ctxt->context, arg);
6511
0
    CAST_TO_NUMBER;
6512
0
    CHECK_TYPE(XPATH_NUMBER);
6513
0
    ctxt->value->floatval /= val;
6514
0
}
6515
6516
/**
6517
 * xmlXPathModValues:
6518
 * @ctxt:  the XPath Parser context
6519
 *
6520
 * Implement the mod operation on XPath objects: @arg1 / @arg2
6521
 * The numeric operators convert their operands to numbers as if
6522
 * by calling the number function.
6523
 */
6524
void
6525
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6526
0
    xmlXPathObjectPtr arg;
6527
0
    double arg1, arg2;
6528
6529
0
    arg = valuePop(ctxt);
6530
0
    if (arg == NULL)
6531
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6532
0
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6533
0
    xmlXPathReleaseObject(ctxt->context, arg);
6534
0
    CAST_TO_NUMBER;
6535
0
    CHECK_TYPE(XPATH_NUMBER);
6536
0
    arg1 = ctxt->value->floatval;
6537
0
    if (arg2 == 0)
6538
0
  ctxt->value->floatval = xmlXPathNAN;
6539
0
    else {
6540
0
  ctxt->value->floatval = fmod(arg1, arg2);
6541
0
    }
6542
0
}
6543
6544
/************************************************************************
6545
 *                  *
6546
 *    The traversal functions         *
6547
 *                  *
6548
 ************************************************************************/
6549
6550
/*
6551
 * A traversal function enumerates nodes along an axis.
6552
 * Initially it must be called with NULL, and it indicates
6553
 * termination on the axis by returning NULL.
6554
 */
6555
typedef xmlNodePtr (*xmlXPathTraversalFunction)
6556
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6557
6558
/*
6559
 * xmlXPathTraversalFunctionExt:
6560
 * A traversal function enumerates nodes along an axis.
6561
 * Initially it must be called with NULL, and it indicates
6562
 * termination on the axis by returning NULL.
6563
 * The context node of the traversal is specified via @contextNode.
6564
 */
6565
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6566
                    (xmlNodePtr cur, xmlNodePtr contextNode);
6567
6568
/*
6569
 * xmlXPathNodeSetMergeFunction:
6570
 * Used for merging node sets in xmlXPathCollectAndTest().
6571
 */
6572
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6573
        (xmlNodeSetPtr, xmlNodeSetPtr);
6574
6575
6576
/**
6577
 * xmlXPathNextSelf:
6578
 * @ctxt:  the XPath Parser context
6579
 * @cur:  the current node in the traversal
6580
 *
6581
 * Traversal function for the "self" direction
6582
 * The self axis contains just the context node itself
6583
 *
6584
 * Returns the next element following that axis
6585
 */
6586
xmlNodePtr
6587
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6588
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6589
0
    if (cur == NULL)
6590
0
        return(ctxt->context->node);
6591
0
    return(NULL);
6592
0
}
6593
6594
/**
6595
 * xmlXPathNextChild:
6596
 * @ctxt:  the XPath Parser context
6597
 * @cur:  the current node in the traversal
6598
 *
6599
 * Traversal function for the "child" direction
6600
 * The child axis contains the children of the context node in document order.
6601
 *
6602
 * Returns the next element following that axis
6603
 */
6604
xmlNodePtr
6605
0
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6606
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6607
0
    if (cur == NULL) {
6608
0
  if (ctxt->context->node == NULL) return(NULL);
6609
0
  switch (ctxt->context->node->type) {
6610
0
            case XML_ELEMENT_NODE:
6611
0
            case XML_TEXT_NODE:
6612
0
            case XML_CDATA_SECTION_NODE:
6613
0
            case XML_ENTITY_REF_NODE:
6614
0
            case XML_ENTITY_NODE:
6615
0
            case XML_PI_NODE:
6616
0
            case XML_COMMENT_NODE:
6617
0
            case XML_NOTATION_NODE:
6618
0
            case XML_DTD_NODE:
6619
0
    return(ctxt->context->node->children);
6620
0
            case XML_DOCUMENT_NODE:
6621
0
            case XML_DOCUMENT_TYPE_NODE:
6622
0
            case XML_DOCUMENT_FRAG_NODE:
6623
0
            case XML_HTML_DOCUMENT_NODE:
6624
0
    return(((xmlDocPtr) ctxt->context->node)->children);
6625
0
      case XML_ELEMENT_DECL:
6626
0
      case XML_ATTRIBUTE_DECL:
6627
0
      case XML_ENTITY_DECL:
6628
0
            case XML_ATTRIBUTE_NODE:
6629
0
      case XML_NAMESPACE_DECL:
6630
0
      case XML_XINCLUDE_START:
6631
0
      case XML_XINCLUDE_END:
6632
0
    return(NULL);
6633
0
  }
6634
0
  return(NULL);
6635
0
    }
6636
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
6637
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
6638
0
  return(NULL);
6639
0
    return(cur->next);
6640
0
}
6641
6642
/**
6643
 * xmlXPathNextChildElement:
6644
 * @ctxt:  the XPath Parser context
6645
 * @cur:  the current node in the traversal
6646
 *
6647
 * Traversal function for the "child" direction and nodes of type element.
6648
 * The child axis contains the children of the context node in document order.
6649
 *
6650
 * Returns the next element following that axis
6651
 */
6652
static xmlNodePtr
6653
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6654
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6655
0
    if (cur == NULL) {
6656
0
  cur = ctxt->context->node;
6657
0
  if (cur == NULL) return(NULL);
6658
  /*
6659
  * Get the first element child.
6660
  */
6661
0
  switch (cur->type) {
6662
0
            case XML_ELEMENT_NODE:
6663
0
      case XML_DOCUMENT_FRAG_NODE:
6664
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6665
0
            case XML_ENTITY_NODE:
6666
0
    cur = cur->children;
6667
0
    if (cur != NULL) {
6668
0
        if (cur->type == XML_ELEMENT_NODE)
6669
0
      return(cur);
6670
0
        do {
6671
0
      cur = cur->next;
6672
0
        } while ((cur != NULL) &&
6673
0
      (cur->type != XML_ELEMENT_NODE));
6674
0
        return(cur);
6675
0
    }
6676
0
    return(NULL);
6677
0
            case XML_DOCUMENT_NODE:
6678
0
            case XML_HTML_DOCUMENT_NODE:
6679
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6680
0
      default:
6681
0
    return(NULL);
6682
0
  }
6683
0
  return(NULL);
6684
0
    }
6685
    /*
6686
    * Get the next sibling element node.
6687
    */
6688
0
    switch (cur->type) {
6689
0
  case XML_ELEMENT_NODE:
6690
0
  case XML_TEXT_NODE:
6691
0
  case XML_ENTITY_REF_NODE:
6692
0
  case XML_ENTITY_NODE:
6693
0
  case XML_CDATA_SECTION_NODE:
6694
0
  case XML_PI_NODE:
6695
0
  case XML_COMMENT_NODE:
6696
0
  case XML_XINCLUDE_END:
6697
0
      break;
6698
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6699
0
  default:
6700
0
      return(NULL);
6701
0
    }
6702
0
    if (cur->next != NULL) {
6703
0
  if (cur->next->type == XML_ELEMENT_NODE)
6704
0
      return(cur->next);
6705
0
  cur = cur->next;
6706
0
  do {
6707
0
      cur = cur->next;
6708
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6709
0
  return(cur);
6710
0
    }
6711
0
    return(NULL);
6712
0
}
6713
6714
#if 0
6715
/**
6716
 * xmlXPathNextDescendantOrSelfElemParent:
6717
 * @ctxt:  the XPath Parser context
6718
 * @cur:  the current node in the traversal
6719
 *
6720
 * Traversal function for the "descendant-or-self" axis.
6721
 * Additionally it returns only nodes which can be parents of
6722
 * element nodes.
6723
 *
6724
 *
6725
 * Returns the next element following that axis
6726
 */
6727
static xmlNodePtr
6728
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
6729
               xmlNodePtr contextNode)
6730
{
6731
    if (cur == NULL) {
6732
  if (contextNode == NULL)
6733
      return(NULL);
6734
  switch (contextNode->type) {
6735
      case XML_ELEMENT_NODE:
6736
      case XML_XINCLUDE_START:
6737
      case XML_DOCUMENT_FRAG_NODE:
6738
      case XML_DOCUMENT_NODE:
6739
      case XML_HTML_DOCUMENT_NODE:
6740
    return(contextNode);
6741
      default:
6742
    return(NULL);
6743
  }
6744
  return(NULL);
6745
    } else {
6746
  xmlNodePtr start = cur;
6747
6748
  while (cur != NULL) {
6749
      switch (cur->type) {
6750
    case XML_ELEMENT_NODE:
6751
    /* TODO: OK to have XInclude here? */
6752
    case XML_XINCLUDE_START:
6753
    case XML_DOCUMENT_FRAG_NODE:
6754
        if (cur != start)
6755
      return(cur);
6756
        if (cur->children != NULL) {
6757
      cur = cur->children;
6758
      continue;
6759
        }
6760
        break;
6761
    /* Not sure if we need those here. */
6762
    case XML_DOCUMENT_NODE:
6763
    case XML_HTML_DOCUMENT_NODE:
6764
        if (cur != start)
6765
      return(cur);
6766
        return(xmlDocGetRootElement((xmlDocPtr) cur));
6767
    default:
6768
        break;
6769
      }
6770
6771
next_sibling:
6772
      if ((cur == NULL) || (cur == contextNode))
6773
    return(NULL);
6774
      if (cur->next != NULL) {
6775
    cur = cur->next;
6776
      } else {
6777
    cur = cur->parent;
6778
    goto next_sibling;
6779
      }
6780
  }
6781
    }
6782
    return(NULL);
6783
}
6784
#endif
6785
6786
/**
6787
 * xmlXPathNextDescendant:
6788
 * @ctxt:  the XPath Parser context
6789
 * @cur:  the current node in the traversal
6790
 *
6791
 * Traversal function for the "descendant" direction
6792
 * the descendant axis contains the descendants of the context node in document
6793
 * order; a descendant is a child or a child of a child and so on.
6794
 *
6795
 * Returns the next element following that axis
6796
 */
6797
xmlNodePtr
6798
0
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6799
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6800
0
    if (cur == NULL) {
6801
0
  if (ctxt->context->node == NULL)
6802
0
      return(NULL);
6803
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6804
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6805
0
      return(NULL);
6806
6807
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6808
0
      return(ctxt->context->doc->children);
6809
0
        return(ctxt->context->node->children);
6810
0
    }
6811
6812
0
    if (cur->type == XML_NAMESPACE_DECL)
6813
0
        return(NULL);
6814
0
    if (cur->children != NULL) {
6815
  /*
6816
   * Do not descend on entities declarations
6817
   */
6818
0
  if (cur->children->type != XML_ENTITY_DECL) {
6819
0
      cur = cur->children;
6820
      /*
6821
       * Skip DTDs
6822
       */
6823
0
      if (cur->type != XML_DTD_NODE)
6824
0
    return(cur);
6825
0
  }
6826
0
    }
6827
6828
0
    if (cur == ctxt->context->node) return(NULL);
6829
6830
0
    while (cur->next != NULL) {
6831
0
  cur = cur->next;
6832
0
  if ((cur->type != XML_ENTITY_DECL) &&
6833
0
      (cur->type != XML_DTD_NODE))
6834
0
      return(cur);
6835
0
    }
6836
6837
0
    do {
6838
0
        cur = cur->parent;
6839
0
  if (cur == NULL) break;
6840
0
  if (cur == ctxt->context->node) return(NULL);
6841
0
  if (cur->next != NULL) {
6842
0
      cur = cur->next;
6843
0
      return(cur);
6844
0
  }
6845
0
    } while (cur != NULL);
6846
0
    return(cur);
6847
0
}
6848
6849
/**
6850
 * xmlXPathNextDescendantOrSelf:
6851
 * @ctxt:  the XPath Parser context
6852
 * @cur:  the current node in the traversal
6853
 *
6854
 * Traversal function for the "descendant-or-self" direction
6855
 * the descendant-or-self axis contains the context node and the descendants
6856
 * of the context node in document order; thus the context node is the first
6857
 * node on the axis, and the first child of the context node is the second node
6858
 * on the axis
6859
 *
6860
 * Returns the next element following that axis
6861
 */
6862
xmlNodePtr
6863
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6864
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6865
0
    if (cur == NULL)
6866
0
        return(ctxt->context->node);
6867
6868
0
    if (ctxt->context->node == NULL)
6869
0
        return(NULL);
6870
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6871
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6872
0
        return(NULL);
6873
6874
0
    return(xmlXPathNextDescendant(ctxt, cur));
6875
0
}
6876
6877
/**
6878
 * xmlXPathNextParent:
6879
 * @ctxt:  the XPath Parser context
6880
 * @cur:  the current node in the traversal
6881
 *
6882
 * Traversal function for the "parent" direction
6883
 * The parent axis contains the parent of the context node, if there is one.
6884
 *
6885
 * Returns the next element following that axis
6886
 */
6887
xmlNodePtr
6888
0
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6889
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6890
    /*
6891
     * the parent of an attribute or namespace node is the element
6892
     * to which the attribute or namespace node is attached
6893
     * Namespace handling !!!
6894
     */
6895
0
    if (cur == NULL) {
6896
0
  if (ctxt->context->node == NULL) return(NULL);
6897
0
  switch (ctxt->context->node->type) {
6898
0
            case XML_ELEMENT_NODE:
6899
0
            case XML_TEXT_NODE:
6900
0
            case XML_CDATA_SECTION_NODE:
6901
0
            case XML_ENTITY_REF_NODE:
6902
0
            case XML_ENTITY_NODE:
6903
0
            case XML_PI_NODE:
6904
0
            case XML_COMMENT_NODE:
6905
0
            case XML_NOTATION_NODE:
6906
0
            case XML_DTD_NODE:
6907
0
      case XML_ELEMENT_DECL:
6908
0
      case XML_ATTRIBUTE_DECL:
6909
0
      case XML_XINCLUDE_START:
6910
0
      case XML_XINCLUDE_END:
6911
0
      case XML_ENTITY_DECL:
6912
0
    if (ctxt->context->node->parent == NULL)
6913
0
        return((xmlNodePtr) ctxt->context->doc);
6914
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6915
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6916
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6917
0
         BAD_CAST "fake node libxslt"))))
6918
0
        return(NULL);
6919
0
    return(ctxt->context->node->parent);
6920
0
            case XML_ATTRIBUTE_NODE: {
6921
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6922
6923
0
    return(att->parent);
6924
0
      }
6925
0
            case XML_DOCUMENT_NODE:
6926
0
            case XML_DOCUMENT_TYPE_NODE:
6927
0
            case XML_DOCUMENT_FRAG_NODE:
6928
0
            case XML_HTML_DOCUMENT_NODE:
6929
0
                return(NULL);
6930
0
      case XML_NAMESPACE_DECL: {
6931
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6932
6933
0
    if ((ns->next != NULL) &&
6934
0
        (ns->next->type != XML_NAMESPACE_DECL))
6935
0
        return((xmlNodePtr) ns->next);
6936
0
                return(NULL);
6937
0
      }
6938
0
  }
6939
0
    }
6940
0
    return(NULL);
6941
0
}
6942
6943
/**
6944
 * xmlXPathNextAncestor:
6945
 * @ctxt:  the XPath Parser context
6946
 * @cur:  the current node in the traversal
6947
 *
6948
 * Traversal function for the "ancestor" direction
6949
 * the ancestor axis contains the ancestors of the context node; the ancestors
6950
 * of the context node consist of the parent of context node and the parent's
6951
 * parent and so on; the nodes are ordered in reverse document order; thus the
6952
 * parent is the first node on the axis, and the parent's parent is the second
6953
 * node on the axis
6954
 *
6955
 * Returns the next element following that axis
6956
 */
6957
xmlNodePtr
6958
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6959
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6960
    /*
6961
     * the parent of an attribute or namespace node is the element
6962
     * to which the attribute or namespace node is attached
6963
     * !!!!!!!!!!!!!
6964
     */
6965
0
    if (cur == NULL) {
6966
0
  if (ctxt->context->node == NULL) return(NULL);
6967
0
  switch (ctxt->context->node->type) {
6968
0
            case XML_ELEMENT_NODE:
6969
0
            case XML_TEXT_NODE:
6970
0
            case XML_CDATA_SECTION_NODE:
6971
0
            case XML_ENTITY_REF_NODE:
6972
0
            case XML_ENTITY_NODE:
6973
0
            case XML_PI_NODE:
6974
0
            case XML_COMMENT_NODE:
6975
0
      case XML_DTD_NODE:
6976
0
      case XML_ELEMENT_DECL:
6977
0
      case XML_ATTRIBUTE_DECL:
6978
0
      case XML_ENTITY_DECL:
6979
0
            case XML_NOTATION_NODE:
6980
0
      case XML_XINCLUDE_START:
6981
0
      case XML_XINCLUDE_END:
6982
0
    if (ctxt->context->node->parent == NULL)
6983
0
        return((xmlNodePtr) ctxt->context->doc);
6984
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6985
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6986
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6987
0
         BAD_CAST "fake node libxslt"))))
6988
0
        return(NULL);
6989
0
    return(ctxt->context->node->parent);
6990
0
            case XML_ATTRIBUTE_NODE: {
6991
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6992
6993
0
    return(tmp->parent);
6994
0
      }
6995
0
            case XML_DOCUMENT_NODE:
6996
0
            case XML_DOCUMENT_TYPE_NODE:
6997
0
            case XML_DOCUMENT_FRAG_NODE:
6998
0
            case XML_HTML_DOCUMENT_NODE:
6999
0
                return(NULL);
7000
0
      case XML_NAMESPACE_DECL: {
7001
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7002
7003
0
    if ((ns->next != NULL) &&
7004
0
        (ns->next->type != XML_NAMESPACE_DECL))
7005
0
        return((xmlNodePtr) ns->next);
7006
    /* Bad, how did that namespace end up here ? */
7007
0
                return(NULL);
7008
0
      }
7009
0
  }
7010
0
  return(NULL);
7011
0
    }
7012
0
    if (cur == ctxt->context->doc->children)
7013
0
  return((xmlNodePtr) ctxt->context->doc);
7014
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7015
0
  return(NULL);
7016
0
    switch (cur->type) {
7017
0
  case XML_ELEMENT_NODE:
7018
0
  case XML_TEXT_NODE:
7019
0
  case XML_CDATA_SECTION_NODE:
7020
0
  case XML_ENTITY_REF_NODE:
7021
0
  case XML_ENTITY_NODE:
7022
0
  case XML_PI_NODE:
7023
0
  case XML_COMMENT_NODE:
7024
0
  case XML_NOTATION_NODE:
7025
0
  case XML_DTD_NODE:
7026
0
        case XML_ELEMENT_DECL:
7027
0
        case XML_ATTRIBUTE_DECL:
7028
0
        case XML_ENTITY_DECL:
7029
0
  case XML_XINCLUDE_START:
7030
0
  case XML_XINCLUDE_END:
7031
0
      if (cur->parent == NULL)
7032
0
    return(NULL);
7033
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
7034
0
    ((cur->parent->name[0] == ' ') ||
7035
0
     (xmlStrEqual(cur->parent->name,
7036
0
            BAD_CAST "fake node libxslt"))))
7037
0
    return(NULL);
7038
0
      return(cur->parent);
7039
0
  case XML_ATTRIBUTE_NODE: {
7040
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
7041
7042
0
      return(att->parent);
7043
0
  }
7044
0
  case XML_NAMESPACE_DECL: {
7045
0
      xmlNsPtr ns = (xmlNsPtr) cur;
7046
7047
0
      if ((ns->next != NULL) &&
7048
0
          (ns->next->type != XML_NAMESPACE_DECL))
7049
0
          return((xmlNodePtr) ns->next);
7050
      /* Bad, how did that namespace end up here ? */
7051
0
            return(NULL);
7052
0
  }
7053
0
  case XML_DOCUMENT_NODE:
7054
0
  case XML_DOCUMENT_TYPE_NODE:
7055
0
  case XML_DOCUMENT_FRAG_NODE:
7056
0
  case XML_HTML_DOCUMENT_NODE:
7057
0
      return(NULL);
7058
0
    }
7059
0
    return(NULL);
7060
0
}
7061
7062
/**
7063
 * xmlXPathNextAncestorOrSelf:
7064
 * @ctxt:  the XPath Parser context
7065
 * @cur:  the current node in the traversal
7066
 *
7067
 * Traversal function for the "ancestor-or-self" direction
7068
 * he ancestor-or-self axis contains the context node and ancestors of
7069
 * the context node in reverse document order; thus the context node is
7070
 * the first node on the axis, and the context node's parent the second;
7071
 * parent here is defined the same as with the parent axis.
7072
 *
7073
 * Returns the next element following that axis
7074
 */
7075
xmlNodePtr
7076
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7077
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7078
0
    if (cur == NULL)
7079
0
        return(ctxt->context->node);
7080
0
    return(xmlXPathNextAncestor(ctxt, cur));
7081
0
}
7082
7083
/**
7084
 * xmlXPathNextFollowingSibling:
7085
 * @ctxt:  the XPath Parser context
7086
 * @cur:  the current node in the traversal
7087
 *
7088
 * Traversal function for the "following-sibling" direction
7089
 * The following-sibling axis contains the following siblings of the context
7090
 * node in document order.
7091
 *
7092
 * Returns the next element following that axis
7093
 */
7094
xmlNodePtr
7095
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7096
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7097
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7098
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
7099
0
  return(NULL);
7100
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7101
0
        return(NULL);
7102
0
    if (cur == NULL)
7103
0
        return(ctxt->context->node->next);
7104
0
    return(cur->next);
7105
0
}
7106
7107
/**
7108
 * xmlXPathNextPrecedingSibling:
7109
 * @ctxt:  the XPath Parser context
7110
 * @cur:  the current node in the traversal
7111
 *
7112
 * Traversal function for the "preceding-sibling" direction
7113
 * The preceding-sibling axis contains the preceding siblings of the context
7114
 * node in reverse document order; the first preceding sibling is first on the
7115
 * axis; the sibling preceding that node is the second on the axis and so on.
7116
 *
7117
 * Returns the next element following that axis
7118
 */
7119
xmlNodePtr
7120
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7121
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7122
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7123
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
7124
0
  return(NULL);
7125
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7126
0
        return(NULL);
7127
0
    if (cur == NULL)
7128
0
        return(ctxt->context->node->prev);
7129
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7130
0
  cur = cur->prev;
7131
0
  if (cur == NULL)
7132
0
      return(ctxt->context->node->prev);
7133
0
    }
7134
0
    return(cur->prev);
7135
0
}
7136
7137
/**
7138
 * xmlXPathNextFollowing:
7139
 * @ctxt:  the XPath Parser context
7140
 * @cur:  the current node in the traversal
7141
 *
7142
 * Traversal function for the "following" direction
7143
 * The following axis contains all nodes in the same document as the context
7144
 * node that are after the context node in document order, excluding any
7145
 * descendants and excluding attribute nodes and namespace nodes; the nodes
7146
 * are ordered in document order
7147
 *
7148
 * Returns the next element following that axis
7149
 */
7150
xmlNodePtr
7151
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7152
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7153
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
7154
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7155
0
        return(cur->children);
7156
7157
0
    if (cur == NULL) {
7158
0
        cur = ctxt->context->node;
7159
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7160
0
            cur = cur->parent;
7161
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7162
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7163
7164
0
            if ((ns->next == NULL) ||
7165
0
                (ns->next->type == XML_NAMESPACE_DECL))
7166
0
                return (NULL);
7167
0
            cur = (xmlNodePtr) ns->next;
7168
0
        }
7169
0
    }
7170
0
    if (cur == NULL) return(NULL) ; /* ERROR */
7171
0
    if (cur->next != NULL) return(cur->next) ;
7172
0
    do {
7173
0
        cur = cur->parent;
7174
0
        if (cur == NULL) break;
7175
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7176
0
        if (cur->next != NULL) return(cur->next);
7177
0
    } while (cur != NULL);
7178
0
    return(cur);
7179
0
}
7180
7181
/*
7182
 * xmlXPathIsAncestor:
7183
 * @ancestor:  the ancestor node
7184
 * @node:  the current node
7185
 *
7186
 * Check that @ancestor is a @node's ancestor
7187
 *
7188
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7189
 */
7190
static int
7191
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7192
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
7193
0
    if (node->type == XML_NAMESPACE_DECL)
7194
0
        return(0);
7195
0
    if (ancestor->type == XML_NAMESPACE_DECL)
7196
0
        return(0);
7197
    /* nodes need to be in the same document */
7198
0
    if (ancestor->doc != node->doc) return(0);
7199
    /* avoid searching if ancestor or node is the root node */
7200
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
7201
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
7202
0
    while (node->parent != NULL) {
7203
0
        if (node->parent == ancestor)
7204
0
            return(1);
7205
0
  node = node->parent;
7206
0
    }
7207
0
    return(0);
7208
0
}
7209
7210
/**
7211
 * xmlXPathNextPreceding:
7212
 * @ctxt:  the XPath Parser context
7213
 * @cur:  the current node in the traversal
7214
 *
7215
 * Traversal function for the "preceding" direction
7216
 * the preceding axis contains all nodes in the same document as the context
7217
 * node that are before the context node in document order, excluding any
7218
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7219
 * ordered in reverse document order
7220
 *
7221
 * Returns the next element following that axis
7222
 */
7223
xmlNodePtr
7224
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7225
0
{
7226
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7227
0
    if (cur == NULL) {
7228
0
        cur = ctxt->context->node;
7229
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7230
0
            cur = cur->parent;
7231
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7232
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7233
7234
0
            if ((ns->next == NULL) ||
7235
0
                (ns->next->type == XML_NAMESPACE_DECL))
7236
0
                return (NULL);
7237
0
            cur = (xmlNodePtr) ns->next;
7238
0
        }
7239
0
    }
7240
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7241
0
  return (NULL);
7242
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7243
0
  cur = cur->prev;
7244
0
    do {
7245
0
        if (cur->prev != NULL) {
7246
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7247
0
            return (cur);
7248
0
        }
7249
7250
0
        cur = cur->parent;
7251
0
        if (cur == NULL)
7252
0
            return (NULL);
7253
0
        if (cur == ctxt->context->doc->children)
7254
0
            return (NULL);
7255
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7256
0
    return (cur);
7257
0
}
7258
7259
/**
7260
 * xmlXPathNextPrecedingInternal:
7261
 * @ctxt:  the XPath Parser context
7262
 * @cur:  the current node in the traversal
7263
 *
7264
 * Traversal function for the "preceding" direction
7265
 * the preceding axis contains all nodes in the same document as the context
7266
 * node that are before the context node in document order, excluding any
7267
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7268
 * ordered in reverse document order
7269
 * This is a faster implementation but internal only since it requires a
7270
 * state kept in the parser context: ctxt->ancestor.
7271
 *
7272
 * Returns the next element following that axis
7273
 */
7274
static xmlNodePtr
7275
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7276
                              xmlNodePtr cur)
7277
0
{
7278
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7279
0
    if (cur == NULL) {
7280
0
        cur = ctxt->context->node;
7281
0
        if (cur == NULL)
7282
0
            return (NULL);
7283
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7284
0
            cur = cur->parent;
7285
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7286
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7287
7288
0
            if ((ns->next == NULL) ||
7289
0
                (ns->next->type == XML_NAMESPACE_DECL))
7290
0
                return (NULL);
7291
0
            cur = (xmlNodePtr) ns->next;
7292
0
        }
7293
0
        ctxt->ancestor = cur->parent;
7294
0
    }
7295
0
    if (cur->type == XML_NAMESPACE_DECL)
7296
0
        return(NULL);
7297
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7298
0
  cur = cur->prev;
7299
0
    while (cur->prev == NULL) {
7300
0
        cur = cur->parent;
7301
0
        if (cur == NULL)
7302
0
            return (NULL);
7303
0
        if (cur == ctxt->context->doc->children)
7304
0
            return (NULL);
7305
0
        if (cur != ctxt->ancestor)
7306
0
            return (cur);
7307
0
        ctxt->ancestor = cur->parent;
7308
0
    }
7309
0
    cur = cur->prev;
7310
0
    while (cur->last != NULL)
7311
0
        cur = cur->last;
7312
0
    return (cur);
7313
0
}
7314
7315
/**
7316
 * xmlXPathNextNamespace:
7317
 * @ctxt:  the XPath Parser context
7318
 * @cur:  the current attribute in the traversal
7319
 *
7320
 * Traversal function for the "namespace" direction
7321
 * the namespace axis contains the namespace nodes of the context node;
7322
 * the order of nodes on this axis is implementation-defined; the axis will
7323
 * be empty unless the context node is an element
7324
 *
7325
 * We keep the XML namespace node at the end of the list.
7326
 *
7327
 * Returns the next element following that axis
7328
 */
7329
xmlNodePtr
7330
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7331
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7332
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7333
0
    if (cur == NULL) {
7334
0
        if (ctxt->context->tmpNsList != NULL)
7335
0
      xmlFree(ctxt->context->tmpNsList);
7336
0
  ctxt->context->tmpNsNr = 0;
7337
0
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7338
0
                             &ctxt->context->tmpNsList) < 0) {
7339
0
            xmlXPathPErrMemory(ctxt);
7340
0
            return(NULL);
7341
0
        }
7342
0
        if (ctxt->context->tmpNsList != NULL) {
7343
0
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7344
0
                ctxt->context->tmpNsNr++;
7345
0
            }
7346
0
        }
7347
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
7348
0
    }
7349
0
    if (ctxt->context->tmpNsNr > 0) {
7350
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7351
0
    } else {
7352
0
  if (ctxt->context->tmpNsList != NULL)
7353
0
      xmlFree(ctxt->context->tmpNsList);
7354
0
  ctxt->context->tmpNsList = NULL;
7355
0
  return(NULL);
7356
0
    }
7357
0
}
7358
7359
/**
7360
 * xmlXPathNextAttribute:
7361
 * @ctxt:  the XPath Parser context
7362
 * @cur:  the current attribute in the traversal
7363
 *
7364
 * Traversal function for the "attribute" direction
7365
 * TODO: support DTD inherited default attributes
7366
 *
7367
 * Returns the next element following that axis
7368
 */
7369
xmlNodePtr
7370
0
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7371
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7372
0
    if (ctxt->context->node == NULL)
7373
0
  return(NULL);
7374
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
7375
0
  return(NULL);
7376
0
    if (cur == NULL) {
7377
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7378
0
      return(NULL);
7379
0
        return((xmlNodePtr)ctxt->context->node->properties);
7380
0
    }
7381
0
    return((xmlNodePtr)cur->next);
7382
0
}
7383
7384
/************************************************************************
7385
 *                  *
7386
 *    NodeTest Functions          *
7387
 *                  *
7388
 ************************************************************************/
7389
7390
#define IS_FUNCTION     200
7391
7392
7393
/************************************************************************
7394
 *                  *
7395
 *    Implicit tree core function library     *
7396
 *                  *
7397
 ************************************************************************/
7398
7399
/**
7400
 * xmlXPathRoot:
7401
 * @ctxt:  the XPath Parser context
7402
 *
7403
 * Initialize the context to the root of the document
7404
 */
7405
void
7406
0
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7407
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
7408
0
  return;
7409
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7410
0
                                            (xmlNodePtr) ctxt->context->doc));
7411
0
}
7412
7413
/************************************************************************
7414
 *                  *
7415
 *    The explicit core function library      *
7416
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7417
 *                  *
7418
 ************************************************************************/
7419
7420
7421
/**
7422
 * xmlXPathLastFunction:
7423
 * @ctxt:  the XPath Parser context
7424
 * @nargs:  the number of arguments
7425
 *
7426
 * Implement the last() XPath function
7427
 *    number last()
7428
 * The last function returns the number of nodes in the context node list.
7429
 */
7430
void
7431
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7432
0
    CHECK_ARITY(0);
7433
0
    if (ctxt->context->contextSize >= 0) {
7434
0
  valuePush(ctxt,
7435
0
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7436
0
    } else {
7437
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7438
0
    }
7439
0
}
7440
7441
/**
7442
 * xmlXPathPositionFunction:
7443
 * @ctxt:  the XPath Parser context
7444
 * @nargs:  the number of arguments
7445
 *
7446
 * Implement the position() XPath function
7447
 *    number position()
7448
 * The position function returns the position of the context node in the
7449
 * context node list. The first position is 1, and so the last position
7450
 * will be equal to last().
7451
 */
7452
void
7453
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7454
0
    CHECK_ARITY(0);
7455
0
    if (ctxt->context->proximityPosition >= 0) {
7456
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7457
0
            (double) ctxt->context->proximityPosition));
7458
0
    } else {
7459
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7460
0
    }
7461
0
}
7462
7463
/**
7464
 * xmlXPathCountFunction:
7465
 * @ctxt:  the XPath Parser context
7466
 * @nargs:  the number of arguments
7467
 *
7468
 * Implement the count() XPath function
7469
 *    number count(node-set)
7470
 */
7471
void
7472
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7473
0
    xmlXPathObjectPtr cur;
7474
7475
0
    CHECK_ARITY(1);
7476
0
    if ((ctxt->value == NULL) ||
7477
0
  ((ctxt->value->type != XPATH_NODESET) &&
7478
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7479
0
  XP_ERROR(XPATH_INVALID_TYPE);
7480
0
    cur = valuePop(ctxt);
7481
7482
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
7483
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7484
0
    else
7485
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7486
0
      (double) cur->nodesetval->nodeNr));
7487
0
    xmlXPathReleaseObject(ctxt->context, cur);
7488
0
}
7489
7490
/**
7491
 * xmlXPathGetElementsByIds:
7492
 * @doc:  the document
7493
 * @ids:  a whitespace separated list of IDs
7494
 *
7495
 * Selects elements by their unique ID.
7496
 *
7497
 * Returns a node-set of selected elements.
7498
 */
7499
static xmlNodeSetPtr
7500
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7501
0
    xmlNodeSetPtr ret;
7502
0
    const xmlChar *cur = ids;
7503
0
    xmlChar *ID;
7504
0
    xmlAttrPtr attr;
7505
0
    xmlNodePtr elem = NULL;
7506
7507
0
    if (ids == NULL) return(NULL);
7508
7509
0
    ret = xmlXPathNodeSetCreate(NULL);
7510
0
    if (ret == NULL)
7511
0
        return(ret);
7512
7513
0
    while (IS_BLANK_CH(*cur)) cur++;
7514
0
    while (*cur != 0) {
7515
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7516
0
      cur++;
7517
7518
0
        ID = xmlStrndup(ids, cur - ids);
7519
0
  if (ID == NULL) {
7520
0
            xmlXPathFreeNodeSet(ret);
7521
0
            return(NULL);
7522
0
        }
7523
        /*
7524
         * We used to check the fact that the value passed
7525
         * was an NCName, but this generated much troubles for
7526
         * me and Aleksey Sanin, people blatantly violated that
7527
         * constraint, like Visa3D spec.
7528
         * if (xmlValidateNCName(ID, 1) == 0)
7529
         */
7530
0
        attr = xmlGetID(doc, ID);
7531
0
        xmlFree(ID);
7532
0
        if (attr != NULL) {
7533
0
            if (attr->type == XML_ATTRIBUTE_NODE)
7534
0
                elem = attr->parent;
7535
0
            else if (attr->type == XML_ELEMENT_NODE)
7536
0
                elem = (xmlNodePtr) attr;
7537
0
            else
7538
0
                elem = NULL;
7539
0
            if (elem != NULL) {
7540
0
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7541
0
                    xmlXPathFreeNodeSet(ret);
7542
0
                    return(NULL);
7543
0
                }
7544
0
            }
7545
0
        }
7546
7547
0
  while (IS_BLANK_CH(*cur)) cur++;
7548
0
  ids = cur;
7549
0
    }
7550
0
    return(ret);
7551
0
}
7552
7553
/**
7554
 * xmlXPathIdFunction:
7555
 * @ctxt:  the XPath Parser context
7556
 * @nargs:  the number of arguments
7557
 *
7558
 * Implement the id() XPath function
7559
 *    node-set id(object)
7560
 * The id function selects elements by their unique ID
7561
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7562
 * then the result is the union of the result of applying id to the
7563
 * string value of each of the nodes in the argument node-set. When the
7564
 * argument to id is of any other type, the argument is converted to a
7565
 * string as if by a call to the string function; the string is split
7566
 * into a whitespace-separated list of tokens (whitespace is any sequence
7567
 * of characters matching the production S); the result is a node-set
7568
 * containing the elements in the same document as the context node that
7569
 * have a unique ID equal to any of the tokens in the list.
7570
 */
7571
void
7572
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7573
0
    xmlChar *tokens;
7574
0
    xmlNodeSetPtr ret;
7575
0
    xmlXPathObjectPtr obj;
7576
7577
0
    CHECK_ARITY(1);
7578
0
    obj = valuePop(ctxt);
7579
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7580
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7581
0
  xmlNodeSetPtr ns;
7582
0
  int i;
7583
7584
0
  ret = xmlXPathNodeSetCreate(NULL);
7585
0
        if (ret == NULL)
7586
0
            xmlXPathPErrMemory(ctxt);
7587
7588
0
  if (obj->nodesetval != NULL) {
7589
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7590
0
    tokens =
7591
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7592
0
                if (tokens == NULL)
7593
0
                    xmlXPathPErrMemory(ctxt);
7594
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7595
0
                if (ns == NULL)
7596
0
                    xmlXPathPErrMemory(ctxt);
7597
0
    ret = xmlXPathNodeSetMerge(ret, ns);
7598
0
                if (ret == NULL)
7599
0
                    xmlXPathPErrMemory(ctxt);
7600
0
    xmlXPathFreeNodeSet(ns);
7601
0
    if (tokens != NULL)
7602
0
        xmlFree(tokens);
7603
0
      }
7604
0
  }
7605
0
  xmlXPathReleaseObject(ctxt->context, obj);
7606
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7607
0
  return;
7608
0
    }
7609
0
    tokens = xmlXPathCastToString(obj);
7610
0
    if (tokens == NULL)
7611
0
        xmlXPathPErrMemory(ctxt);
7612
0
    xmlXPathReleaseObject(ctxt->context, obj);
7613
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7614
0
    if (ret == NULL)
7615
0
        xmlXPathPErrMemory(ctxt);
7616
0
    xmlFree(tokens);
7617
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7618
0
    return;
7619
0
}
7620
7621
/**
7622
 * xmlXPathLocalNameFunction:
7623
 * @ctxt:  the XPath Parser context
7624
 * @nargs:  the number of arguments
7625
 *
7626
 * Implement the local-name() XPath function
7627
 *    string local-name(node-set?)
7628
 * The local-name function returns a string containing the local part
7629
 * of the name of the node in the argument node-set that is first in
7630
 * document order. If the node-set is empty or the first node has no
7631
 * name, an empty string is returned. If the argument is omitted it
7632
 * defaults to the context node.
7633
 */
7634
void
7635
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7636
0
    xmlXPathObjectPtr cur;
7637
7638
0
    if (ctxt == NULL) return;
7639
7640
0
    if (nargs == 0) {
7641
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7642
0
  nargs = 1;
7643
0
    }
7644
7645
0
    CHECK_ARITY(1);
7646
0
    if ((ctxt->value == NULL) ||
7647
0
  ((ctxt->value->type != XPATH_NODESET) &&
7648
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7649
0
  XP_ERROR(XPATH_INVALID_TYPE);
7650
0
    cur = valuePop(ctxt);
7651
7652
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7653
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7654
0
    } else {
7655
0
  int i = 0; /* Should be first in document order !!!!! */
7656
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7657
0
  case XML_ELEMENT_NODE:
7658
0
  case XML_ATTRIBUTE_NODE:
7659
0
  case XML_PI_NODE:
7660
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7661
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7662
0
      else
7663
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7664
0
      cur->nodesetval->nodeTab[i]->name));
7665
0
      break;
7666
0
  case XML_NAMESPACE_DECL:
7667
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7668
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7669
0
      break;
7670
0
  default:
7671
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7672
0
  }
7673
0
    }
7674
0
    xmlXPathReleaseObject(ctxt->context, cur);
7675
0
}
7676
7677
/**
7678
 * xmlXPathNamespaceURIFunction:
7679
 * @ctxt:  the XPath Parser context
7680
 * @nargs:  the number of arguments
7681
 *
7682
 * Implement the namespace-uri() XPath function
7683
 *    string namespace-uri(node-set?)
7684
 * The namespace-uri function returns a string containing the
7685
 * namespace URI of the expanded name of the node in the argument
7686
 * node-set that is first in document order. If the node-set is empty,
7687
 * the first node has no name, or the expanded name has no namespace
7688
 * URI, an empty string is returned. If the argument is omitted it
7689
 * defaults to the context node.
7690
 */
7691
void
7692
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7693
0
    xmlXPathObjectPtr cur;
7694
7695
0
    if (ctxt == NULL) return;
7696
7697
0
    if (nargs == 0) {
7698
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7699
0
  nargs = 1;
7700
0
    }
7701
0
    CHECK_ARITY(1);
7702
0
    if ((ctxt->value == NULL) ||
7703
0
  ((ctxt->value->type != XPATH_NODESET) &&
7704
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7705
0
  XP_ERROR(XPATH_INVALID_TYPE);
7706
0
    cur = valuePop(ctxt);
7707
7708
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7709
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7710
0
    } else {
7711
0
  int i = 0; /* Should be first in document order !!!!! */
7712
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7713
0
  case XML_ELEMENT_NODE:
7714
0
  case XML_ATTRIBUTE_NODE:
7715
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7716
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7717
0
      else
7718
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7719
0
        cur->nodesetval->nodeTab[i]->ns->href));
7720
0
      break;
7721
0
  default:
7722
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7723
0
  }
7724
0
    }
7725
0
    xmlXPathReleaseObject(ctxt->context, cur);
7726
0
}
7727
7728
/**
7729
 * xmlXPathNameFunction:
7730
 * @ctxt:  the XPath Parser context
7731
 * @nargs:  the number of arguments
7732
 *
7733
 * Implement the name() XPath function
7734
 *    string name(node-set?)
7735
 * The name function returns a string containing a QName representing
7736
 * the name of the node in the argument node-set that is first in document
7737
 * order. The QName must represent the name with respect to the namespace
7738
 * declarations in effect on the node whose name is being represented.
7739
 * Typically, this will be the form in which the name occurred in the XML
7740
 * source. This need not be the case if there are namespace declarations
7741
 * in effect on the node that associate multiple prefixes with the same
7742
 * namespace. However, an implementation may include information about
7743
 * the original prefix in its representation of nodes; in this case, an
7744
 * implementation can ensure that the returned string is always the same
7745
 * as the QName used in the XML source. If the argument it omitted it
7746
 * defaults to the context node.
7747
 * Libxml keep the original prefix so the "real qualified name" used is
7748
 * returned.
7749
 */
7750
static void
7751
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7752
0
{
7753
0
    xmlXPathObjectPtr cur;
7754
7755
0
    if (nargs == 0) {
7756
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7757
0
        nargs = 1;
7758
0
    }
7759
7760
0
    CHECK_ARITY(1);
7761
0
    if ((ctxt->value == NULL) ||
7762
0
        ((ctxt->value->type != XPATH_NODESET) &&
7763
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
7764
0
        XP_ERROR(XPATH_INVALID_TYPE);
7765
0
    cur = valuePop(ctxt);
7766
7767
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7768
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7769
0
    } else {
7770
0
        int i = 0;              /* Should be first in document order !!!!! */
7771
7772
0
        switch (cur->nodesetval->nodeTab[i]->type) {
7773
0
            case XML_ELEMENT_NODE:
7774
0
            case XML_ATTRIBUTE_NODE:
7775
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7776
0
        valuePush(ctxt,
7777
0
      xmlXPathCacheNewCString(ctxt, ""));
7778
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7779
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7780
0
        valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7781
0
          cur->nodesetval->nodeTab[i]->name));
7782
0
    } else {
7783
0
        xmlChar *fullname;
7784
7785
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7786
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
7787
0
             NULL, 0);
7788
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7789
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7790
0
        if (fullname == NULL)
7791
0
                        xmlXPathPErrMemory(ctxt);
7792
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7793
0
                }
7794
0
                break;
7795
0
            default:
7796
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7797
0
        cur->nodesetval->nodeTab[i]));
7798
0
                xmlXPathLocalNameFunction(ctxt, 1);
7799
0
        }
7800
0
    }
7801
0
    xmlXPathReleaseObject(ctxt->context, cur);
7802
0
}
7803
7804
7805
/**
7806
 * xmlXPathStringFunction:
7807
 * @ctxt:  the XPath Parser context
7808
 * @nargs:  the number of arguments
7809
 *
7810
 * Implement the string() XPath function
7811
 *    string string(object?)
7812
 * The string function converts an object to a string as follows:
7813
 *    - A node-set is converted to a string by returning the value of
7814
 *      the node in the node-set that is first in document order.
7815
 *      If the node-set is empty, an empty string is returned.
7816
 *    - A number is converted to a string as follows
7817
 *      + NaN is converted to the string NaN
7818
 *      + positive zero is converted to the string 0
7819
 *      + negative zero is converted to the string 0
7820
 *      + positive infinity is converted to the string Infinity
7821
 *      + negative infinity is converted to the string -Infinity
7822
 *      + if the number is an integer, the number is represented in
7823
 *        decimal form as a Number with no decimal point and no leading
7824
 *        zeros, preceded by a minus sign (-) if the number is negative
7825
 *      + otherwise, the number is represented in decimal form as a
7826
 *        Number including a decimal point with at least one digit
7827
 *        before the decimal point and at least one digit after the
7828
 *        decimal point, preceded by a minus sign (-) if the number
7829
 *        is negative; there must be no leading zeros before the decimal
7830
 *        point apart possibly from the one required digit immediately
7831
 *        before the decimal point; beyond the one required digit
7832
 *        after the decimal point there must be as many, but only as
7833
 *        many, more digits as are needed to uniquely distinguish the
7834
 *        number from all other IEEE 754 numeric values.
7835
 *    - The boolean false value is converted to the string false.
7836
 *      The boolean true value is converted to the string true.
7837
 *
7838
 * If the argument is omitted, it defaults to a node-set with the
7839
 * context node as its only member.
7840
 */
7841
void
7842
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7843
0
    xmlXPathObjectPtr cur;
7844
0
    xmlChar *stringval;
7845
7846
0
    if (ctxt == NULL) return;
7847
0
    if (nargs == 0) {
7848
0
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7849
0
        if (stringval == NULL)
7850
0
            xmlXPathPErrMemory(ctxt);
7851
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7852
0
  return;
7853
0
    }
7854
7855
0
    CHECK_ARITY(1);
7856
0
    cur = valuePop(ctxt);
7857
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7858
0
    if (cur->type != XPATH_STRING) {
7859
0
        stringval = xmlXPathCastToString(cur);
7860
0
        if (stringval == NULL)
7861
0
            xmlXPathPErrMemory(ctxt);
7862
0
        xmlXPathReleaseObject(ctxt->context, cur);
7863
0
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7864
0
    }
7865
0
    valuePush(ctxt, cur);
7866
0
}
7867
7868
/**
7869
 * xmlXPathStringLengthFunction:
7870
 * @ctxt:  the XPath Parser context
7871
 * @nargs:  the number of arguments
7872
 *
7873
 * Implement the string-length() XPath function
7874
 *    number string-length(string?)
7875
 * The string-length returns the number of characters in the string
7876
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7877
 * the context node converted to a string, in other words the value
7878
 * of the context node.
7879
 */
7880
void
7881
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7882
0
    xmlXPathObjectPtr cur;
7883
7884
0
    if (nargs == 0) {
7885
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
7886
0
      return;
7887
0
  if (ctxt->context->node == NULL) {
7888
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7889
0
  } else {
7890
0
      xmlChar *content;
7891
7892
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
7893
0
            if (content == NULL)
7894
0
                xmlXPathPErrMemory(ctxt);
7895
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7896
0
    xmlUTF8Strlen(content)));
7897
0
      xmlFree(content);
7898
0
  }
7899
0
  return;
7900
0
    }
7901
0
    CHECK_ARITY(1);
7902
0
    CAST_TO_STRING;
7903
0
    CHECK_TYPE(XPATH_STRING);
7904
0
    cur = valuePop(ctxt);
7905
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7906
0
  xmlUTF8Strlen(cur->stringval)));
7907
0
    xmlXPathReleaseObject(ctxt->context, cur);
7908
0
}
7909
7910
/**
7911
 * xmlXPathConcatFunction:
7912
 * @ctxt:  the XPath Parser context
7913
 * @nargs:  the number of arguments
7914
 *
7915
 * Implement the concat() XPath function
7916
 *    string concat(string, string, string*)
7917
 * The concat function returns the concatenation of its arguments.
7918
 */
7919
void
7920
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7921
0
    xmlXPathObjectPtr cur, newobj;
7922
0
    xmlChar *tmp;
7923
7924
0
    if (ctxt == NULL) return;
7925
0
    if (nargs < 2) {
7926
0
  CHECK_ARITY(2);
7927
0
    }
7928
7929
0
    CAST_TO_STRING;
7930
0
    cur = valuePop(ctxt);
7931
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7932
0
  xmlXPathReleaseObject(ctxt->context, cur);
7933
0
  return;
7934
0
    }
7935
0
    nargs--;
7936
7937
0
    while (nargs > 0) {
7938
0
  CAST_TO_STRING;
7939
0
  newobj = valuePop(ctxt);
7940
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7941
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7942
0
      xmlXPathReleaseObject(ctxt->context, cur);
7943
0
      XP_ERROR(XPATH_INVALID_TYPE);
7944
0
  }
7945
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7946
0
        if (tmp == NULL)
7947
0
            xmlXPathPErrMemory(ctxt);
7948
0
  newobj->stringval = cur->stringval;
7949
0
  cur->stringval = tmp;
7950
0
  xmlXPathReleaseObject(ctxt->context, newobj);
7951
0
  nargs--;
7952
0
    }
7953
0
    valuePush(ctxt, cur);
7954
0
}
7955
7956
/**
7957
 * xmlXPathContainsFunction:
7958
 * @ctxt:  the XPath Parser context
7959
 * @nargs:  the number of arguments
7960
 *
7961
 * Implement the contains() XPath function
7962
 *    boolean contains(string, string)
7963
 * The contains function returns true if the first argument string
7964
 * contains the second argument string, and otherwise returns false.
7965
 */
7966
void
7967
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7968
0
    xmlXPathObjectPtr hay, needle;
7969
7970
0
    CHECK_ARITY(2);
7971
0
    CAST_TO_STRING;
7972
0
    CHECK_TYPE(XPATH_STRING);
7973
0
    needle = valuePop(ctxt);
7974
0
    CAST_TO_STRING;
7975
0
    hay = valuePop(ctxt);
7976
7977
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7978
0
  xmlXPathReleaseObject(ctxt->context, hay);
7979
0
  xmlXPathReleaseObject(ctxt->context, needle);
7980
0
  XP_ERROR(XPATH_INVALID_TYPE);
7981
0
    }
7982
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7983
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7984
0
    else
7985
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7986
0
    xmlXPathReleaseObject(ctxt->context, hay);
7987
0
    xmlXPathReleaseObject(ctxt->context, needle);
7988
0
}
7989
7990
/**
7991
 * xmlXPathStartsWithFunction:
7992
 * @ctxt:  the XPath Parser context
7993
 * @nargs:  the number of arguments
7994
 *
7995
 * Implement the starts-with() XPath function
7996
 *    boolean starts-with(string, string)
7997
 * The starts-with function returns true if the first argument string
7998
 * starts with the second argument string, and otherwise returns false.
7999
 */
8000
void
8001
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8002
0
    xmlXPathObjectPtr hay, needle;
8003
0
    int n;
8004
8005
0
    CHECK_ARITY(2);
8006
0
    CAST_TO_STRING;
8007
0
    CHECK_TYPE(XPATH_STRING);
8008
0
    needle = valuePop(ctxt);
8009
0
    CAST_TO_STRING;
8010
0
    hay = valuePop(ctxt);
8011
8012
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8013
0
  xmlXPathReleaseObject(ctxt->context, hay);
8014
0
  xmlXPathReleaseObject(ctxt->context, needle);
8015
0
  XP_ERROR(XPATH_INVALID_TYPE);
8016
0
    }
8017
0
    n = xmlStrlen(needle->stringval);
8018
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
8019
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8020
0
    else
8021
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8022
0
    xmlXPathReleaseObject(ctxt->context, hay);
8023
0
    xmlXPathReleaseObject(ctxt->context, needle);
8024
0
}
8025
8026
/**
8027
 * xmlXPathSubstringFunction:
8028
 * @ctxt:  the XPath Parser context
8029
 * @nargs:  the number of arguments
8030
 *
8031
 * Implement the substring() XPath function
8032
 *    string substring(string, number, number?)
8033
 * The substring function returns the substring of the first argument
8034
 * starting at the position specified in the second argument with
8035
 * length specified in the third argument. For example,
8036
 * substring("12345",2,3) returns "234". If the third argument is not
8037
 * specified, it returns the substring starting at the position specified
8038
 * in the second argument and continuing to the end of the string. For
8039
 * example, substring("12345",2) returns "2345".  More precisely, each
8040
 * character in the string (see [3.6 Strings]) is considered to have a
8041
 * numeric position: the position of the first character is 1, the position
8042
 * of the second character is 2 and so on. The returned substring contains
8043
 * those characters for which the position of the character is greater than
8044
 * or equal to the second argument and, if the third argument is specified,
8045
 * less than the sum of the second and third arguments; the comparisons
8046
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8047
 *  - substring("12345", 1.5, 2.6) returns "234"
8048
 *  - substring("12345", 0, 3) returns "12"
8049
 *  - substring("12345", 0 div 0, 3) returns ""
8050
 *  - substring("12345", 1, 0 div 0) returns ""
8051
 *  - substring("12345", -42, 1 div 0) returns "12345"
8052
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
8053
 */
8054
void
8055
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8056
0
    xmlXPathObjectPtr str, start, len;
8057
0
    double le=0, in;
8058
0
    int i = 1, j = INT_MAX;
8059
8060
0
    if (nargs < 2) {
8061
0
  CHECK_ARITY(2);
8062
0
    }
8063
0
    if (nargs > 3) {
8064
0
  CHECK_ARITY(3);
8065
0
    }
8066
    /*
8067
     * take care of possible last (position) argument
8068
    */
8069
0
    if (nargs == 3) {
8070
0
  CAST_TO_NUMBER;
8071
0
  CHECK_TYPE(XPATH_NUMBER);
8072
0
  len = valuePop(ctxt);
8073
0
  le = len->floatval;
8074
0
  xmlXPathReleaseObject(ctxt->context, len);
8075
0
    }
8076
8077
0
    CAST_TO_NUMBER;
8078
0
    CHECK_TYPE(XPATH_NUMBER);
8079
0
    start = valuePop(ctxt);
8080
0
    in = start->floatval;
8081
0
    xmlXPathReleaseObject(ctxt->context, start);
8082
0
    CAST_TO_STRING;
8083
0
    CHECK_TYPE(XPATH_STRING);
8084
0
    str = valuePop(ctxt);
8085
8086
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8087
0
        i = INT_MAX;
8088
0
    } else if (in >= 1.0) {
8089
0
        i = (int)in;
8090
0
        if (in - floor(in) >= 0.5)
8091
0
            i += 1;
8092
0
    }
8093
8094
0
    if (nargs == 3) {
8095
0
        double rin, rle, end;
8096
8097
0
        rin = floor(in);
8098
0
        if (in - rin >= 0.5)
8099
0
            rin += 1.0;
8100
8101
0
        rle = floor(le);
8102
0
        if (le - rle >= 0.5)
8103
0
            rle += 1.0;
8104
8105
0
        end = rin + rle;
8106
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8107
0
            j = 1;
8108
0
        } else if (end < INT_MAX) {
8109
0
            j = (int)end;
8110
0
        }
8111
0
    }
8112
8113
0
    i -= 1;
8114
0
    j -= 1;
8115
8116
0
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
8117
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
8118
0
        if (ret == NULL)
8119
0
            xmlXPathPErrMemory(ctxt);
8120
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
8121
0
  xmlFree(ret);
8122
0
    } else {
8123
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
8124
0
    }
8125
8126
0
    xmlXPathReleaseObject(ctxt->context, str);
8127
0
}
8128
8129
/**
8130
 * xmlXPathSubstringBeforeFunction:
8131
 * @ctxt:  the XPath Parser context
8132
 * @nargs:  the number of arguments
8133
 *
8134
 * Implement the substring-before() XPath function
8135
 *    string substring-before(string, string)
8136
 * The substring-before function returns the substring of the first
8137
 * argument string that precedes the first occurrence of the second
8138
 * argument string in the first argument string, or the empty string
8139
 * if the first argument string does not contain the second argument
8140
 * string. For example, substring-before("1999/04/01","/") returns 1999.
8141
 */
8142
void
8143
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8144
0
    xmlXPathObjectPtr str = NULL;
8145
0
    xmlXPathObjectPtr find = NULL;
8146
0
    const xmlChar *point;
8147
0
    xmlChar *result;
8148
8149
0
    CHECK_ARITY(2);
8150
0
    CAST_TO_STRING;
8151
0
    find = valuePop(ctxt);
8152
0
    CAST_TO_STRING;
8153
0
    str = valuePop(ctxt);
8154
0
    if (ctxt->error != 0)
8155
0
        goto error;
8156
8157
0
    point = xmlStrstr(str->stringval, find->stringval);
8158
0
    if (point == NULL) {
8159
0
        result = xmlStrdup(BAD_CAST "");
8160
0
    } else {
8161
0
        result = xmlStrndup(str->stringval, point - str->stringval);
8162
0
    }
8163
0
    if (result == NULL) {
8164
0
        xmlXPathPErrMemory(ctxt);
8165
0
        goto error;
8166
0
    }
8167
0
    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8168
8169
0
error:
8170
0
    xmlXPathReleaseObject(ctxt->context, str);
8171
0
    xmlXPathReleaseObject(ctxt->context, find);
8172
0
}
8173
8174
/**
8175
 * xmlXPathSubstringAfterFunction:
8176
 * @ctxt:  the XPath Parser context
8177
 * @nargs:  the number of arguments
8178
 *
8179
 * Implement the substring-after() XPath function
8180
 *    string substring-after(string, string)
8181
 * The substring-after function returns the substring of the first
8182
 * argument string that follows the first occurrence of the second
8183
 * argument string in the first argument string, or the empty string
8184
 * if the first argument string does not contain the second argument
8185
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8186
 * and substring-after("1999/04/01","19") returns 99/04/01.
8187
 */
8188
void
8189
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8190
0
    xmlXPathObjectPtr str = NULL;
8191
0
    xmlXPathObjectPtr find = NULL;
8192
0
    const xmlChar *point;
8193
0
    xmlChar *result;
8194
8195
0
    CHECK_ARITY(2);
8196
0
    CAST_TO_STRING;
8197
0
    find = valuePop(ctxt);
8198
0
    CAST_TO_STRING;
8199
0
    str = valuePop(ctxt);
8200
0
    if (ctxt->error != 0)
8201
0
        goto error;
8202
8203
0
    point = xmlStrstr(str->stringval, find->stringval);
8204
0
    if (point == NULL) {
8205
0
        result = xmlStrdup(BAD_CAST "");
8206
0
    } else {
8207
0
        result = xmlStrdup(point + xmlStrlen(find->stringval));
8208
0
    }
8209
0
    if (result == NULL) {
8210
0
        xmlXPathPErrMemory(ctxt);
8211
0
        goto error;
8212
0
    }
8213
0
    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8214
8215
0
error:
8216
0
    xmlXPathReleaseObject(ctxt->context, str);
8217
0
    xmlXPathReleaseObject(ctxt->context, find);
8218
0
}
8219
8220
/**
8221
 * xmlXPathNormalizeFunction:
8222
 * @ctxt:  the XPath Parser context
8223
 * @nargs:  the number of arguments
8224
 *
8225
 * Implement the normalize-space() XPath function
8226
 *    string normalize-space(string?)
8227
 * The normalize-space function returns the argument string with white
8228
 * space normalized by stripping leading and trailing whitespace
8229
 * and replacing sequences of whitespace characters by a single
8230
 * space. Whitespace characters are the same allowed by the S production
8231
 * in XML. If the argument is omitted, it defaults to the context
8232
 * node converted to a string, in other words the value of the context node.
8233
 */
8234
void
8235
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8236
0
    xmlChar *source, *target;
8237
0
    int blank;
8238
8239
0
    if (ctxt == NULL) return;
8240
0
    if (nargs == 0) {
8241
        /* Use current context node */
8242
0
        source = xmlXPathCastNodeToString(ctxt->context->node);
8243
0
        if (source == NULL)
8244
0
            xmlXPathPErrMemory(ctxt);
8245
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
8246
0
        nargs = 1;
8247
0
    }
8248
8249
0
    CHECK_ARITY(1);
8250
0
    CAST_TO_STRING;
8251
0
    CHECK_TYPE(XPATH_STRING);
8252
0
    source = ctxt->value->stringval;
8253
0
    if (source == NULL)
8254
0
        return;
8255
0
    target = source;
8256
8257
    /* Skip leading whitespaces */
8258
0
    while (IS_BLANK_CH(*source))
8259
0
        source++;
8260
8261
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8262
0
    blank = 0;
8263
0
    while (*source) {
8264
0
        if (IS_BLANK_CH(*source)) {
8265
0
      blank = 1;
8266
0
        } else {
8267
0
            if (blank) {
8268
0
                *target++ = 0x20;
8269
0
                blank = 0;
8270
0
            }
8271
0
            *target++ = *source;
8272
0
        }
8273
0
        source++;
8274
0
    }
8275
0
    *target = 0;
8276
0
}
8277
8278
/**
8279
 * xmlXPathTranslateFunction:
8280
 * @ctxt:  the XPath Parser context
8281
 * @nargs:  the number of arguments
8282
 *
8283
 * Implement the translate() XPath function
8284
 *    string translate(string, string, string)
8285
 * The translate function returns the first argument string with
8286
 * occurrences of characters in the second argument string replaced
8287
 * by the character at the corresponding position in the third argument
8288
 * string. For example, translate("bar","abc","ABC") returns the string
8289
 * BAr. If there is a character in the second argument string with no
8290
 * character at a corresponding position in the third argument string
8291
 * (because the second argument string is longer than the third argument
8292
 * string), then occurrences of that character in the first argument
8293
 * string are removed. For example, translate("--aaa--","abc-","ABC")
8294
 * returns "AAA". If a character occurs more than once in second
8295
 * argument string, then the first occurrence determines the replacement
8296
 * character. If the third argument string is longer than the second
8297
 * argument string, then excess characters are ignored.
8298
 */
8299
void
8300
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8301
0
    xmlXPathObjectPtr str = NULL;
8302
0
    xmlXPathObjectPtr from = NULL;
8303
0
    xmlXPathObjectPtr to = NULL;
8304
0
    xmlBufPtr target;
8305
0
    int offset, max;
8306
0
    int ch;
8307
0
    const xmlChar *point;
8308
0
    xmlChar *cptr;
8309
8310
0
    CHECK_ARITY(3);
8311
8312
0
    CAST_TO_STRING;
8313
0
    to = valuePop(ctxt);
8314
0
    CAST_TO_STRING;
8315
0
    from = valuePop(ctxt);
8316
0
    CAST_TO_STRING;
8317
0
    str = valuePop(ctxt);
8318
0
    if (ctxt->error != 0)
8319
0
        goto error;
8320
8321
0
    target = xmlBufCreate();
8322
0
    if (target == NULL) {
8323
0
        xmlXPathPErrMemory(ctxt);
8324
0
        goto error;
8325
0
    }
8326
8327
0
    max = xmlUTF8Strlen(to->stringval);
8328
0
    for (cptr = str->stringval; (ch=*cptr); ) {
8329
0
        offset = xmlUTF8Strloc(from->stringval, cptr);
8330
0
        if (offset >= 0) {
8331
0
            if (offset < max) {
8332
0
                point = xmlUTF8Strpos(to->stringval, offset);
8333
0
                if (point)
8334
0
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8335
0
            }
8336
0
        } else
8337
0
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8338
8339
        /* Step to next character in input */
8340
0
        cptr++;
8341
0
        if ( ch & 0x80 ) {
8342
            /* if not simple ascii, verify proper format */
8343
0
            if ( (ch & 0xc0) != 0xc0 ) {
8344
0
                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8345
0
                break;
8346
0
            }
8347
            /* then skip over remaining bytes for this char */
8348
0
            while ( (ch <<= 1) & 0x80 )
8349
0
                if ( (*cptr++ & 0xc0) != 0x80 ) {
8350
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8351
0
                    break;
8352
0
                }
8353
0
            if (ch & 0x80) /* must have had error encountered */
8354
0
                break;
8355
0
        }
8356
0
    }
8357
8358
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
8359
0
    xmlBufFree(target);
8360
0
error:
8361
0
    xmlXPathReleaseObject(ctxt->context, str);
8362
0
    xmlXPathReleaseObject(ctxt->context, from);
8363
0
    xmlXPathReleaseObject(ctxt->context, to);
8364
0
}
8365
8366
/**
8367
 * xmlXPathBooleanFunction:
8368
 * @ctxt:  the XPath Parser context
8369
 * @nargs:  the number of arguments
8370
 *
8371
 * Implement the boolean() XPath function
8372
 *    boolean boolean(object)
8373
 * The boolean function converts its argument to a boolean as follows:
8374
 *    - a number is true if and only if it is neither positive or
8375
 *      negative zero nor NaN
8376
 *    - a node-set is true if and only if it is non-empty
8377
 *    - a string is true if and only if its length is non-zero
8378
 */
8379
void
8380
0
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8381
0
    xmlXPathObjectPtr cur;
8382
8383
0
    CHECK_ARITY(1);
8384
0
    cur = valuePop(ctxt);
8385
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8386
0
    if (cur->type != XPATH_BOOLEAN) {
8387
0
        int boolval = xmlXPathCastToBoolean(cur);
8388
8389
0
        xmlXPathReleaseObject(ctxt->context, cur);
8390
0
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8391
0
    }
8392
0
    valuePush(ctxt, cur);
8393
0
}
8394
8395
/**
8396
 * xmlXPathNotFunction:
8397
 * @ctxt:  the XPath Parser context
8398
 * @nargs:  the number of arguments
8399
 *
8400
 * Implement the not() XPath function
8401
 *    boolean not(boolean)
8402
 * The not function returns true if its argument is false,
8403
 * and false otherwise.
8404
 */
8405
void
8406
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8407
0
    CHECK_ARITY(1);
8408
0
    CAST_TO_BOOLEAN;
8409
0
    CHECK_TYPE(XPATH_BOOLEAN);
8410
0
    ctxt->value->boolval = ! ctxt->value->boolval;
8411
0
}
8412
8413
/**
8414
 * xmlXPathTrueFunction:
8415
 * @ctxt:  the XPath Parser context
8416
 * @nargs:  the number of arguments
8417
 *
8418
 * Implement the true() XPath function
8419
 *    boolean true()
8420
 */
8421
void
8422
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8423
0
    CHECK_ARITY(0);
8424
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8425
0
}
8426
8427
/**
8428
 * xmlXPathFalseFunction:
8429
 * @ctxt:  the XPath Parser context
8430
 * @nargs:  the number of arguments
8431
 *
8432
 * Implement the false() XPath function
8433
 *    boolean false()
8434
 */
8435
void
8436
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8437
0
    CHECK_ARITY(0);
8438
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8439
0
}
8440
8441
/**
8442
 * xmlXPathLangFunction:
8443
 * @ctxt:  the XPath Parser context
8444
 * @nargs:  the number of arguments
8445
 *
8446
 * Implement the lang() XPath function
8447
 *    boolean lang(string)
8448
 * The lang function returns true or false depending on whether the
8449
 * language of the context node as specified by xml:lang attributes
8450
 * is the same as or is a sublanguage of the language specified by
8451
 * the argument string. The language of the context node is determined
8452
 * by the value of the xml:lang attribute on the context node, or, if
8453
 * the context node has no xml:lang attribute, by the value of the
8454
 * xml:lang attribute on the nearest ancestor of the context node that
8455
 * has an xml:lang attribute. If there is no such attribute, then lang
8456
 * returns false. If there is such an attribute, then lang returns
8457
 * true if the attribute value is equal to the argument ignoring case,
8458
 * or if there is some suffix starting with - such that the attribute
8459
 * value is equal to the argument ignoring that suffix of the attribute
8460
 * value and ignoring case.
8461
 */
8462
void
8463
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8464
0
    xmlXPathObjectPtr val;
8465
0
    xmlNodePtr cur;
8466
0
    xmlChar *theLang;
8467
0
    const xmlChar *lang;
8468
0
    int ret = 0;
8469
0
    int i;
8470
8471
0
    CHECK_ARITY(1);
8472
0
    CAST_TO_STRING;
8473
0
    CHECK_TYPE(XPATH_STRING);
8474
0
    val = valuePop(ctxt);
8475
0
    lang = val->stringval;
8476
0
    cur = ctxt->context->node;
8477
0
    while (cur != NULL) {
8478
0
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8479
0
                                &theLang) < 0)
8480
0
            xmlXPathPErrMemory(ctxt);
8481
0
        if (theLang != NULL)
8482
0
            break;
8483
0
        cur = cur->parent;
8484
0
    }
8485
0
    if ((theLang != NULL) && (lang != NULL)) {
8486
0
        for (i = 0;lang[i] != 0;i++)
8487
0
            if (toupper(lang[i]) != toupper(theLang[i]))
8488
0
                goto not_equal;
8489
0
        if ((theLang[i] == 0) || (theLang[i] == '-'))
8490
0
            ret = 1;
8491
0
    }
8492
0
not_equal:
8493
0
    if (theLang != NULL)
8494
0
  xmlFree((void *)theLang);
8495
8496
0
    xmlXPathReleaseObject(ctxt->context, val);
8497
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8498
0
}
8499
8500
/**
8501
 * xmlXPathNumberFunction:
8502
 * @ctxt:  the XPath Parser context
8503
 * @nargs:  the number of arguments
8504
 *
8505
 * Implement the number() XPath function
8506
 *    number number(object?)
8507
 */
8508
void
8509
0
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8510
0
    xmlXPathObjectPtr cur;
8511
0
    double res;
8512
8513
0
    if (ctxt == NULL) return;
8514
0
    if (nargs == 0) {
8515
0
  if (ctxt->context->node == NULL) {
8516
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8517
0
  } else {
8518
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8519
0
            if (content == NULL)
8520
0
                xmlXPathPErrMemory(ctxt);
8521
8522
0
      res = xmlXPathStringEvalNumber(content);
8523
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8524
0
      xmlFree(content);
8525
0
  }
8526
0
  return;
8527
0
    }
8528
8529
0
    CHECK_ARITY(1);
8530
0
    cur = valuePop(ctxt);
8531
0
    if (cur->type != XPATH_NUMBER) {
8532
0
        double floatval;
8533
8534
0
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8535
0
        xmlXPathReleaseObject(ctxt->context, cur);
8536
0
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8537
0
    }
8538
0
    valuePush(ctxt, cur);
8539
0
}
8540
8541
/**
8542
 * xmlXPathSumFunction:
8543
 * @ctxt:  the XPath Parser context
8544
 * @nargs:  the number of arguments
8545
 *
8546
 * Implement the sum() XPath function
8547
 *    number sum(node-set)
8548
 * The sum function returns the sum of the values of the nodes in
8549
 * the argument node-set.
8550
 */
8551
void
8552
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8553
0
    xmlXPathObjectPtr cur;
8554
0
    int i;
8555
0
    double res = 0.0;
8556
8557
0
    CHECK_ARITY(1);
8558
0
    if ((ctxt->value == NULL) ||
8559
0
  ((ctxt->value->type != XPATH_NODESET) &&
8560
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8561
0
  XP_ERROR(XPATH_INVALID_TYPE);
8562
0
    cur = valuePop(ctxt);
8563
8564
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8565
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8566
0
      res += xmlXPathNodeToNumberInternal(ctxt,
8567
0
                                                cur->nodesetval->nodeTab[i]);
8568
0
  }
8569
0
    }
8570
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8571
0
    xmlXPathReleaseObject(ctxt->context, cur);
8572
0
}
8573
8574
/**
8575
 * xmlXPathFloorFunction:
8576
 * @ctxt:  the XPath Parser context
8577
 * @nargs:  the number of arguments
8578
 *
8579
 * Implement the floor() XPath function
8580
 *    number floor(number)
8581
 * The floor function returns the largest (closest to positive infinity)
8582
 * number that is not greater than the argument and that is an integer.
8583
 */
8584
void
8585
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8586
0
    CHECK_ARITY(1);
8587
0
    CAST_TO_NUMBER;
8588
0
    CHECK_TYPE(XPATH_NUMBER);
8589
8590
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
8591
0
}
8592
8593
/**
8594
 * xmlXPathCeilingFunction:
8595
 * @ctxt:  the XPath Parser context
8596
 * @nargs:  the number of arguments
8597
 *
8598
 * Implement the ceiling() XPath function
8599
 *    number ceiling(number)
8600
 * The ceiling function returns the smallest (closest to negative infinity)
8601
 * number that is not less than the argument and that is an integer.
8602
 */
8603
void
8604
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8605
0
    CHECK_ARITY(1);
8606
0
    CAST_TO_NUMBER;
8607
0
    CHECK_TYPE(XPATH_NUMBER);
8608
8609
#ifdef _AIX
8610
    /* Work around buggy ceil() function on AIX */
8611
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8612
#else
8613
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8614
0
#endif
8615
0
}
8616
8617
/**
8618
 * xmlXPathRoundFunction:
8619
 * @ctxt:  the XPath Parser context
8620
 * @nargs:  the number of arguments
8621
 *
8622
 * Implement the round() XPath function
8623
 *    number round(number)
8624
 * The round function returns the number that is closest to the
8625
 * argument and that is an integer. If there are two such numbers,
8626
 * then the one that is closest to positive infinity is returned.
8627
 */
8628
void
8629
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8630
0
    double f;
8631
8632
0
    CHECK_ARITY(1);
8633
0
    CAST_TO_NUMBER;
8634
0
    CHECK_TYPE(XPATH_NUMBER);
8635
8636
0
    f = ctxt->value->floatval;
8637
8638
0
    if ((f >= -0.5) && (f < 0.5)) {
8639
        /* Handles negative zero. */
8640
0
        ctxt->value->floatval *= 0.0;
8641
0
    }
8642
0
    else {
8643
0
        double rounded = floor(f);
8644
0
        if (f - rounded >= 0.5)
8645
0
            rounded += 1.0;
8646
0
        ctxt->value->floatval = rounded;
8647
0
    }
8648
0
}
8649
8650
/************************************************************************
8651
 *                  *
8652
 *      The Parser          *
8653
 *                  *
8654
 ************************************************************************/
8655
8656
/*
8657
 * a few forward declarations since we use a recursive call based
8658
 * implementation.
8659
 */
8660
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8661
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8662
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8663
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8664
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8665
                                    int qualified);
8666
8667
/**
8668
 * xmlXPathCurrentChar:
8669
 * @ctxt:  the XPath parser context
8670
 * @cur:  pointer to the beginning of the char
8671
 * @len:  pointer to the length of the char read
8672
 *
8673
 * The current char value, if using UTF-8 this may actually span multiple
8674
 * bytes in the input buffer.
8675
 *
8676
 * Returns the current char value and its length
8677
 */
8678
8679
static int
8680
0
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8681
0
    unsigned char c;
8682
0
    unsigned int val;
8683
0
    const xmlChar *cur;
8684
8685
0
    if (ctxt == NULL)
8686
0
  return(0);
8687
0
    cur = ctxt->cur;
8688
8689
    /*
8690
     * We are supposed to handle UTF8, check it's valid
8691
     * From rfc2044: encoding of the Unicode values on UTF-8:
8692
     *
8693
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
8694
     * 0000 0000-0000 007F   0xxxxxxx
8695
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
8696
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
8697
     *
8698
     * Check for the 0x110000 limit too
8699
     */
8700
0
    c = *cur;
8701
0
    if (c & 0x80) {
8702
0
  if ((cur[1] & 0xc0) != 0x80)
8703
0
      goto encoding_error;
8704
0
  if ((c & 0xe0) == 0xe0) {
8705
8706
0
      if ((cur[2] & 0xc0) != 0x80)
8707
0
    goto encoding_error;
8708
0
      if ((c & 0xf0) == 0xf0) {
8709
0
    if (((c & 0xf8) != 0xf0) ||
8710
0
        ((cur[3] & 0xc0) != 0x80))
8711
0
        goto encoding_error;
8712
    /* 4-byte code */
8713
0
    *len = 4;
8714
0
    val = (cur[0] & 0x7) << 18;
8715
0
    val |= (cur[1] & 0x3f) << 12;
8716
0
    val |= (cur[2] & 0x3f) << 6;
8717
0
    val |= cur[3] & 0x3f;
8718
0
      } else {
8719
        /* 3-byte code */
8720
0
    *len = 3;
8721
0
    val = (cur[0] & 0xf) << 12;
8722
0
    val |= (cur[1] & 0x3f) << 6;
8723
0
    val |= cur[2] & 0x3f;
8724
0
      }
8725
0
  } else {
8726
    /* 2-byte code */
8727
0
      *len = 2;
8728
0
      val = (cur[0] & 0x1f) << 6;
8729
0
      val |= cur[1] & 0x3f;
8730
0
  }
8731
0
  if (!IS_CHAR(val)) {
8732
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8733
0
  }
8734
0
  return(val);
8735
0
    } else {
8736
  /* 1-byte code */
8737
0
  *len = 1;
8738
0
  return(*cur);
8739
0
    }
8740
0
encoding_error:
8741
    /*
8742
     * If we detect an UTF8 error that probably means that the
8743
     * input encoding didn't get properly advertised in the
8744
     * declaration header. Report the error and switch the encoding
8745
     * to ISO-Latin-1 (if you don't like this policy, just declare the
8746
     * encoding !)
8747
     */
8748
0
    *len = 0;
8749
0
    XP_ERROR0(XPATH_ENCODING_ERROR);
8750
0
}
8751
8752
/**
8753
 * xmlXPathParseNCName:
8754
 * @ctxt:  the XPath Parser context
8755
 *
8756
 * parse an XML namespace non qualified name.
8757
 *
8758
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8759
 *
8760
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8761
 *                       CombiningChar | Extender
8762
 *
8763
 * Returns the namespace name or NULL
8764
 */
8765
8766
xmlChar *
8767
0
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8768
0
    const xmlChar *in;
8769
0
    xmlChar *ret;
8770
0
    int count = 0;
8771
8772
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8773
    /*
8774
     * Accelerator for simple ASCII names
8775
     */
8776
0
    in = ctxt->cur;
8777
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
8778
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
8779
0
  (*in == '_')) {
8780
0
  in++;
8781
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
8782
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
8783
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
8784
0
         (*in == '_') || (*in == '.') ||
8785
0
         (*in == '-'))
8786
0
      in++;
8787
0
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8788
0
            (*in == '[') || (*in == ']') || (*in == ':') ||
8789
0
            (*in == '@') || (*in == '*')) {
8790
0
      count = in - ctxt->cur;
8791
0
      if (count == 0)
8792
0
    return(NULL);
8793
0
      ret = xmlStrndup(ctxt->cur, count);
8794
0
            if (ret == NULL)
8795
0
                xmlXPathPErrMemory(ctxt);
8796
0
      ctxt->cur = in;
8797
0
      return(ret);
8798
0
  }
8799
0
    }
8800
0
    return(xmlXPathParseNameComplex(ctxt, 0));
8801
0
}
8802
8803
8804
/**
8805
 * xmlXPathParseQName:
8806
 * @ctxt:  the XPath Parser context
8807
 * @prefix:  a xmlChar **
8808
 *
8809
 * parse an XML qualified name
8810
 *
8811
 * [NS 5] QName ::= (Prefix ':')? LocalPart
8812
 *
8813
 * [NS 6] Prefix ::= NCName
8814
 *
8815
 * [NS 7] LocalPart ::= NCName
8816
 *
8817
 * Returns the function returns the local part, and prefix is updated
8818
 *   to get the Prefix if any.
8819
 */
8820
8821
static xmlChar *
8822
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8823
0
    xmlChar *ret = NULL;
8824
8825
0
    *prefix = NULL;
8826
0
    ret = xmlXPathParseNCName(ctxt);
8827
0
    if (ret && CUR == ':') {
8828
0
        *prefix = ret;
8829
0
  NEXT;
8830
0
  ret = xmlXPathParseNCName(ctxt);
8831
0
    }
8832
0
    return(ret);
8833
0
}
8834
8835
/**
8836
 * xmlXPathParseName:
8837
 * @ctxt:  the XPath Parser context
8838
 *
8839
 * parse an XML name
8840
 *
8841
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8842
 *                  CombiningChar | Extender
8843
 *
8844
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8845
 *
8846
 * Returns the namespace name or NULL
8847
 */
8848
8849
xmlChar *
8850
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8851
0
    const xmlChar *in;
8852
0
    xmlChar *ret;
8853
0
    size_t count = 0;
8854
8855
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8856
    /*
8857
     * Accelerator for simple ASCII names
8858
     */
8859
0
    in = ctxt->cur;
8860
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
8861
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
8862
0
  (*in == '_') || (*in == ':')) {
8863
0
  in++;
8864
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
8865
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
8866
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
8867
0
         (*in == '_') || (*in == '-') ||
8868
0
         (*in == ':') || (*in == '.'))
8869
0
      in++;
8870
0
  if ((*in > 0) && (*in < 0x80)) {
8871
0
      count = in - ctxt->cur;
8872
0
            if (count > XML_MAX_NAME_LENGTH) {
8873
0
                ctxt->cur = in;
8874
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
8875
0
            }
8876
0
      ret = xmlStrndup(ctxt->cur, count);
8877
0
            if (ret == NULL)
8878
0
                xmlXPathPErrMemory(ctxt);
8879
0
      ctxt->cur = in;
8880
0
      return(ret);
8881
0
  }
8882
0
    }
8883
0
    return(xmlXPathParseNameComplex(ctxt, 1));
8884
0
}
8885
8886
static xmlChar *
8887
0
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8888
0
    xmlChar *ret;
8889
0
    xmlChar buf[XML_MAX_NAMELEN + 5];
8890
0
    int len = 0, l;
8891
0
    int c;
8892
8893
    /*
8894
     * Handler for more complex cases
8895
     */
8896
0
    c = CUR_CHAR(l);
8897
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8898
0
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8899
0
        (c == '*') || /* accelerators */
8900
0
  (!IS_LETTER(c) && (c != '_') &&
8901
0
         ((!qualified) || (c != ':')))) {
8902
0
  return(NULL);
8903
0
    }
8904
8905
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8906
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8907
0
            (c == '.') || (c == '-') ||
8908
0
      (c == '_') || ((qualified) && (c == ':')) ||
8909
0
      (IS_COMBINING(c)) ||
8910
0
      (IS_EXTENDER(c)))) {
8911
0
  COPY_BUF(l,buf,len,c);
8912
0
  NEXTL(l);
8913
0
  c = CUR_CHAR(l);
8914
0
  if (len >= XML_MAX_NAMELEN) {
8915
      /*
8916
       * Okay someone managed to make a huge name, so he's ready to pay
8917
       * for the processing speed.
8918
       */
8919
0
      xmlChar *buffer;
8920
0
      int max = len * 2;
8921
8922
0
            if (len > XML_MAX_NAME_LENGTH) {
8923
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
8924
0
            }
8925
0
      buffer = (xmlChar *) xmlMallocAtomic(max);
8926
0
      if (buffer == NULL) {
8927
0
                xmlXPathPErrMemory(ctxt);
8928
0
                return(NULL);
8929
0
      }
8930
0
      memcpy(buffer, buf, len);
8931
0
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8932
0
       (c == '.') || (c == '-') ||
8933
0
       (c == '_') || ((qualified) && (c == ':')) ||
8934
0
       (IS_COMBINING(c)) ||
8935
0
       (IS_EXTENDER(c))) {
8936
0
    if (len + 10 > max) {
8937
0
                    xmlChar *tmp;
8938
0
                    if (max > XML_MAX_NAME_LENGTH) {
8939
0
                        xmlFree(buffer);
8940
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
8941
0
                    }
8942
0
        max *= 2;
8943
0
        tmp = (xmlChar *) xmlRealloc(buffer, max);
8944
0
        if (tmp == NULL) {
8945
0
                        xmlFree(buffer);
8946
0
                        xmlXPathPErrMemory(ctxt);
8947
0
                        return(NULL);
8948
0
        }
8949
0
                    buffer = tmp;
8950
0
    }
8951
0
    COPY_BUF(l,buffer,len,c);
8952
0
    NEXTL(l);
8953
0
    c = CUR_CHAR(l);
8954
0
      }
8955
0
      buffer[len] = 0;
8956
0
      return(buffer);
8957
0
  }
8958
0
    }
8959
0
    if (len == 0)
8960
0
  return(NULL);
8961
0
    ret = xmlStrndup(buf, len);
8962
0
    if (ret == NULL)
8963
0
        xmlXPathPErrMemory(ctxt);
8964
0
    return(ret);
8965
0
}
8966
8967
0
#define MAX_FRAC 20
8968
8969
/**
8970
 * xmlXPathStringEvalNumber:
8971
 * @str:  A string to scan
8972
 *
8973
 *  [30a]  Float  ::= Number ('e' Digits?)?
8974
 *
8975
 *  [30]   Number ::=   Digits ('.' Digits?)?
8976
 *                    | '.' Digits
8977
 *  [31]   Digits ::=   [0-9]+
8978
 *
8979
 * Compile a Number in the string
8980
 * In complement of the Number expression, this function also handles
8981
 * negative values : '-' Number.
8982
 *
8983
 * Returns the double value.
8984
 */
8985
double
8986
0
xmlXPathStringEvalNumber(const xmlChar *str) {
8987
0
    const xmlChar *cur = str;
8988
0
    double ret;
8989
0
    int ok = 0;
8990
0
    int isneg = 0;
8991
0
    int exponent = 0;
8992
0
    int is_exponent_negative = 0;
8993
0
#ifdef __GNUC__
8994
0
    unsigned long tmp = 0;
8995
0
    double temp;
8996
0
#endif
8997
0
    if (cur == NULL) return(0);
8998
0
    while (IS_BLANK_CH(*cur)) cur++;
8999
0
    if (*cur == '-') {
9000
0
  isneg = 1;
9001
0
  cur++;
9002
0
    }
9003
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9004
0
        return(xmlXPathNAN);
9005
0
    }
9006
9007
0
#ifdef __GNUC__
9008
    /*
9009
     * tmp/temp is a workaround against a gcc compiler bug
9010
     * http://veillard.com/gcc.bug
9011
     */
9012
0
    ret = 0;
9013
0
    while ((*cur >= '0') && (*cur <= '9')) {
9014
0
  ret = ret * 10;
9015
0
  tmp = (*cur - '0');
9016
0
  ok = 1;
9017
0
  cur++;
9018
0
  temp = (double) tmp;
9019
0
  ret = ret + temp;
9020
0
    }
9021
#else
9022
    ret = 0;
9023
    while ((*cur >= '0') && (*cur <= '9')) {
9024
  ret = ret * 10 + (*cur - '0');
9025
  ok = 1;
9026
  cur++;
9027
    }
9028
#endif
9029
9030
0
    if (*cur == '.') {
9031
0
  int v, frac = 0, max;
9032
0
  double fraction = 0;
9033
9034
0
        cur++;
9035
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9036
0
      return(xmlXPathNAN);
9037
0
  }
9038
0
        while (*cur == '0') {
9039
0
      frac = frac + 1;
9040
0
      cur++;
9041
0
        }
9042
0
        max = frac + MAX_FRAC;
9043
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9044
0
      v = (*cur - '0');
9045
0
      fraction = fraction * 10 + v;
9046
0
      frac = frac + 1;
9047
0
      cur++;
9048
0
  }
9049
0
  fraction /= pow(10.0, frac);
9050
0
  ret = ret + fraction;
9051
0
  while ((*cur >= '0') && (*cur <= '9'))
9052
0
      cur++;
9053
0
    }
9054
0
    if ((*cur == 'e') || (*cur == 'E')) {
9055
0
      cur++;
9056
0
      if (*cur == '-') {
9057
0
  is_exponent_negative = 1;
9058
0
  cur++;
9059
0
      } else if (*cur == '+') {
9060
0
        cur++;
9061
0
      }
9062
0
      while ((*cur >= '0') && (*cur <= '9')) {
9063
0
        if (exponent < 1000000)
9064
0
    exponent = exponent * 10 + (*cur - '0');
9065
0
  cur++;
9066
0
      }
9067
0
    }
9068
0
    while (IS_BLANK_CH(*cur)) cur++;
9069
0
    if (*cur != 0) return(xmlXPathNAN);
9070
0
    if (isneg) ret = -ret;
9071
0
    if (is_exponent_negative) exponent = -exponent;
9072
0
    ret *= pow(10.0, (double)exponent);
9073
0
    return(ret);
9074
0
}
9075
9076
/**
9077
 * xmlXPathCompNumber:
9078
 * @ctxt:  the XPath Parser context
9079
 *
9080
 *  [30]   Number ::=   Digits ('.' Digits?)?
9081
 *                    | '.' Digits
9082
 *  [31]   Digits ::=   [0-9]+
9083
 *
9084
 * Compile a Number, then push it on the stack
9085
 *
9086
 */
9087
static void
9088
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9089
0
{
9090
0
    double ret = 0.0;
9091
0
    int ok = 0;
9092
0
    int exponent = 0;
9093
0
    int is_exponent_negative = 0;
9094
0
    xmlXPathObjectPtr num;
9095
0
#ifdef __GNUC__
9096
0
    unsigned long tmp = 0;
9097
0
    double temp;
9098
0
#endif
9099
9100
0
    CHECK_ERROR;
9101
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9102
0
        XP_ERROR(XPATH_NUMBER_ERROR);
9103
0
    }
9104
0
#ifdef __GNUC__
9105
    /*
9106
     * tmp/temp is a workaround against a gcc compiler bug
9107
     * http://veillard.com/gcc.bug
9108
     */
9109
0
    ret = 0;
9110
0
    while ((CUR >= '0') && (CUR <= '9')) {
9111
0
  ret = ret * 10;
9112
0
  tmp = (CUR - '0');
9113
0
        ok = 1;
9114
0
        NEXT;
9115
0
  temp = (double) tmp;
9116
0
  ret = ret + temp;
9117
0
    }
9118
#else
9119
    ret = 0;
9120
    while ((CUR >= '0') && (CUR <= '9')) {
9121
  ret = ret * 10 + (CUR - '0');
9122
  ok = 1;
9123
  NEXT;
9124
    }
9125
#endif
9126
0
    if (CUR == '.') {
9127
0
  int v, frac = 0, max;
9128
0
  double fraction = 0;
9129
9130
0
        NEXT;
9131
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9132
0
            XP_ERROR(XPATH_NUMBER_ERROR);
9133
0
        }
9134
0
        while (CUR == '0') {
9135
0
            frac = frac + 1;
9136
0
            NEXT;
9137
0
        }
9138
0
        max = frac + MAX_FRAC;
9139
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9140
0
      v = (CUR - '0');
9141
0
      fraction = fraction * 10 + v;
9142
0
      frac = frac + 1;
9143
0
            NEXT;
9144
0
        }
9145
0
        fraction /= pow(10.0, frac);
9146
0
        ret = ret + fraction;
9147
0
        while ((CUR >= '0') && (CUR <= '9'))
9148
0
            NEXT;
9149
0
    }
9150
0
    if ((CUR == 'e') || (CUR == 'E')) {
9151
0
        NEXT;
9152
0
        if (CUR == '-') {
9153
0
            is_exponent_negative = 1;
9154
0
            NEXT;
9155
0
        } else if (CUR == '+') {
9156
0
      NEXT;
9157
0
  }
9158
0
        while ((CUR >= '0') && (CUR <= '9')) {
9159
0
            if (exponent < 1000000)
9160
0
                exponent = exponent * 10 + (CUR - '0');
9161
0
            NEXT;
9162
0
        }
9163
0
        if (is_exponent_negative)
9164
0
            exponent = -exponent;
9165
0
        ret *= pow(10.0, (double) exponent);
9166
0
    }
9167
0
    num = xmlXPathCacheNewFloat(ctxt, ret);
9168
0
    if (num == NULL) {
9169
0
  ctxt->error = XPATH_MEMORY_ERROR;
9170
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9171
0
                              NULL) == -1) {
9172
0
        xmlXPathReleaseObject(ctxt->context, num);
9173
0
    }
9174
0
}
9175
9176
/**
9177
 * xmlXPathParseLiteral:
9178
 * @ctxt:  the XPath Parser context
9179
 *
9180
 * Parse a Literal
9181
 *
9182
 *  [29]   Literal ::=   '"' [^"]* '"'
9183
 *                    | "'" [^']* "'"
9184
 *
9185
 * Returns the value found or NULL in case of error
9186
 */
9187
static xmlChar *
9188
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9189
0
    const xmlChar *q;
9190
0
    xmlChar *ret = NULL;
9191
0
    int quote;
9192
9193
0
    if (CUR == '"') {
9194
0
        quote = '"';
9195
0
    } else if (CUR == '\'') {
9196
0
        quote = '\'';
9197
0
    } else {
9198
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9199
0
    }
9200
9201
0
    NEXT;
9202
0
    q = CUR_PTR;
9203
0
    while (CUR != quote) {
9204
0
        int ch;
9205
0
        int len = 4;
9206
9207
0
        if (CUR == 0)
9208
0
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9209
0
        ch = xmlGetUTF8Char(CUR_PTR, &len);
9210
0
        if ((ch < 0) || (IS_CHAR(ch) == 0))
9211
0
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
9212
0
        CUR_PTR += len;
9213
0
    }
9214
0
    ret = xmlStrndup(q, CUR_PTR - q);
9215
0
    if (ret == NULL)
9216
0
        xmlXPathPErrMemory(ctxt);
9217
0
    NEXT;
9218
0
    return(ret);
9219
0
}
9220
9221
/**
9222
 * xmlXPathCompLiteral:
9223
 * @ctxt:  the XPath Parser context
9224
 *
9225
 * Parse a Literal and push it on the stack.
9226
 *
9227
 *  [29]   Literal ::=   '"' [^"]* '"'
9228
 *                    | "'" [^']* "'"
9229
 *
9230
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
9231
 */
9232
static void
9233
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9234
0
    xmlChar *ret = NULL;
9235
0
    xmlXPathObjectPtr lit;
9236
9237
0
    ret = xmlXPathParseLiteral(ctxt);
9238
0
    if (ret == NULL)
9239
0
        return;
9240
0
    lit = xmlXPathCacheNewString(ctxt, ret);
9241
0
    if (lit == NULL) {
9242
0
        ctxt->error = XPATH_MEMORY_ERROR;
9243
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9244
0
                              NULL) == -1) {
9245
0
        xmlXPathReleaseObject(ctxt->context, lit);
9246
0
    }
9247
0
    xmlFree(ret);
9248
0
}
9249
9250
/**
9251
 * xmlXPathCompVariableReference:
9252
 * @ctxt:  the XPath Parser context
9253
 *
9254
 * Parse a VariableReference, evaluate it and push it on the stack.
9255
 *
9256
 * The variable bindings consist of a mapping from variable names
9257
 * to variable values. The value of a variable is an object, which can be
9258
 * of any of the types that are possible for the value of an expression,
9259
 * and may also be of additional types not specified here.
9260
 *
9261
 * Early evaluation is possible since:
9262
 * The variable bindings [...] used to evaluate a subexpression are
9263
 * always the same as those used to evaluate the containing expression.
9264
 *
9265
 *  [36]   VariableReference ::=   '$' QName
9266
 */
9267
static void
9268
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9269
0
    xmlChar *name;
9270
0
    xmlChar *prefix;
9271
9272
0
    SKIP_BLANKS;
9273
0
    if (CUR != '$') {
9274
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9275
0
    }
9276
0
    NEXT;
9277
0
    name = xmlXPathParseQName(ctxt, &prefix);
9278
0
    if (name == NULL) {
9279
0
        xmlFree(prefix);
9280
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9281
0
    }
9282
0
    ctxt->comp->last = -1;
9283
0
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9284
0
        xmlFree(prefix);
9285
0
        xmlFree(name);
9286
0
    }
9287
0
    SKIP_BLANKS;
9288
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9289
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9290
0
    }
9291
0
}
9292
9293
/**
9294
 * xmlXPathIsNodeType:
9295
 * @name:  a name string
9296
 *
9297
 * Is the name given a NodeType one.
9298
 *
9299
 *  [38]   NodeType ::=   'comment'
9300
 *                    | 'text'
9301
 *                    | 'processing-instruction'
9302
 *                    | 'node'
9303
 *
9304
 * Returns 1 if true 0 otherwise
9305
 */
9306
int
9307
0
xmlXPathIsNodeType(const xmlChar *name) {
9308
0
    if (name == NULL)
9309
0
  return(0);
9310
9311
0
    if (xmlStrEqual(name, BAD_CAST "node"))
9312
0
  return(1);
9313
0
    if (xmlStrEqual(name, BAD_CAST "text"))
9314
0
  return(1);
9315
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
9316
0
  return(1);
9317
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9318
0
  return(1);
9319
0
    return(0);
9320
0
}
9321
9322
/**
9323
 * xmlXPathCompFunctionCall:
9324
 * @ctxt:  the XPath Parser context
9325
 *
9326
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9327
 *  [17]   Argument ::=   Expr
9328
 *
9329
 * Compile a function call, the evaluation of all arguments are
9330
 * pushed on the stack
9331
 */
9332
static void
9333
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9334
0
    xmlChar *name;
9335
0
    xmlChar *prefix;
9336
0
    int nbargs = 0;
9337
0
    int sort = 1;
9338
9339
0
    name = xmlXPathParseQName(ctxt, &prefix);
9340
0
    if (name == NULL) {
9341
0
  xmlFree(prefix);
9342
0
  XP_ERROR(XPATH_EXPR_ERROR);
9343
0
    }
9344
0
    SKIP_BLANKS;
9345
9346
0
    if (CUR != '(') {
9347
0
  xmlFree(name);
9348
0
  xmlFree(prefix);
9349
0
  XP_ERROR(XPATH_EXPR_ERROR);
9350
0
    }
9351
0
    NEXT;
9352
0
    SKIP_BLANKS;
9353
9354
    /*
9355
    * Optimization for count(): we don't need the node-set to be sorted.
9356
    */
9357
0
    if ((prefix == NULL) && (name[0] == 'c') &&
9358
0
  xmlStrEqual(name, BAD_CAST "count"))
9359
0
    {
9360
0
  sort = 0;
9361
0
    }
9362
0
    ctxt->comp->last = -1;
9363
0
    if (CUR != ')') {
9364
0
  while (CUR != 0) {
9365
0
      int op1 = ctxt->comp->last;
9366
0
      ctxt->comp->last = -1;
9367
0
      xmlXPathCompileExpr(ctxt, sort);
9368
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
9369
0
    xmlFree(name);
9370
0
    xmlFree(prefix);
9371
0
    return;
9372
0
      }
9373
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9374
0
      nbargs++;
9375
0
      if (CUR == ')') break;
9376
0
      if (CUR != ',') {
9377
0
    xmlFree(name);
9378
0
    xmlFree(prefix);
9379
0
    XP_ERROR(XPATH_EXPR_ERROR);
9380
0
      }
9381
0
      NEXT;
9382
0
      SKIP_BLANKS;
9383
0
  }
9384
0
    }
9385
0
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9386
0
        xmlFree(prefix);
9387
0
        xmlFree(name);
9388
0
    }
9389
0
    NEXT;
9390
0
    SKIP_BLANKS;
9391
0
}
9392
9393
/**
9394
 * xmlXPathCompPrimaryExpr:
9395
 * @ctxt:  the XPath Parser context
9396
 *
9397
 *  [15]   PrimaryExpr ::=   VariableReference
9398
 *                | '(' Expr ')'
9399
 *                | Literal
9400
 *                | Number
9401
 *                | FunctionCall
9402
 *
9403
 * Compile a primary expression.
9404
 */
9405
static void
9406
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9407
0
    SKIP_BLANKS;
9408
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9409
0
    else if (CUR == '(') {
9410
0
  NEXT;
9411
0
  SKIP_BLANKS;
9412
0
  xmlXPathCompileExpr(ctxt, 1);
9413
0
  CHECK_ERROR;
9414
0
  if (CUR != ')') {
9415
0
      XP_ERROR(XPATH_EXPR_ERROR);
9416
0
  }
9417
0
  NEXT;
9418
0
  SKIP_BLANKS;
9419
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9420
0
  xmlXPathCompNumber(ctxt);
9421
0
    } else if ((CUR == '\'') || (CUR == '"')) {
9422
0
  xmlXPathCompLiteral(ctxt);
9423
0
    } else {
9424
0
  xmlXPathCompFunctionCall(ctxt);
9425
0
    }
9426
0
    SKIP_BLANKS;
9427
0
}
9428
9429
/**
9430
 * xmlXPathCompFilterExpr:
9431
 * @ctxt:  the XPath Parser context
9432
 *
9433
 *  [20]   FilterExpr ::=   PrimaryExpr
9434
 *               | FilterExpr Predicate
9435
 *
9436
 * Compile a filter expression.
9437
 * Square brackets are used to filter expressions in the same way that
9438
 * they are used in location paths. It is an error if the expression to
9439
 * be filtered does not evaluate to a node-set. The context node list
9440
 * used for evaluating the expression in square brackets is the node-set
9441
 * to be filtered listed in document order.
9442
 */
9443
9444
static void
9445
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9446
0
    xmlXPathCompPrimaryExpr(ctxt);
9447
0
    CHECK_ERROR;
9448
0
    SKIP_BLANKS;
9449
9450
0
    while (CUR == '[') {
9451
0
  xmlXPathCompPredicate(ctxt, 1);
9452
0
  SKIP_BLANKS;
9453
0
    }
9454
9455
9456
0
}
9457
9458
/**
9459
 * xmlXPathScanName:
9460
 * @ctxt:  the XPath Parser context
9461
 *
9462
 * Trickery: parse an XML name but without consuming the input flow
9463
 * Needed to avoid insanity in the parser state.
9464
 *
9465
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9466
 *                  CombiningChar | Extender
9467
 *
9468
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9469
 *
9470
 * [6] Names ::= Name (S Name)*
9471
 *
9472
 * Returns the Name parsed or NULL
9473
 */
9474
9475
static xmlChar *
9476
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9477
0
    int l;
9478
0
    int c;
9479
0
    const xmlChar *cur;
9480
0
    xmlChar *ret;
9481
9482
0
    cur = ctxt->cur;
9483
9484
0
    c = CUR_CHAR(l);
9485
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9486
0
  (!IS_LETTER(c) && (c != '_') &&
9487
0
         (c != ':'))) {
9488
0
  return(NULL);
9489
0
    }
9490
9491
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9492
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9493
0
            (c == '.') || (c == '-') ||
9494
0
      (c == '_') || (c == ':') ||
9495
0
      (IS_COMBINING(c)) ||
9496
0
      (IS_EXTENDER(c)))) {
9497
0
  NEXTL(l);
9498
0
  c = CUR_CHAR(l);
9499
0
    }
9500
0
    ret = xmlStrndup(cur, ctxt->cur - cur);
9501
0
    if (ret == NULL)
9502
0
        xmlXPathPErrMemory(ctxt);
9503
0
    ctxt->cur = cur;
9504
0
    return(ret);
9505
0
}
9506
9507
/**
9508
 * xmlXPathCompPathExpr:
9509
 * @ctxt:  the XPath Parser context
9510
 *
9511
 *  [19]   PathExpr ::=   LocationPath
9512
 *               | FilterExpr
9513
 *               | FilterExpr '/' RelativeLocationPath
9514
 *               | FilterExpr '//' RelativeLocationPath
9515
 *
9516
 * Compile a path expression.
9517
 * The / operator and // operators combine an arbitrary expression
9518
 * and a relative location path. It is an error if the expression
9519
 * does not evaluate to a node-set.
9520
 * The / operator does composition in the same way as when / is
9521
 * used in a location path. As in location paths, // is short for
9522
 * /descendant-or-self::node()/.
9523
 */
9524
9525
static void
9526
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9527
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
9528
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
9529
9530
0
    SKIP_BLANKS;
9531
0
    if ((CUR == '$') || (CUR == '(') ||
9532
0
  (IS_ASCII_DIGIT(CUR)) ||
9533
0
        (CUR == '\'') || (CUR == '"') ||
9534
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9535
0
  lc = 0;
9536
0
    } else if (CUR == '*') {
9537
  /* relative or absolute location path */
9538
0
  lc = 1;
9539
0
    } else if (CUR == '/') {
9540
  /* relative or absolute location path */
9541
0
  lc = 1;
9542
0
    } else if (CUR == '@') {
9543
  /* relative abbreviated attribute location path */
9544
0
  lc = 1;
9545
0
    } else if (CUR == '.') {
9546
  /* relative abbreviated attribute location path */
9547
0
  lc = 1;
9548
0
    } else {
9549
  /*
9550
   * Problem is finding if we have a name here whether it's:
9551
   *   - a nodetype
9552
   *   - a function call in which case it's followed by '('
9553
   *   - an axis in which case it's followed by ':'
9554
   *   - a element name
9555
   * We do an a priori analysis here rather than having to
9556
   * maintain parsed token content through the recursive function
9557
   * calls. This looks uglier but makes the code easier to
9558
   * read/write/debug.
9559
   */
9560
0
  SKIP_BLANKS;
9561
0
  name = xmlXPathScanName(ctxt);
9562
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9563
0
      lc = 1;
9564
0
      xmlFree(name);
9565
0
  } else if (name != NULL) {
9566
0
      int len =xmlStrlen(name);
9567
9568
9569
0
      while (NXT(len) != 0) {
9570
0
    if (NXT(len) == '/') {
9571
        /* element name */
9572
0
        lc = 1;
9573
0
        break;
9574
0
    } else if (IS_BLANK_CH(NXT(len))) {
9575
        /* ignore blanks */
9576
0
        ;
9577
0
    } else if (NXT(len) == ':') {
9578
0
        lc = 1;
9579
0
        break;
9580
0
    } else if ((NXT(len) == '(')) {
9581
        /* Node Type or Function */
9582
0
        if (xmlXPathIsNodeType(name)) {
9583
0
      lc = 1;
9584
#ifdef LIBXML_XPTR_LOCS_ENABLED
9585
                    } else if (ctxt->xptr &&
9586
                               xmlStrEqual(name, BAD_CAST "range-to")) {
9587
                        lc = 1;
9588
#endif
9589
0
        } else {
9590
0
      lc = 0;
9591
0
        }
9592
0
                    break;
9593
0
    } else if ((NXT(len) == '[')) {
9594
        /* element name */
9595
0
        lc = 1;
9596
0
        break;
9597
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9598
0
         (NXT(len) == '=')) {
9599
0
        lc = 1;
9600
0
        break;
9601
0
    } else {
9602
0
        lc = 1;
9603
0
        break;
9604
0
    }
9605
0
    len++;
9606
0
      }
9607
0
      if (NXT(len) == 0) {
9608
    /* element name */
9609
0
    lc = 1;
9610
0
      }
9611
0
      xmlFree(name);
9612
0
  } else {
9613
      /* make sure all cases are covered explicitly */
9614
0
      XP_ERROR(XPATH_EXPR_ERROR);
9615
0
  }
9616
0
    }
9617
9618
0
    if (lc) {
9619
0
  if (CUR == '/') {
9620
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9621
0
  } else {
9622
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9623
0
  }
9624
0
  xmlXPathCompLocationPath(ctxt);
9625
0
    } else {
9626
0
  xmlXPathCompFilterExpr(ctxt);
9627
0
  CHECK_ERROR;
9628
0
  if ((CUR == '/') && (NXT(1) == '/')) {
9629
0
      SKIP(2);
9630
0
      SKIP_BLANKS;
9631
9632
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9633
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9634
9635
0
      xmlXPathCompRelativeLocationPath(ctxt);
9636
0
  } else if (CUR == '/') {
9637
0
      xmlXPathCompRelativeLocationPath(ctxt);
9638
0
  }
9639
0
    }
9640
0
    SKIP_BLANKS;
9641
0
}
9642
9643
/**
9644
 * xmlXPathCompUnionExpr:
9645
 * @ctxt:  the XPath Parser context
9646
 *
9647
 *  [18]   UnionExpr ::=   PathExpr
9648
 *               | UnionExpr '|' PathExpr
9649
 *
9650
 * Compile an union expression.
9651
 */
9652
9653
static void
9654
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9655
0
    xmlXPathCompPathExpr(ctxt);
9656
0
    CHECK_ERROR;
9657
0
    SKIP_BLANKS;
9658
0
    while (CUR == '|') {
9659
0
  int op1 = ctxt->comp->last;
9660
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9661
9662
0
  NEXT;
9663
0
  SKIP_BLANKS;
9664
0
  xmlXPathCompPathExpr(ctxt);
9665
9666
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9667
9668
0
  SKIP_BLANKS;
9669
0
    }
9670
0
}
9671
9672
/**
9673
 * xmlXPathCompUnaryExpr:
9674
 * @ctxt:  the XPath Parser context
9675
 *
9676
 *  [27]   UnaryExpr ::=   UnionExpr
9677
 *                   | '-' UnaryExpr
9678
 *
9679
 * Compile an unary expression.
9680
 */
9681
9682
static void
9683
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9684
0
    int minus = 0;
9685
0
    int found = 0;
9686
9687
0
    SKIP_BLANKS;
9688
0
    while (CUR == '-') {
9689
0
        minus = 1 - minus;
9690
0
  found = 1;
9691
0
  NEXT;
9692
0
  SKIP_BLANKS;
9693
0
    }
9694
9695
0
    xmlXPathCompUnionExpr(ctxt);
9696
0
    CHECK_ERROR;
9697
0
    if (found) {
9698
0
  if (minus)
9699
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9700
0
  else
9701
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9702
0
    }
9703
0
}
9704
9705
/**
9706
 * xmlXPathCompMultiplicativeExpr:
9707
 * @ctxt:  the XPath Parser context
9708
 *
9709
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
9710
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
9711
 *                   | MultiplicativeExpr 'div' UnaryExpr
9712
 *                   | MultiplicativeExpr 'mod' UnaryExpr
9713
 *  [34]   MultiplyOperator ::=   '*'
9714
 *
9715
 * Compile an Additive expression.
9716
 */
9717
9718
static void
9719
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9720
0
    xmlXPathCompUnaryExpr(ctxt);
9721
0
    CHECK_ERROR;
9722
0
    SKIP_BLANKS;
9723
0
    while ((CUR == '*') ||
9724
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9725
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9726
0
  int op = -1;
9727
0
  int op1 = ctxt->comp->last;
9728
9729
0
        if (CUR == '*') {
9730
0
      op = 0;
9731
0
      NEXT;
9732
0
  } else if (CUR == 'd') {
9733
0
      op = 1;
9734
0
      SKIP(3);
9735
0
  } else if (CUR == 'm') {
9736
0
      op = 2;
9737
0
      SKIP(3);
9738
0
  }
9739
0
  SKIP_BLANKS;
9740
0
        xmlXPathCompUnaryExpr(ctxt);
9741
0
  CHECK_ERROR;
9742
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9743
0
  SKIP_BLANKS;
9744
0
    }
9745
0
}
9746
9747
/**
9748
 * xmlXPathCompAdditiveExpr:
9749
 * @ctxt:  the XPath Parser context
9750
 *
9751
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
9752
 *                   | AdditiveExpr '+' MultiplicativeExpr
9753
 *                   | AdditiveExpr '-' MultiplicativeExpr
9754
 *
9755
 * Compile an Additive expression.
9756
 */
9757
9758
static void
9759
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9760
9761
0
    xmlXPathCompMultiplicativeExpr(ctxt);
9762
0
    CHECK_ERROR;
9763
0
    SKIP_BLANKS;
9764
0
    while ((CUR == '+') || (CUR == '-')) {
9765
0
  int plus;
9766
0
  int op1 = ctxt->comp->last;
9767
9768
0
        if (CUR == '+') plus = 1;
9769
0
  else plus = 0;
9770
0
  NEXT;
9771
0
  SKIP_BLANKS;
9772
0
        xmlXPathCompMultiplicativeExpr(ctxt);
9773
0
  CHECK_ERROR;
9774
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9775
0
  SKIP_BLANKS;
9776
0
    }
9777
0
}
9778
9779
/**
9780
 * xmlXPathCompRelationalExpr:
9781
 * @ctxt:  the XPath Parser context
9782
 *
9783
 *  [24]   RelationalExpr ::=   AdditiveExpr
9784
 *                 | RelationalExpr '<' AdditiveExpr
9785
 *                 | RelationalExpr '>' AdditiveExpr
9786
 *                 | RelationalExpr '<=' AdditiveExpr
9787
 *                 | RelationalExpr '>=' AdditiveExpr
9788
 *
9789
 *  A <= B > C is allowed ? Answer from James, yes with
9790
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9791
 *  which is basically what got implemented.
9792
 *
9793
 * Compile a Relational expression, then push the result
9794
 * on the stack
9795
 */
9796
9797
static void
9798
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9799
0
    xmlXPathCompAdditiveExpr(ctxt);
9800
0
    CHECK_ERROR;
9801
0
    SKIP_BLANKS;
9802
0
    while ((CUR == '<') || (CUR == '>')) {
9803
0
  int inf, strict;
9804
0
  int op1 = ctxt->comp->last;
9805
9806
0
        if (CUR == '<') inf = 1;
9807
0
  else inf = 0;
9808
0
  if (NXT(1) == '=') strict = 0;
9809
0
  else strict = 1;
9810
0
  NEXT;
9811
0
  if (!strict) NEXT;
9812
0
  SKIP_BLANKS;
9813
0
        xmlXPathCompAdditiveExpr(ctxt);
9814
0
  CHECK_ERROR;
9815
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9816
0
  SKIP_BLANKS;
9817
0
    }
9818
0
}
9819
9820
/**
9821
 * xmlXPathCompEqualityExpr:
9822
 * @ctxt:  the XPath Parser context
9823
 *
9824
 *  [23]   EqualityExpr ::=   RelationalExpr
9825
 *                 | EqualityExpr '=' RelationalExpr
9826
 *                 | EqualityExpr '!=' RelationalExpr
9827
 *
9828
 *  A != B != C is allowed ? Answer from James, yes with
9829
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
9830
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
9831
 *  which is basically what got implemented.
9832
 *
9833
 * Compile an Equality expression.
9834
 *
9835
 */
9836
static void
9837
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9838
0
    xmlXPathCompRelationalExpr(ctxt);
9839
0
    CHECK_ERROR;
9840
0
    SKIP_BLANKS;
9841
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9842
0
  int eq;
9843
0
  int op1 = ctxt->comp->last;
9844
9845
0
        if (CUR == '=') eq = 1;
9846
0
  else eq = 0;
9847
0
  NEXT;
9848
0
  if (!eq) NEXT;
9849
0
  SKIP_BLANKS;
9850
0
        xmlXPathCompRelationalExpr(ctxt);
9851
0
  CHECK_ERROR;
9852
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9853
0
  SKIP_BLANKS;
9854
0
    }
9855
0
}
9856
9857
/**
9858
 * xmlXPathCompAndExpr:
9859
 * @ctxt:  the XPath Parser context
9860
 *
9861
 *  [22]   AndExpr ::=   EqualityExpr
9862
 *                 | AndExpr 'and' EqualityExpr
9863
 *
9864
 * Compile an AND expression.
9865
 *
9866
 */
9867
static void
9868
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9869
0
    xmlXPathCompEqualityExpr(ctxt);
9870
0
    CHECK_ERROR;
9871
0
    SKIP_BLANKS;
9872
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9873
0
  int op1 = ctxt->comp->last;
9874
0
        SKIP(3);
9875
0
  SKIP_BLANKS;
9876
0
        xmlXPathCompEqualityExpr(ctxt);
9877
0
  CHECK_ERROR;
9878
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9879
0
  SKIP_BLANKS;
9880
0
    }
9881
0
}
9882
9883
/**
9884
 * xmlXPathCompileExpr:
9885
 * @ctxt:  the XPath Parser context
9886
 *
9887
 *  [14]   Expr ::=   OrExpr
9888
 *  [21]   OrExpr ::=   AndExpr
9889
 *                 | OrExpr 'or' AndExpr
9890
 *
9891
 * Parse and compile an expression
9892
 */
9893
static void
9894
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9895
0
    xmlXPathContextPtr xpctxt = ctxt->context;
9896
9897
0
    if (xpctxt != NULL) {
9898
0
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9899
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9900
        /*
9901
         * Parsing a single '(' pushes about 10 functions on the call stack
9902
         * before recursing!
9903
         */
9904
0
        xpctxt->depth += 10;
9905
0
    }
9906
9907
0
    xmlXPathCompAndExpr(ctxt);
9908
0
    CHECK_ERROR;
9909
0
    SKIP_BLANKS;
9910
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9911
0
  int op1 = ctxt->comp->last;
9912
0
        SKIP(2);
9913
0
  SKIP_BLANKS;
9914
0
        xmlXPathCompAndExpr(ctxt);
9915
0
  CHECK_ERROR;
9916
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9917
0
  SKIP_BLANKS;
9918
0
    }
9919
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9920
  /* more ops could be optimized too */
9921
  /*
9922
  * This is the main place to eliminate sorting for
9923
  * operations which don't require a sorted node-set.
9924
  * E.g. count().
9925
  */
9926
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9927
0
    }
9928
9929
0
    if (xpctxt != NULL)
9930
0
        xpctxt->depth -= 10;
9931
0
}
9932
9933
/**
9934
 * xmlXPathCompPredicate:
9935
 * @ctxt:  the XPath Parser context
9936
 * @filter:  act as a filter
9937
 *
9938
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
9939
 *  [9]   PredicateExpr ::=   Expr
9940
 *
9941
 * Compile a predicate expression
9942
 */
9943
static void
9944
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9945
0
    int op1 = ctxt->comp->last;
9946
9947
0
    SKIP_BLANKS;
9948
0
    if (CUR != '[') {
9949
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9950
0
    }
9951
0
    NEXT;
9952
0
    SKIP_BLANKS;
9953
9954
0
    ctxt->comp->last = -1;
9955
    /*
9956
    * This call to xmlXPathCompileExpr() will deactivate sorting
9957
    * of the predicate result.
9958
    * TODO: Sorting is still activated for filters, since I'm not
9959
    *  sure if needed. Normally sorting should not be needed, since
9960
    *  a filter can only diminish the number of items in a sequence,
9961
    *  but won't change its order; so if the initial sequence is sorted,
9962
    *  subsequent sorting is not needed.
9963
    */
9964
0
    if (! filter)
9965
0
  xmlXPathCompileExpr(ctxt, 0);
9966
0
    else
9967
0
  xmlXPathCompileExpr(ctxt, 1);
9968
0
    CHECK_ERROR;
9969
9970
0
    if (CUR != ']') {
9971
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9972
0
    }
9973
9974
0
    if (filter)
9975
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9976
0
    else
9977
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9978
9979
0
    NEXT;
9980
0
    SKIP_BLANKS;
9981
0
}
9982
9983
/**
9984
 * xmlXPathCompNodeTest:
9985
 * @ctxt:  the XPath Parser context
9986
 * @test:  pointer to a xmlXPathTestVal
9987
 * @type:  pointer to a xmlXPathTypeVal
9988
 * @prefix:  placeholder for a possible name prefix
9989
 *
9990
 * [7] NodeTest ::=   NameTest
9991
 *        | NodeType '(' ')'
9992
 *        | 'processing-instruction' '(' Literal ')'
9993
 *
9994
 * [37] NameTest ::=  '*'
9995
 *        | NCName ':' '*'
9996
 *        | QName
9997
 * [38] NodeType ::= 'comment'
9998
 *       | 'text'
9999
 *       | 'processing-instruction'
10000
 *       | 'node'
10001
 *
10002
 * Returns the name found and updates @test, @type and @prefix appropriately
10003
 */
10004
static xmlChar *
10005
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10006
               xmlXPathTypeVal *type, xmlChar **prefix,
10007
0
         xmlChar *name) {
10008
0
    int blanks;
10009
10010
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10011
0
  return(NULL);
10012
0
    }
10013
0
    *type = (xmlXPathTypeVal) 0;
10014
0
    *test = (xmlXPathTestVal) 0;
10015
0
    *prefix = NULL;
10016
0
    SKIP_BLANKS;
10017
10018
0
    if ((name == NULL) && (CUR == '*')) {
10019
  /*
10020
   * All elements
10021
   */
10022
0
  NEXT;
10023
0
  *test = NODE_TEST_ALL;
10024
0
  return(NULL);
10025
0
    }
10026
10027
0
    if (name == NULL)
10028
0
  name = xmlXPathParseNCName(ctxt);
10029
0
    if (name == NULL) {
10030
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
10031
0
    }
10032
10033
0
    blanks = IS_BLANK_CH(CUR);
10034
0
    SKIP_BLANKS;
10035
0
    if (CUR == '(') {
10036
0
  NEXT;
10037
  /*
10038
   * NodeType or PI search
10039
   */
10040
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
10041
0
      *type = NODE_TYPE_COMMENT;
10042
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
10043
0
      *type = NODE_TYPE_NODE;
10044
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10045
0
      *type = NODE_TYPE_PI;
10046
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
10047
0
      *type = NODE_TYPE_TEXT;
10048
0
  else {
10049
0
      if (name != NULL)
10050
0
    xmlFree(name);
10051
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
10052
0
  }
10053
10054
0
  *test = NODE_TEST_TYPE;
10055
10056
0
  SKIP_BLANKS;
10057
0
  if (*type == NODE_TYPE_PI) {
10058
      /*
10059
       * Specific case: search a PI by name.
10060
       */
10061
0
      if (name != NULL)
10062
0
    xmlFree(name);
10063
0
      name = NULL;
10064
0
      if (CUR != ')') {
10065
0
    name = xmlXPathParseLiteral(ctxt);
10066
0
    *test = NODE_TEST_PI;
10067
0
    SKIP_BLANKS;
10068
0
      }
10069
0
  }
10070
0
  if (CUR != ')') {
10071
0
      if (name != NULL)
10072
0
    xmlFree(name);
10073
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10074
0
  }
10075
0
  NEXT;
10076
0
  return(name);
10077
0
    }
10078
0
    *test = NODE_TEST_NAME;
10079
0
    if ((!blanks) && (CUR == ':')) {
10080
0
  NEXT;
10081
10082
  /*
10083
   * Since currently the parser context don't have a
10084
   * namespace list associated:
10085
   * The namespace name for this prefix can be computed
10086
   * only at evaluation time. The compilation is done
10087
   * outside of any context.
10088
   */
10089
#if 0
10090
  *prefix = xmlXPathNsLookup(ctxt->context, name);
10091
  if (name != NULL)
10092
      xmlFree(name);
10093
  if (*prefix == NULL) {
10094
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10095
  }
10096
#else
10097
0
  *prefix = name;
10098
0
#endif
10099
10100
0
  if (CUR == '*') {
10101
      /*
10102
       * All elements
10103
       */
10104
0
      NEXT;
10105
0
      *test = NODE_TEST_ALL;
10106
0
      return(NULL);
10107
0
  }
10108
10109
0
  name = xmlXPathParseNCName(ctxt);
10110
0
  if (name == NULL) {
10111
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
10112
0
  }
10113
0
    }
10114
0
    return(name);
10115
0
}
10116
10117
/**
10118
 * xmlXPathIsAxisName:
10119
 * @name:  a preparsed name token
10120
 *
10121
 * [6] AxisName ::=   'ancestor'
10122
 *                  | 'ancestor-or-self'
10123
 *                  | 'attribute'
10124
 *                  | 'child'
10125
 *                  | 'descendant'
10126
 *                  | 'descendant-or-self'
10127
 *                  | 'following'
10128
 *                  | 'following-sibling'
10129
 *                  | 'namespace'
10130
 *                  | 'parent'
10131
 *                  | 'preceding'
10132
 *                  | 'preceding-sibling'
10133
 *                  | 'self'
10134
 *
10135
 * Returns the axis or 0
10136
 */
10137
static xmlXPathAxisVal
10138
0
xmlXPathIsAxisName(const xmlChar *name) {
10139
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10140
0
    switch (name[0]) {
10141
0
  case 'a':
10142
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
10143
0
    ret = AXIS_ANCESTOR;
10144
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10145
0
    ret = AXIS_ANCESTOR_OR_SELF;
10146
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
10147
0
    ret = AXIS_ATTRIBUTE;
10148
0
      break;
10149
0
  case 'c':
10150
0
      if (xmlStrEqual(name, BAD_CAST "child"))
10151
0
    ret = AXIS_CHILD;
10152
0
      break;
10153
0
  case 'd':
10154
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
10155
0
    ret = AXIS_DESCENDANT;
10156
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10157
0
    ret = AXIS_DESCENDANT_OR_SELF;
10158
0
      break;
10159
0
  case 'f':
10160
0
      if (xmlStrEqual(name, BAD_CAST "following"))
10161
0
    ret = AXIS_FOLLOWING;
10162
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10163
0
    ret = AXIS_FOLLOWING_SIBLING;
10164
0
      break;
10165
0
  case 'n':
10166
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
10167
0
    ret = AXIS_NAMESPACE;
10168
0
      break;
10169
0
  case 'p':
10170
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
10171
0
    ret = AXIS_PARENT;
10172
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
10173
0
    ret = AXIS_PRECEDING;
10174
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10175
0
    ret = AXIS_PRECEDING_SIBLING;
10176
0
      break;
10177
0
  case 's':
10178
0
      if (xmlStrEqual(name, BAD_CAST "self"))
10179
0
    ret = AXIS_SELF;
10180
0
      break;
10181
0
    }
10182
0
    return(ret);
10183
0
}
10184
10185
/**
10186
 * xmlXPathCompStep:
10187
 * @ctxt:  the XPath Parser context
10188
 *
10189
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
10190
 *                  | AbbreviatedStep
10191
 *
10192
 * [12] AbbreviatedStep ::=   '.' | '..'
10193
 *
10194
 * [5] AxisSpecifier ::= AxisName '::'
10195
 *                  | AbbreviatedAxisSpecifier
10196
 *
10197
 * [13] AbbreviatedAxisSpecifier ::= '@'?
10198
 *
10199
 * Modified for XPtr range support as:
10200
 *
10201
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10202
 *                     | AbbreviatedStep
10203
 *                     | 'range-to' '(' Expr ')' Predicate*
10204
 *
10205
 * Compile one step in a Location Path
10206
 * A location step of . is short for self::node(). This is
10207
 * particularly useful in conjunction with //. For example, the
10208
 * location path .//para is short for
10209
 * self::node()/descendant-or-self::node()/child::para
10210
 * and so will select all para descendant elements of the context
10211
 * node.
10212
 * Similarly, a location step of .. is short for parent::node().
10213
 * For example, ../title is short for parent::node()/child::title
10214
 * and so will select the title children of the parent of the context
10215
 * node.
10216
 */
10217
static void
10218
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10219
#ifdef LIBXML_XPTR_LOCS_ENABLED
10220
    int rangeto = 0;
10221
    int op2 = -1;
10222
#endif
10223
10224
0
    SKIP_BLANKS;
10225
0
    if ((CUR == '.') && (NXT(1) == '.')) {
10226
0
  SKIP(2);
10227
0
  SKIP_BLANKS;
10228
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10229
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10230
0
    } else if (CUR == '.') {
10231
0
  NEXT;
10232
0
  SKIP_BLANKS;
10233
0
    } else {
10234
0
  xmlChar *name = NULL;
10235
0
  xmlChar *prefix = NULL;
10236
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
10237
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10238
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10239
0
  int op1;
10240
10241
  /*
10242
   * The modification needed for XPointer change to the production
10243
   */
10244
#ifdef LIBXML_XPTR_LOCS_ENABLED
10245
  if (ctxt->xptr) {
10246
      name = xmlXPathParseNCName(ctxt);
10247
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10248
                op2 = ctxt->comp->last;
10249
    xmlFree(name);
10250
    SKIP_BLANKS;
10251
    if (CUR != '(') {
10252
        XP_ERROR(XPATH_EXPR_ERROR);
10253
    }
10254
    NEXT;
10255
    SKIP_BLANKS;
10256
10257
    xmlXPathCompileExpr(ctxt, 1);
10258
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10259
    CHECK_ERROR;
10260
10261
    SKIP_BLANKS;
10262
    if (CUR != ')') {
10263
        XP_ERROR(XPATH_EXPR_ERROR);
10264
    }
10265
    NEXT;
10266
    rangeto = 1;
10267
    goto eval_predicates;
10268
      }
10269
  }
10270
#endif
10271
0
  if (CUR == '*') {
10272
0
      axis = AXIS_CHILD;
10273
0
  } else {
10274
0
      if (name == NULL)
10275
0
    name = xmlXPathParseNCName(ctxt);
10276
0
      if (name != NULL) {
10277
0
    axis = xmlXPathIsAxisName(name);
10278
0
    if (axis != 0) {
10279
0
        SKIP_BLANKS;
10280
0
        if ((CUR == ':') && (NXT(1) == ':')) {
10281
0
      SKIP(2);
10282
0
      xmlFree(name);
10283
0
      name = NULL;
10284
0
        } else {
10285
      /* an element name can conflict with an axis one :-\ */
10286
0
      axis = AXIS_CHILD;
10287
0
        }
10288
0
    } else {
10289
0
        axis = AXIS_CHILD;
10290
0
    }
10291
0
      } else if (CUR == '@') {
10292
0
    NEXT;
10293
0
    axis = AXIS_ATTRIBUTE;
10294
0
      } else {
10295
0
    axis = AXIS_CHILD;
10296
0
      }
10297
0
  }
10298
10299
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
10300
0
            xmlFree(name);
10301
0
            return;
10302
0
        }
10303
10304
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10305
0
  if (test == 0)
10306
0
      return;
10307
10308
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
10309
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10310
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10311
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10312
0
      }
10313
0
  }
10314
10315
#ifdef LIBXML_XPTR_LOCS_ENABLED
10316
eval_predicates:
10317
#endif
10318
0
  op1 = ctxt->comp->last;
10319
0
  ctxt->comp->last = -1;
10320
10321
0
  SKIP_BLANKS;
10322
0
  while (CUR == '[') {
10323
0
      xmlXPathCompPredicate(ctxt, 0);
10324
0
  }
10325
10326
#ifdef LIBXML_XPTR_LOCS_ENABLED
10327
  if (rangeto) {
10328
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10329
  } else
10330
#endif
10331
0
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10332
0
                           test, type, (void *)prefix, (void *)name) == -1) {
10333
0
            xmlFree(prefix);
10334
0
            xmlFree(name);
10335
0
        }
10336
0
    }
10337
0
}
10338
10339
/**
10340
 * xmlXPathCompRelativeLocationPath:
10341
 * @ctxt:  the XPath Parser context
10342
 *
10343
 *  [3]   RelativeLocationPath ::=   Step
10344
 *                     | RelativeLocationPath '/' Step
10345
 *                     | AbbreviatedRelativeLocationPath
10346
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
10347
 *
10348
 * Compile a relative location path.
10349
 */
10350
static void
10351
xmlXPathCompRelativeLocationPath
10352
0
(xmlXPathParserContextPtr ctxt) {
10353
0
    SKIP_BLANKS;
10354
0
    if ((CUR == '/') && (NXT(1) == '/')) {
10355
0
  SKIP(2);
10356
0
  SKIP_BLANKS;
10357
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10358
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10359
0
    } else if (CUR == '/') {
10360
0
      NEXT;
10361
0
  SKIP_BLANKS;
10362
0
    }
10363
0
    xmlXPathCompStep(ctxt);
10364
0
    CHECK_ERROR;
10365
0
    SKIP_BLANKS;
10366
0
    while (CUR == '/') {
10367
0
  if ((CUR == '/') && (NXT(1) == '/')) {
10368
0
      SKIP(2);
10369
0
      SKIP_BLANKS;
10370
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10371
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10372
0
      xmlXPathCompStep(ctxt);
10373
0
  } else if (CUR == '/') {
10374
0
      NEXT;
10375
0
      SKIP_BLANKS;
10376
0
      xmlXPathCompStep(ctxt);
10377
0
  }
10378
0
  SKIP_BLANKS;
10379
0
    }
10380
0
}
10381
10382
/**
10383
 * xmlXPathCompLocationPath:
10384
 * @ctxt:  the XPath Parser context
10385
 *
10386
 *  [1]   LocationPath ::=   RelativeLocationPath
10387
 *                     | AbsoluteLocationPath
10388
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
10389
 *                     | AbbreviatedAbsoluteLocationPath
10390
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
10391
 *                           '//' RelativeLocationPath
10392
 *
10393
 * Compile a location path
10394
 *
10395
 * // is short for /descendant-or-self::node()/. For example,
10396
 * //para is short for /descendant-or-self::node()/child::para and
10397
 * so will select any para element in the document (even a para element
10398
 * that is a document element will be selected by //para since the
10399
 * document element node is a child of the root node); div//para is
10400
 * short for div/descendant-or-self::node()/child::para and so will
10401
 * select all para descendants of div children.
10402
 */
10403
static void
10404
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10405
0
    SKIP_BLANKS;
10406
0
    if (CUR != '/') {
10407
0
        xmlXPathCompRelativeLocationPath(ctxt);
10408
0
    } else {
10409
0
  while (CUR == '/') {
10410
0
      if ((CUR == '/') && (NXT(1) == '/')) {
10411
0
    SKIP(2);
10412
0
    SKIP_BLANKS;
10413
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10414
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10415
0
    xmlXPathCompRelativeLocationPath(ctxt);
10416
0
      } else if (CUR == '/') {
10417
0
    NEXT;
10418
0
    SKIP_BLANKS;
10419
0
    if ((CUR != 0 ) &&
10420
0
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10421
0
         (CUR == '@') || (CUR == '*')))
10422
0
        xmlXPathCompRelativeLocationPath(ctxt);
10423
0
      }
10424
0
      CHECK_ERROR;
10425
0
  }
10426
0
    }
10427
0
}
10428
10429
/************************************************************************
10430
 *                  *
10431
 *    XPath precompiled expression evaluation     *
10432
 *                  *
10433
 ************************************************************************/
10434
10435
static int
10436
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10437
10438
/**
10439
 * xmlXPathNodeSetFilter:
10440
 * @ctxt:  the XPath Parser context
10441
 * @set: the node set to filter
10442
 * @filterOpIndex: the index of the predicate/filter op
10443
 * @minPos: minimum position in the filtered set (1-based)
10444
 * @maxPos: maximum position in the filtered set (1-based)
10445
 * @hasNsNodes: true if the node set may contain namespace nodes
10446
 *
10447
 * Filter a node set, keeping only nodes for which the predicate expression
10448
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10449
 * filtered result.
10450
 */
10451
static void
10452
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10453
          xmlNodeSetPtr set,
10454
          int filterOpIndex,
10455
                      int minPos, int maxPos,
10456
          int hasNsNodes)
10457
0
{
10458
0
    xmlXPathContextPtr xpctxt;
10459
0
    xmlNodePtr oldnode;
10460
0
    xmlDocPtr olddoc;
10461
0
    xmlXPathStepOpPtr filterOp;
10462
0
    int oldcs, oldpp;
10463
0
    int i, j, pos;
10464
10465
0
    if ((set == NULL) || (set->nodeNr == 0))
10466
0
        return;
10467
10468
    /*
10469
    * Check if the node set contains a sufficient number of nodes for
10470
    * the requested range.
10471
    */
10472
0
    if (set->nodeNr < minPos) {
10473
0
        xmlXPathNodeSetClear(set, hasNsNodes);
10474
0
        return;
10475
0
    }
10476
10477
0
    xpctxt = ctxt->context;
10478
0
    oldnode = xpctxt->node;
10479
0
    olddoc = xpctxt->doc;
10480
0
    oldcs = xpctxt->contextSize;
10481
0
    oldpp = xpctxt->proximityPosition;
10482
0
    filterOp = &ctxt->comp->steps[filterOpIndex];
10483
10484
0
    xpctxt->contextSize = set->nodeNr;
10485
10486
0
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10487
0
        xmlNodePtr node = set->nodeTab[i];
10488
0
        int res;
10489
10490
0
        xpctxt->node = node;
10491
0
        xpctxt->proximityPosition = i + 1;
10492
10493
        /*
10494
        * Also set the xpath document in case things like
10495
        * key() are evaluated in the predicate.
10496
        *
10497
        * TODO: Get real doc for namespace nodes.
10498
        */
10499
0
        if ((node->type != XML_NAMESPACE_DECL) &&
10500
0
            (node->doc != NULL))
10501
0
            xpctxt->doc = node->doc;
10502
10503
0
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10504
10505
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
10506
0
            break;
10507
0
        if (res < 0) {
10508
            /* Shouldn't happen */
10509
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10510
0
            break;
10511
0
        }
10512
10513
0
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10514
0
            if (i != j) {
10515
0
                set->nodeTab[j] = node;
10516
0
                set->nodeTab[i] = NULL;
10517
0
            }
10518
10519
0
            j += 1;
10520
0
        } else {
10521
            /* Remove the entry from the initial node set. */
10522
0
            set->nodeTab[i] = NULL;
10523
0
            if (node->type == XML_NAMESPACE_DECL)
10524
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10525
0
        }
10526
10527
0
        if (res != 0) {
10528
0
            if (pos == maxPos) {
10529
0
                i += 1;
10530
0
                break;
10531
0
            }
10532
10533
0
            pos += 1;
10534
0
        }
10535
0
    }
10536
10537
    /* Free remaining nodes. */
10538
0
    if (hasNsNodes) {
10539
0
        for (; i < set->nodeNr; i++) {
10540
0
            xmlNodePtr node = set->nodeTab[i];
10541
0
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10542
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10543
0
        }
10544
0
    }
10545
10546
0
    set->nodeNr = j;
10547
10548
    /* If too many elements were removed, shrink table to preserve memory. */
10549
0
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10550
0
        (set->nodeNr < set->nodeMax / 2)) {
10551
0
        xmlNodePtr *tmp;
10552
0
        int nodeMax = set->nodeNr;
10553
10554
0
        if (nodeMax < XML_NODESET_DEFAULT)
10555
0
            nodeMax = XML_NODESET_DEFAULT;
10556
0
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10557
0
                nodeMax * sizeof(xmlNodePtr));
10558
0
        if (tmp == NULL) {
10559
0
            xmlXPathPErrMemory(ctxt);
10560
0
        } else {
10561
0
            set->nodeTab = tmp;
10562
0
            set->nodeMax = nodeMax;
10563
0
        }
10564
0
    }
10565
10566
0
    xpctxt->node = oldnode;
10567
0
    xpctxt->doc = olddoc;
10568
0
    xpctxt->contextSize = oldcs;
10569
0
    xpctxt->proximityPosition = oldpp;
10570
0
}
10571
10572
#ifdef LIBXML_XPTR_LOCS_ENABLED
10573
/**
10574
 * xmlXPathLocationSetFilter:
10575
 * @ctxt:  the XPath Parser context
10576
 * @locset: the location set to filter
10577
 * @filterOpIndex: the index of the predicate/filter op
10578
 * @minPos: minimum position in the filtered set (1-based)
10579
 * @maxPos: maximum position in the filtered set (1-based)
10580
 *
10581
 * Filter a location set, keeping only nodes for which the predicate
10582
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
10583
 * in the filtered result.
10584
 */
10585
static void
10586
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10587
              xmlLocationSetPtr locset,
10588
              int filterOpIndex,
10589
                          int minPos, int maxPos)
10590
{
10591
    xmlXPathContextPtr xpctxt;
10592
    xmlNodePtr oldnode;
10593
    xmlDocPtr olddoc;
10594
    xmlXPathStepOpPtr filterOp;
10595
    int oldcs, oldpp;
10596
    int i, j, pos;
10597
10598
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10599
        return;
10600
10601
    xpctxt = ctxt->context;
10602
    oldnode = xpctxt->node;
10603
    olddoc = xpctxt->doc;
10604
    oldcs = xpctxt->contextSize;
10605
    oldpp = xpctxt->proximityPosition;
10606
    filterOp = &ctxt->comp->steps[filterOpIndex];
10607
10608
    xpctxt->contextSize = locset->locNr;
10609
10610
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10611
        xmlNodePtr contextNode = locset->locTab[i]->user;
10612
        int res;
10613
10614
        xpctxt->node = contextNode;
10615
        xpctxt->proximityPosition = i + 1;
10616
10617
        /*
10618
        * Also set the xpath document in case things like
10619
        * key() are evaluated in the predicate.
10620
        *
10621
        * TODO: Get real doc for namespace nodes.
10622
        */
10623
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
10624
            (contextNode->doc != NULL))
10625
            xpctxt->doc = contextNode->doc;
10626
10627
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10628
10629
        if (ctxt->error != XPATH_EXPRESSION_OK)
10630
            break;
10631
        if (res < 0) {
10632
            /* Shouldn't happen */
10633
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10634
            break;
10635
        }
10636
10637
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10638
            if (i != j) {
10639
                locset->locTab[j] = locset->locTab[i];
10640
                locset->locTab[i] = NULL;
10641
            }
10642
10643
            j += 1;
10644
        } else {
10645
            /* Remove the entry from the initial location set. */
10646
            xmlXPathFreeObject(locset->locTab[i]);
10647
            locset->locTab[i] = NULL;
10648
        }
10649
10650
        if (res != 0) {
10651
            if (pos == maxPos) {
10652
                i += 1;
10653
                break;
10654
            }
10655
10656
            pos += 1;
10657
        }
10658
    }
10659
10660
    /* Free remaining nodes. */
10661
    for (; i < locset->locNr; i++)
10662
        xmlXPathFreeObject(locset->locTab[i]);
10663
10664
    locset->locNr = j;
10665
10666
    /* If too many elements were removed, shrink table to preserve memory. */
10667
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
10668
        (locset->locNr < locset->locMax / 2)) {
10669
        xmlXPathObjectPtr *tmp;
10670
        int locMax = locset->locNr;
10671
10672
        if (locMax < XML_NODESET_DEFAULT)
10673
            locMax = XML_NODESET_DEFAULT;
10674
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10675
                locMax * sizeof(xmlXPathObjectPtr));
10676
        if (tmp == NULL) {
10677
            xmlXPathPErrMemory(ctxt);
10678
        } else {
10679
            locset->locTab = tmp;
10680
            locset->locMax = locMax;
10681
        }
10682
    }
10683
10684
    xpctxt->node = oldnode;
10685
    xpctxt->doc = olddoc;
10686
    xpctxt->contextSize = oldcs;
10687
    xpctxt->proximityPosition = oldpp;
10688
}
10689
#endif /* LIBXML_XPTR_LOCS_ENABLED */
10690
10691
/**
10692
 * xmlXPathCompOpEvalPredicate:
10693
 * @ctxt:  the XPath Parser context
10694
 * @op: the predicate op
10695
 * @set: the node set to filter
10696
 * @minPos: minimum position in the filtered set (1-based)
10697
 * @maxPos: maximum position in the filtered set (1-based)
10698
 * @hasNsNodes: true if the node set may contain namespace nodes
10699
 *
10700
 * Filter a node set, keeping only nodes for which the sequence of predicate
10701
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10702
 * in the filtered result.
10703
 */
10704
static void
10705
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10706
          xmlXPathStepOpPtr op,
10707
          xmlNodeSetPtr set,
10708
                            int minPos, int maxPos,
10709
          int hasNsNodes)
10710
0
{
10711
0
    if (op->ch1 != -1) {
10712
0
  xmlXPathCompExprPtr comp = ctxt->comp;
10713
  /*
10714
  * Process inner predicates first.
10715
  */
10716
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10717
0
            XP_ERROR(XPATH_INVALID_OPERAND);
10718
0
  }
10719
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10720
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10721
0
        ctxt->context->depth += 1;
10722
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10723
0
                                    1, set->nodeNr, hasNsNodes);
10724
0
        ctxt->context->depth -= 1;
10725
0
  CHECK_ERROR;
10726
0
    }
10727
10728
0
    if (op->ch2 != -1)
10729
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10730
0
}
10731
10732
static int
10733
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10734
          xmlXPathStepOpPtr op,
10735
          int *maxPos)
10736
0
{
10737
10738
0
    xmlXPathStepOpPtr exprOp;
10739
10740
    /*
10741
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10742
    */
10743
10744
    /*
10745
    * If not -1, then ch1 will point to:
10746
    * 1) For predicates (XPATH_OP_PREDICATE):
10747
    *    - an inner predicate operator
10748
    * 2) For filters (XPATH_OP_FILTER):
10749
    *    - an inner filter operator OR
10750
    *    - an expression selecting the node set.
10751
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
10752
    */
10753
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10754
0
  return(0);
10755
10756
0
    if (op->ch2 != -1) {
10757
0
  exprOp = &ctxt->comp->steps[op->ch2];
10758
0
    } else
10759
0
  return(0);
10760
10761
0
    if ((exprOp != NULL) &&
10762
0
  (exprOp->op == XPATH_OP_VALUE) &&
10763
0
  (exprOp->value4 != NULL) &&
10764
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10765
0
    {
10766
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10767
10768
  /*
10769
  * We have a "[n]" predicate here.
10770
  * TODO: Unfortunately this simplistic test here is not
10771
  * able to detect a position() predicate in compound
10772
  * expressions like "[@attr = 'a" and position() = 1],
10773
  * and even not the usage of position() in
10774
  * "[position() = 1]"; thus - obviously - a position-range,
10775
  * like it "[position() < 5]", is also not detected.
10776
  * Maybe we could rewrite the AST to ease the optimization.
10777
  */
10778
10779
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10780
0
      *maxPos = (int) floatval;
10781
0
            if (floatval == (double) *maxPos)
10782
0
                return(1);
10783
0
        }
10784
0
    }
10785
0
    return(0);
10786
0
}
10787
10788
static int
10789
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10790
                           xmlXPathStepOpPtr op,
10791
         xmlNodePtr * first, xmlNodePtr * last,
10792
         int toBool)
10793
0
{
10794
10795
0
#define XP_TEST_HIT \
10796
0
    if (hasAxisRange != 0) { \
10797
0
  if (++pos == maxPos) { \
10798
0
      if (addNode(seq, cur) < 0) \
10799
0
          xmlXPathPErrMemory(ctxt); \
10800
0
      goto axis_range_end; } \
10801
0
    } else { \
10802
0
  if (addNode(seq, cur) < 0) \
10803
0
      xmlXPathPErrMemory(ctxt); \
10804
0
  if (breakOnFirstHit) goto first_hit; }
10805
10806
0
#define XP_TEST_HIT_NS \
10807
0
    if (hasAxisRange != 0) { \
10808
0
  if (++pos == maxPos) { \
10809
0
      hasNsNodes = 1; \
10810
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10811
0
          xmlXPathPErrMemory(ctxt); \
10812
0
  goto axis_range_end; } \
10813
0
    } else { \
10814
0
  hasNsNodes = 1; \
10815
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10816
0
      xmlXPathPErrMemory(ctxt); \
10817
0
  if (breakOnFirstHit) goto first_hit; }
10818
10819
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10820
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10821
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10822
0
    const xmlChar *prefix = op->value4;
10823
0
    const xmlChar *name = op->value5;
10824
0
    const xmlChar *URI = NULL;
10825
10826
0
    int total = 0, hasNsNodes = 0;
10827
    /* The popped object holding the context nodes */
10828
0
    xmlXPathObjectPtr obj;
10829
    /* The set of context nodes for the node tests */
10830
0
    xmlNodeSetPtr contextSeq;
10831
0
    int contextIdx;
10832
0
    xmlNodePtr contextNode;
10833
    /* The final resulting node set wrt to all context nodes */
10834
0
    xmlNodeSetPtr outSeq;
10835
    /*
10836
    * The temporary resulting node set wrt 1 context node.
10837
    * Used to feed predicate evaluation.
10838
    */
10839
0
    xmlNodeSetPtr seq;
10840
0
    xmlNodePtr cur;
10841
    /* First predicate operator */
10842
0
    xmlXPathStepOpPtr predOp;
10843
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
10844
0
    int hasPredicateRange, hasAxisRange, pos;
10845
0
    int breakOnFirstHit;
10846
10847
0
    xmlXPathTraversalFunction next = NULL;
10848
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10849
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
10850
0
    xmlNodePtr oldContextNode;
10851
0
    xmlXPathContextPtr xpctxt = ctxt->context;
10852
10853
10854
0
    CHECK_TYPE0(XPATH_NODESET);
10855
0
    obj = valuePop(ctxt);
10856
    /*
10857
    * Setup namespaces.
10858
    */
10859
0
    if (prefix != NULL) {
10860
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
10861
0
        if (URI == NULL) {
10862
0
      xmlXPathReleaseObject(xpctxt, obj);
10863
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10864
0
  }
10865
0
    }
10866
    /*
10867
    * Setup axis.
10868
    *
10869
    * MAYBE FUTURE TODO: merging optimizations:
10870
    * - If the nodes to be traversed wrt to the initial nodes and
10871
    *   the current axis cannot overlap, then we could avoid searching
10872
    *   for duplicates during the merge.
10873
    *   But the question is how/when to evaluate if they cannot overlap.
10874
    *   Example: if we know that for two initial nodes, the one is
10875
    *   not in the ancestor-or-self axis of the other, then we could safely
10876
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10877
    *   the descendant-or-self axis.
10878
    */
10879
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
10880
0
    switch (axis) {
10881
0
        case AXIS_ANCESTOR:
10882
0
            first = NULL;
10883
0
            next = xmlXPathNextAncestor;
10884
0
            break;
10885
0
        case AXIS_ANCESTOR_OR_SELF:
10886
0
            first = NULL;
10887
0
            next = xmlXPathNextAncestorOrSelf;
10888
0
            break;
10889
0
        case AXIS_ATTRIBUTE:
10890
0
            first = NULL;
10891
0
      last = NULL;
10892
0
            next = xmlXPathNextAttribute;
10893
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10894
0
            break;
10895
0
        case AXIS_CHILD:
10896
0
      last = NULL;
10897
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10898
0
    (type == NODE_TYPE_NODE))
10899
0
      {
10900
    /*
10901
    * Optimization if an element node type is 'element'.
10902
    */
10903
0
    next = xmlXPathNextChildElement;
10904
0
      } else
10905
0
    next = xmlXPathNextChild;
10906
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10907
0
            break;
10908
0
        case AXIS_DESCENDANT:
10909
0
      last = NULL;
10910
0
            next = xmlXPathNextDescendant;
10911
0
            break;
10912
0
        case AXIS_DESCENDANT_OR_SELF:
10913
0
      last = NULL;
10914
0
            next = xmlXPathNextDescendantOrSelf;
10915
0
            break;
10916
0
        case AXIS_FOLLOWING:
10917
0
      last = NULL;
10918
0
            next = xmlXPathNextFollowing;
10919
0
            break;
10920
0
        case AXIS_FOLLOWING_SIBLING:
10921
0
      last = NULL;
10922
0
            next = xmlXPathNextFollowingSibling;
10923
0
            break;
10924
0
        case AXIS_NAMESPACE:
10925
0
            first = NULL;
10926
0
      last = NULL;
10927
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10928
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10929
0
            break;
10930
0
        case AXIS_PARENT:
10931
0
            first = NULL;
10932
0
            next = xmlXPathNextParent;
10933
0
            break;
10934
0
        case AXIS_PRECEDING:
10935
0
            first = NULL;
10936
0
            next = xmlXPathNextPrecedingInternal;
10937
0
            break;
10938
0
        case AXIS_PRECEDING_SIBLING:
10939
0
            first = NULL;
10940
0
            next = xmlXPathNextPrecedingSibling;
10941
0
            break;
10942
0
        case AXIS_SELF:
10943
0
            first = NULL;
10944
0
      last = NULL;
10945
0
            next = xmlXPathNextSelf;
10946
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10947
0
            break;
10948
0
    }
10949
10950
0
    if (next == NULL) {
10951
0
  xmlXPathReleaseObject(xpctxt, obj);
10952
0
        return(0);
10953
0
    }
10954
0
    contextSeq = obj->nodesetval;
10955
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10956
0
        valuePush(ctxt, obj);
10957
0
        return(0);
10958
0
    }
10959
    /*
10960
    * Predicate optimization ---------------------------------------------
10961
    * If this step has a last predicate, which contains a position(),
10962
    * then we'll optimize (although not exactly "position()", but only
10963
    * the  short-hand form, i.e., "[n]".
10964
    *
10965
    * Example - expression "/foo[parent::bar][1]":
10966
    *
10967
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
10968
    *   ROOT                               -- op->ch1
10969
    *   PREDICATE                          -- op->ch2 (predOp)
10970
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
10971
    *       SORT
10972
    *         COLLECT  'parent' 'name' 'node' bar
10973
    *           NODE
10974
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
10975
    *
10976
    */
10977
0
    maxPos = 0;
10978
0
    predOp = NULL;
10979
0
    hasPredicateRange = 0;
10980
0
    hasAxisRange = 0;
10981
0
    if (op->ch2 != -1) {
10982
  /*
10983
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
10984
  */
10985
0
  predOp = &ctxt->comp->steps[op->ch2];
10986
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
10987
0
      if (predOp->ch1 != -1) {
10988
    /*
10989
    * Use the next inner predicate operator.
10990
    */
10991
0
    predOp = &ctxt->comp->steps[predOp->ch1];
10992
0
    hasPredicateRange = 1;
10993
0
      } else {
10994
    /*
10995
    * There's no other predicate than the [n] predicate.
10996
    */
10997
0
    predOp = NULL;
10998
0
    hasAxisRange = 1;
10999
0
      }
11000
0
  }
11001
0
    }
11002
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11003
    /*
11004
    * Axis traversal -----------------------------------------------------
11005
    */
11006
    /*
11007
     * 2.3 Node Tests
11008
     *  - For the attribute axis, the principal node type is attribute.
11009
     *  - For the namespace axis, the principal node type is namespace.
11010
     *  - For other axes, the principal node type is element.
11011
     *
11012
     * A node test * is true for any node of the
11013
     * principal node type. For example, child::* will
11014
     * select all element children of the context node
11015
     */
11016
0
    oldContextNode = xpctxt->node;
11017
0
    addNode = xmlXPathNodeSetAddUnique;
11018
0
    outSeq = NULL;
11019
0
    seq = NULL;
11020
0
    contextNode = NULL;
11021
0
    contextIdx = 0;
11022
11023
11024
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11025
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
11026
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
11027
11028
0
  if (seq == NULL) {
11029
0
      seq = xmlXPathNodeSetCreate(NULL);
11030
0
      if (seq == NULL) {
11031
0
                xmlXPathPErrMemory(ctxt);
11032
0
    total = 0;
11033
0
    goto error;
11034
0
      }
11035
0
  }
11036
  /*
11037
  * Traverse the axis and test the nodes.
11038
  */
11039
0
  pos = 0;
11040
0
  cur = NULL;
11041
0
  hasNsNodes = 0;
11042
0
        do {
11043
0
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
11044
0
                goto error;
11045
11046
0
            cur = next(ctxt, cur);
11047
0
            if (cur == NULL)
11048
0
                break;
11049
11050
      /*
11051
      * QUESTION TODO: What does the "first" and "last" stuff do?
11052
      */
11053
0
            if ((first != NULL) && (*first != NULL)) {
11054
0
    if (*first == cur)
11055
0
        break;
11056
0
    if (((total % 256) == 0) &&
11057
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11058
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
11059
#else
11060
        (xmlXPathCmpNodes(*first, cur) >= 0))
11061
#endif
11062
0
    {
11063
0
        break;
11064
0
    }
11065
0
      }
11066
0
      if ((last != NULL) && (*last != NULL)) {
11067
0
    if (*last == cur)
11068
0
        break;
11069
0
    if (((total % 256) == 0) &&
11070
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11071
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
11072
#else
11073
        (xmlXPathCmpNodes(cur, *last) >= 0))
11074
#endif
11075
0
    {
11076
0
        break;
11077
0
    }
11078
0
      }
11079
11080
0
            total++;
11081
11082
0
      switch (test) {
11083
0
                case NODE_TEST_NONE:
11084
0
        total = 0;
11085
0
        goto error;
11086
0
                case NODE_TEST_TYPE:
11087
0
        if (type == NODE_TYPE_NODE) {
11088
0
      switch (cur->type) {
11089
0
          case XML_DOCUMENT_NODE:
11090
0
          case XML_HTML_DOCUMENT_NODE:
11091
0
          case XML_ELEMENT_NODE:
11092
0
          case XML_ATTRIBUTE_NODE:
11093
0
          case XML_PI_NODE:
11094
0
          case XML_COMMENT_NODE:
11095
0
          case XML_CDATA_SECTION_NODE:
11096
0
          case XML_TEXT_NODE:
11097
0
        XP_TEST_HIT
11098
0
        break;
11099
0
          case XML_NAMESPACE_DECL: {
11100
0
        if (axis == AXIS_NAMESPACE) {
11101
0
            XP_TEST_HIT_NS
11102
0
        } else {
11103
0
                              hasNsNodes = 1;
11104
0
            XP_TEST_HIT
11105
0
        }
11106
0
        break;
11107
0
                            }
11108
0
          default:
11109
0
        break;
11110
0
      }
11111
0
        } else if (cur->type == (xmlElementType) type) {
11112
0
      if (cur->type == XML_NAMESPACE_DECL)
11113
0
          XP_TEST_HIT_NS
11114
0
      else
11115
0
          XP_TEST_HIT
11116
0
        } else if ((type == NODE_TYPE_TEXT) &&
11117
0
       (cur->type == XML_CDATA_SECTION_NODE))
11118
0
        {
11119
0
      XP_TEST_HIT
11120
0
        }
11121
0
        break;
11122
0
                case NODE_TEST_PI:
11123
0
                    if ((cur->type == XML_PI_NODE) &&
11124
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
11125
0
        {
11126
0
      XP_TEST_HIT
11127
0
                    }
11128
0
                    break;
11129
0
                case NODE_TEST_ALL:
11130
0
                    if (axis == AXIS_ATTRIBUTE) {
11131
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
11132
0
      {
11133
0
                            if (prefix == NULL)
11134
0
          {
11135
0
        XP_TEST_HIT
11136
0
                            } else if ((cur->ns != NULL) &&
11137
0
        (xmlStrEqual(URI, cur->ns->href)))
11138
0
          {
11139
0
        XP_TEST_HIT
11140
0
                            }
11141
0
                        }
11142
0
                    } else if (axis == AXIS_NAMESPACE) {
11143
0
                        if (cur->type == XML_NAMESPACE_DECL)
11144
0
      {
11145
0
          XP_TEST_HIT_NS
11146
0
                        }
11147
0
                    } else {
11148
0
                        if (cur->type == XML_ELEMENT_NODE) {
11149
0
                            if (prefix == NULL)
11150
0
          {
11151
0
        XP_TEST_HIT
11152
11153
0
                            } else if ((cur->ns != NULL) &&
11154
0
        (xmlStrEqual(URI, cur->ns->href)))
11155
0
          {
11156
0
        XP_TEST_HIT
11157
0
                            }
11158
0
                        }
11159
0
                    }
11160
0
                    break;
11161
0
                case NODE_TEST_NS:{
11162
                        /* TODO */
11163
0
                        break;
11164
0
                    }
11165
0
                case NODE_TEST_NAME:
11166
0
                    if (axis == AXIS_ATTRIBUTE) {
11167
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
11168
0
          break;
11169
0
        } else if (axis == AXIS_NAMESPACE) {
11170
0
                        if (cur->type != XML_NAMESPACE_DECL)
11171
0
          break;
11172
0
        } else {
11173
0
            if (cur->type != XML_ELEMENT_NODE)
11174
0
          break;
11175
0
        }
11176
0
                    switch (cur->type) {
11177
0
                        case XML_ELEMENT_NODE:
11178
0
                            if (xmlStrEqual(name, cur->name)) {
11179
0
                                if (prefix == NULL) {
11180
0
                                    if (cur->ns == NULL)
11181
0
            {
11182
0
          XP_TEST_HIT
11183
0
                                    }
11184
0
                                } else {
11185
0
                                    if ((cur->ns != NULL) &&
11186
0
                                        (xmlStrEqual(URI, cur->ns->href)))
11187
0
            {
11188
0
          XP_TEST_HIT
11189
0
                                    }
11190
0
                                }
11191
0
                            }
11192
0
                            break;
11193
0
                        case XML_ATTRIBUTE_NODE:{
11194
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
11195
11196
0
                                if (xmlStrEqual(name, attr->name)) {
11197
0
                                    if (prefix == NULL) {
11198
0
                                        if ((attr->ns == NULL) ||
11199
0
                                            (attr->ns->prefix == NULL))
11200
0
          {
11201
0
              XP_TEST_HIT
11202
0
                                        }
11203
0
                                    } else {
11204
0
                                        if ((attr->ns != NULL) &&
11205
0
                                            (xmlStrEqual(URI,
11206
0
                attr->ns->href)))
11207
0
          {
11208
0
              XP_TEST_HIT
11209
0
                                        }
11210
0
                                    }
11211
0
                                }
11212
0
                                break;
11213
0
                            }
11214
0
                        case XML_NAMESPACE_DECL:
11215
0
                            if (cur->type == XML_NAMESPACE_DECL) {
11216
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
11217
11218
0
                                if ((ns->prefix != NULL) && (name != NULL)
11219
0
                                    && (xmlStrEqual(ns->prefix, name)))
11220
0
        {
11221
0
            XP_TEST_HIT_NS
11222
0
                                }
11223
0
                            }
11224
0
                            break;
11225
0
                        default:
11226
0
                            break;
11227
0
                    }
11228
0
                    break;
11229
0
      } /* switch(test) */
11230
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11231
11232
0
  goto apply_predicates;
11233
11234
0
axis_range_end: /* ----------------------------------------------------- */
11235
  /*
11236
  * We have a "/foo[n]", and position() = n was reached.
11237
  * Note that we can have as well "/foo/::parent::foo[1]", so
11238
  * a duplicate-aware merge is still needed.
11239
  * Merge with the result.
11240
  */
11241
0
  if (outSeq == NULL) {
11242
0
      outSeq = seq;
11243
0
      seq = NULL;
11244
0
  } else {
11245
0
      outSeq = mergeAndClear(outSeq, seq);
11246
0
            if (outSeq == NULL)
11247
0
                xmlXPathPErrMemory(ctxt);
11248
0
        }
11249
  /*
11250
  * Break if only a true/false result was requested.
11251
  */
11252
0
  if (toBool)
11253
0
      break;
11254
0
  continue;
11255
11256
0
first_hit: /* ---------------------------------------------------------- */
11257
  /*
11258
  * Break if only a true/false result was requested and
11259
  * no predicates existed and a node test succeeded.
11260
  */
11261
0
  if (outSeq == NULL) {
11262
0
      outSeq = seq;
11263
0
      seq = NULL;
11264
0
  } else {
11265
0
      outSeq = mergeAndClear(outSeq, seq);
11266
0
            if (outSeq == NULL)
11267
0
                xmlXPathPErrMemory(ctxt);
11268
0
        }
11269
0
  break;
11270
11271
0
apply_predicates: /* --------------------------------------------------- */
11272
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
11273
0
      goto error;
11274
11275
        /*
11276
  * Apply predicates.
11277
  */
11278
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
11279
      /*
11280
      * E.g. when we have a "/foo[some expression][n]".
11281
      */
11282
      /*
11283
      * QUESTION TODO: The old predicate evaluation took into
11284
      *  account location-sets.
11285
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11286
      *  Do we expect such a set here?
11287
      *  All what I learned now from the evaluation semantics
11288
      *  does not indicate that a location-set will be processed
11289
      *  here, so this looks OK.
11290
      */
11291
      /*
11292
      * Iterate over all predicates, starting with the outermost
11293
      * predicate.
11294
      * TODO: Problem: we cannot execute the inner predicates first
11295
      *  since we cannot go back *up* the operator tree!
11296
      *  Options we have:
11297
      *  1) Use of recursive functions (like is it currently done
11298
      *     via xmlXPathCompOpEval())
11299
      *  2) Add a predicate evaluation information stack to the
11300
      *     context struct
11301
      *  3) Change the way the operators are linked; we need a
11302
      *     "parent" field on xmlXPathStepOp
11303
      *
11304
      * For the moment, I'll try to solve this with a recursive
11305
      * function: xmlXPathCompOpEvalPredicate().
11306
      */
11307
0
      if (hasPredicateRange != 0)
11308
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11309
0
              hasNsNodes);
11310
0
      else
11311
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11312
0
              hasNsNodes);
11313
11314
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
11315
0
    total = 0;
11316
0
    goto error;
11317
0
      }
11318
0
        }
11319
11320
0
        if (seq->nodeNr > 0) {
11321
      /*
11322
      * Add to result set.
11323
      */
11324
0
      if (outSeq == NULL) {
11325
0
    outSeq = seq;
11326
0
    seq = NULL;
11327
0
      } else {
11328
0
    outSeq = mergeAndClear(outSeq, seq);
11329
0
                if (outSeq == NULL)
11330
0
                    xmlXPathPErrMemory(ctxt);
11331
0
      }
11332
11333
0
            if (toBool)
11334
0
                break;
11335
0
  }
11336
0
    }
11337
11338
0
error:
11339
0
    if ((obj->boolval) && (obj->user != NULL)) {
11340
  /*
11341
  * QUESTION TODO: What does this do and why?
11342
  * TODO: Do we have to do this also for the "error"
11343
  * cleanup further down?
11344
  */
11345
0
  ctxt->value->boolval = 1;
11346
0
  ctxt->value->user = obj->user;
11347
0
  obj->user = NULL;
11348
0
  obj->boolval = 0;
11349
0
    }
11350
0
    xmlXPathReleaseObject(xpctxt, obj);
11351
11352
    /*
11353
    * Ensure we return at least an empty set.
11354
    */
11355
0
    if (outSeq == NULL) {
11356
0
  if ((seq != NULL) && (seq->nodeNr == 0)) {
11357
0
      outSeq = seq;
11358
0
        } else {
11359
0
      outSeq = xmlXPathNodeSetCreate(NULL);
11360
0
            if (outSeq == NULL)
11361
0
                xmlXPathPErrMemory(ctxt);
11362
0
        }
11363
0
    }
11364
0
    if ((seq != NULL) && (seq != outSeq)) {
11365
0
   xmlXPathFreeNodeSet(seq);
11366
0
    }
11367
    /*
11368
    * Hand over the result. Better to push the set also in
11369
    * case of errors.
11370
    */
11371
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
11372
    /*
11373
    * Reset the context node.
11374
    */
11375
0
    xpctxt->node = oldContextNode;
11376
    /*
11377
    * When traversing the namespace axis in "toBool" mode, it's
11378
    * possible that tmpNsList wasn't freed.
11379
    */
11380
0
    if (xpctxt->tmpNsList != NULL) {
11381
0
        xmlFree(xpctxt->tmpNsList);
11382
0
        xpctxt->tmpNsList = NULL;
11383
0
    }
11384
11385
0
    return(total);
11386
0
}
11387
11388
static int
11389
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11390
            xmlXPathStepOpPtr op, xmlNodePtr * first);
11391
11392
/**
11393
 * xmlXPathCompOpEvalFirst:
11394
 * @ctxt:  the XPath parser context with the compiled expression
11395
 * @op:  an XPath compiled operation
11396
 * @first:  the first elem found so far
11397
 *
11398
 * Evaluate the Precompiled XPath operation searching only the first
11399
 * element in document order
11400
 *
11401
 * Returns the number of examined objects.
11402
 */
11403
static int
11404
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11405
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
11406
0
{
11407
0
    int total = 0, cur;
11408
0
    xmlXPathCompExprPtr comp;
11409
0
    xmlXPathObjectPtr arg1, arg2;
11410
11411
0
    CHECK_ERROR0;
11412
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11413
0
        return(0);
11414
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11415
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11416
0
    ctxt->context->depth += 1;
11417
0
    comp = ctxt->comp;
11418
0
    switch (op->op) {
11419
0
        case XPATH_OP_END:
11420
0
            break;
11421
0
        case XPATH_OP_UNION:
11422
0
            total =
11423
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11424
0
                                        first);
11425
0
      CHECK_ERROR0;
11426
0
            if ((ctxt->value != NULL)
11427
0
                && (ctxt->value->type == XPATH_NODESET)
11428
0
                && (ctxt->value->nodesetval != NULL)
11429
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
11430
                /*
11431
                 * limit tree traversing to first node in the result
11432
                 */
11433
    /*
11434
    * OPTIMIZE TODO: This implicitly sorts
11435
    *  the result, even if not needed. E.g. if the argument
11436
    *  of the count() function, no sorting is needed.
11437
    * OPTIMIZE TODO: How do we know if the node-list wasn't
11438
    *  already sorted?
11439
    */
11440
0
    if (ctxt->value->nodesetval->nodeNr > 1)
11441
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
11442
0
                *first = ctxt->value->nodesetval->nodeTab[0];
11443
0
            }
11444
0
            cur =
11445
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11446
0
                                        first);
11447
0
      CHECK_ERROR0;
11448
11449
0
            arg2 = valuePop(ctxt);
11450
0
            arg1 = valuePop(ctxt);
11451
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11452
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11453
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11454
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11455
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11456
0
            }
11457
0
            if ((ctxt->context->opLimit != 0) &&
11458
0
                (((arg1->nodesetval != NULL) &&
11459
0
                  (xmlXPathCheckOpLimit(ctxt,
11460
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11461
0
                 ((arg2->nodesetval != NULL) &&
11462
0
                  (xmlXPathCheckOpLimit(ctxt,
11463
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11464
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11465
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11466
0
                break;
11467
0
            }
11468
11469
0
            if ((arg2->nodesetval != NULL) &&
11470
0
                (arg2->nodesetval->nodeNr != 0)) {
11471
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11472
0
                                                        arg2->nodesetval);
11473
0
                if (arg1->nodesetval == NULL)
11474
0
                    xmlXPathPErrMemory(ctxt);
11475
0
            }
11476
0
            valuePush(ctxt, arg1);
11477
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11478
            /* optimizer */
11479
0
      if (total > cur)
11480
0
    xmlXPathCompSwap(op);
11481
0
            total += cur;
11482
0
            break;
11483
0
        case XPATH_OP_ROOT:
11484
0
            xmlXPathRoot(ctxt);
11485
0
            break;
11486
0
        case XPATH_OP_NODE:
11487
0
            if (op->ch1 != -1)
11488
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11489
0
      CHECK_ERROR0;
11490
0
            if (op->ch2 != -1)
11491
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11492
0
      CHECK_ERROR0;
11493
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11494
0
    ctxt->context->node));
11495
0
            break;
11496
0
        case XPATH_OP_COLLECT:{
11497
0
                if (op->ch1 == -1)
11498
0
                    break;
11499
11500
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11501
0
    CHECK_ERROR0;
11502
11503
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11504
0
                break;
11505
0
            }
11506
0
        case XPATH_OP_VALUE:
11507
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11508
0
            break;
11509
0
        case XPATH_OP_SORT:
11510
0
            if (op->ch1 != -1)
11511
0
                total +=
11512
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11513
0
                                            first);
11514
0
      CHECK_ERROR0;
11515
0
            if ((ctxt->value != NULL)
11516
0
                && (ctxt->value->type == XPATH_NODESET)
11517
0
                && (ctxt->value->nodesetval != NULL)
11518
0
    && (ctxt->value->nodesetval->nodeNr > 1))
11519
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11520
0
            break;
11521
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
11522
0
  case XPATH_OP_FILTER:
11523
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11524
0
            break;
11525
0
#endif
11526
0
        default:
11527
0
            total += xmlXPathCompOpEval(ctxt, op);
11528
0
            break;
11529
0
    }
11530
11531
0
    ctxt->context->depth -= 1;
11532
0
    return(total);
11533
0
}
11534
11535
/**
11536
 * xmlXPathCompOpEvalLast:
11537
 * @ctxt:  the XPath parser context with the compiled expression
11538
 * @op:  an XPath compiled operation
11539
 * @last:  the last elem found so far
11540
 *
11541
 * Evaluate the Precompiled XPath operation searching only the last
11542
 * element in document order
11543
 *
11544
 * Returns the number of nodes traversed
11545
 */
11546
static int
11547
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11548
                       xmlNodePtr * last)
11549
0
{
11550
0
    int total = 0, cur;
11551
0
    xmlXPathCompExprPtr comp;
11552
0
    xmlXPathObjectPtr arg1, arg2;
11553
11554
0
    CHECK_ERROR0;
11555
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11556
0
        return(0);
11557
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11558
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11559
0
    ctxt->context->depth += 1;
11560
0
    comp = ctxt->comp;
11561
0
    switch (op->op) {
11562
0
        case XPATH_OP_END:
11563
0
            break;
11564
0
        case XPATH_OP_UNION:
11565
0
            total =
11566
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11567
0
      CHECK_ERROR0;
11568
0
            if ((ctxt->value != NULL)
11569
0
                && (ctxt->value->type == XPATH_NODESET)
11570
0
                && (ctxt->value->nodesetval != NULL)
11571
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
11572
                /*
11573
                 * limit tree traversing to first node in the result
11574
                 */
11575
0
    if (ctxt->value->nodesetval->nodeNr > 1)
11576
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
11577
0
                *last =
11578
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
11579
0
                                                     nodesetval->nodeNr -
11580
0
                                                     1];
11581
0
            }
11582
0
            cur =
11583
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11584
0
      CHECK_ERROR0;
11585
0
            if ((ctxt->value != NULL)
11586
0
                && (ctxt->value->type == XPATH_NODESET)
11587
0
                && (ctxt->value->nodesetval != NULL)
11588
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11589
0
            }
11590
11591
0
            arg2 = valuePop(ctxt);
11592
0
            arg1 = valuePop(ctxt);
11593
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11594
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11595
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11596
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11597
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11598
0
            }
11599
0
            if ((ctxt->context->opLimit != 0) &&
11600
0
                (((arg1->nodesetval != NULL) &&
11601
0
                  (xmlXPathCheckOpLimit(ctxt,
11602
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11603
0
                 ((arg2->nodesetval != NULL) &&
11604
0
                  (xmlXPathCheckOpLimit(ctxt,
11605
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11606
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11607
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11608
0
                break;
11609
0
            }
11610
11611
0
            if ((arg2->nodesetval != NULL) &&
11612
0
                (arg2->nodesetval->nodeNr != 0)) {
11613
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11614
0
                                                        arg2->nodesetval);
11615
0
                if (arg1->nodesetval == NULL)
11616
0
                    xmlXPathPErrMemory(ctxt);
11617
0
            }
11618
0
            valuePush(ctxt, arg1);
11619
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11620
            /* optimizer */
11621
0
      if (total > cur)
11622
0
    xmlXPathCompSwap(op);
11623
0
            total += cur;
11624
0
            break;
11625
0
        case XPATH_OP_ROOT:
11626
0
            xmlXPathRoot(ctxt);
11627
0
            break;
11628
0
        case XPATH_OP_NODE:
11629
0
            if (op->ch1 != -1)
11630
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11631
0
      CHECK_ERROR0;
11632
0
            if (op->ch2 != -1)
11633
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11634
0
      CHECK_ERROR0;
11635
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11636
0
    ctxt->context->node));
11637
0
            break;
11638
0
        case XPATH_OP_COLLECT:{
11639
0
                if (op->ch1 == -1)
11640
0
                    break;
11641
11642
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11643
0
    CHECK_ERROR0;
11644
11645
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11646
0
                break;
11647
0
            }
11648
0
        case XPATH_OP_VALUE:
11649
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11650
0
            break;
11651
0
        case XPATH_OP_SORT:
11652
0
            if (op->ch1 != -1)
11653
0
                total +=
11654
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11655
0
                                           last);
11656
0
      CHECK_ERROR0;
11657
0
            if ((ctxt->value != NULL)
11658
0
                && (ctxt->value->type == XPATH_NODESET)
11659
0
                && (ctxt->value->nodesetval != NULL)
11660
0
    && (ctxt->value->nodesetval->nodeNr > 1))
11661
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11662
0
            break;
11663
0
        default:
11664
0
            total += xmlXPathCompOpEval(ctxt, op);
11665
0
            break;
11666
0
    }
11667
11668
0
    ctxt->context->depth -= 1;
11669
0
    return (total);
11670
0
}
11671
11672
#ifdef XP_OPTIMIZED_FILTER_FIRST
11673
static int
11674
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11675
            xmlXPathStepOpPtr op, xmlNodePtr * first)
11676
0
{
11677
0
    int total = 0;
11678
0
    xmlXPathCompExprPtr comp;
11679
0
    xmlXPathObjectPtr obj;
11680
0
    xmlNodeSetPtr set;
11681
11682
0
    CHECK_ERROR0;
11683
0
    comp = ctxt->comp;
11684
    /*
11685
    * Optimization for ()[last()] selection i.e. the last elem
11686
    */
11687
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
11688
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11689
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11690
0
  int f = comp->steps[op->ch2].ch1;
11691
11692
0
  if ((f != -1) &&
11693
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11694
0
      (comp->steps[f].value5 == NULL) &&
11695
0
      (comp->steps[f].value == 0) &&
11696
0
      (comp->steps[f].value4 != NULL) &&
11697
0
      (xmlStrEqual
11698
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
11699
0
      xmlNodePtr last = NULL;
11700
11701
0
      total +=
11702
0
    xmlXPathCompOpEvalLast(ctxt,
11703
0
        &comp->steps[op->ch1],
11704
0
        &last);
11705
0
      CHECK_ERROR0;
11706
      /*
11707
      * The nodeset should be in document order,
11708
      * Keep only the last value
11709
      */
11710
0
      if ((ctxt->value != NULL) &&
11711
0
    (ctxt->value->type == XPATH_NODESET) &&
11712
0
    (ctxt->value->nodesetval != NULL) &&
11713
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
11714
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
11715
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11716
0
    *first = *(ctxt->value->nodesetval->nodeTab);
11717
0
      }
11718
0
      return (total);
11719
0
  }
11720
0
    }
11721
11722
0
    if (op->ch1 != -1)
11723
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11724
0
    CHECK_ERROR0;
11725
0
    if (op->ch2 == -1)
11726
0
  return (total);
11727
0
    if (ctxt->value == NULL)
11728
0
  return (total);
11729
11730
#ifdef LIBXML_XPTR_LOCS_ENABLED
11731
    /*
11732
    * Hum are we filtering the result of an XPointer expression
11733
    */
11734
    if (ctxt->value->type == XPATH_LOCATIONSET) {
11735
        xmlLocationSetPtr locset = ctxt->value->user;
11736
11737
        if (locset != NULL) {
11738
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
11739
            if (locset->locNr > 0)
11740
                *first = (xmlNodePtr) locset->locTab[0]->user;
11741
        }
11742
11743
  return (total);
11744
    }
11745
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11746
11747
    /*
11748
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11749
     * the stack. We have to temporarily remove the nodeset object from the
11750
     * stack to avoid freeing it prematurely.
11751
     */
11752
0
    CHECK_TYPE0(XPATH_NODESET);
11753
0
    obj = valuePop(ctxt);
11754
0
    set = obj->nodesetval;
11755
0
    if (set != NULL) {
11756
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11757
0
        if (set->nodeNr > 0)
11758
0
            *first = set->nodeTab[0];
11759
0
    }
11760
0
    valuePush(ctxt, obj);
11761
11762
0
    return (total);
11763
0
}
11764
#endif /* XP_OPTIMIZED_FILTER_FIRST */
11765
11766
/**
11767
 * xmlXPathCompOpEval:
11768
 * @ctxt:  the XPath parser context with the compiled expression
11769
 * @op:  an XPath compiled operation
11770
 *
11771
 * Evaluate the Precompiled XPath operation
11772
 * Returns the number of nodes traversed
11773
 */
11774
static int
11775
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11776
0
{
11777
0
    int total = 0;
11778
0
    int equal, ret;
11779
0
    xmlXPathCompExprPtr comp;
11780
0
    xmlXPathObjectPtr arg1, arg2;
11781
11782
0
    CHECK_ERROR0;
11783
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11784
0
        return(0);
11785
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11786
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11787
0
    ctxt->context->depth += 1;
11788
0
    comp = ctxt->comp;
11789
0
    switch (op->op) {
11790
0
        case XPATH_OP_END:
11791
0
            break;
11792
0
        case XPATH_OP_AND:
11793
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11794
0
      CHECK_ERROR0;
11795
0
            xmlXPathBooleanFunction(ctxt, 1);
11796
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11797
0
                break;
11798
0
            arg2 = valuePop(ctxt);
11799
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11800
0
      if (ctxt->error) {
11801
0
    xmlXPathFreeObject(arg2);
11802
0
    break;
11803
0
      }
11804
0
            xmlXPathBooleanFunction(ctxt, 1);
11805
0
            if (ctxt->value != NULL)
11806
0
                ctxt->value->boolval &= arg2->boolval;
11807
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11808
0
            break;
11809
0
        case XPATH_OP_OR:
11810
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11811
0
      CHECK_ERROR0;
11812
0
            xmlXPathBooleanFunction(ctxt, 1);
11813
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11814
0
                break;
11815
0
            arg2 = valuePop(ctxt);
11816
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11817
0
      if (ctxt->error) {
11818
0
    xmlXPathFreeObject(arg2);
11819
0
    break;
11820
0
      }
11821
0
            xmlXPathBooleanFunction(ctxt, 1);
11822
0
            if (ctxt->value != NULL)
11823
0
                ctxt->value->boolval |= arg2->boolval;
11824
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11825
0
            break;
11826
0
        case XPATH_OP_EQUAL:
11827
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11828
0
      CHECK_ERROR0;
11829
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11830
0
      CHECK_ERROR0;
11831
0
      if (op->value)
11832
0
    equal = xmlXPathEqualValues(ctxt);
11833
0
      else
11834
0
    equal = xmlXPathNotEqualValues(ctxt);
11835
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11836
0
            break;
11837
0
        case XPATH_OP_CMP:
11838
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11839
0
      CHECK_ERROR0;
11840
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11841
0
      CHECK_ERROR0;
11842
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11843
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11844
0
            break;
11845
0
        case XPATH_OP_PLUS:
11846
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11847
0
      CHECK_ERROR0;
11848
0
            if (op->ch2 != -1) {
11849
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11850
0
      }
11851
0
      CHECK_ERROR0;
11852
0
            if (op->value == 0)
11853
0
                xmlXPathSubValues(ctxt);
11854
0
            else if (op->value == 1)
11855
0
                xmlXPathAddValues(ctxt);
11856
0
            else if (op->value == 2)
11857
0
                xmlXPathValueFlipSign(ctxt);
11858
0
            else if (op->value == 3) {
11859
0
                CAST_TO_NUMBER;
11860
0
                CHECK_TYPE0(XPATH_NUMBER);
11861
0
            }
11862
0
            break;
11863
0
        case XPATH_OP_MULT:
11864
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11865
0
      CHECK_ERROR0;
11866
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11867
0
      CHECK_ERROR0;
11868
0
            if (op->value == 0)
11869
0
                xmlXPathMultValues(ctxt);
11870
0
            else if (op->value == 1)
11871
0
                xmlXPathDivValues(ctxt);
11872
0
            else if (op->value == 2)
11873
0
                xmlXPathModValues(ctxt);
11874
0
            break;
11875
0
        case XPATH_OP_UNION:
11876
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11877
0
      CHECK_ERROR0;
11878
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11879
0
      CHECK_ERROR0;
11880
11881
0
            arg2 = valuePop(ctxt);
11882
0
            arg1 = valuePop(ctxt);
11883
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11884
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11885
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11886
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11887
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11888
0
            }
11889
0
            if ((ctxt->context->opLimit != 0) &&
11890
0
                (((arg1->nodesetval != NULL) &&
11891
0
                  (xmlXPathCheckOpLimit(ctxt,
11892
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11893
0
                 ((arg2->nodesetval != NULL) &&
11894
0
                  (xmlXPathCheckOpLimit(ctxt,
11895
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11896
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11897
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11898
0
                break;
11899
0
            }
11900
11901
0
      if (((arg2->nodesetval != NULL) &&
11902
0
     (arg2->nodesetval->nodeNr != 0)))
11903
0
      {
11904
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11905
0
              arg2->nodesetval);
11906
0
                if (arg1->nodesetval == NULL)
11907
0
                    xmlXPathPErrMemory(ctxt);
11908
0
      }
11909
11910
0
            valuePush(ctxt, arg1);
11911
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11912
0
            break;
11913
0
        case XPATH_OP_ROOT:
11914
0
            xmlXPathRoot(ctxt);
11915
0
            break;
11916
0
        case XPATH_OP_NODE:
11917
0
            if (op->ch1 != -1)
11918
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11919
0
      CHECK_ERROR0;
11920
0
            if (op->ch2 != -1)
11921
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11922
0
      CHECK_ERROR0;
11923
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11924
0
                                                    ctxt->context->node));
11925
0
            break;
11926
0
        case XPATH_OP_COLLECT:{
11927
0
                if (op->ch1 == -1)
11928
0
                    break;
11929
11930
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11931
0
    CHECK_ERROR0;
11932
11933
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11934
0
                break;
11935
0
            }
11936
0
        case XPATH_OP_VALUE:
11937
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11938
0
            break;
11939
0
        case XPATH_OP_VARIABLE:{
11940
0
    xmlXPathObjectPtr val;
11941
11942
0
                if (op->ch1 != -1)
11943
0
                    total +=
11944
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11945
0
                if (op->value5 == NULL) {
11946
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
11947
0
        if (val == NULL)
11948
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11949
0
                    valuePush(ctxt, val);
11950
0
    } else {
11951
0
                    const xmlChar *URI;
11952
11953
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
11954
0
                    if (URI == NULL) {
11955
0
                        XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11956
0
                        break;
11957
0
                    }
11958
0
        val = xmlXPathVariableLookupNS(ctxt->context,
11959
0
                                                       op->value4, URI);
11960
0
        if (val == NULL)
11961
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11962
0
                    valuePush(ctxt, val);
11963
0
                }
11964
0
                break;
11965
0
            }
11966
0
        case XPATH_OP_FUNCTION:{
11967
0
                xmlXPathFunction func;
11968
0
                const xmlChar *oldFunc, *oldFuncURI;
11969
0
    int i;
11970
0
                int frame;
11971
11972
0
                frame = ctxt->valueNr;
11973
0
                if (op->ch1 != -1) {
11974
0
                    total +=
11975
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11976
0
                    if (ctxt->error != XPATH_EXPRESSION_OK)
11977
0
                        break;
11978
0
                }
11979
0
    if (ctxt->valueNr < frame + op->value)
11980
0
        XP_ERROR0(XPATH_INVALID_OPERAND);
11981
0
    for (i = 0; i < op->value; i++) {
11982
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
11983
0
      XP_ERROR0(XPATH_INVALID_OPERAND);
11984
0
                }
11985
0
                if (op->cache != NULL)
11986
0
                    func = op->cache;
11987
0
                else {
11988
0
                    const xmlChar *URI = NULL;
11989
11990
0
                    if (op->value5 == NULL)
11991
0
                        func =
11992
0
                            xmlXPathFunctionLookup(ctxt->context,
11993
0
                                                   op->value4);
11994
0
                    else {
11995
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
11996
0
                        if (URI == NULL)
11997
0
                            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11998
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
11999
0
                                                        op->value4, URI);
12000
0
                    }
12001
0
                    if (func == NULL)
12002
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12003
0
                    op->cache = func;
12004
0
                    op->cacheURI = (void *) URI;
12005
0
                }
12006
0
                oldFunc = ctxt->context->function;
12007
0
                oldFuncURI = ctxt->context->functionURI;
12008
0
                ctxt->context->function = op->value4;
12009
0
                ctxt->context->functionURI = op->cacheURI;
12010
0
                func(ctxt, op->value);
12011
0
                ctxt->context->function = oldFunc;
12012
0
                ctxt->context->functionURI = oldFuncURI;
12013
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12014
0
                    (ctxt->valueNr != frame + 1))
12015
0
                    XP_ERROR0(XPATH_STACK_ERROR);
12016
0
                break;
12017
0
            }
12018
0
        case XPATH_OP_ARG:
12019
0
            if (op->ch1 != -1) {
12020
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12021
0
          CHECK_ERROR0;
12022
0
            }
12023
0
            if (op->ch2 != -1) {
12024
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12025
0
          CHECK_ERROR0;
12026
0
      }
12027
0
            break;
12028
0
        case XPATH_OP_PREDICATE:
12029
0
        case XPATH_OP_FILTER:{
12030
0
                xmlXPathObjectPtr obj;
12031
0
                xmlNodeSetPtr set;
12032
12033
                /*
12034
                 * Optimization for ()[1] selection i.e. the first elem
12035
                 */
12036
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
12037
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12038
        /*
12039
        * FILTER TODO: Can we assume that the inner processing
12040
        *  will result in an ordered list if we have an
12041
        *  XPATH_OP_FILTER?
12042
        *  What about an additional field or flag on
12043
        *  xmlXPathObject like @sorted ? This way we wouldn't need
12044
        *  to assume anything, so it would be more robust and
12045
        *  easier to optimize.
12046
        */
12047
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12048
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12049
#else
12050
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12051
#endif
12052
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12053
0
                    xmlXPathObjectPtr val;
12054
12055
0
                    val = comp->steps[op->ch2].value4;
12056
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12057
0
                        (val->floatval == 1.0)) {
12058
0
                        xmlNodePtr first = NULL;
12059
12060
0
                        total +=
12061
0
                            xmlXPathCompOpEvalFirst(ctxt,
12062
0
                                                    &comp->steps[op->ch1],
12063
0
                                                    &first);
12064
0
      CHECK_ERROR0;
12065
                        /*
12066
                         * The nodeset should be in document order,
12067
                         * Keep only the first value
12068
                         */
12069
0
                        if ((ctxt->value != NULL) &&
12070
0
                            (ctxt->value->type == XPATH_NODESET) &&
12071
0
                            (ctxt->value->nodesetval != NULL) &&
12072
0
                            (ctxt->value->nodesetval->nodeNr > 1))
12073
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12074
0
                                                        1, 1);
12075
0
                        break;
12076
0
                    }
12077
0
                }
12078
                /*
12079
                 * Optimization for ()[last()] selection i.e. the last elem
12080
                 */
12081
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
12082
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12083
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12084
0
                    int f = comp->steps[op->ch2].ch1;
12085
12086
0
                    if ((f != -1) &&
12087
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12088
0
                        (comp->steps[f].value5 == NULL) &&
12089
0
                        (comp->steps[f].value == 0) &&
12090
0
                        (comp->steps[f].value4 != NULL) &&
12091
0
                        (xmlStrEqual
12092
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
12093
0
                        xmlNodePtr last = NULL;
12094
12095
0
                        total +=
12096
0
                            xmlXPathCompOpEvalLast(ctxt,
12097
0
                                                   &comp->steps[op->ch1],
12098
0
                                                   &last);
12099
0
      CHECK_ERROR0;
12100
                        /*
12101
                         * The nodeset should be in document order,
12102
                         * Keep only the last value
12103
                         */
12104
0
                        if ((ctxt->value != NULL) &&
12105
0
                            (ctxt->value->type == XPATH_NODESET) &&
12106
0
                            (ctxt->value->nodesetval != NULL) &&
12107
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
12108
0
                            (ctxt->value->nodesetval->nodeNr > 1))
12109
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12110
0
                        break;
12111
0
                    }
12112
0
                }
12113
    /*
12114
    * Process inner predicates first.
12115
    * Example "index[parent::book][1]":
12116
    * ...
12117
    *   PREDICATE   <-- we are here "[1]"
12118
    *     PREDICATE <-- process "[parent::book]" first
12119
    *       SORT
12120
    *         COLLECT  'parent' 'name' 'node' book
12121
    *           NODE
12122
    *     ELEM Object is a number : 1
12123
    */
12124
0
                if (op->ch1 != -1)
12125
0
                    total +=
12126
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12127
0
    CHECK_ERROR0;
12128
0
                if (op->ch2 == -1)
12129
0
                    break;
12130
0
                if (ctxt->value == NULL)
12131
0
                    break;
12132
12133
#ifdef LIBXML_XPTR_LOCS_ENABLED
12134
                /*
12135
                 * Hum are we filtering the result of an XPointer expression
12136
                 */
12137
                if (ctxt->value->type == XPATH_LOCATIONSET) {
12138
                    xmlLocationSetPtr locset = ctxt->value->user;
12139
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12140
                                              1, locset->locNr);
12141
                    break;
12142
                }
12143
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12144
12145
                /*
12146
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
12147
                 * nodes from the stack. We have to temporarily remove the
12148
                 * nodeset object from the stack to avoid freeing it
12149
                 * prematurely.
12150
                 */
12151
0
                CHECK_TYPE0(XPATH_NODESET);
12152
0
                obj = valuePop(ctxt);
12153
0
                set = obj->nodesetval;
12154
0
                if (set != NULL)
12155
0
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12156
0
                                          1, set->nodeNr, 1);
12157
0
                valuePush(ctxt, obj);
12158
0
                break;
12159
0
            }
12160
0
        case XPATH_OP_SORT:
12161
0
            if (op->ch1 != -1)
12162
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12163
0
      CHECK_ERROR0;
12164
0
            if ((ctxt->value != NULL) &&
12165
0
                (ctxt->value->type == XPATH_NODESET) &&
12166
0
                (ctxt->value->nodesetval != NULL) &&
12167
0
    (ctxt->value->nodesetval->nodeNr > 1))
12168
0
      {
12169
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12170
0
      }
12171
0
            break;
12172
#ifdef LIBXML_XPTR_LOCS_ENABLED
12173
        case XPATH_OP_RANGETO:{
12174
                xmlXPathObjectPtr range;
12175
                xmlXPathObjectPtr res, obj;
12176
                xmlXPathObjectPtr tmp;
12177
                xmlLocationSetPtr newlocset = NULL;
12178
        xmlLocationSetPtr oldlocset;
12179
                xmlNodeSetPtr oldset;
12180
                xmlNodePtr oldnode = ctxt->context->node;
12181
                int oldcs = ctxt->context->contextSize;
12182
                int oldpp = ctxt->context->proximityPosition;
12183
                int i, j;
12184
12185
                if (op->ch1 != -1) {
12186
                    total +=
12187
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12188
                    CHECK_ERROR0;
12189
                }
12190
                if (ctxt->value == NULL) {
12191
                    XP_ERROR0(XPATH_INVALID_OPERAND);
12192
                }
12193
                if (op->ch2 == -1)
12194
                    break;
12195
12196
                if (ctxt->value->type == XPATH_LOCATIONSET) {
12197
                    /*
12198
                     * Extract the old locset, and then evaluate the result of the
12199
                     * expression for all the element in the locset. use it to grow
12200
                     * up a new locset.
12201
                     */
12202
                    CHECK_TYPE0(XPATH_LOCATIONSET);
12203
12204
                    if ((ctxt->value->user == NULL) ||
12205
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12206
                        break;
12207
12208
                    obj = valuePop(ctxt);
12209
                    oldlocset = obj->user;
12210
12211
                    newlocset = xmlXPtrLocationSetCreate(NULL);
12212
12213
                    for (i = 0; i < oldlocset->locNr; i++) {
12214
                        /*
12215
                         * Run the evaluation with a node list made of a
12216
                         * single item in the nodelocset.
12217
                         */
12218
                        ctxt->context->node = oldlocset->locTab[i]->user;
12219
                        ctxt->context->contextSize = oldlocset->locNr;
12220
                        ctxt->context->proximityPosition = i + 1;
12221
                        tmp = xmlXPathCacheNewNodeSet(ctxt,
12222
                                                      ctxt->context->node);
12223
                        valuePush(ctxt, tmp);
12224
12225
                        if (op->ch2 != -1)
12226
                            total +=
12227
                                xmlXPathCompOpEval(ctxt,
12228
                                                   &comp->steps[op->ch2]);
12229
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12230
                            xmlXPtrFreeLocationSet(newlocset);
12231
                            goto rangeto_error;
12232
      }
12233
12234
                        res = valuePop(ctxt);
12235
      if (res->type == XPATH_LOCATIONSET) {
12236
          xmlLocationSetPtr rloc =
12237
              (xmlLocationSetPtr)res->user;
12238
          for (j=0; j<rloc->locNr; j++) {
12239
              range = xmlXPtrNewRange(
12240
          oldlocset->locTab[i]->user,
12241
          oldlocset->locTab[i]->index,
12242
          rloc->locTab[j]->user2,
12243
          rloc->locTab[j]->index2);
12244
        if (range != NULL) {
12245
            xmlXPtrLocationSetAdd(newlocset, range);
12246
        }
12247
          }
12248
      } else {
12249
          range = xmlXPtrNewRangeNodeObject(
12250
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
12251
                            if (range != NULL) {
12252
                                xmlXPtrLocationSetAdd(newlocset,range);
12253
          }
12254
                        }
12255
12256
                        /*
12257
                         * Cleanup
12258
                         */
12259
                        if (res != NULL) {
12260
          xmlXPathReleaseObject(ctxt->context, res);
12261
      }
12262
                        if (ctxt->value == tmp) {
12263
                            res = valuePop(ctxt);
12264
          xmlXPathReleaseObject(ctxt->context, res);
12265
                        }
12266
                    }
12267
    } else {  /* Not a location set */
12268
                    CHECK_TYPE0(XPATH_NODESET);
12269
                    obj = valuePop(ctxt);
12270
                    oldset = obj->nodesetval;
12271
12272
                    newlocset = xmlXPtrLocationSetCreate(NULL);
12273
12274
                    if (oldset != NULL) {
12275
                        for (i = 0; i < oldset->nodeNr; i++) {
12276
                            /*
12277
                             * Run the evaluation with a node list made of a single item
12278
                             * in the nodeset.
12279
                             */
12280
                            ctxt->context->node = oldset->nodeTab[i];
12281
          /*
12282
          * OPTIMIZE TODO: Avoid recreation for every iteration.
12283
          */
12284
                            tmp = xmlXPathCacheNewNodeSet(ctxt,
12285
                                                          ctxt->context->node);
12286
                            valuePush(ctxt, tmp);
12287
12288
                            if (op->ch2 != -1)
12289
                                total +=
12290
                                    xmlXPathCompOpEval(ctxt,
12291
                                                   &comp->steps[op->ch2]);
12292
          if (ctxt->error != XPATH_EXPRESSION_OK) {
12293
                                xmlXPtrFreeLocationSet(newlocset);
12294
                                goto rangeto_error;
12295
          }
12296
12297
                            res = valuePop(ctxt);
12298
                            range =
12299
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12300
                                                      res);
12301
                            if (range != NULL) {
12302
                                xmlXPtrLocationSetAdd(newlocset, range);
12303
                            }
12304
12305
                            /*
12306
                             * Cleanup
12307
                             */
12308
                            if (res != NULL) {
12309
        xmlXPathReleaseObject(ctxt->context, res);
12310
          }
12311
                            if (ctxt->value == tmp) {
12312
                                res = valuePop(ctxt);
12313
        xmlXPathReleaseObject(ctxt->context, res);
12314
                            }
12315
                        }
12316
                    }
12317
                }
12318
12319
                /*
12320
                 * The result is used as the new evaluation set.
12321
                 */
12322
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12323
rangeto_error:
12324
    xmlXPathReleaseObject(ctxt->context, obj);
12325
                ctxt->context->node = oldnode;
12326
                ctxt->context->contextSize = oldcs;
12327
                ctxt->context->proximityPosition = oldpp;
12328
                break;
12329
            }
12330
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12331
0
        default:
12332
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
12333
0
            break;
12334
0
    }
12335
12336
0
    ctxt->context->depth -= 1;
12337
0
    return (total);
12338
0
}
12339
12340
/**
12341
 * xmlXPathCompOpEvalToBoolean:
12342
 * @ctxt:  the XPath parser context
12343
 *
12344
 * Evaluates if the expression evaluates to true.
12345
 *
12346
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
12347
 */
12348
static int
12349
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12350
          xmlXPathStepOpPtr op,
12351
          int isPredicate)
12352
0
{
12353
0
    xmlXPathObjectPtr resObj = NULL;
12354
12355
0
start:
12356
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12357
0
        return(0);
12358
    /* comp = ctxt->comp; */
12359
0
    switch (op->op) {
12360
0
        case XPATH_OP_END:
12361
0
            return (0);
12362
0
  case XPATH_OP_VALUE:
12363
0
      resObj = (xmlXPathObjectPtr) op->value4;
12364
0
      if (isPredicate)
12365
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12366
0
      return(xmlXPathCastToBoolean(resObj));
12367
0
  case XPATH_OP_SORT:
12368
      /*
12369
      * We don't need sorting for boolean results. Skip this one.
12370
      */
12371
0
            if (op->ch1 != -1) {
12372
0
    op = &ctxt->comp->steps[op->ch1];
12373
0
    goto start;
12374
0
      }
12375
0
      return(0);
12376
0
  case XPATH_OP_COLLECT:
12377
0
      if (op->ch1 == -1)
12378
0
    return(0);
12379
12380
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12381
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12382
0
    return(-1);
12383
12384
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12385
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12386
0
    return(-1);
12387
12388
0
      resObj = valuePop(ctxt);
12389
0
      if (resObj == NULL)
12390
0
    return(-1);
12391
0
      break;
12392
0
  default:
12393
      /*
12394
      * Fallback to call xmlXPathCompOpEval().
12395
      */
12396
0
      xmlXPathCompOpEval(ctxt, op);
12397
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12398
0
    return(-1);
12399
12400
0
      resObj = valuePop(ctxt);
12401
0
      if (resObj == NULL)
12402
0
    return(-1);
12403
0
      break;
12404
0
    }
12405
12406
0
    if (resObj) {
12407
0
  int res;
12408
12409
0
  if (resObj->type == XPATH_BOOLEAN) {
12410
0
      res = resObj->boolval;
12411
0
  } else if (isPredicate) {
12412
      /*
12413
      * For predicates a result of type "number" is handled
12414
      * differently:
12415
      * SPEC XPath 1.0:
12416
      * "If the result is a number, the result will be converted
12417
      *  to true if the number is equal to the context position
12418
      *  and will be converted to false otherwise;"
12419
      */
12420
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12421
0
  } else {
12422
0
      res = xmlXPathCastToBoolean(resObj);
12423
0
  }
12424
0
  xmlXPathReleaseObject(ctxt->context, resObj);
12425
0
  return(res);
12426
0
    }
12427
12428
0
    return(0);
12429
0
}
12430
12431
#ifdef XPATH_STREAMING
12432
/**
12433
 * xmlXPathRunStreamEval:
12434
 * @pctxt:  the XPath parser context with the compiled expression
12435
 *
12436
 * Evaluate the Precompiled Streamable XPath expression in the given context.
12437
 */
12438
static int
12439
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
12440
          xmlXPathObjectPtr *resultSeq, int toBool)
12441
{
12442
    int max_depth, min_depth;
12443
    int from_root;
12444
    int ret, depth;
12445
    int eval_all_nodes;
12446
    xmlNodePtr cur = NULL, limit = NULL;
12447
    xmlStreamCtxtPtr patstream = NULL;
12448
    xmlXPathContextPtr ctxt = pctxt->context;
12449
12450
    if ((ctxt == NULL) || (comp == NULL))
12451
        return(-1);
12452
    max_depth = xmlPatternMaxDepth(comp);
12453
    if (max_depth == -1)
12454
        return(-1);
12455
    if (max_depth == -2)
12456
        max_depth = 10000;
12457
    min_depth = xmlPatternMinDepth(comp);
12458
    if (min_depth == -1)
12459
        return(-1);
12460
    from_root = xmlPatternFromRoot(comp);
12461
    if (from_root < 0)
12462
        return(-1);
12463
#if 0
12464
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12465
#endif
12466
12467
    if (! toBool) {
12468
  if (resultSeq == NULL)
12469
      return(-1);
12470
  *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
12471
  if (*resultSeq == NULL)
12472
      return(-1);
12473
    }
12474
12475
    /*
12476
     * handle the special cases of "/" amd "." being matched
12477
     */
12478
    if (min_depth == 0) {
12479
        int res;
12480
12481
  if (from_root) {
12482
      /* Select "/" */
12483
      if (toBool)
12484
    return(1);
12485
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12486
                                           (xmlNodePtr) ctxt->doc);
12487
  } else {
12488
      /* Select "self::node()" */
12489
      if (toBool)
12490
    return(1);
12491
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12492
                                           ctxt->node);
12493
  }
12494
12495
        if (res < 0)
12496
            xmlXPathPErrMemory(pctxt);
12497
    }
12498
    if (max_depth == 0) {
12499
  return(0);
12500
    }
12501
12502
    if (from_root) {
12503
        cur = (xmlNodePtr)ctxt->doc;
12504
    } else if (ctxt->node != NULL) {
12505
        switch (ctxt->node->type) {
12506
            case XML_ELEMENT_NODE:
12507
            case XML_DOCUMENT_NODE:
12508
            case XML_DOCUMENT_FRAG_NODE:
12509
            case XML_HTML_DOCUMENT_NODE:
12510
          cur = ctxt->node;
12511
    break;
12512
            case XML_ATTRIBUTE_NODE:
12513
            case XML_TEXT_NODE:
12514
            case XML_CDATA_SECTION_NODE:
12515
            case XML_ENTITY_REF_NODE:
12516
            case XML_ENTITY_NODE:
12517
            case XML_PI_NODE:
12518
            case XML_COMMENT_NODE:
12519
            case XML_NOTATION_NODE:
12520
            case XML_DTD_NODE:
12521
            case XML_DOCUMENT_TYPE_NODE:
12522
            case XML_ELEMENT_DECL:
12523
            case XML_ATTRIBUTE_DECL:
12524
            case XML_ENTITY_DECL:
12525
            case XML_NAMESPACE_DECL:
12526
            case XML_XINCLUDE_START:
12527
            case XML_XINCLUDE_END:
12528
    break;
12529
  }
12530
  limit = cur;
12531
    }
12532
    if (cur == NULL) {
12533
        return(0);
12534
    }
12535
12536
    patstream = xmlPatternGetStreamCtxt(comp);
12537
    if (patstream == NULL) {
12538
        xmlXPathPErrMemory(pctxt);
12539
  return(-1);
12540
    }
12541
12542
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12543
12544
    if (from_root) {
12545
  ret = xmlStreamPush(patstream, NULL, NULL);
12546
  if (ret < 0) {
12547
  } else if (ret == 1) {
12548
      if (toBool)
12549
    goto return_1;
12550
      if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
12551
                xmlXPathPErrMemory(pctxt);
12552
  }
12553
    }
12554
    depth = 0;
12555
    goto scan_children;
12556
next_node:
12557
    do {
12558
        if (ctxt->opLimit != 0) {
12559
            if (ctxt->opCount >= ctxt->opLimit) {
12560
                xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
12561
                xmlFreeStreamCtxt(patstream);
12562
                return(-1);
12563
            }
12564
            ctxt->opCount++;
12565
        }
12566
12567
  switch (cur->type) {
12568
      case XML_ELEMENT_NODE:
12569
      case XML_TEXT_NODE:
12570
      case XML_CDATA_SECTION_NODE:
12571
      case XML_COMMENT_NODE:
12572
      case XML_PI_NODE:
12573
    if (cur->type == XML_ELEMENT_NODE) {
12574
        ret = xmlStreamPush(patstream, cur->name,
12575
        (cur->ns ? cur->ns->href : NULL));
12576
    } else if (eval_all_nodes)
12577
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12578
    else
12579
        break;
12580
12581
    if (ret < 0) {
12582
        xmlXPathPErrMemory(pctxt);
12583
    } else if (ret == 1) {
12584
        if (toBool)
12585
      goto return_1;
12586
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12587
                                                 cur) < 0)
12588
                        xmlXPathPErrMemory(pctxt);
12589
    }
12590
    if ((cur->children == NULL) || (depth >= max_depth)) {
12591
        ret = xmlStreamPop(patstream);
12592
        while (cur->next != NULL) {
12593
      cur = cur->next;
12594
      if ((cur->type != XML_ENTITY_DECL) &&
12595
          (cur->type != XML_DTD_NODE))
12596
          goto next_node;
12597
        }
12598
    }
12599
      default:
12600
    break;
12601
  }
12602
12603
scan_children:
12604
  if (cur->type == XML_NAMESPACE_DECL) break;
12605
  if ((cur->children != NULL) && (depth < max_depth)) {
12606
      /*
12607
       * Do not descend on entities declarations
12608
       */
12609
      if (cur->children->type != XML_ENTITY_DECL) {
12610
    cur = cur->children;
12611
    depth++;
12612
    /*
12613
     * Skip DTDs
12614
     */
12615
    if (cur->type != XML_DTD_NODE)
12616
        continue;
12617
      }
12618
  }
12619
12620
  if (cur == limit)
12621
      break;
12622
12623
  while (cur->next != NULL) {
12624
      cur = cur->next;
12625
      if ((cur->type != XML_ENTITY_DECL) &&
12626
    (cur->type != XML_DTD_NODE))
12627
    goto next_node;
12628
  }
12629
12630
  do {
12631
      cur = cur->parent;
12632
      depth--;
12633
      if ((cur == NULL) || (cur == limit) ||
12634
                (cur->type == XML_DOCUMENT_NODE))
12635
          goto done;
12636
      if (cur->type == XML_ELEMENT_NODE) {
12637
    ret = xmlStreamPop(patstream);
12638
      } else if ((eval_all_nodes) &&
12639
    ((cur->type == XML_TEXT_NODE) ||
12640
     (cur->type == XML_CDATA_SECTION_NODE) ||
12641
     (cur->type == XML_COMMENT_NODE) ||
12642
     (cur->type == XML_PI_NODE)))
12643
      {
12644
    ret = xmlStreamPop(patstream);
12645
      }
12646
      if (cur->next != NULL) {
12647
    cur = cur->next;
12648
    break;
12649
      }
12650
  } while (cur != NULL);
12651
12652
    } while ((cur != NULL) && (depth >= 0));
12653
12654
done:
12655
12656
    if (patstream)
12657
  xmlFreeStreamCtxt(patstream);
12658
    return(0);
12659
12660
return_1:
12661
    if (patstream)
12662
  xmlFreeStreamCtxt(patstream);
12663
    return(1);
12664
}
12665
#endif /* XPATH_STREAMING */
12666
12667
/**
12668
 * xmlXPathRunEval:
12669
 * @ctxt:  the XPath parser context with the compiled expression
12670
 * @toBool:  evaluate to a boolean result
12671
 *
12672
 * Evaluate the Precompiled XPath expression in the given context.
12673
 */
12674
static int
12675
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12676
0
{
12677
0
    xmlXPathCompExprPtr comp;
12678
0
    int oldDepth;
12679
12680
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
12681
0
  return(-1);
12682
12683
0
    if (ctxt->valueTab == NULL) {
12684
  /* Allocate the value stack */
12685
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
12686
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12687
0
  if (ctxt->valueTab == NULL) {
12688
0
      xmlXPathPErrMemory(ctxt);
12689
0
      return(-1);
12690
0
  }
12691
0
  ctxt->valueNr = 0;
12692
0
  ctxt->valueMax = 10;
12693
0
  ctxt->value = NULL;
12694
0
    }
12695
#ifdef XPATH_STREAMING
12696
    if (ctxt->comp->stream) {
12697
  int res;
12698
12699
  if (toBool) {
12700
      /*
12701
      * Evaluation to boolean result.
12702
      */
12703
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12704
      if (res != -1)
12705
    return(res);
12706
  } else {
12707
      xmlXPathObjectPtr resObj = NULL;
12708
12709
      /*
12710
      * Evaluation to a sequence.
12711
      */
12712
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12713
12714
      if ((res != -1) && (resObj != NULL)) {
12715
    valuePush(ctxt, resObj);
12716
    return(0);
12717
      }
12718
      if (resObj != NULL)
12719
    xmlXPathReleaseObject(ctxt->context, resObj);
12720
  }
12721
  /*
12722
  * QUESTION TODO: This falls back to normal XPath evaluation
12723
  * if res == -1. Is this intended?
12724
  */
12725
    }
12726
#endif
12727
0
    comp = ctxt->comp;
12728
0
    if (comp->last < 0) {
12729
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12730
0
  return(-1);
12731
0
    }
12732
0
    oldDepth = ctxt->context->depth;
12733
0
    if (toBool)
12734
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
12735
0
      &comp->steps[comp->last], 0));
12736
0
    else
12737
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12738
0
    ctxt->context->depth = oldDepth;
12739
12740
0
    return(0);
12741
0
}
12742
12743
/************************************************************************
12744
 *                  *
12745
 *      Public interfaces       *
12746
 *                  *
12747
 ************************************************************************/
12748
12749
/**
12750
 * xmlXPathEvalPredicate:
12751
 * @ctxt:  the XPath context
12752
 * @res:  the Predicate Expression evaluation result
12753
 *
12754
 * Evaluate a predicate result for the current node.
12755
 * A PredicateExpr is evaluated by evaluating the Expr and converting
12756
 * the result to a boolean. If the result is a number, the result will
12757
 * be converted to true if the number is equal to the position of the
12758
 * context node in the context node list (as returned by the position
12759
 * function) and will be converted to false otherwise; if the result
12760
 * is not a number, then the result will be converted as if by a call
12761
 * to the boolean function.
12762
 *
12763
 * Returns 1 if predicate is true, 0 otherwise
12764
 */
12765
int
12766
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12767
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
12768
0
    switch (res->type) {
12769
0
        case XPATH_BOOLEAN:
12770
0
      return(res->boolval);
12771
0
        case XPATH_NUMBER:
12772
0
      return(res->floatval == ctxt->proximityPosition);
12773
0
        case XPATH_NODESET:
12774
0
        case XPATH_XSLT_TREE:
12775
0
      if (res->nodesetval == NULL)
12776
0
    return(0);
12777
0
      return(res->nodesetval->nodeNr != 0);
12778
0
        case XPATH_STRING:
12779
0
      return((res->stringval != NULL) &&
12780
0
             (xmlStrlen(res->stringval) != 0));
12781
0
        default:
12782
0
      break;
12783
0
    }
12784
0
    return(0);
12785
0
}
12786
12787
/**
12788
 * xmlXPathEvaluatePredicateResult:
12789
 * @ctxt:  the XPath Parser context
12790
 * @res:  the Predicate Expression evaluation result
12791
 *
12792
 * Evaluate a predicate result for the current node.
12793
 * A PredicateExpr is evaluated by evaluating the Expr and converting
12794
 * the result to a boolean. If the result is a number, the result will
12795
 * be converted to true if the number is equal to the position of the
12796
 * context node in the context node list (as returned by the position
12797
 * function) and will be converted to false otherwise; if the result
12798
 * is not a number, then the result will be converted as if by a call
12799
 * to the boolean function.
12800
 *
12801
 * Returns 1 if predicate is true, 0 otherwise
12802
 */
12803
int
12804
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12805
0
                                xmlXPathObjectPtr res) {
12806
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
12807
0
    switch (res->type) {
12808
0
        case XPATH_BOOLEAN:
12809
0
      return(res->boolval);
12810
0
        case XPATH_NUMBER:
12811
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12812
      return((res->floatval == ctxt->context->proximityPosition) &&
12813
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12814
#else
12815
0
      return(res->floatval == ctxt->context->proximityPosition);
12816
0
#endif
12817
0
        case XPATH_NODESET:
12818
0
        case XPATH_XSLT_TREE:
12819
0
      if (res->nodesetval == NULL)
12820
0
    return(0);
12821
0
      return(res->nodesetval->nodeNr != 0);
12822
0
        case XPATH_STRING:
12823
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
12824
#ifdef LIBXML_XPTR_LOCS_ENABLED
12825
  case XPATH_LOCATIONSET:{
12826
      xmlLocationSetPtr ptr = res->user;
12827
      if (ptr == NULL)
12828
          return(0);
12829
      return (ptr->locNr != 0);
12830
      }
12831
#endif
12832
0
        default:
12833
0
      break;
12834
0
    }
12835
0
    return(0);
12836
0
}
12837
12838
#ifdef XPATH_STREAMING
12839
/**
12840
 * xmlXPathTryStreamCompile:
12841
 * @ctxt: an XPath context
12842
 * @str:  the XPath expression
12843
 *
12844
 * Try to compile the XPath expression as a streamable subset.
12845
 *
12846
 * Returns the compiled expression or NULL if failed to compile.
12847
 */
12848
static xmlXPathCompExprPtr
12849
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12850
    /*
12851
     * Optimization: use streaming patterns when the XPath expression can
12852
     * be compiled to a stream lookup
12853
     */
12854
    xmlPatternPtr stream;
12855
    xmlXPathCompExprPtr comp;
12856
    xmlDictPtr dict = NULL;
12857
    const xmlChar **namespaces = NULL;
12858
    xmlNsPtr ns;
12859
    int i, j;
12860
12861
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12862
        (!xmlStrchr(str, '@'))) {
12863
  const xmlChar *tmp;
12864
        int res;
12865
12866
  /*
12867
   * We don't try to handle expressions using the verbose axis
12868
   * specifiers ("::"), just the simplified form at this point.
12869
   * Additionally, if there is no list of namespaces available and
12870
   *  there's a ":" in the expression, indicating a prefixed QName,
12871
   *  then we won't try to compile either. xmlPatterncompile() needs
12872
   *  to have a list of namespaces at compilation time in order to
12873
   *  compile prefixed name tests.
12874
   */
12875
  tmp = xmlStrchr(str, ':');
12876
  if ((tmp != NULL) &&
12877
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12878
      return(NULL);
12879
12880
  if (ctxt != NULL) {
12881
      dict = ctxt->dict;
12882
      if (ctxt->nsNr > 0) {
12883
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12884
    if (namespaces == NULL) {
12885
        xmlXPathErrMemory(ctxt);
12886
        return(NULL);
12887
    }
12888
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12889
        ns = ctxt->namespaces[j];
12890
        namespaces[i++] = ns->href;
12891
        namespaces[i++] = ns->prefix;
12892
    }
12893
    namespaces[i++] = NULL;
12894
    namespaces[i] = NULL;
12895
      }
12896
  }
12897
12898
  res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12899
                                    &stream);
12900
  if (namespaces != NULL) {
12901
      xmlFree((xmlChar **)namespaces);
12902
  }
12903
        if (res < 0) {
12904
            xmlXPathErrMemory(ctxt);
12905
            return(NULL);
12906
        }
12907
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12908
      comp = xmlXPathNewCompExpr();
12909
      if (comp == NULL) {
12910
    xmlXPathErrMemory(ctxt);
12911
          xmlFreePattern(stream);
12912
    return(NULL);
12913
      }
12914
      comp->stream = stream;
12915
      comp->dict = dict;
12916
      if (comp->dict)
12917
    xmlDictReference(comp->dict);
12918
      return(comp);
12919
  }
12920
  xmlFreePattern(stream);
12921
    }
12922
    return(NULL);
12923
}
12924
#endif /* XPATH_STREAMING */
12925
12926
static void
12927
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12928
                           xmlXPathStepOpPtr op)
12929
0
{
12930
0
    xmlXPathCompExprPtr comp = pctxt->comp;
12931
0
    xmlXPathContextPtr ctxt;
12932
12933
    /*
12934
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12935
    * internal representation.
12936
    */
12937
12938
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12939
0
        (op->ch1 != -1) &&
12940
0
        (op->ch2 == -1 /* no predicate */))
12941
0
    {
12942
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12943
12944
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12945
0
            ((xmlXPathAxisVal) prevop->value ==
12946
0
                AXIS_DESCENDANT_OR_SELF) &&
12947
0
            (prevop->ch2 == -1) &&
12948
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12949
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12950
0
        {
12951
            /*
12952
            * This is a "descendant-or-self::node()" without predicates.
12953
            * Try to eliminate it.
12954
            */
12955
12956
0
            switch ((xmlXPathAxisVal) op->value) {
12957
0
                case AXIS_CHILD:
12958
0
                case AXIS_DESCENDANT:
12959
                    /*
12960
                    * Convert "descendant-or-self::node()/child::" or
12961
                    * "descendant-or-self::node()/descendant::" to
12962
                    * "descendant::"
12963
                    */
12964
0
                    op->ch1   = prevop->ch1;
12965
0
                    op->value = AXIS_DESCENDANT;
12966
0
                    break;
12967
0
                case AXIS_SELF:
12968
0
                case AXIS_DESCENDANT_OR_SELF:
12969
                    /*
12970
                    * Convert "descendant-or-self::node()/self::" or
12971
                    * "descendant-or-self::node()/descendant-or-self::" to
12972
                    * to "descendant-or-self::"
12973
                    */
12974
0
                    op->ch1   = prevop->ch1;
12975
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
12976
0
                    break;
12977
0
                default:
12978
0
                    break;
12979
0
            }
12980
0
  }
12981
0
    }
12982
12983
    /* OP_VALUE has invalid ch1. */
12984
0
    if (op->op == XPATH_OP_VALUE)
12985
0
        return;
12986
12987
    /* Recurse */
12988
0
    ctxt = pctxt->context;
12989
0
    if (ctxt != NULL) {
12990
0
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
12991
0
            return;
12992
0
        ctxt->depth += 1;
12993
0
    }
12994
0
    if (op->ch1 != -1)
12995
0
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
12996
0
    if (op->ch2 != -1)
12997
0
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
12998
0
    if (ctxt != NULL)
12999
0
        ctxt->depth -= 1;
13000
0
}
13001
13002
/**
13003
 * xmlXPathCtxtCompile:
13004
 * @ctxt: an XPath context
13005
 * @str:  the XPath expression
13006
 *
13007
 * Compile an XPath expression
13008
 *
13009
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13010
 *         the caller has to free the object.
13011
 */
13012
xmlXPathCompExprPtr
13013
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13014
0
    xmlXPathParserContextPtr pctxt;
13015
0
    xmlXPathCompExprPtr comp;
13016
0
    int oldDepth = 0;
13017
13018
#ifdef XPATH_STREAMING
13019
    comp = xmlXPathTryStreamCompile(ctxt, str);
13020
    if (comp != NULL)
13021
        return(comp);
13022
#endif
13023
13024
0
    xmlInitParser();
13025
13026
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
13027
0
    if (pctxt == NULL)
13028
0
        return NULL;
13029
0
    if (ctxt != NULL)
13030
0
        oldDepth = ctxt->depth;
13031
0
    xmlXPathCompileExpr(pctxt, 1);
13032
0
    if (ctxt != NULL)
13033
0
        ctxt->depth = oldDepth;
13034
13035
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
13036
0
    {
13037
0
        xmlXPathFreeParserContext(pctxt);
13038
0
        return(NULL);
13039
0
    }
13040
13041
0
    if (*pctxt->cur != 0) {
13042
  /*
13043
   * aleksey: in some cases this line prints *second* error message
13044
   * (see bug #78858) and probably this should be fixed.
13045
   * However, we are not sure that all error messages are printed
13046
   * out in other places. It's not critical so we leave it as-is for now
13047
   */
13048
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13049
0
  comp = NULL;
13050
0
    } else {
13051
0
  comp = pctxt->comp;
13052
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
13053
0
            if (ctxt != NULL)
13054
0
                oldDepth = ctxt->depth;
13055
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13056
0
            if (ctxt != NULL)
13057
0
                ctxt->depth = oldDepth;
13058
0
  }
13059
0
  pctxt->comp = NULL;
13060
0
    }
13061
0
    xmlXPathFreeParserContext(pctxt);
13062
13063
0
    if (comp != NULL) {
13064
0
  comp->expr = xmlStrdup(str);
13065
0
    }
13066
0
    return(comp);
13067
0
}
13068
13069
/**
13070
 * xmlXPathCompile:
13071
 * @str:  the XPath expression
13072
 *
13073
 * Compile an XPath expression
13074
 *
13075
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13076
 *         the caller has to free the object.
13077
 */
13078
xmlXPathCompExprPtr
13079
0
xmlXPathCompile(const xmlChar *str) {
13080
0
    return(xmlXPathCtxtCompile(NULL, str));
13081
0
}
13082
13083
/**
13084
 * xmlXPathCompiledEvalInternal:
13085
 * @comp:  the compiled XPath expression
13086
 * @ctxt:  the XPath context
13087
 * @resObj: the resulting XPath object or NULL
13088
 * @toBool: 1 if only a boolean result is requested
13089
 *
13090
 * Evaluate the Precompiled XPath expression in the given context.
13091
 * The caller has to free @resObj.
13092
 *
13093
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13094
 *         the caller has to free the object.
13095
 */
13096
static int
13097
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13098
           xmlXPathContextPtr ctxt,
13099
           xmlXPathObjectPtr *resObjPtr,
13100
           int toBool)
13101
0
{
13102
0
    xmlXPathParserContextPtr pctxt;
13103
0
    xmlXPathObjectPtr resObj = NULL;
13104
#ifndef LIBXML_THREAD_ENABLED
13105
    static int reentance = 0;
13106
#endif
13107
0
    int res;
13108
13109
0
    if (comp == NULL)
13110
0
  return(-1);
13111
0
    xmlInitParser();
13112
13113
0
    xmlResetError(&ctxt->lastError);
13114
13115
#ifndef LIBXML_THREAD_ENABLED
13116
    reentance++;
13117
    if (reentance > 1)
13118
  xmlXPathDisableOptimizer = 1;
13119
#endif
13120
13121
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
13122
0
    if (pctxt == NULL)
13123
0
        return(-1);
13124
0
    res = xmlXPathRunEval(pctxt, toBool);
13125
13126
0
    if (pctxt->error == XPATH_EXPRESSION_OK) {
13127
0
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
13128
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
13129
0
        else if (!toBool)
13130
0
            resObj = valuePop(pctxt);
13131
0
    }
13132
13133
0
    if (resObjPtr)
13134
0
        *resObjPtr = resObj;
13135
0
    else
13136
0
        xmlXPathReleaseObject(ctxt, resObj);
13137
13138
0
    pctxt->comp = NULL;
13139
0
    xmlXPathFreeParserContext(pctxt);
13140
#ifndef LIBXML_THREAD_ENABLED
13141
    reentance--;
13142
#endif
13143
13144
0
    return(res);
13145
0
}
13146
13147
/**
13148
 * xmlXPathCompiledEval:
13149
 * @comp:  the compiled XPath expression
13150
 * @ctx:  the XPath context
13151
 *
13152
 * Evaluate the Precompiled XPath expression in the given context.
13153
 *
13154
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13155
 *         the caller has to free the object.
13156
 */
13157
xmlXPathObjectPtr
13158
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13159
0
{
13160
0
    xmlXPathObjectPtr res = NULL;
13161
13162
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13163
0
    return(res);
13164
0
}
13165
13166
/**
13167
 * xmlXPathCompiledEvalToBoolean:
13168
 * @comp:  the compiled XPath expression
13169
 * @ctxt:  the XPath context
13170
 *
13171
 * Applies the XPath boolean() function on the result of the given
13172
 * compiled expression.
13173
 *
13174
 * Returns 1 if the expression evaluated to true, 0 if to false and
13175
 *         -1 in API and internal errors.
13176
 */
13177
int
13178
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13179
            xmlXPathContextPtr ctxt)
13180
0
{
13181
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13182
0
}
13183
13184
/**
13185
 * xmlXPathEvalExpr:
13186
 * @ctxt:  the XPath Parser context
13187
 *
13188
 * Parse and evaluate an XPath expression in the given context,
13189
 * then push the result on the context stack
13190
 */
13191
void
13192
0
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13193
#ifdef XPATH_STREAMING
13194
    xmlXPathCompExprPtr comp;
13195
#endif
13196
0
    int oldDepth = 0;
13197
13198
0
    if (ctxt == NULL)
13199
0
        return;
13200
0
    if (ctxt->context->lastError.code != 0)
13201
0
        return;
13202
13203
#ifdef XPATH_STREAMING
13204
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13205
    if ((comp == NULL) &&
13206
        (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
13207
        xmlXPathPErrMemory(ctxt);
13208
        return;
13209
    }
13210
    if (comp != NULL) {
13211
        if (ctxt->comp != NULL)
13212
      xmlXPathFreeCompExpr(ctxt->comp);
13213
        ctxt->comp = comp;
13214
    } else
13215
#endif
13216
0
    {
13217
0
        if (ctxt->context != NULL)
13218
0
            oldDepth = ctxt->context->depth;
13219
0
  xmlXPathCompileExpr(ctxt, 1);
13220
0
        if (ctxt->context != NULL)
13221
0
            ctxt->context->depth = oldDepth;
13222
0
        CHECK_ERROR;
13223
13224
        /* Check for trailing characters. */
13225
0
        if (*ctxt->cur != 0)
13226
0
            XP_ERROR(XPATH_EXPR_ERROR);
13227
13228
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13229
0
            if (ctxt->context != NULL)
13230
0
                oldDepth = ctxt->context->depth;
13231
0
      xmlXPathOptimizeExpression(ctxt,
13232
0
    &ctxt->comp->steps[ctxt->comp->last]);
13233
0
            if (ctxt->context != NULL)
13234
0
                ctxt->context->depth = oldDepth;
13235
0
        }
13236
0
    }
13237
13238
0
    xmlXPathRunEval(ctxt, 0);
13239
0
}
13240
13241
/**
13242
 * xmlXPathEval:
13243
 * @str:  the XPath expression
13244
 * @ctx:  the XPath context
13245
 *
13246
 * Evaluate the XPath Location Path in the given context.
13247
 *
13248
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13249
 *         the caller has to free the object.
13250
 */
13251
xmlXPathObjectPtr
13252
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13253
0
    xmlXPathParserContextPtr ctxt;
13254
0
    xmlXPathObjectPtr res;
13255
13256
0
    if (ctx == NULL)
13257
0
        return(NULL);
13258
13259
0
    xmlInitParser();
13260
13261
0
    xmlResetError(&ctx->lastError);
13262
13263
0
    ctxt = xmlXPathNewParserContext(str, ctx);
13264
0
    if (ctxt == NULL)
13265
0
        return NULL;
13266
0
    xmlXPathEvalExpr(ctxt);
13267
13268
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
13269
0
  res = NULL;
13270
0
    } else if (ctxt->valueNr != 1) {
13271
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
13272
0
  res = NULL;
13273
0
    } else {
13274
0
  res = valuePop(ctxt);
13275
0
    }
13276
13277
0
    xmlXPathFreeParserContext(ctxt);
13278
0
    return(res);
13279
0
}
13280
13281
/**
13282
 * xmlXPathSetContextNode:
13283
 * @node: the node to to use as the context node
13284
 * @ctx:  the XPath context
13285
 *
13286
 * Sets 'node' as the context node. The node must be in the same
13287
 * document as that associated with the context.
13288
 *
13289
 * Returns -1 in case of error or 0 if successful
13290
 */
13291
int
13292
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13293
0
    if ((node == NULL) || (ctx == NULL))
13294
0
        return(-1);
13295
13296
0
    if (node->doc == ctx->doc) {
13297
0
        ctx->node = node;
13298
0
  return(0);
13299
0
    }
13300
0
    return(-1);
13301
0
}
13302
13303
/**
13304
 * xmlXPathNodeEval:
13305
 * @node: the node to to use as the context node
13306
 * @str:  the XPath expression
13307
 * @ctx:  the XPath context
13308
 *
13309
 * Evaluate the XPath Location Path in the given context. The node 'node'
13310
 * is set as the context node. The context node is not restored.
13311
 *
13312
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13313
 *         the caller has to free the object.
13314
 */
13315
xmlXPathObjectPtr
13316
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13317
0
    if (str == NULL)
13318
0
        return(NULL);
13319
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
13320
0
        return(NULL);
13321
0
    return(xmlXPathEval(str, ctx));
13322
0
}
13323
13324
/**
13325
 * xmlXPathEvalExpression:
13326
 * @str:  the XPath expression
13327
 * @ctxt:  the XPath context
13328
 *
13329
 * Alias for xmlXPathEval().
13330
 *
13331
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13332
 *         the caller has to free the object.
13333
 */
13334
xmlXPathObjectPtr
13335
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13336
0
    return(xmlXPathEval(str, ctxt));
13337
0
}
13338
13339
/************************************************************************
13340
 *                  *
13341
 *  Extra functions not pertaining to the XPath spec    *
13342
 *                  *
13343
 ************************************************************************/
13344
/**
13345
 * xmlXPathEscapeUriFunction:
13346
 * @ctxt:  the XPath Parser context
13347
 * @nargs:  the number of arguments
13348
 *
13349
 * Implement the escape-uri() XPath function
13350
 *    string escape-uri(string $str, bool $escape-reserved)
13351
 *
13352
 * This function applies the URI escaping rules defined in section 2 of [RFC
13353
 * 2396] to the string supplied as $uri-part, which typically represents all
13354
 * or part of a URI. The effect of the function is to replace any special
13355
 * character in the string by an escape sequence of the form %xx%yy...,
13356
 * where xxyy... is the hexadecimal representation of the octets used to
13357
 * represent the character in UTF-8.
13358
 *
13359
 * The set of characters that are escaped depends on the setting of the
13360
 * boolean argument $escape-reserved.
13361
 *
13362
 * If $escape-reserved is true, all characters are escaped other than lower
13363
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13364
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13365
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13366
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13367
 * A-F).
13368
 *
13369
 * If $escape-reserved is false, the behavior differs in that characters
13370
 * referred to in [RFC 2396] as reserved characters are not escaped. These
13371
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13372
 *
13373
 * [RFC 2396] does not define whether escaped URIs should use lower case or
13374
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
13375
 * compared using string comparison functions, this function must always use
13376
 * the upper-case letters A-F.
13377
 *
13378
 * Generally, $escape-reserved should be set to true when escaping a string
13379
 * that is to form a single part of a URI, and to false when escaping an
13380
 * entire URI or URI reference.
13381
 *
13382
 * In the case of non-ascii characters, the string is encoded according to
13383
 * utf-8 and then converted according to RFC 2396.
13384
 *
13385
 * Examples
13386
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13387
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13388
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13389
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13390
 *
13391
 */
13392
static void
13393
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13394
0
    xmlXPathObjectPtr str;
13395
0
    int escape_reserved;
13396
0
    xmlBufPtr target;
13397
0
    xmlChar *cptr;
13398
0
    xmlChar escape[4];
13399
13400
0
    CHECK_ARITY(2);
13401
13402
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
13403
13404
0
    CAST_TO_STRING;
13405
0
    str = valuePop(ctxt);
13406
13407
0
    target = xmlBufCreate();
13408
13409
0
    escape[0] = '%';
13410
0
    escape[3] = 0;
13411
13412
0
    if (target) {
13413
0
  for (cptr = str->stringval; *cptr; cptr++) {
13414
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
13415
0
    (*cptr >= 'a' && *cptr <= 'z') ||
13416
0
    (*cptr >= '0' && *cptr <= '9') ||
13417
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
13418
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
13419
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13420
0
    (*cptr == '%' &&
13421
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13422
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
13423
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
13424
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13425
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
13426
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
13427
0
    (!escape_reserved &&
13428
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13429
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
13430
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
13431
0
      *cptr == ','))) {
13432
0
    xmlBufAdd(target, cptr, 1);
13433
0
      } else {
13434
0
    if ((*cptr >> 4) < 10)
13435
0
        escape[1] = '0' + (*cptr >> 4);
13436
0
    else
13437
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
13438
0
    if ((*cptr & 0xF) < 10)
13439
0
        escape[2] = '0' + (*cptr & 0xF);
13440
0
    else
13441
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
13442
13443
0
    xmlBufAdd(target, &escape[0], 3);
13444
0
      }
13445
0
  }
13446
0
    }
13447
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
13448
0
    xmlBufFree(target);
13449
0
    xmlXPathReleaseObject(ctxt->context, str);
13450
0
}
13451
13452
/**
13453
 * xmlXPathRegisterAllFunctions:
13454
 * @ctxt:  the XPath context
13455
 *
13456
 * Registers all default XPath functions in this context
13457
 */
13458
void
13459
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13460
0
{
13461
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13462
0
                         xmlXPathBooleanFunction);
13463
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13464
0
                         xmlXPathCeilingFunction);
13465
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13466
0
                         xmlXPathCountFunction);
13467
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13468
0
                         xmlXPathConcatFunction);
13469
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13470
0
                         xmlXPathContainsFunction);
13471
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13472
0
                         xmlXPathIdFunction);
13473
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13474
0
                         xmlXPathFalseFunction);
13475
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13476
0
                         xmlXPathFloorFunction);
13477
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13478
0
                         xmlXPathLastFunction);
13479
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13480
0
                         xmlXPathLangFunction);
13481
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13482
0
                         xmlXPathLocalNameFunction);
13483
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13484
0
                         xmlXPathNotFunction);
13485
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13486
0
                         xmlXPathNameFunction);
13487
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13488
0
                         xmlXPathNamespaceURIFunction);
13489
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13490
0
                         xmlXPathNormalizeFunction);
13491
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13492
0
                         xmlXPathNumberFunction);
13493
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13494
0
                         xmlXPathPositionFunction);
13495
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13496
0
                         xmlXPathRoundFunction);
13497
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13498
0
                         xmlXPathStringFunction);
13499
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13500
0
                         xmlXPathStringLengthFunction);
13501
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13502
0
                         xmlXPathStartsWithFunction);
13503
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13504
0
                         xmlXPathSubstringFunction);
13505
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13506
0
                         xmlXPathSubstringBeforeFunction);
13507
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13508
0
                         xmlXPathSubstringAfterFunction);
13509
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13510
0
                         xmlXPathSumFunction);
13511
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13512
0
                         xmlXPathTrueFunction);
13513
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13514
0
                         xmlXPathTranslateFunction);
13515
13516
0
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13517
0
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13518
0
                         xmlXPathEscapeUriFunction);
13519
0
}
13520
13521
#endif /* LIBXML_XPATH_ENABLED */