Coverage Report

Created: 2025-07-18 06:08

/src/tinysparql/subprojects/libxml2-2.13.1/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
0
xmlInitXPathInternal(void) {
167
0
#if defined(NAN) && defined(INFINITY)
168
0
    xmlXPathNAN = NAN;
169
0
    xmlXPathPINF = INFINITY;
170
0
    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
0
}
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
0
xmlXPathIsNaN(double val) {
190
0
#ifdef isnan
191
0
    return isnan(val);
192
#else
193
    return !(val == val);
194
#endif
195
0
}
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 const xmlNs xmlXPathXMLNamespaceStruct = {
228
    NULL,
229
    XML_NAMESPACE_DECL,
230
    XML_XML_NAMESPACE,
231
    BAD_CAST "xml",
232
    NULL,
233
    NULL
234
};
235
static const xmlNs *const 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
 *
628
 * Handle a memory allocation failure.
629
 */
630
void
631
xmlXPathErrMemory(xmlXPathContextPtr ctxt)
632
0
{
633
0
    if (ctxt == NULL)
634
0
        return;
635
0
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
636
0
                        &ctxt->lastError);
637
0
}
638
639
/**
640
 * xmlXPathPErrMemory:
641
 * @ctxt:  an XPath parser context
642
 *
643
 * Handle a memory allocation failure.
644
 */
645
void
646
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
647
0
{
648
0
    if (ctxt == NULL)
649
0
        return;
650
0
    ctxt->error = XPATH_MEMORY_ERROR;
651
0
    xmlXPathErrMemory(ctxt->context);
652
0
}
653
654
/**
655
 * xmlXPathErr:
656
 * @ctxt:  a XPath parser context
657
 * @code:  the error code
658
 *
659
 * Handle an XPath error
660
 */
661
void
662
xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
663
0
{
664
0
    xmlStructuredErrorFunc schannel = NULL;
665
0
    xmlGenericErrorFunc channel = NULL;
666
0
    void *data = NULL;
667
0
    xmlNodePtr node = NULL;
668
0
    int res;
669
670
0
    if (ctxt == NULL)
671
0
        return;
672
0
    if ((code < 0) || (code > MAXERRNO))
673
0
  code = MAXERRNO;
674
    /* Only report the first error */
675
0
    if (ctxt->error != 0)
676
0
        return;
677
678
0
    ctxt->error = code;
679
680
0
    if (ctxt->context != NULL) {
681
0
        xmlErrorPtr err = &ctxt->context->lastError;
682
683
        /* Don't overwrite memory error. */
684
0
        if (err->code == XML_ERR_NO_MEMORY)
685
0
            return;
686
687
        /* cleanup current last error */
688
0
        xmlResetError(err);
689
690
0
        err->domain = XML_FROM_XPATH;
691
0
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
692
0
        err->level = XML_ERR_ERROR;
693
0
        if (ctxt->base != NULL) {
694
0
            err->str1 = (char *) xmlStrdup(ctxt->base);
695
0
            if (err->str1 == NULL) {
696
0
                xmlXPathPErrMemory(ctxt);
697
0
                return;
698
0
            }
699
0
        }
700
0
        err->int1 = ctxt->cur - ctxt->base;
701
0
        err->node = ctxt->context->debugNode;
702
703
0
        schannel = ctxt->context->error;
704
0
        data = ctxt->context->userData;
705
0
        node = ctxt->context->debugNode;
706
0
    }
707
708
0
    if (schannel == NULL) {
709
0
        channel = xmlGenericError;
710
0
        data = xmlGenericErrorContext;
711
0
    }
712
713
0
    res = __xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
714
0
                          code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
715
0
                          XML_ERR_ERROR, NULL, 0,
716
0
                          (const char *) ctxt->base, NULL, NULL,
717
0
                          ctxt->cur - ctxt->base, 0,
718
0
                          "%s", xmlXPathErrorMessages[code]);
719
0
    if (res < 0)
720
0
        xmlXPathPErrMemory(ctxt);
721
0
}
722
723
/**
724
 * xmlXPatherror:
725
 * @ctxt:  the XPath Parser context
726
 * @file:  the file name
727
 * @line:  the line number
728
 * @no:  the error number
729
 *
730
 * Formats an error message.
731
 */
732
void
733
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
734
0
              int line ATTRIBUTE_UNUSED, int no) {
735
0
    xmlXPathErr(ctxt, no);
736
0
}
737
738
/**
739
 * xmlXPathCheckOpLimit:
740
 * @ctxt:  the XPath Parser context
741
 * @opCount:  the number of operations to be added
742
 *
743
 * Adds opCount to the running total of operations and returns -1 if the
744
 * operation limit is exceeded. Returns 0 otherwise.
745
 */
746
static int
747
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
748
0
    xmlXPathContextPtr xpctxt = ctxt->context;
749
750
0
    if ((opCount > xpctxt->opLimit) ||
751
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
752
0
        xpctxt->opCount = xpctxt->opLimit;
753
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
754
0
        return(-1);
755
0
    }
756
757
0
    xpctxt->opCount += opCount;
758
0
    return(0);
759
0
}
760
761
#define OP_LIMIT_EXCEEDED(ctxt, n) \
762
0
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
763
764
/************************************************************************
765
 *                  *
766
 *      Parser Types          *
767
 *                  *
768
 ************************************************************************/
769
770
/*
771
 * Types are private:
772
 */
773
774
typedef enum {
775
    XPATH_OP_END=0,
776
    XPATH_OP_AND,
777
    XPATH_OP_OR,
778
    XPATH_OP_EQUAL,
779
    XPATH_OP_CMP,
780
    XPATH_OP_PLUS,
781
    XPATH_OP_MULT,
782
    XPATH_OP_UNION,
783
    XPATH_OP_ROOT,
784
    XPATH_OP_NODE,
785
    XPATH_OP_COLLECT,
786
    XPATH_OP_VALUE, /* 11 */
787
    XPATH_OP_VARIABLE,
788
    XPATH_OP_FUNCTION,
789
    XPATH_OP_ARG,
790
    XPATH_OP_PREDICATE,
791
    XPATH_OP_FILTER, /* 16 */
792
    XPATH_OP_SORT /* 17 */
793
#ifdef LIBXML_XPTR_LOCS_ENABLED
794
    ,XPATH_OP_RANGETO
795
#endif
796
} xmlXPathOp;
797
798
typedef enum {
799
    AXIS_ANCESTOR = 1,
800
    AXIS_ANCESTOR_OR_SELF,
801
    AXIS_ATTRIBUTE,
802
    AXIS_CHILD,
803
    AXIS_DESCENDANT,
804
    AXIS_DESCENDANT_OR_SELF,
805
    AXIS_FOLLOWING,
806
    AXIS_FOLLOWING_SIBLING,
807
    AXIS_NAMESPACE,
808
    AXIS_PARENT,
809
    AXIS_PRECEDING,
810
    AXIS_PRECEDING_SIBLING,
811
    AXIS_SELF
812
} xmlXPathAxisVal;
813
814
typedef enum {
815
    NODE_TEST_NONE = 0,
816
    NODE_TEST_TYPE = 1,
817
    NODE_TEST_PI = 2,
818
    NODE_TEST_ALL = 3,
819
    NODE_TEST_NS = 4,
820
    NODE_TEST_NAME = 5
821
} xmlXPathTestVal;
822
823
typedef enum {
824
    NODE_TYPE_NODE = 0,
825
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
826
    NODE_TYPE_TEXT = XML_TEXT_NODE,
827
    NODE_TYPE_PI = XML_PI_NODE
828
} xmlXPathTypeVal;
829
830
typedef struct _xmlXPathStepOp xmlXPathStepOp;
831
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
832
struct _xmlXPathStepOp {
833
    xmlXPathOp op;    /* The identifier of the operation */
834
    int ch1;      /* First child */
835
    int ch2;      /* Second child */
836
    int value;
837
    int value2;
838
    int value3;
839
    void *value4;
840
    void *value5;
841
    xmlXPathFunction cache;
842
    void *cacheURI;
843
};
844
845
struct _xmlXPathCompExpr {
846
    int nbStep;     /* Number of steps in this expression */
847
    int maxStep;    /* Maximum number of steps allocated */
848
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
849
    int last;     /* index of last step in expression */
850
    xmlChar *expr;    /* the expression being computed */
851
    xmlDictPtr dict;    /* the dictionary to use if any */
852
#ifdef XPATH_STREAMING
853
    xmlPatternPtr stream;
854
#endif
855
};
856
857
/************************************************************************
858
 *                  *
859
 *      Forward declarations        *
860
 *                  *
861
 ************************************************************************/
862
863
static void
864
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
865
static int
866
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
867
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
868
static int
869
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
870
          xmlXPathStepOpPtr op,
871
          int isPredicate);
872
static void
873
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
874
875
/************************************************************************
876
 *                  *
877
 *      Parser Type functions       *
878
 *                  *
879
 ************************************************************************/
880
881
/**
882
 * xmlXPathNewCompExpr:
883
 *
884
 * Create a new Xpath component
885
 *
886
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
887
 */
888
static xmlXPathCompExprPtr
889
0
xmlXPathNewCompExpr(void) {
890
0
    xmlXPathCompExprPtr cur;
891
892
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
893
0
    if (cur == NULL)
894
0
  return(NULL);
895
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
896
0
    cur->maxStep = 10;
897
0
    cur->nbStep = 0;
898
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
899
0
                                     sizeof(xmlXPathStepOp));
900
0
    if (cur->steps == NULL) {
901
0
  xmlFree(cur);
902
0
  return(NULL);
903
0
    }
904
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
905
0
    cur->last = -1;
906
0
    return(cur);
907
0
}
908
909
/**
910
 * xmlXPathFreeCompExpr:
911
 * @comp:  an XPATH comp
912
 *
913
 * Free up the memory allocated by @comp
914
 */
915
void
916
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
917
0
{
918
0
    xmlXPathStepOpPtr op;
919
0
    int i;
920
921
0
    if (comp == NULL)
922
0
        return;
923
0
    if (comp->dict == NULL) {
924
0
  for (i = 0; i < comp->nbStep; i++) {
925
0
      op = &comp->steps[i];
926
0
      if (op->value4 != NULL) {
927
0
    if (op->op == XPATH_OP_VALUE)
928
0
        xmlXPathFreeObject(op->value4);
929
0
    else
930
0
        xmlFree(op->value4);
931
0
      }
932
0
      if (op->value5 != NULL)
933
0
    xmlFree(op->value5);
934
0
  }
935
0
    } else {
936
0
  for (i = 0; i < comp->nbStep; i++) {
937
0
      op = &comp->steps[i];
938
0
      if (op->value4 != NULL) {
939
0
    if (op->op == XPATH_OP_VALUE)
940
0
        xmlXPathFreeObject(op->value4);
941
0
      }
942
0
  }
943
0
        xmlDictFree(comp->dict);
944
0
    }
945
0
    if (comp->steps != NULL) {
946
0
        xmlFree(comp->steps);
947
0
    }
948
#ifdef XPATH_STREAMING
949
    if (comp->stream != NULL) {
950
        xmlFreePatternList(comp->stream);
951
    }
952
#endif
953
0
    if (comp->expr != NULL) {
954
0
        xmlFree(comp->expr);
955
0
    }
956
957
0
    xmlFree(comp);
958
0
}
959
960
/**
961
 * xmlXPathCompExprAdd:
962
 * @comp:  the compiled expression
963
 * @ch1: first child index
964
 * @ch2: second child index
965
 * @op:  an op
966
 * @value:  the first int value
967
 * @value2:  the second int value
968
 * @value3:  the third int value
969
 * @value4:  the first string value
970
 * @value5:  the second string value
971
 *
972
 * Add a step to an XPath Compiled Expression
973
 *
974
 * Returns -1 in case of failure, the index otherwise
975
 */
976
static int
977
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
978
   xmlXPathOp op, int value,
979
0
   int value2, int value3, void *value4, void *value5) {
980
0
    xmlXPathCompExprPtr comp = ctxt->comp;
981
0
    if (comp->nbStep >= comp->maxStep) {
982
0
  xmlXPathStepOp *real;
983
984
0
        if (comp->maxStep >= XPATH_MAX_STEPS) {
985
0
      xmlXPathPErrMemory(ctxt);
986
0
      return(-1);
987
0
        }
988
0
  comp->maxStep *= 2;
989
0
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
990
0
                          comp->maxStep * sizeof(xmlXPathStepOp));
991
0
  if (real == NULL) {
992
0
      comp->maxStep /= 2;
993
0
      xmlXPathPErrMemory(ctxt);
994
0
      return(-1);
995
0
  }
996
0
  comp->steps = real;
997
0
    }
998
0
    comp->last = comp->nbStep;
999
0
    comp->steps[comp->nbStep].ch1 = ch1;
1000
0
    comp->steps[comp->nbStep].ch2 = ch2;
1001
0
    comp->steps[comp->nbStep].op = op;
1002
0
    comp->steps[comp->nbStep].value = value;
1003
0
    comp->steps[comp->nbStep].value2 = value2;
1004
0
    comp->steps[comp->nbStep].value3 = value3;
1005
0
    if ((comp->dict != NULL) &&
1006
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1007
0
   (op == XPATH_OP_COLLECT))) {
1008
0
        if (value4 != NULL) {
1009
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1010
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1011
0
      xmlFree(value4);
1012
0
  } else
1013
0
      comp->steps[comp->nbStep].value4 = NULL;
1014
0
        if (value5 != NULL) {
1015
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1016
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1017
0
      xmlFree(value5);
1018
0
  } else
1019
0
      comp->steps[comp->nbStep].value5 = NULL;
1020
0
    } else {
1021
0
  comp->steps[comp->nbStep].value4 = value4;
1022
0
  comp->steps[comp->nbStep].value5 = value5;
1023
0
    }
1024
0
    comp->steps[comp->nbStep].cache = NULL;
1025
0
    return(comp->nbStep++);
1026
0
}
1027
1028
/**
1029
 * xmlXPathCompSwap:
1030
 * @comp:  the compiled expression
1031
 * @op: operation index
1032
 *
1033
 * Swaps 2 operations in the compiled expression
1034
 */
1035
static void
1036
0
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1037
0
    int tmp;
1038
1039
#ifndef LIBXML_THREAD_ENABLED
1040
    /*
1041
     * Since this manipulates possibly shared variables, this is
1042
     * disabled if one detects that the library is used in a multithreaded
1043
     * application
1044
     */
1045
    if (xmlXPathDisableOptimizer)
1046
  return;
1047
#endif
1048
1049
0
    tmp = op->ch1;
1050
0
    op->ch1 = op->ch2;
1051
0
    op->ch2 = tmp;
1052
0
}
1053
1054
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1055
0
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1056
0
                  (op), (val), (val2), (val3), (val4), (val5))
1057
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1058
0
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1059
0
                  (op), (val), (val2), (val3), (val4), (val5))
1060
1061
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1062
0
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1063
1064
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1065
0
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1066
1067
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1068
0
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1069
0
      (val), (val2), 0 ,NULL ,NULL)
1070
1071
/************************************************************************
1072
 *                  *
1073
 *    XPath object cache structures       *
1074
 *                  *
1075
 ************************************************************************/
1076
1077
/* #define XP_DEFAULT_CACHE_ON */
1078
1079
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1080
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1081
struct _xmlXPathContextCache {
1082
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1083
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1084
    int numNodeset;
1085
    int maxNodeset;
1086
    int numMisc;
1087
    int maxMisc;
1088
};
1089
1090
/************************************************************************
1091
 *                  *
1092
 *    Debugging related functions       *
1093
 *                  *
1094
 ************************************************************************/
1095
1096
#ifdef LIBXML_DEBUG_ENABLED
1097
static void
1098
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1099
0
    int i;
1100
0
    char shift[100];
1101
1102
0
    for (i = 0;((i < depth) && (i < 25));i++)
1103
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1104
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1105
0
    if (cur == NULL) {
1106
0
  fprintf(output, "%s", shift);
1107
0
  fprintf(output, "Node is NULL !\n");
1108
0
  return;
1109
1110
0
    }
1111
1112
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1113
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1114
0
  fprintf(output, "%s", shift);
1115
0
  fprintf(output, " /\n");
1116
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1117
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1118
0
    else
1119
0
  xmlDebugDumpOneNode(output, cur, depth);
1120
0
}
1121
static void
1122
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1123
0
    xmlNodePtr tmp;
1124
0
    int i;
1125
0
    char shift[100];
1126
1127
0
    for (i = 0;((i < depth) && (i < 25));i++)
1128
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1129
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1130
0
    if (cur == NULL) {
1131
0
  fprintf(output, "%s", shift);
1132
0
  fprintf(output, "Node is NULL !\n");
1133
0
  return;
1134
1135
0
    }
1136
1137
0
    while (cur != NULL) {
1138
0
  tmp = cur;
1139
0
  cur = cur->next;
1140
0
  xmlDebugDumpOneNode(output, tmp, depth);
1141
0
    }
1142
0
}
1143
1144
static void
1145
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1146
0
    int i;
1147
0
    char shift[100];
1148
1149
0
    for (i = 0;((i < depth) && (i < 25));i++)
1150
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1151
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1152
1153
0
    if (cur == NULL) {
1154
0
  fprintf(output, "%s", shift);
1155
0
  fprintf(output, "NodeSet is NULL !\n");
1156
0
  return;
1157
1158
0
    }
1159
1160
0
    if (cur != NULL) {
1161
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1162
0
  for (i = 0;i < cur->nodeNr;i++) {
1163
0
      fprintf(output, "%s", shift);
1164
0
      fprintf(output, "%d", i + 1);
1165
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1166
0
  }
1167
0
    }
1168
0
}
1169
1170
static void
1171
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1172
0
    int i;
1173
0
    char shift[100];
1174
1175
0
    for (i = 0;((i < depth) && (i < 25));i++)
1176
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1177
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1178
1179
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1180
0
  fprintf(output, "%s", shift);
1181
0
  fprintf(output, "Value Tree is NULL !\n");
1182
0
  return;
1183
1184
0
    }
1185
1186
0
    fprintf(output, "%s", shift);
1187
0
    fprintf(output, "%d", i + 1);
1188
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1189
0
}
1190
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1191
static void
1192
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1193
    int i;
1194
    char shift[100];
1195
1196
    for (i = 0;((i < depth) && (i < 25));i++)
1197
        shift[2 * i] = shift[2 * i + 1] = ' ';
1198
    shift[2 * i] = shift[2 * i + 1] = 0;
1199
1200
    if (cur == NULL) {
1201
  fprintf(output, "%s", shift);
1202
  fprintf(output, "LocationSet is NULL !\n");
1203
  return;
1204
1205
    }
1206
1207
    for (i = 0;i < cur->locNr;i++) {
1208
  fprintf(output, "%s", shift);
1209
        fprintf(output, "%d : ", i + 1);
1210
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1211
    }
1212
}
1213
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1214
1215
/**
1216
 * xmlXPathDebugDumpObject:
1217
 * @output:  the FILE * to dump the output
1218
 * @cur:  the object to inspect
1219
 * @depth:  indentation level
1220
 *
1221
 * Dump the content of the object for debugging purposes
1222
 */
1223
void
1224
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1225
0
    int i;
1226
0
    char shift[100];
1227
1228
0
    if (output == NULL) return;
1229
1230
0
    for (i = 0;((i < depth) && (i < 25));i++)
1231
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1232
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1233
1234
1235
0
    fprintf(output, "%s", shift);
1236
1237
0
    if (cur == NULL) {
1238
0
        fprintf(output, "Object is empty (NULL)\n");
1239
0
  return;
1240
0
    }
1241
0
    switch(cur->type) {
1242
0
        case XPATH_UNDEFINED:
1243
0
      fprintf(output, "Object is uninitialized\n");
1244
0
      break;
1245
0
        case XPATH_NODESET:
1246
0
      fprintf(output, "Object is a Node Set :\n");
1247
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1248
0
      break;
1249
0
  case XPATH_XSLT_TREE:
1250
0
      fprintf(output, "Object is an XSLT value tree :\n");
1251
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1252
0
      break;
1253
0
        case XPATH_BOOLEAN:
1254
0
      fprintf(output, "Object is a Boolean : ");
1255
0
      if (cur->boolval) fprintf(output, "true\n");
1256
0
      else fprintf(output, "false\n");
1257
0
      break;
1258
0
        case XPATH_NUMBER:
1259
0
      switch (xmlXPathIsInf(cur->floatval)) {
1260
0
      case 1:
1261
0
    fprintf(output, "Object is a number : Infinity\n");
1262
0
    break;
1263
0
      case -1:
1264
0
    fprintf(output, "Object is a number : -Infinity\n");
1265
0
    break;
1266
0
      default:
1267
0
    if (xmlXPathIsNaN(cur->floatval)) {
1268
0
        fprintf(output, "Object is a number : NaN\n");
1269
0
    } else if (cur->floatval == 0) {
1270
                    /* Omit sign for negative zero. */
1271
0
        fprintf(output, "Object is a number : 0\n");
1272
0
    } else {
1273
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1274
0
    }
1275
0
      }
1276
0
      break;
1277
0
        case XPATH_STRING:
1278
0
      fprintf(output, "Object is a string : ");
1279
0
      xmlDebugDumpString(output, cur->stringval);
1280
0
      fprintf(output, "\n");
1281
0
      break;
1282
#ifdef LIBXML_XPTR_LOCS_ENABLED
1283
  case XPATH_POINT:
1284
      fprintf(output, "Object is a point : index %d in node", cur->index);
1285
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1286
      fprintf(output, "\n");
1287
      break;
1288
  case XPATH_RANGE:
1289
      if ((cur->user2 == NULL) ||
1290
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1291
    fprintf(output, "Object is a collapsed range :\n");
1292
    fprintf(output, "%s", shift);
1293
    if (cur->index >= 0)
1294
        fprintf(output, "index %d in ", cur->index);
1295
    fprintf(output, "node\n");
1296
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1297
                    depth + 1);
1298
      } else  {
1299
    fprintf(output, "Object is a range :\n");
1300
    fprintf(output, "%s", shift);
1301
    fprintf(output, "From ");
1302
    if (cur->index >= 0)
1303
        fprintf(output, "index %d in ", cur->index);
1304
    fprintf(output, "node\n");
1305
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1306
                    depth + 1);
1307
    fprintf(output, "%s", shift);
1308
    fprintf(output, "To ");
1309
    if (cur->index2 >= 0)
1310
        fprintf(output, "index %d in ", cur->index2);
1311
    fprintf(output, "node\n");
1312
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1313
                    depth + 1);
1314
    fprintf(output, "\n");
1315
      }
1316
      break;
1317
  case XPATH_LOCATIONSET:
1318
      fprintf(output, "Object is a Location Set:\n");
1319
      xmlXPathDebugDumpLocationSet(output,
1320
        (xmlLocationSetPtr) cur->user, depth);
1321
      break;
1322
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1323
0
  case XPATH_USERS:
1324
0
      fprintf(output, "Object is user defined\n");
1325
0
      break;
1326
0
    }
1327
0
}
1328
1329
static void
1330
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1331
0
                       xmlXPathStepOpPtr op, int depth) {
1332
0
    int i;
1333
0
    char shift[100];
1334
1335
0
    for (i = 0;((i < depth) && (i < 25));i++)
1336
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1337
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1338
1339
0
    fprintf(output, "%s", shift);
1340
0
    if (op == NULL) {
1341
0
  fprintf(output, "Step is NULL\n");
1342
0
  return;
1343
0
    }
1344
0
    switch (op->op) {
1345
0
        case XPATH_OP_END:
1346
0
      fprintf(output, "END"); break;
1347
0
        case XPATH_OP_AND:
1348
0
      fprintf(output, "AND"); break;
1349
0
        case XPATH_OP_OR:
1350
0
      fprintf(output, "OR"); break;
1351
0
        case XPATH_OP_EQUAL:
1352
0
       if (op->value)
1353
0
     fprintf(output, "EQUAL =");
1354
0
       else
1355
0
     fprintf(output, "EQUAL !=");
1356
0
       break;
1357
0
        case XPATH_OP_CMP:
1358
0
       if (op->value)
1359
0
     fprintf(output, "CMP <");
1360
0
       else
1361
0
     fprintf(output, "CMP >");
1362
0
       if (!op->value2)
1363
0
     fprintf(output, "=");
1364
0
       break;
1365
0
        case XPATH_OP_PLUS:
1366
0
       if (op->value == 0)
1367
0
     fprintf(output, "PLUS -");
1368
0
       else if (op->value == 1)
1369
0
     fprintf(output, "PLUS +");
1370
0
       else if (op->value == 2)
1371
0
     fprintf(output, "PLUS unary -");
1372
0
       else if (op->value == 3)
1373
0
     fprintf(output, "PLUS unary - -");
1374
0
       break;
1375
0
        case XPATH_OP_MULT:
1376
0
       if (op->value == 0)
1377
0
     fprintf(output, "MULT *");
1378
0
       else if (op->value == 1)
1379
0
     fprintf(output, "MULT div");
1380
0
       else
1381
0
     fprintf(output, "MULT mod");
1382
0
       break;
1383
0
        case XPATH_OP_UNION:
1384
0
       fprintf(output, "UNION"); break;
1385
0
        case XPATH_OP_ROOT:
1386
0
       fprintf(output, "ROOT"); break;
1387
0
        case XPATH_OP_NODE:
1388
0
       fprintf(output, "NODE"); break;
1389
0
        case XPATH_OP_SORT:
1390
0
       fprintf(output, "SORT"); break;
1391
0
        case XPATH_OP_COLLECT: {
1392
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1393
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1394
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1395
0
      const xmlChar *prefix = op->value4;
1396
0
      const xmlChar *name = op->value5;
1397
1398
0
      fprintf(output, "COLLECT ");
1399
0
      switch (axis) {
1400
0
    case AXIS_ANCESTOR:
1401
0
        fprintf(output, " 'ancestors' "); break;
1402
0
    case AXIS_ANCESTOR_OR_SELF:
1403
0
        fprintf(output, " 'ancestors-or-self' "); break;
1404
0
    case AXIS_ATTRIBUTE:
1405
0
        fprintf(output, " 'attributes' "); break;
1406
0
    case AXIS_CHILD:
1407
0
        fprintf(output, " 'child' "); break;
1408
0
    case AXIS_DESCENDANT:
1409
0
        fprintf(output, " 'descendant' "); break;
1410
0
    case AXIS_DESCENDANT_OR_SELF:
1411
0
        fprintf(output, " 'descendant-or-self' "); break;
1412
0
    case AXIS_FOLLOWING:
1413
0
        fprintf(output, " 'following' "); break;
1414
0
    case AXIS_FOLLOWING_SIBLING:
1415
0
        fprintf(output, " 'following-siblings' "); break;
1416
0
    case AXIS_NAMESPACE:
1417
0
        fprintf(output, " 'namespace' "); break;
1418
0
    case AXIS_PARENT:
1419
0
        fprintf(output, " 'parent' "); break;
1420
0
    case AXIS_PRECEDING:
1421
0
        fprintf(output, " 'preceding' "); break;
1422
0
    case AXIS_PRECEDING_SIBLING:
1423
0
        fprintf(output, " 'preceding-sibling' "); break;
1424
0
    case AXIS_SELF:
1425
0
        fprintf(output, " 'self' "); break;
1426
0
      }
1427
0
      switch (test) {
1428
0
                case NODE_TEST_NONE:
1429
0
        fprintf(output, "'none' "); break;
1430
0
                case NODE_TEST_TYPE:
1431
0
        fprintf(output, "'type' "); break;
1432
0
                case NODE_TEST_PI:
1433
0
        fprintf(output, "'PI' "); break;
1434
0
                case NODE_TEST_ALL:
1435
0
        fprintf(output, "'all' "); break;
1436
0
                case NODE_TEST_NS:
1437
0
        fprintf(output, "'namespace' "); break;
1438
0
                case NODE_TEST_NAME:
1439
0
        fprintf(output, "'name' "); break;
1440
0
      }
1441
0
      switch (type) {
1442
0
                case NODE_TYPE_NODE:
1443
0
        fprintf(output, "'node' "); break;
1444
0
                case NODE_TYPE_COMMENT:
1445
0
        fprintf(output, "'comment' "); break;
1446
0
                case NODE_TYPE_TEXT:
1447
0
        fprintf(output, "'text' "); break;
1448
0
                case NODE_TYPE_PI:
1449
0
        fprintf(output, "'PI' "); break;
1450
0
      }
1451
0
      if (prefix != NULL)
1452
0
    fprintf(output, "%s:", prefix);
1453
0
      if (name != NULL)
1454
0
    fprintf(output, "%s", (const char *) name);
1455
0
      break;
1456
1457
0
        }
1458
0
  case XPATH_OP_VALUE: {
1459
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1460
1461
0
      fprintf(output, "ELEM ");
1462
0
      xmlXPathDebugDumpObject(output, object, 0);
1463
0
      goto finish;
1464
0
  }
1465
0
  case XPATH_OP_VARIABLE: {
1466
0
      const xmlChar *prefix = op->value5;
1467
0
      const xmlChar *name = op->value4;
1468
1469
0
      if (prefix != NULL)
1470
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1471
0
      else
1472
0
    fprintf(output, "VARIABLE %s", name);
1473
0
      break;
1474
0
  }
1475
0
  case XPATH_OP_FUNCTION: {
1476
0
      int nbargs = op->value;
1477
0
      const xmlChar *prefix = op->value5;
1478
0
      const xmlChar *name = op->value4;
1479
1480
0
      if (prefix != NULL)
1481
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1482
0
      prefix, name, nbargs);
1483
0
      else
1484
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1485
0
      break;
1486
0
  }
1487
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1488
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1489
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1490
#ifdef LIBXML_XPTR_LOCS_ENABLED
1491
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1492
#endif
1493
0
  default:
1494
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1495
0
    }
1496
0
    fprintf(output, "\n");
1497
0
finish:
1498
0
    if (op->ch1 >= 0)
1499
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1500
0
    if (op->ch2 >= 0)
1501
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1502
0
}
1503
1504
/**
1505
 * xmlXPathDebugDumpCompExpr:
1506
 * @output:  the FILE * for the output
1507
 * @comp:  the precompiled XPath expression
1508
 * @depth:  the indentation level.
1509
 *
1510
 * Dumps the tree of the compiled XPath expression.
1511
 */
1512
void
1513
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1514
0
                    int depth) {
1515
0
    int i;
1516
0
    char shift[100];
1517
1518
0
    if ((output == NULL) || (comp == NULL)) return;
1519
1520
0
    for (i = 0;((i < depth) && (i < 25));i++)
1521
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1522
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1523
1524
0
    fprintf(output, "%s", shift);
1525
1526
#ifdef XPATH_STREAMING
1527
    if (comp->stream) {
1528
        fprintf(output, "Streaming Expression\n");
1529
    } else
1530
#endif
1531
0
    {
1532
0
        fprintf(output, "Compiled Expression : %d elements\n",
1533
0
                comp->nbStep);
1534
0
        i = comp->last;
1535
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1536
0
    }
1537
0
}
1538
1539
#endif /* LIBXML_DEBUG_ENABLED */
1540
1541
/************************************************************************
1542
 *                  *
1543
 *      XPath object caching        *
1544
 *                  *
1545
 ************************************************************************/
1546
1547
/**
1548
 * xmlXPathNewCache:
1549
 *
1550
 * Create a new object cache
1551
 *
1552
 * Returns the xmlXPathCache just allocated.
1553
 */
1554
static xmlXPathContextCachePtr
1555
xmlXPathNewCache(void)
1556
0
{
1557
0
    xmlXPathContextCachePtr ret;
1558
1559
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1560
0
    if (ret == NULL)
1561
0
  return(NULL);
1562
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1563
0
    ret->maxNodeset = 100;
1564
0
    ret->maxMisc = 100;
1565
0
    return(ret);
1566
0
}
1567
1568
static void
1569
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1570
0
{
1571
0
    while (list != NULL) {
1572
0
        xmlXPathObjectPtr next;
1573
1574
0
        next = (void *) list->stringval;
1575
1576
0
  if (list->nodesetval != NULL) {
1577
0
      if (list->nodesetval->nodeTab != NULL)
1578
0
    xmlFree(list->nodesetval->nodeTab);
1579
0
      xmlFree(list->nodesetval);
1580
0
  }
1581
0
  xmlFree(list);
1582
1583
0
        list = next;
1584
0
    }
1585
0
}
1586
1587
static void
1588
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1589
0
{
1590
0
    if (cache == NULL)
1591
0
  return;
1592
0
    if (cache->nodesetObjs)
1593
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1594
0
    if (cache->miscObjs)
1595
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1596
0
    xmlFree(cache);
1597
0
}
1598
1599
/**
1600
 * xmlXPathContextSetCache:
1601
 *
1602
 * @ctxt:  the XPath context
1603
 * @active: enables/disables (creates/frees) the cache
1604
 * @value: a value with semantics dependent on @options
1605
 * @options: options (currently only the value 0 is used)
1606
 *
1607
 * Creates/frees an object cache on the XPath context.
1608
 * If activates XPath objects (xmlXPathObject) will be cached internally
1609
 * to be reused.
1610
 * @options:
1611
 *   0: This will set the XPath object caching:
1612
 *      @value:
1613
 *        This will set the maximum number of XPath objects
1614
 *        to be cached per slot
1615
 *        There are two slots for node-set and misc objects.
1616
 *        Use <0 for the default number (100).
1617
 *   Other values for @options have currently no effect.
1618
 *
1619
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1620
 */
1621
int
1622
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1623
      int active,
1624
      int value,
1625
      int options)
1626
0
{
1627
0
    if (ctxt == NULL)
1628
0
  return(-1);
1629
0
    if (active) {
1630
0
  xmlXPathContextCachePtr cache;
1631
1632
0
  if (ctxt->cache == NULL) {
1633
0
      ctxt->cache = xmlXPathNewCache();
1634
0
      if (ctxt->cache == NULL) {
1635
0
                xmlXPathErrMemory(ctxt);
1636
0
    return(-1);
1637
0
            }
1638
0
  }
1639
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1640
0
  if (options == 0) {
1641
0
      if (value < 0)
1642
0
    value = 100;
1643
0
      cache->maxNodeset = value;
1644
0
      cache->maxMisc = value;
1645
0
  }
1646
0
    } else if (ctxt->cache != NULL) {
1647
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1648
0
  ctxt->cache = NULL;
1649
0
    }
1650
0
    return(0);
1651
0
}
1652
1653
/**
1654
 * xmlXPathCacheWrapNodeSet:
1655
 * @pctxt: the XPath context
1656
 * @val:  the NodePtr value
1657
 *
1658
 * This is the cached version of xmlXPathWrapNodeSet().
1659
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1660
 *
1661
 * Returns the created or reused object.
1662
 *
1663
 * In case of error the node set is destroyed and NULL is returned.
1664
 */
1665
static xmlXPathObjectPtr
1666
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1667
0
{
1668
0
    xmlXPathObjectPtr ret;
1669
0
    xmlXPathContextPtr ctxt = pctxt->context;
1670
1671
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1672
0
  xmlXPathContextCachePtr cache =
1673
0
      (xmlXPathContextCachePtr) ctxt->cache;
1674
1675
0
  if (cache->miscObjs != NULL) {
1676
0
      ret = cache->miscObjs;
1677
0
            cache->miscObjs = (void *) ret->stringval;
1678
0
            cache->numMisc -= 1;
1679
0
            ret->stringval = NULL;
1680
0
      ret->type = XPATH_NODESET;
1681
0
      ret->nodesetval = val;
1682
0
      return(ret);
1683
0
  }
1684
0
    }
1685
1686
0
    ret = xmlXPathWrapNodeSet(val);
1687
0
    if (ret == NULL)
1688
0
        xmlXPathPErrMemory(pctxt);
1689
0
    return(ret);
1690
0
}
1691
1692
/**
1693
 * xmlXPathCacheWrapString:
1694
 * @pctxt the XPath context
1695
 * @val:  the xmlChar * value
1696
 *
1697
 * This is the cached version of xmlXPathWrapString().
1698
 * Wraps the @val string into an XPath object.
1699
 *
1700
 * Returns the created or reused object.
1701
 */
1702
static xmlXPathObjectPtr
1703
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1704
0
{
1705
0
    xmlXPathObjectPtr ret;
1706
0
    xmlXPathContextPtr ctxt = pctxt->context;
1707
1708
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1709
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1710
1711
0
  if (cache->miscObjs != NULL) {
1712
0
      ret = cache->miscObjs;
1713
0
            cache->miscObjs = (void *) ret->stringval;
1714
0
            cache->numMisc -= 1;
1715
0
      ret->type = XPATH_STRING;
1716
0
      ret->stringval = val;
1717
0
      return(ret);
1718
0
  }
1719
0
    }
1720
1721
0
    ret = xmlXPathWrapString(val);
1722
0
    if (ret == NULL)
1723
0
        xmlXPathPErrMemory(pctxt);
1724
0
    return(ret);
1725
0
}
1726
1727
/**
1728
 * xmlXPathCacheNewNodeSet:
1729
 * @pctxt the XPath context
1730
 * @val:  the NodePtr value
1731
 *
1732
 * This is the cached version of xmlXPathNewNodeSet().
1733
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1734
 * it with the single Node @val
1735
 *
1736
 * Returns the created or reused object.
1737
 */
1738
static xmlXPathObjectPtr
1739
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1740
0
{
1741
0
    xmlXPathObjectPtr ret;
1742
0
    xmlXPathContextPtr ctxt = pctxt->context;
1743
1744
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1745
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1746
1747
0
  if (cache->nodesetObjs != NULL) {
1748
      /*
1749
      * Use the nodeset-cache.
1750
      */
1751
0
      ret = cache->nodesetObjs;
1752
0
            cache->nodesetObjs = (void *) ret->stringval;
1753
0
            cache->numNodeset -= 1;
1754
0
            ret->stringval = NULL;
1755
0
      ret->type = XPATH_NODESET;
1756
0
      ret->boolval = 0;
1757
0
      if (val) {
1758
0
    if ((ret->nodesetval->nodeMax == 0) ||
1759
0
        (val->type == XML_NAMESPACE_DECL))
1760
0
    {
1761
0
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1762
0
                        xmlXPathPErrMemory(pctxt);
1763
0
    } else {
1764
0
        ret->nodesetval->nodeTab[0] = val;
1765
0
        ret->nodesetval->nodeNr = 1;
1766
0
    }
1767
0
      }
1768
0
      return(ret);
1769
0
  } else if (cache->miscObjs != NULL) {
1770
0
            xmlNodeSetPtr set;
1771
      /*
1772
      * Fallback to misc-cache.
1773
      */
1774
1775
0
      set = xmlXPathNodeSetCreate(val);
1776
0
      if (set == NULL) {
1777
0
                xmlXPathPErrMemory(pctxt);
1778
0
    return(NULL);
1779
0
      }
1780
1781
0
      ret = cache->miscObjs;
1782
0
            cache->miscObjs = (void *) ret->stringval;
1783
0
            cache->numMisc -= 1;
1784
0
            ret->stringval = NULL;
1785
0
      ret->type = XPATH_NODESET;
1786
0
      ret->boolval = 0;
1787
0
      ret->nodesetval = set;
1788
0
      return(ret);
1789
0
  }
1790
0
    }
1791
0
    ret = xmlXPathNewNodeSet(val);
1792
0
    if (ret == NULL)
1793
0
        xmlXPathPErrMemory(pctxt);
1794
0
    return(ret);
1795
0
}
1796
1797
/**
1798
 * xmlXPathCacheNewString:
1799
 * @pctxt the XPath context
1800
 * @val:  the xmlChar * value
1801
 *
1802
 * This is the cached version of xmlXPathNewString().
1803
 * Acquire an xmlXPathObjectPtr of type string and of value @val
1804
 *
1805
 * Returns the created or reused object.
1806
 */
1807
static xmlXPathObjectPtr
1808
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1809
0
{
1810
0
    xmlXPathObjectPtr ret;
1811
0
    xmlXPathContextPtr ctxt = pctxt->context;
1812
1813
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1814
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1815
1816
0
  if (cache->miscObjs != NULL) {
1817
0
            xmlChar *copy;
1818
1819
0
            if (val == NULL)
1820
0
                val = BAD_CAST "";
1821
0
            copy = xmlStrdup(val);
1822
0
            if (copy == NULL) {
1823
0
                xmlXPathPErrMemory(pctxt);
1824
0
                return(NULL);
1825
0
            }
1826
1827
0
      ret = cache->miscObjs;
1828
0
            cache->miscObjs = (void *) ret->stringval;
1829
0
            cache->numMisc -= 1;
1830
0
      ret->type = XPATH_STRING;
1831
0
            ret->stringval = copy;
1832
0
      return(ret);
1833
0
  }
1834
0
    }
1835
1836
0
    ret = xmlXPathNewString(val);
1837
0
    if (ret == NULL)
1838
0
        xmlXPathPErrMemory(pctxt);
1839
0
    return(ret);
1840
0
}
1841
1842
/**
1843
 * xmlXPathCacheNewCString:
1844
 * @pctxt the XPath context
1845
 * @val:  the char * value
1846
 *
1847
 * This is the cached version of xmlXPathNewCString().
1848
 * Acquire an xmlXPathObjectPtr of type string and of value @val
1849
 *
1850
 * Returns the created or reused object.
1851
 */
1852
static xmlXPathObjectPtr
1853
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1854
0
{
1855
0
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1856
0
}
1857
1858
/**
1859
 * xmlXPathCacheNewBoolean:
1860
 * @pctxt the XPath context
1861
 * @val:  the boolean value
1862
 *
1863
 * This is the cached version of xmlXPathNewBoolean().
1864
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1865
 *
1866
 * Returns the created or reused object.
1867
 */
1868
static xmlXPathObjectPtr
1869
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1870
0
{
1871
0
    xmlXPathObjectPtr ret;
1872
0
    xmlXPathContextPtr ctxt = pctxt->context;
1873
1874
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1875
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1876
1877
0
  if (cache->miscObjs != NULL) {
1878
0
      ret = cache->miscObjs;
1879
0
            cache->miscObjs = (void *) ret->stringval;
1880
0
            cache->numMisc -= 1;
1881
0
            ret->stringval = NULL;
1882
0
      ret->type = XPATH_BOOLEAN;
1883
0
      ret->boolval = (val != 0);
1884
0
      return(ret);
1885
0
  }
1886
0
    }
1887
1888
0
    ret = xmlXPathNewBoolean(val);
1889
0
    if (ret == NULL)
1890
0
        xmlXPathPErrMemory(pctxt);
1891
0
    return(ret);
1892
0
}
1893
1894
/**
1895
 * xmlXPathCacheNewFloat:
1896
 * @pctxt the XPath context
1897
 * @val:  the double value
1898
 *
1899
 * This is the cached version of xmlXPathNewFloat().
1900
 * Acquires an xmlXPathObjectPtr of type double and of value @val
1901
 *
1902
 * Returns the created or reused object.
1903
 */
1904
static xmlXPathObjectPtr
1905
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1906
0
{
1907
0
    xmlXPathObjectPtr ret;
1908
0
    xmlXPathContextPtr ctxt = pctxt->context;
1909
1910
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1911
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1912
1913
0
  if (cache->miscObjs != NULL) {
1914
0
      ret = cache->miscObjs;
1915
0
            cache->miscObjs = (void *) ret->stringval;
1916
0
            cache->numMisc -= 1;
1917
0
            ret->stringval = NULL;
1918
0
      ret->type = XPATH_NUMBER;
1919
0
      ret->floatval = val;
1920
0
      return(ret);
1921
0
  }
1922
0
    }
1923
1924
0
    ret = xmlXPathNewFloat(val);
1925
0
    if (ret == NULL)
1926
0
        xmlXPathPErrMemory(pctxt);
1927
0
    return(ret);
1928
0
}
1929
1930
/**
1931
 * xmlXPathCacheObjectCopy:
1932
 * @pctxt the XPath context
1933
 * @val:  the original object
1934
 *
1935
 * This is the cached version of xmlXPathObjectCopy().
1936
 * Acquire a copy of a given object
1937
 *
1938
 * Returns a created or reused created object.
1939
 */
1940
static xmlXPathObjectPtr
1941
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1942
0
{
1943
0
    xmlXPathObjectPtr ret;
1944
0
    xmlXPathContextPtr ctxt = pctxt->context;
1945
1946
0
    if (val == NULL)
1947
0
  return(NULL);
1948
1949
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1950
0
  switch (val->type) {
1951
0
            case XPATH_NODESET: {
1952
0
                xmlNodeSetPtr set;
1953
1954
0
                set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1955
0
                if (set == NULL) {
1956
0
                    xmlXPathPErrMemory(pctxt);
1957
0
                    return(NULL);
1958
0
                }
1959
0
                return(xmlXPathCacheWrapNodeSet(pctxt, set));
1960
0
            }
1961
0
      case XPATH_STRING:
1962
0
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1963
0
      case XPATH_BOOLEAN:
1964
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1965
0
      case XPATH_NUMBER:
1966
0
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1967
0
      default:
1968
0
    break;
1969
0
  }
1970
0
    }
1971
0
    ret = xmlXPathObjectCopy(val);
1972
0
    if (ret == NULL)
1973
0
        xmlXPathPErrMemory(pctxt);
1974
0
    return(ret);
1975
0
}
1976
1977
/************************************************************************
1978
 *                  *
1979
 *    Parser stacks related functions and macros    *
1980
 *                  *
1981
 ************************************************************************/
1982
1983
/**
1984
 * xmlXPathCastToNumberInternal:
1985
 * @ctxt:  parser context
1986
 * @val:  an XPath object
1987
 *
1988
 * Converts an XPath object to its number value
1989
 *
1990
 * Returns the number value
1991
 */
1992
static double
1993
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1994
0
                             xmlXPathObjectPtr val) {
1995
0
    double ret = 0.0;
1996
1997
0
    if (val == NULL)
1998
0
  return(xmlXPathNAN);
1999
0
    switch (val->type) {
2000
0
    case XPATH_UNDEFINED:
2001
0
  ret = xmlXPathNAN;
2002
0
  break;
2003
0
    case XPATH_NODESET:
2004
0
    case XPATH_XSLT_TREE: {
2005
0
        xmlChar *str;
2006
2007
0
  str = xmlXPathCastNodeSetToString(val->nodesetval);
2008
0
        if (str == NULL) {
2009
0
            xmlXPathPErrMemory(ctxt);
2010
0
            ret = xmlXPathNAN;
2011
0
        } else {
2012
0
      ret = xmlXPathCastStringToNumber(str);
2013
0
            xmlFree(str);
2014
0
        }
2015
0
  break;
2016
0
    }
2017
0
    case XPATH_STRING:
2018
0
  ret = xmlXPathCastStringToNumber(val->stringval);
2019
0
  break;
2020
0
    case XPATH_NUMBER:
2021
0
  ret = val->floatval;
2022
0
  break;
2023
0
    case XPATH_BOOLEAN:
2024
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
2025
0
  break;
2026
0
    case XPATH_USERS:
2027
#ifdef LIBXML_XPTR_LOCS_ENABLED
2028
    case XPATH_POINT:
2029
    case XPATH_RANGE:
2030
    case XPATH_LOCATIONSET:
2031
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2032
  /* TODO */
2033
0
  ret = xmlXPathNAN;
2034
0
  break;
2035
0
    }
2036
0
    return(ret);
2037
0
}
2038
2039
/**
2040
 * valuePop:
2041
 * @ctxt: an XPath evaluation context
2042
 *
2043
 * Pops the top XPath object from the value stack
2044
 *
2045
 * Returns the XPath object just removed
2046
 */
2047
xmlXPathObjectPtr
2048
valuePop(xmlXPathParserContextPtr ctxt)
2049
0
{
2050
0
    xmlXPathObjectPtr ret;
2051
2052
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2053
0
        return (NULL);
2054
2055
0
    ctxt->valueNr--;
2056
0
    if (ctxt->valueNr > 0)
2057
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2058
0
    else
2059
0
        ctxt->value = NULL;
2060
0
    ret = ctxt->valueTab[ctxt->valueNr];
2061
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
2062
0
    return (ret);
2063
0
}
2064
/**
2065
 * valuePush:
2066
 * @ctxt:  an XPath evaluation context
2067
 * @value:  the XPath object
2068
 *
2069
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2070
 * a memory error is recorded in the parser context.
2071
 *
2072
 * Returns the number of items on the value stack, or -1 in case of error.
2073
 *
2074
 * The object is destroyed in case of error.
2075
 */
2076
int
2077
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2078
0
{
2079
0
    if (ctxt == NULL) return(-1);
2080
0
    if (value == NULL) {
2081
        /*
2082
         * A NULL value typically indicates that a memory allocation failed.
2083
         */
2084
0
        xmlXPathPErrMemory(ctxt);
2085
0
        return(-1);
2086
0
    }
2087
0
    if (ctxt->valueNr >= ctxt->valueMax) {
2088
0
        xmlXPathObjectPtr *tmp;
2089
2090
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2091
0
            xmlXPathPErrMemory(ctxt);
2092
0
            xmlXPathFreeObject(value);
2093
0
            return (-1);
2094
0
        }
2095
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2096
0
                                             2 * ctxt->valueMax *
2097
0
                                             sizeof(ctxt->valueTab[0]));
2098
0
        if (tmp == NULL) {
2099
0
            xmlXPathPErrMemory(ctxt);
2100
0
            xmlXPathFreeObject(value);
2101
0
            return (-1);
2102
0
        }
2103
0
        ctxt->valueMax *= 2;
2104
0
  ctxt->valueTab = tmp;
2105
0
    }
2106
0
    ctxt->valueTab[ctxt->valueNr] = value;
2107
0
    ctxt->value = value;
2108
0
    return (ctxt->valueNr++);
2109
0
}
2110
2111
/**
2112
 * xmlXPathPopBoolean:
2113
 * @ctxt:  an XPath parser context
2114
 *
2115
 * Pops a boolean from the stack, handling conversion if needed.
2116
 * Check error with #xmlXPathCheckError.
2117
 *
2118
 * Returns the boolean
2119
 */
2120
int
2121
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2122
0
    xmlXPathObjectPtr obj;
2123
0
    int ret;
2124
2125
0
    obj = valuePop(ctxt);
2126
0
    if (obj == NULL) {
2127
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2128
0
  return(0);
2129
0
    }
2130
0
    if (obj->type != XPATH_BOOLEAN)
2131
0
  ret = xmlXPathCastToBoolean(obj);
2132
0
    else
2133
0
        ret = obj->boolval;
2134
0
    xmlXPathReleaseObject(ctxt->context, obj);
2135
0
    return(ret);
2136
0
}
2137
2138
/**
2139
 * xmlXPathPopNumber:
2140
 * @ctxt:  an XPath parser context
2141
 *
2142
 * Pops a number from the stack, handling conversion if needed.
2143
 * Check error with #xmlXPathCheckError.
2144
 *
2145
 * Returns the number
2146
 */
2147
double
2148
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2149
0
    xmlXPathObjectPtr obj;
2150
0
    double ret;
2151
2152
0
    obj = valuePop(ctxt);
2153
0
    if (obj == NULL) {
2154
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2155
0
  return(0);
2156
0
    }
2157
0
    if (obj->type != XPATH_NUMBER)
2158
0
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2159
0
    else
2160
0
        ret = obj->floatval;
2161
0
    xmlXPathReleaseObject(ctxt->context, obj);
2162
0
    return(ret);
2163
0
}
2164
2165
/**
2166
 * xmlXPathPopString:
2167
 * @ctxt:  an XPath parser context
2168
 *
2169
 * Pops a string from the stack, handling conversion if needed.
2170
 * Check error with #xmlXPathCheckError.
2171
 *
2172
 * Returns the string
2173
 */
2174
xmlChar *
2175
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2176
0
    xmlXPathObjectPtr obj;
2177
0
    xmlChar * ret;
2178
2179
0
    obj = valuePop(ctxt);
2180
0
    if (obj == NULL) {
2181
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2182
0
  return(NULL);
2183
0
    }
2184
0
    ret = xmlXPathCastToString(obj);
2185
0
    if (ret == NULL)
2186
0
        xmlXPathPErrMemory(ctxt);
2187
0
    xmlXPathReleaseObject(ctxt->context, obj);
2188
0
    return(ret);
2189
0
}
2190
2191
/**
2192
 * xmlXPathPopNodeSet:
2193
 * @ctxt:  an XPath parser context
2194
 *
2195
 * Pops a node-set from the stack, handling conversion if needed.
2196
 * Check error with #xmlXPathCheckError.
2197
 *
2198
 * Returns the node-set
2199
 */
2200
xmlNodeSetPtr
2201
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2202
0
    xmlXPathObjectPtr obj;
2203
0
    xmlNodeSetPtr ret;
2204
2205
0
    if (ctxt == NULL) return(NULL);
2206
0
    if (ctxt->value == NULL) {
2207
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2208
0
  return(NULL);
2209
0
    }
2210
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2211
0
  xmlXPathSetTypeError(ctxt);
2212
0
  return(NULL);
2213
0
    }
2214
0
    obj = valuePop(ctxt);
2215
0
    ret = obj->nodesetval;
2216
#if 0
2217
    /* to fix memory leak of not clearing obj->user */
2218
    if (obj->boolval && obj->user != NULL)
2219
        xmlFreeNodeList((xmlNodePtr) obj->user);
2220
#endif
2221
0
    obj->nodesetval = NULL;
2222
0
    xmlXPathReleaseObject(ctxt->context, obj);
2223
0
    return(ret);
2224
0
}
2225
2226
/**
2227
 * xmlXPathPopExternal:
2228
 * @ctxt:  an XPath parser context
2229
 *
2230
 * Pops an external object from the stack, handling conversion if needed.
2231
 * Check error with #xmlXPathCheckError.
2232
 *
2233
 * Returns the object
2234
 */
2235
void *
2236
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2237
0
    xmlXPathObjectPtr obj;
2238
0
    void * ret;
2239
2240
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2241
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2242
0
  return(NULL);
2243
0
    }
2244
0
    if (ctxt->value->type != XPATH_USERS) {
2245
0
  xmlXPathSetTypeError(ctxt);
2246
0
  return(NULL);
2247
0
    }
2248
0
    obj = valuePop(ctxt);
2249
0
    ret = obj->user;
2250
0
    obj->user = NULL;
2251
0
    xmlXPathReleaseObject(ctxt->context, obj);
2252
0
    return(ret);
2253
0
}
2254
2255
/*
2256
 * Macros for accessing the content. Those should be used only by the parser,
2257
 * and not exported.
2258
 *
2259
 * Dirty macros, i.e. one need to make assumption on the context to use them
2260
 *
2261
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2262
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2263
 *           in ISO-Latin or UTF-8.
2264
 *           This should be used internally by the parser
2265
 *           only to compare to ASCII values otherwise it would break when
2266
 *           running with UTF-8 encoding.
2267
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2268
 *           to compare on ASCII based substring.
2269
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2270
 *           strings within the parser.
2271
 *   CURRENT Returns the current char value, with the full decoding of
2272
 *           UTF-8 if we are using this mode. It returns an int.
2273
 *   NEXT    Skip to the next character, this does the proper decoding
2274
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2275
 *           It returns the pointer to the current xmlChar.
2276
 */
2277
2278
0
#define CUR (*ctxt->cur)
2279
0
#define SKIP(val) ctxt->cur += (val)
2280
0
#define NXT(val) ctxt->cur[(val)]
2281
0
#define CUR_PTR ctxt->cur
2282
0
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2283
2284
#define COPY_BUF(l,b,i,v)                                              \
2285
0
    if (l == 1) b[i++] = v;                                            \
2286
0
    else i += xmlCopyChar(l,&b[i],v)
2287
2288
0
#define NEXTL(l)  ctxt->cur += l
2289
2290
#define SKIP_BLANKS             \
2291
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2292
2293
#define CURRENT (*ctxt->cur)
2294
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2295
2296
2297
#ifndef DBL_DIG
2298
#define DBL_DIG 16
2299
#endif
2300
#ifndef DBL_EPSILON
2301
#define DBL_EPSILON 1E-9
2302
#endif
2303
2304
0
#define UPPER_DOUBLE 1E9
2305
0
#define LOWER_DOUBLE 1E-5
2306
#define LOWER_DOUBLE_EXP 5
2307
2308
#define INTEGER_DIGITS DBL_DIG
2309
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2310
0
#define EXPONENT_DIGITS (3 + 2)
2311
2312
/**
2313
 * xmlXPathFormatNumber:
2314
 * @number:     number to format
2315
 * @buffer:     output buffer
2316
 * @buffersize: size of output buffer
2317
 *
2318
 * Convert the number into a string representation.
2319
 */
2320
static void
2321
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2322
0
{
2323
0
    switch (xmlXPathIsInf(number)) {
2324
0
    case 1:
2325
0
  if (buffersize > (int)sizeof("Infinity"))
2326
0
      snprintf(buffer, buffersize, "Infinity");
2327
0
  break;
2328
0
    case -1:
2329
0
  if (buffersize > (int)sizeof("-Infinity"))
2330
0
      snprintf(buffer, buffersize, "-Infinity");
2331
0
  break;
2332
0
    default:
2333
0
  if (xmlXPathIsNaN(number)) {
2334
0
      if (buffersize > (int)sizeof("NaN"))
2335
0
    snprintf(buffer, buffersize, "NaN");
2336
0
  } else if (number == 0) {
2337
            /* Omit sign for negative zero. */
2338
0
      snprintf(buffer, buffersize, "0");
2339
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2340
0
                   (number == (int) number)) {
2341
0
      char work[30];
2342
0
      char *ptr, *cur;
2343
0
      int value = (int) number;
2344
2345
0
            ptr = &buffer[0];
2346
0
      if (value == 0) {
2347
0
    *ptr++ = '0';
2348
0
      } else {
2349
0
    snprintf(work, 29, "%d", value);
2350
0
    cur = &work[0];
2351
0
    while ((*cur) && (ptr - buffer < buffersize)) {
2352
0
        *ptr++ = *cur++;
2353
0
    }
2354
0
      }
2355
0
      if (ptr - buffer < buffersize) {
2356
0
    *ptr = 0;
2357
0
      } else if (buffersize > 0) {
2358
0
    ptr--;
2359
0
    *ptr = 0;
2360
0
      }
2361
0
  } else {
2362
      /*
2363
        For the dimension of work,
2364
            DBL_DIG is number of significant digits
2365
      EXPONENT is only needed for "scientific notation"
2366
            3 is sign, decimal point, and terminating zero
2367
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2368
        Note that this dimension is slightly (a few characters)
2369
        larger than actually necessary.
2370
      */
2371
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2372
0
      int integer_place, fraction_place;
2373
0
      char *ptr;
2374
0
      char *after_fraction;
2375
0
      double absolute_value;
2376
0
      int size;
2377
2378
0
      absolute_value = fabs(number);
2379
2380
      /*
2381
       * First choose format - scientific or regular floating point.
2382
       * In either case, result is in work, and after_fraction points
2383
       * just past the fractional part.
2384
      */
2385
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
2386
0
      (absolute_value < LOWER_DOUBLE)) &&
2387
0
     (absolute_value != 0.0) ) {
2388
    /* Use scientific notation */
2389
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2390
0
    fraction_place = DBL_DIG - 1;
2391
0
    size = snprintf(work, sizeof(work),"%*.*e",
2392
0
       integer_place, fraction_place, number);
2393
0
    while ((size > 0) && (work[size] != 'e')) size--;
2394
2395
0
      }
2396
0
      else {
2397
    /* Use regular notation */
2398
0
    if (absolute_value > 0.0) {
2399
0
        integer_place = (int)log10(absolute_value);
2400
0
        if (integer_place > 0)
2401
0
            fraction_place = DBL_DIG - integer_place - 1;
2402
0
        else
2403
0
            fraction_place = DBL_DIG - integer_place;
2404
0
    } else {
2405
0
        fraction_place = 1;
2406
0
    }
2407
0
    size = snprintf(work, sizeof(work), "%0.*f",
2408
0
        fraction_place, number);
2409
0
      }
2410
2411
      /* Remove leading spaces sometimes inserted by snprintf */
2412
0
      while (work[0] == ' ') {
2413
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2414
0
    size--;
2415
0
      }
2416
2417
      /* Remove fractional trailing zeroes */
2418
0
      after_fraction = work + size;
2419
0
      ptr = after_fraction;
2420
0
      while (*(--ptr) == '0')
2421
0
    ;
2422
0
      if (*ptr != '.')
2423
0
          ptr++;
2424
0
      while ((*ptr++ = *after_fraction++) != 0);
2425
2426
      /* Finally copy result back to caller */
2427
0
      size = strlen(work) + 1;
2428
0
      if (size > buffersize) {
2429
0
    work[buffersize - 1] = 0;
2430
0
    size = buffersize;
2431
0
      }
2432
0
      memmove(buffer, work, size);
2433
0
  }
2434
0
  break;
2435
0
    }
2436
0
}
2437
2438
2439
/************************************************************************
2440
 *                  *
2441
 *      Routines to handle NodeSets     *
2442
 *                  *
2443
 ************************************************************************/
2444
2445
/**
2446
 * xmlXPathOrderDocElems:
2447
 * @doc:  an input document
2448
 *
2449
 * Call this routine to speed up XPath computation on static documents.
2450
 * This stamps all the element nodes with the document order
2451
 * Like for line information, the order is kept in the element->content
2452
 * field, the value stored is actually - the node number (starting at -1)
2453
 * to be able to differentiate from line numbers.
2454
 *
2455
 * Returns the number of elements found in the document or -1 in case
2456
 *    of error.
2457
 */
2458
long
2459
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
2460
0
    ptrdiff_t count = 0;
2461
0
    xmlNodePtr cur;
2462
2463
0
    if (doc == NULL)
2464
0
  return(-1);
2465
0
    cur = doc->children;
2466
0
    while (cur != NULL) {
2467
0
  if (cur->type == XML_ELEMENT_NODE) {
2468
0
      cur->content = (void *) (-(++count));
2469
0
      if (cur->children != NULL) {
2470
0
    cur = cur->children;
2471
0
    continue;
2472
0
      }
2473
0
  }
2474
0
  if (cur->next != NULL) {
2475
0
      cur = cur->next;
2476
0
      continue;
2477
0
  }
2478
0
  do {
2479
0
      cur = cur->parent;
2480
0
      if (cur == NULL)
2481
0
    break;
2482
0
      if (cur == (xmlNodePtr) doc) {
2483
0
    cur = NULL;
2484
0
    break;
2485
0
      }
2486
0
      if (cur->next != NULL) {
2487
0
    cur = cur->next;
2488
0
    break;
2489
0
      }
2490
0
  } while (cur != NULL);
2491
0
    }
2492
0
    return(count);
2493
0
}
2494
2495
/**
2496
 * xmlXPathCmpNodes:
2497
 * @node1:  the first node
2498
 * @node2:  the second node
2499
 *
2500
 * Compare two nodes w.r.t document order
2501
 *
2502
 * Returns -2 in case of error 1 if first point < second point, 0 if
2503
 *         it's the same node, -1 otherwise
2504
 */
2505
int
2506
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2507
0
    int depth1, depth2;
2508
0
    int attr1 = 0, attr2 = 0;
2509
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2510
0
    xmlNodePtr cur, root;
2511
2512
0
    if ((node1 == NULL) || (node2 == NULL))
2513
0
  return(-2);
2514
    /*
2515
     * a couple of optimizations which will avoid computations in most cases
2516
     */
2517
0
    if (node1 == node2)   /* trivial case */
2518
0
  return(0);
2519
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2520
0
  attr1 = 1;
2521
0
  attrNode1 = node1;
2522
0
  node1 = node1->parent;
2523
0
    }
2524
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2525
0
  attr2 = 1;
2526
0
  attrNode2 = node2;
2527
0
  node2 = node2->parent;
2528
0
    }
2529
0
    if (node1 == node2) {
2530
0
  if (attr1 == attr2) {
2531
      /* not required, but we keep attributes in order */
2532
0
      if (attr1 != 0) {
2533
0
          cur = attrNode2->prev;
2534
0
    while (cur != NULL) {
2535
0
        if (cur == attrNode1)
2536
0
            return (1);
2537
0
        cur = cur->prev;
2538
0
    }
2539
0
    return (-1);
2540
0
      }
2541
0
      return(0);
2542
0
  }
2543
0
  if (attr2 == 1)
2544
0
      return(1);
2545
0
  return(-1);
2546
0
    }
2547
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2548
0
        (node2->type == XML_NAMESPACE_DECL))
2549
0
  return(1);
2550
0
    if (node1 == node2->prev)
2551
0
  return(1);
2552
0
    if (node1 == node2->next)
2553
0
  return(-1);
2554
2555
    /*
2556
     * Speedup using document order if available.
2557
     */
2558
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2559
0
  (node2->type == XML_ELEMENT_NODE) &&
2560
0
  (0 > (ptrdiff_t) node1->content) &&
2561
0
  (0 > (ptrdiff_t) node2->content) &&
2562
0
  (node1->doc == node2->doc)) {
2563
0
  ptrdiff_t l1, l2;
2564
2565
0
  l1 = -((ptrdiff_t) node1->content);
2566
0
  l2 = -((ptrdiff_t) node2->content);
2567
0
  if (l1 < l2)
2568
0
      return(1);
2569
0
  if (l1 > l2)
2570
0
      return(-1);
2571
0
    }
2572
2573
    /*
2574
     * compute depth to root
2575
     */
2576
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2577
0
  if (cur->parent == node1)
2578
0
      return(1);
2579
0
  depth2++;
2580
0
    }
2581
0
    root = cur;
2582
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2583
0
  if (cur->parent == node2)
2584
0
      return(-1);
2585
0
  depth1++;
2586
0
    }
2587
    /*
2588
     * Distinct document (or distinct entities :-( ) case.
2589
     */
2590
0
    if (root != cur) {
2591
0
  return(-2);
2592
0
    }
2593
    /*
2594
     * get the nearest common ancestor.
2595
     */
2596
0
    while (depth1 > depth2) {
2597
0
  depth1--;
2598
0
  node1 = node1->parent;
2599
0
    }
2600
0
    while (depth2 > depth1) {
2601
0
  depth2--;
2602
0
  node2 = node2->parent;
2603
0
    }
2604
0
    while (node1->parent != node2->parent) {
2605
0
  node1 = node1->parent;
2606
0
  node2 = node2->parent;
2607
  /* should not happen but just in case ... */
2608
0
  if ((node1 == NULL) || (node2 == NULL))
2609
0
      return(-2);
2610
0
    }
2611
    /*
2612
     * Find who's first.
2613
     */
2614
0
    if (node1 == node2->prev)
2615
0
  return(1);
2616
0
    if (node1 == node2->next)
2617
0
  return(-1);
2618
    /*
2619
     * Speedup using document order if available.
2620
     */
2621
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2622
0
  (node2->type == XML_ELEMENT_NODE) &&
2623
0
  (0 > (ptrdiff_t) node1->content) &&
2624
0
  (0 > (ptrdiff_t) node2->content) &&
2625
0
  (node1->doc == node2->doc)) {
2626
0
  ptrdiff_t l1, l2;
2627
2628
0
  l1 = -((ptrdiff_t) node1->content);
2629
0
  l2 = -((ptrdiff_t) node2->content);
2630
0
  if (l1 < l2)
2631
0
      return(1);
2632
0
  if (l1 > l2)
2633
0
      return(-1);
2634
0
    }
2635
2636
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2637
0
  if (cur == node2)
2638
0
      return(1);
2639
0
    return(-1); /* assume there is no sibling list corruption */
2640
0
}
2641
2642
/**
2643
 * xmlXPathNodeSetSort:
2644
 * @set:  the node set
2645
 *
2646
 * Sort the node set in document order
2647
 */
2648
void
2649
0
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2650
#ifndef WITH_TIM_SORT
2651
    int i, j, incr, len;
2652
    xmlNodePtr tmp;
2653
#endif
2654
2655
0
    if (set == NULL)
2656
0
  return;
2657
2658
#ifndef WITH_TIM_SORT
2659
    /*
2660
     * Use the old Shell's sort implementation to sort the node-set
2661
     * Timsort ought to be quite faster
2662
     */
2663
    len = set->nodeNr;
2664
    for (incr = len / 2; incr > 0; incr /= 2) {
2665
  for (i = incr; i < len; i++) {
2666
      j = i - incr;
2667
      while (j >= 0) {
2668
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2669
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
2670
      set->nodeTab[j + incr]) == -1)
2671
#else
2672
    if (xmlXPathCmpNodes(set->nodeTab[j],
2673
      set->nodeTab[j + incr]) == -1)
2674
#endif
2675
    {
2676
        tmp = set->nodeTab[j];
2677
        set->nodeTab[j] = set->nodeTab[j + incr];
2678
        set->nodeTab[j + incr] = tmp;
2679
        j -= incr;
2680
    } else
2681
        break;
2682
      }
2683
  }
2684
    }
2685
#else /* WITH_TIM_SORT */
2686
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2687
0
#endif /* WITH_TIM_SORT */
2688
0
}
2689
2690
0
#define XML_NODESET_DEFAULT 10
2691
/**
2692
 * xmlXPathNodeSetDupNs:
2693
 * @node:  the parent node of the namespace XPath node
2694
 * @ns:  the libxml namespace declaration node.
2695
 *
2696
 * Namespace node in libxml don't match the XPath semantic. In a node set
2697
 * the namespace nodes are duplicated and the next pointer is set to the
2698
 * parent node in the XPath semantic.
2699
 *
2700
 * Returns the newly created object.
2701
 */
2702
static xmlNodePtr
2703
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2704
0
    xmlNsPtr cur;
2705
2706
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2707
0
  return(NULL);
2708
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2709
0
  return((xmlNodePtr) ns);
2710
2711
    /*
2712
     * Allocate a new Namespace and fill the fields.
2713
     */
2714
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2715
0
    if (cur == NULL)
2716
0
  return(NULL);
2717
0
    memset(cur, 0, sizeof(xmlNs));
2718
0
    cur->type = XML_NAMESPACE_DECL;
2719
0
    if (ns->href != NULL) {
2720
0
  cur->href = xmlStrdup(ns->href);
2721
0
        if (cur->href == NULL) {
2722
0
            xmlFree(cur);
2723
0
            return(NULL);
2724
0
        }
2725
0
    }
2726
0
    if (ns->prefix != NULL) {
2727
0
  cur->prefix = xmlStrdup(ns->prefix);
2728
0
        if (cur->prefix == NULL) {
2729
0
            xmlFree((xmlChar *) cur->href);
2730
0
            xmlFree(cur);
2731
0
            return(NULL);
2732
0
        }
2733
0
    }
2734
0
    cur->next = (xmlNsPtr) node;
2735
0
    return((xmlNodePtr) cur);
2736
0
}
2737
2738
/**
2739
 * xmlXPathNodeSetFreeNs:
2740
 * @ns:  the XPath namespace node found in a nodeset.
2741
 *
2742
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2743
 * the namespace nodes are duplicated and the next pointer is set to the
2744
 * parent node in the XPath semantic. Check if such a node needs to be freed
2745
 */
2746
void
2747
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2748
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2749
0
  return;
2750
2751
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2752
0
  if (ns->href != NULL)
2753
0
      xmlFree((xmlChar *)ns->href);
2754
0
  if (ns->prefix != NULL)
2755
0
      xmlFree((xmlChar *)ns->prefix);
2756
0
  xmlFree(ns);
2757
0
    }
2758
0
}
2759
2760
/**
2761
 * xmlXPathNodeSetCreate:
2762
 * @val:  an initial xmlNodePtr, or NULL
2763
 *
2764
 * Create a new xmlNodeSetPtr of type double and of value @val
2765
 *
2766
 * Returns the newly created object.
2767
 */
2768
xmlNodeSetPtr
2769
0
xmlXPathNodeSetCreate(xmlNodePtr val) {
2770
0
    xmlNodeSetPtr ret;
2771
2772
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2773
0
    if (ret == NULL)
2774
0
  return(NULL);
2775
0
    memset(ret, 0 , sizeof(xmlNodeSet));
2776
0
    if (val != NULL) {
2777
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2778
0
               sizeof(xmlNodePtr));
2779
0
  if (ret->nodeTab == NULL) {
2780
0
      xmlFree(ret);
2781
0
      return(NULL);
2782
0
  }
2783
0
  memset(ret->nodeTab, 0 ,
2784
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2785
0
        ret->nodeMax = XML_NODESET_DEFAULT;
2786
0
  if (val->type == XML_NAMESPACE_DECL) {
2787
0
      xmlNsPtr ns = (xmlNsPtr) val;
2788
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2789
2790
0
            if (nsNode == NULL) {
2791
0
                xmlXPathFreeNodeSet(ret);
2792
0
                return(NULL);
2793
0
            }
2794
0
      ret->nodeTab[ret->nodeNr++] = nsNode;
2795
0
  } else
2796
0
      ret->nodeTab[ret->nodeNr++] = val;
2797
0
    }
2798
0
    return(ret);
2799
0
}
2800
2801
/**
2802
 * xmlXPathNodeSetContains:
2803
 * @cur:  the node-set
2804
 * @val:  the node
2805
 *
2806
 * checks whether @cur contains @val
2807
 *
2808
 * Returns true (1) if @cur contains @val, false (0) otherwise
2809
 */
2810
int
2811
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2812
0
    int i;
2813
2814
0
    if ((cur == NULL) || (val == NULL)) return(0);
2815
0
    if (val->type == XML_NAMESPACE_DECL) {
2816
0
  for (i = 0; i < cur->nodeNr; i++) {
2817
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2818
0
    xmlNsPtr ns1, ns2;
2819
2820
0
    ns1 = (xmlNsPtr) val;
2821
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2822
0
    if (ns1 == ns2)
2823
0
        return(1);
2824
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2825
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2826
0
        return(1);
2827
0
      }
2828
0
  }
2829
0
    } else {
2830
0
  for (i = 0; i < cur->nodeNr; i++) {
2831
0
      if (cur->nodeTab[i] == val)
2832
0
    return(1);
2833
0
  }
2834
0
    }
2835
0
    return(0);
2836
0
}
2837
2838
/**
2839
 * xmlXPathNodeSetAddNs:
2840
 * @cur:  the initial node set
2841
 * @node:  the hosting node
2842
 * @ns:  a the namespace node
2843
 *
2844
 * add a new namespace node to an existing NodeSet
2845
 *
2846
 * Returns 0 in case of success and -1 in case of error
2847
 */
2848
int
2849
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2850
0
    int i;
2851
0
    xmlNodePtr nsNode;
2852
2853
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2854
0
        (ns->type != XML_NAMESPACE_DECL) ||
2855
0
  (node->type != XML_ELEMENT_NODE))
2856
0
  return(-1);
2857
2858
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2859
    /*
2860
     * prevent duplicates
2861
     */
2862
0
    for (i = 0;i < cur->nodeNr;i++) {
2863
0
        if ((cur->nodeTab[i] != NULL) &&
2864
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2865
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2866
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2867
0
      return(0);
2868
0
    }
2869
2870
    /*
2871
     * grow the nodeTab if needed
2872
     */
2873
0
    if (cur->nodeMax == 0) {
2874
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2875
0
               sizeof(xmlNodePtr));
2876
0
  if (cur->nodeTab == NULL)
2877
0
      return(-1);
2878
0
  memset(cur->nodeTab, 0 ,
2879
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2880
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2881
0
    } else if (cur->nodeNr == cur->nodeMax) {
2882
0
        xmlNodePtr *temp;
2883
2884
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2885
0
            return(-1);
2886
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2887
0
              sizeof(xmlNodePtr));
2888
0
  if (temp == NULL)
2889
0
      return(-1);
2890
0
        cur->nodeMax *= 2;
2891
0
  cur->nodeTab = temp;
2892
0
    }
2893
0
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2894
0
    if(nsNode == NULL)
2895
0
        return(-1);
2896
0
    cur->nodeTab[cur->nodeNr++] = nsNode;
2897
0
    return(0);
2898
0
}
2899
2900
/**
2901
 * xmlXPathNodeSetAdd:
2902
 * @cur:  the initial node set
2903
 * @val:  a new xmlNodePtr
2904
 *
2905
 * add a new xmlNodePtr to an existing NodeSet
2906
 *
2907
 * Returns 0 in case of success, and -1 in case of error
2908
 */
2909
int
2910
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2911
0
    int i;
2912
2913
0
    if ((cur == NULL) || (val == NULL)) return(-1);
2914
2915
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2916
    /*
2917
     * prevent duplicates
2918
     */
2919
0
    for (i = 0;i < cur->nodeNr;i++)
2920
0
        if (cur->nodeTab[i] == val) return(0);
2921
2922
    /*
2923
     * grow the nodeTab if needed
2924
     */
2925
0
    if (cur->nodeMax == 0) {
2926
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2927
0
               sizeof(xmlNodePtr));
2928
0
  if (cur->nodeTab == NULL)
2929
0
      return(-1);
2930
0
  memset(cur->nodeTab, 0 ,
2931
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2932
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2933
0
    } else if (cur->nodeNr == cur->nodeMax) {
2934
0
        xmlNodePtr *temp;
2935
2936
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2937
0
            return(-1);
2938
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2939
0
              sizeof(xmlNodePtr));
2940
0
  if (temp == NULL)
2941
0
      return(-1);
2942
0
        cur->nodeMax *= 2;
2943
0
  cur->nodeTab = temp;
2944
0
    }
2945
0
    if (val->type == XML_NAMESPACE_DECL) {
2946
0
  xmlNsPtr ns = (xmlNsPtr) val;
2947
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2948
2949
0
        if (nsNode == NULL)
2950
0
            return(-1);
2951
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2952
0
    } else
2953
0
  cur->nodeTab[cur->nodeNr++] = val;
2954
0
    return(0);
2955
0
}
2956
2957
/**
2958
 * xmlXPathNodeSetAddUnique:
2959
 * @cur:  the initial node set
2960
 * @val:  a new xmlNodePtr
2961
 *
2962
 * add a new xmlNodePtr to an existing NodeSet, optimized version
2963
 * when we are sure the node is not already in the set.
2964
 *
2965
 * Returns 0 in case of success and -1 in case of failure
2966
 */
2967
int
2968
0
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2969
0
    if ((cur == NULL) || (val == NULL)) return(-1);
2970
2971
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2972
    /*
2973
     * grow the nodeTab if needed
2974
     */
2975
0
    if (cur->nodeMax == 0) {
2976
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2977
0
               sizeof(xmlNodePtr));
2978
0
  if (cur->nodeTab == NULL)
2979
0
      return(-1);
2980
0
  memset(cur->nodeTab, 0 ,
2981
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2982
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2983
0
    } else if (cur->nodeNr == cur->nodeMax) {
2984
0
        xmlNodePtr *temp;
2985
2986
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2987
0
            return(-1);
2988
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2989
0
              sizeof(xmlNodePtr));
2990
0
  if (temp == NULL)
2991
0
      return(-1);
2992
0
  cur->nodeTab = temp;
2993
0
        cur->nodeMax *= 2;
2994
0
    }
2995
0
    if (val->type == XML_NAMESPACE_DECL) {
2996
0
  xmlNsPtr ns = (xmlNsPtr) val;
2997
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2998
2999
0
        if (nsNode == NULL)
3000
0
            return(-1);
3001
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
3002
0
    } else
3003
0
  cur->nodeTab[cur->nodeNr++] = val;
3004
0
    return(0);
3005
0
}
3006
3007
/**
3008
 * xmlXPathNodeSetMerge:
3009
 * @val1:  the first NodeSet or NULL
3010
 * @val2:  the second NodeSet
3011
 *
3012
 * Merges two nodesets, all nodes from @val2 are added to @val1
3013
 * if @val1 is NULL, a new set is created and copied from @val2
3014
 *
3015
 * Returns @val1 once extended or NULL in case of error.
3016
 *
3017
 * Frees @val1 in case of error.
3018
 */
3019
xmlNodeSetPtr
3020
0
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3021
0
    int i, j, initNr, skip;
3022
0
    xmlNodePtr n1, n2;
3023
3024
0
    if (val1 == NULL) {
3025
0
  val1 = xmlXPathNodeSetCreate(NULL);
3026
0
        if (val1 == NULL)
3027
0
            return (NULL);
3028
0
    }
3029
0
    if (val2 == NULL)
3030
0
        return(val1);
3031
3032
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3033
0
    initNr = val1->nodeNr;
3034
3035
0
    for (i = 0;i < val2->nodeNr;i++) {
3036
0
  n2 = val2->nodeTab[i];
3037
  /*
3038
   * check against duplicates
3039
   */
3040
0
  skip = 0;
3041
0
  for (j = 0; j < initNr; j++) {
3042
0
      n1 = val1->nodeTab[j];
3043
0
      if (n1 == n2) {
3044
0
    skip = 1;
3045
0
    break;
3046
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3047
0
           (n2->type == XML_NAMESPACE_DECL)) {
3048
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3049
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3050
0
      ((xmlNsPtr) n2)->prefix)))
3051
0
    {
3052
0
        skip = 1;
3053
0
        break;
3054
0
    }
3055
0
      }
3056
0
  }
3057
0
  if (skip)
3058
0
      continue;
3059
3060
  /*
3061
   * grow the nodeTab if needed
3062
   */
3063
0
  if (val1->nodeMax == 0) {
3064
0
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3065
0
                sizeof(xmlNodePtr));
3066
0
      if (val1->nodeTab == NULL)
3067
0
    goto error;
3068
0
      memset(val1->nodeTab, 0 ,
3069
0
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3070
0
      val1->nodeMax = XML_NODESET_DEFAULT;
3071
0
  } else if (val1->nodeNr == val1->nodeMax) {
3072
0
      xmlNodePtr *temp;
3073
3074
0
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3075
0
                goto error;
3076
0
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3077
0
               sizeof(xmlNodePtr));
3078
0
      if (temp == NULL)
3079
0
    goto error;
3080
0
      val1->nodeTab = temp;
3081
0
      val1->nodeMax *= 2;
3082
0
  }
3083
0
  if (n2->type == XML_NAMESPACE_DECL) {
3084
0
      xmlNsPtr ns = (xmlNsPtr) n2;
3085
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3086
3087
0
            if (nsNode == NULL)
3088
0
                goto error;
3089
0
      val1->nodeTab[val1->nodeNr++] = nsNode;
3090
0
  } else
3091
0
      val1->nodeTab[val1->nodeNr++] = n2;
3092
0
    }
3093
3094
0
    return(val1);
3095
3096
0
error:
3097
0
    xmlXPathFreeNodeSet(val1);
3098
0
    return(NULL);
3099
0
}
3100
3101
3102
/**
3103
 * xmlXPathNodeSetMergeAndClear:
3104
 * @set1:  the first NodeSet or NULL
3105
 * @set2:  the second NodeSet
3106
 *
3107
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3108
 * Checks for duplicate nodes. Clears set2.
3109
 *
3110
 * Returns @set1 once extended or NULL in case of error.
3111
 *
3112
 * Frees @set1 in case of error.
3113
 */
3114
static xmlNodeSetPtr
3115
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3116
0
{
3117
0
    {
3118
0
  int i, j, initNbSet1;
3119
0
  xmlNodePtr n1, n2;
3120
3121
0
  initNbSet1 = set1->nodeNr;
3122
0
  for (i = 0;i < set2->nodeNr;i++) {
3123
0
      n2 = set2->nodeTab[i];
3124
      /*
3125
      * Skip duplicates.
3126
      */
3127
0
      for (j = 0; j < initNbSet1; j++) {
3128
0
    n1 = set1->nodeTab[j];
3129
0
    if (n1 == n2) {
3130
0
        goto skip_node;
3131
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3132
0
        (n2->type == XML_NAMESPACE_DECL))
3133
0
    {
3134
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3135
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3136
0
      ((xmlNsPtr) n2)->prefix)))
3137
0
        {
3138
      /*
3139
      * Free the namespace node.
3140
      */
3141
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3142
0
      goto skip_node;
3143
0
        }
3144
0
    }
3145
0
      }
3146
      /*
3147
      * grow the nodeTab if needed
3148
      */
3149
0
      if (set1->nodeMax == 0) {
3150
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3151
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3152
0
    if (set1->nodeTab == NULL)
3153
0
        goto error;
3154
0
    memset(set1->nodeTab, 0,
3155
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3156
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3157
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3158
0
    xmlNodePtr *temp;
3159
3160
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3161
0
                    goto error;
3162
0
    temp = (xmlNodePtr *) xmlRealloc(
3163
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3164
0
    if (temp == NULL)
3165
0
        goto error;
3166
0
    set1->nodeTab = temp;
3167
0
    set1->nodeMax *= 2;
3168
0
      }
3169
0
      set1->nodeTab[set1->nodeNr++] = n2;
3170
0
skip_node:
3171
0
            set2->nodeTab[i] = NULL;
3172
0
  }
3173
0
    }
3174
0
    set2->nodeNr = 0;
3175
0
    return(set1);
3176
3177
0
error:
3178
0
    xmlXPathFreeNodeSet(set1);
3179
0
    xmlXPathNodeSetClear(set2, 1);
3180
0
    return(NULL);
3181
0
}
3182
3183
/**
3184
 * xmlXPathNodeSetMergeAndClearNoDupls:
3185
 * @set1:  the first NodeSet or NULL
3186
 * @set2:  the second NodeSet
3187
 *
3188
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3189
 * Doesn't check for duplicate nodes. Clears set2.
3190
 *
3191
 * Returns @set1 once extended or NULL in case of error.
3192
 *
3193
 * Frees @set1 in case of error.
3194
 */
3195
static xmlNodeSetPtr
3196
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3197
0
{
3198
0
    {
3199
0
  int i;
3200
0
  xmlNodePtr n2;
3201
3202
0
  for (i = 0;i < set2->nodeNr;i++) {
3203
0
      n2 = set2->nodeTab[i];
3204
0
      if (set1->nodeMax == 0) {
3205
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3206
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3207
0
    if (set1->nodeTab == NULL)
3208
0
        goto error;
3209
0
    memset(set1->nodeTab, 0,
3210
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3211
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3212
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3213
0
    xmlNodePtr *temp;
3214
3215
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3216
0
                    goto error;
3217
0
    temp = (xmlNodePtr *) xmlRealloc(
3218
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3219
0
    if (temp == NULL)
3220
0
        goto error;
3221
0
    set1->nodeTab = temp;
3222
0
    set1->nodeMax *= 2;
3223
0
      }
3224
0
      set1->nodeTab[set1->nodeNr++] = n2;
3225
0
            set2->nodeTab[i] = NULL;
3226
0
  }
3227
0
    }
3228
0
    set2->nodeNr = 0;
3229
0
    return(set1);
3230
3231
0
error:
3232
0
    xmlXPathFreeNodeSet(set1);
3233
0
    xmlXPathNodeSetClear(set2, 1);
3234
0
    return(NULL);
3235
0
}
3236
3237
/**
3238
 * xmlXPathNodeSetDel:
3239
 * @cur:  the initial node set
3240
 * @val:  an xmlNodePtr
3241
 *
3242
 * Removes an xmlNodePtr from an existing NodeSet
3243
 */
3244
void
3245
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3246
0
    int i;
3247
3248
0
    if (cur == NULL) return;
3249
0
    if (val == NULL) return;
3250
3251
    /*
3252
     * find node in nodeTab
3253
     */
3254
0
    for (i = 0;i < cur->nodeNr;i++)
3255
0
        if (cur->nodeTab[i] == val) break;
3256
3257
0
    if (i >= cur->nodeNr) { /* not found */
3258
0
        return;
3259
0
    }
3260
0
    if ((cur->nodeTab[i] != NULL) &&
3261
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3262
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3263
0
    cur->nodeNr--;
3264
0
    for (;i < cur->nodeNr;i++)
3265
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
3266
0
    cur->nodeTab[cur->nodeNr] = NULL;
3267
0
}
3268
3269
/**
3270
 * xmlXPathNodeSetRemove:
3271
 * @cur:  the initial node set
3272
 * @val:  the index to remove
3273
 *
3274
 * Removes an entry from an existing NodeSet list.
3275
 */
3276
void
3277
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3278
0
    if (cur == NULL) return;
3279
0
    if (val >= cur->nodeNr) return;
3280
0
    if ((cur->nodeTab[val] != NULL) &&
3281
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3282
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3283
0
    cur->nodeNr--;
3284
0
    for (;val < cur->nodeNr;val++)
3285
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
3286
0
    cur->nodeTab[cur->nodeNr] = NULL;
3287
0
}
3288
3289
/**
3290
 * xmlXPathFreeNodeSet:
3291
 * @obj:  the xmlNodeSetPtr to free
3292
 *
3293
 * Free the NodeSet compound (not the actual nodes !).
3294
 */
3295
void
3296
0
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3297
0
    if (obj == NULL) return;
3298
0
    if (obj->nodeTab != NULL) {
3299
0
  int i;
3300
3301
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3302
0
  for (i = 0;i < obj->nodeNr;i++)
3303
0
      if ((obj->nodeTab[i] != NULL) &&
3304
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3305
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3306
0
  xmlFree(obj->nodeTab);
3307
0
    }
3308
0
    xmlFree(obj);
3309
0
}
3310
3311
/**
3312
 * xmlXPathNodeSetClearFromPos:
3313
 * @set: the node set to be cleared
3314
 * @pos: the start position to clear from
3315
 *
3316
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3317
 * are feed) starting with the entry at @pos, but does *not* free the list
3318
 * itself. Sets the length of the list to @pos.
3319
 */
3320
static void
3321
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3322
0
{
3323
0
    if ((set == NULL) || (pos >= set->nodeNr))
3324
0
  return;
3325
0
    else if ((hasNsNodes)) {
3326
0
  int i;
3327
0
  xmlNodePtr node;
3328
3329
0
  for (i = pos; i < set->nodeNr; i++) {
3330
0
      node = set->nodeTab[i];
3331
0
      if ((node != NULL) &&
3332
0
    (node->type == XML_NAMESPACE_DECL))
3333
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3334
0
  }
3335
0
    }
3336
0
    set->nodeNr = pos;
3337
0
}
3338
3339
/**
3340
 * xmlXPathNodeSetClear:
3341
 * @set:  the node set to clear
3342
 *
3343
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3344
 * are feed), but does *not* free the list itself. Sets the length of the
3345
 * list to 0.
3346
 */
3347
static void
3348
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3349
0
{
3350
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3351
0
}
3352
3353
/**
3354
 * xmlXPathNodeSetKeepLast:
3355
 * @set: the node set to be cleared
3356
 *
3357
 * Move the last node to the first position and clear temporary XPath objects
3358
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3359
 * to 1.
3360
 */
3361
static void
3362
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3363
0
{
3364
0
    int i;
3365
0
    xmlNodePtr node;
3366
3367
0
    if ((set == NULL) || (set->nodeNr <= 1))
3368
0
  return;
3369
0
    for (i = 0; i < set->nodeNr - 1; i++) {
3370
0
        node = set->nodeTab[i];
3371
0
        if ((node != NULL) &&
3372
0
            (node->type == XML_NAMESPACE_DECL))
3373
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3374
0
    }
3375
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3376
0
    set->nodeNr = 1;
3377
0
}
3378
3379
/**
3380
 * xmlXPathNewNodeSet:
3381
 * @val:  the NodePtr value
3382
 *
3383
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3384
 * it with the single Node @val
3385
 *
3386
 * Returns the newly created object.
3387
 */
3388
xmlXPathObjectPtr
3389
0
xmlXPathNewNodeSet(xmlNodePtr val) {
3390
0
    xmlXPathObjectPtr ret;
3391
3392
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3393
0
    if (ret == NULL)
3394
0
  return(NULL);
3395
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3396
0
    ret->type = XPATH_NODESET;
3397
0
    ret->boolval = 0;
3398
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3399
0
    if (ret->nodesetval == NULL) {
3400
0
        xmlFree(ret);
3401
0
        return(NULL);
3402
0
    }
3403
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3404
0
    return(ret);
3405
0
}
3406
3407
/**
3408
 * xmlXPathNewValueTree:
3409
 * @val:  the NodePtr value
3410
 *
3411
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3412
 * it with the tree root @val
3413
 *
3414
 * Returns the newly created object.
3415
 */
3416
xmlXPathObjectPtr
3417
0
xmlXPathNewValueTree(xmlNodePtr val) {
3418
0
    xmlXPathObjectPtr ret;
3419
3420
0
    ret = xmlXPathNewNodeSet(val);
3421
0
    if (ret == NULL)
3422
0
  return(NULL);
3423
0
    ret->type = XPATH_XSLT_TREE;
3424
3425
0
    return(ret);
3426
0
}
3427
3428
/**
3429
 * xmlXPathNewNodeSetList:
3430
 * @val:  an existing NodeSet
3431
 *
3432
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3433
 * it with the Nodeset @val
3434
 *
3435
 * Returns the newly created object.
3436
 */
3437
xmlXPathObjectPtr
3438
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3439
0
{
3440
0
    xmlXPathObjectPtr ret;
3441
3442
0
    if (val == NULL)
3443
0
        ret = NULL;
3444
0
    else if (val->nodeTab == NULL)
3445
0
        ret = xmlXPathNewNodeSet(NULL);
3446
0
    else {
3447
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3448
0
        if (ret) {
3449
0
            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3450
0
            if (ret->nodesetval == NULL) {
3451
0
                xmlFree(ret);
3452
0
                return(NULL);
3453
0
            }
3454
0
        }
3455
0
    }
3456
3457
0
    return (ret);
3458
0
}
3459
3460
/**
3461
 * xmlXPathWrapNodeSet:
3462
 * @val:  the NodePtr value
3463
 *
3464
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3465
 *
3466
 * Returns the newly created object.
3467
 *
3468
 * In case of error the node set is destroyed and NULL is returned.
3469
 */
3470
xmlXPathObjectPtr
3471
0
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3472
0
    xmlXPathObjectPtr ret;
3473
3474
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3475
0
    if (ret == NULL) {
3476
0
        xmlXPathFreeNodeSet(val);
3477
0
  return(NULL);
3478
0
    }
3479
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3480
0
    ret->type = XPATH_NODESET;
3481
0
    ret->nodesetval = val;
3482
0
    return(ret);
3483
0
}
3484
3485
/**
3486
 * xmlXPathFreeNodeSetList:
3487
 * @obj:  an existing NodeSetList object
3488
 *
3489
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3490
 * the list contrary to xmlXPathFreeObject().
3491
 */
3492
void
3493
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3494
0
    if (obj == NULL) return;
3495
0
    xmlFree(obj);
3496
0
}
3497
3498
/**
3499
 * xmlXPathDifference:
3500
 * @nodes1:  a node-set
3501
 * @nodes2:  a node-set
3502
 *
3503
 * Implements the EXSLT - Sets difference() function:
3504
 *    node-set set:difference (node-set, node-set)
3505
 *
3506
 * Returns the difference between the two node sets, or nodes1 if
3507
 *         nodes2 is empty
3508
 */
3509
xmlNodeSetPtr
3510
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3511
0
    xmlNodeSetPtr ret;
3512
0
    int i, l1;
3513
0
    xmlNodePtr cur;
3514
3515
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3516
0
  return(nodes1);
3517
3518
0
    ret = xmlXPathNodeSetCreate(NULL);
3519
0
    if (ret == NULL)
3520
0
        return(NULL);
3521
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3522
0
  return(ret);
3523
3524
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3525
3526
0
    for (i = 0; i < l1; i++) {
3527
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3528
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3529
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3530
0
                xmlXPathFreeNodeSet(ret);
3531
0
          return(NULL);
3532
0
            }
3533
0
  }
3534
0
    }
3535
0
    return(ret);
3536
0
}
3537
3538
/**
3539
 * xmlXPathIntersection:
3540
 * @nodes1:  a node-set
3541
 * @nodes2:  a node-set
3542
 *
3543
 * Implements the EXSLT - Sets intersection() function:
3544
 *    node-set set:intersection (node-set, node-set)
3545
 *
3546
 * Returns a node set comprising the nodes that are within both the
3547
 *         node sets passed as arguments
3548
 */
3549
xmlNodeSetPtr
3550
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3551
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3552
0
    int i, l1;
3553
0
    xmlNodePtr cur;
3554
3555
0
    if (ret == NULL)
3556
0
        return(ret);
3557
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3558
0
  return(ret);
3559
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3560
0
  return(ret);
3561
3562
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3563
3564
0
    for (i = 0; i < l1; i++) {
3565
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3566
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3567
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3568
0
                xmlXPathFreeNodeSet(ret);
3569
0
          return(NULL);
3570
0
            }
3571
0
  }
3572
0
    }
3573
0
    return(ret);
3574
0
}
3575
3576
/**
3577
 * xmlXPathDistinctSorted:
3578
 * @nodes:  a node-set, sorted by document order
3579
 *
3580
 * Implements the EXSLT - Sets distinct() function:
3581
 *    node-set set:distinct (node-set)
3582
 *
3583
 * Returns a subset of the nodes contained in @nodes, or @nodes if
3584
 *         it is empty
3585
 */
3586
xmlNodeSetPtr
3587
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3588
0
    xmlNodeSetPtr ret;
3589
0
    xmlHashTablePtr hash;
3590
0
    int i, l;
3591
0
    xmlChar * strval;
3592
0
    xmlNodePtr cur;
3593
3594
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3595
0
  return(nodes);
3596
3597
0
    ret = xmlXPathNodeSetCreate(NULL);
3598
0
    if (ret == NULL)
3599
0
        return(ret);
3600
0
    l = xmlXPathNodeSetGetLength(nodes);
3601
0
    hash = xmlHashCreate (l);
3602
0
    for (i = 0; i < l; i++) {
3603
0
  cur = xmlXPathNodeSetItem(nodes, i);
3604
0
  strval = xmlXPathCastNodeToString(cur);
3605
0
  if (xmlHashLookup(hash, strval) == NULL) {
3606
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3607
0
                xmlFree(strval);
3608
0
                goto error;
3609
0
            }
3610
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3611
0
          goto error;
3612
0
  } else {
3613
0
      xmlFree(strval);
3614
0
  }
3615
0
    }
3616
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3617
0
    return(ret);
3618
3619
0
error:
3620
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3621
0
    xmlXPathFreeNodeSet(ret);
3622
0
    return(NULL);
3623
0
}
3624
3625
/**
3626
 * xmlXPathDistinct:
3627
 * @nodes:  a node-set
3628
 *
3629
 * Implements the EXSLT - Sets distinct() function:
3630
 *    node-set set:distinct (node-set)
3631
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3632
 * is called with the sorted node-set
3633
 *
3634
 * Returns a subset of the nodes contained in @nodes, or @nodes if
3635
 *         it is empty
3636
 */
3637
xmlNodeSetPtr
3638
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
3639
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3640
0
  return(nodes);
3641
3642
0
    xmlXPathNodeSetSort(nodes);
3643
0
    return(xmlXPathDistinctSorted(nodes));
3644
0
}
3645
3646
/**
3647
 * xmlXPathHasSameNodes:
3648
 * @nodes1:  a node-set
3649
 * @nodes2:  a node-set
3650
 *
3651
 * Implements the EXSLT - Sets has-same-nodes function:
3652
 *    boolean set:has-same-node(node-set, node-set)
3653
 *
3654
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3655
 *         otherwise
3656
 */
3657
int
3658
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3659
0
    int i, l;
3660
0
    xmlNodePtr cur;
3661
3662
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3663
0
  xmlXPathNodeSetIsEmpty(nodes2))
3664
0
  return(0);
3665
3666
0
    l = xmlXPathNodeSetGetLength(nodes1);
3667
0
    for (i = 0; i < l; i++) {
3668
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3669
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3670
0
      return(1);
3671
0
    }
3672
0
    return(0);
3673
0
}
3674
3675
/**
3676
 * xmlXPathNodeLeadingSorted:
3677
 * @nodes: a node-set, sorted by document order
3678
 * @node: a node
3679
 *
3680
 * Implements the EXSLT - Sets leading() function:
3681
 *    node-set set:leading (node-set, node-set)
3682
 *
3683
 * Returns the nodes in @nodes that precede @node in document order,
3684
 *         @nodes if @node is NULL or an empty node-set if @nodes
3685
 *         doesn't contain @node
3686
 */
3687
xmlNodeSetPtr
3688
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3689
0
    int i, l;
3690
0
    xmlNodePtr cur;
3691
0
    xmlNodeSetPtr ret;
3692
3693
0
    if (node == NULL)
3694
0
  return(nodes);
3695
3696
0
    ret = xmlXPathNodeSetCreate(NULL);
3697
0
    if (ret == NULL)
3698
0
        return(ret);
3699
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3700
0
  (!xmlXPathNodeSetContains(nodes, node)))
3701
0
  return(ret);
3702
3703
0
    l = xmlXPathNodeSetGetLength(nodes);
3704
0
    for (i = 0; i < l; i++) {
3705
0
  cur = xmlXPathNodeSetItem(nodes, i);
3706
0
  if (cur == node)
3707
0
      break;
3708
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3709
0
            xmlXPathFreeNodeSet(ret);
3710
0
      return(NULL);
3711
0
        }
3712
0
    }
3713
0
    return(ret);
3714
0
}
3715
3716
/**
3717
 * xmlXPathNodeLeading:
3718
 * @nodes:  a node-set
3719
 * @node:  a node
3720
 *
3721
 * Implements the EXSLT - Sets leading() function:
3722
 *    node-set set:leading (node-set, node-set)
3723
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3724
 * is called.
3725
 *
3726
 * Returns the nodes in @nodes that precede @node in document order,
3727
 *         @nodes if @node is NULL or an empty node-set if @nodes
3728
 *         doesn't contain @node
3729
 */
3730
xmlNodeSetPtr
3731
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3732
0
    xmlXPathNodeSetSort(nodes);
3733
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3734
0
}
3735
3736
/**
3737
 * xmlXPathLeadingSorted:
3738
 * @nodes1:  a node-set, sorted by document order
3739
 * @nodes2:  a node-set, sorted by document order
3740
 *
3741
 * Implements the EXSLT - Sets leading() function:
3742
 *    node-set set:leading (node-set, node-set)
3743
 *
3744
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3745
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3746
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3747
 */
3748
xmlNodeSetPtr
3749
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3750
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3751
0
  return(nodes1);
3752
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3753
0
             xmlXPathNodeSetItem(nodes2, 1)));
3754
0
}
3755
3756
/**
3757
 * xmlXPathLeading:
3758
 * @nodes1:  a node-set
3759
 * @nodes2:  a node-set
3760
 *
3761
 * Implements the EXSLT - Sets leading() function:
3762
 *    node-set set:leading (node-set, node-set)
3763
 * @nodes1 and @nodes2 are sorted by document order, then
3764
 * #exslSetsLeadingSorted is called.
3765
 *
3766
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3767
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3768
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3769
 */
3770
xmlNodeSetPtr
3771
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3772
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3773
0
  return(nodes1);
3774
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3775
0
  return(xmlXPathNodeSetCreate(NULL));
3776
0
    xmlXPathNodeSetSort(nodes1);
3777
0
    xmlXPathNodeSetSort(nodes2);
3778
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3779
0
             xmlXPathNodeSetItem(nodes2, 1)));
3780
0
}
3781
3782
/**
3783
 * xmlXPathNodeTrailingSorted:
3784
 * @nodes: a node-set, sorted by document order
3785
 * @node: a node
3786
 *
3787
 * Implements the EXSLT - Sets trailing() function:
3788
 *    node-set set:trailing (node-set, node-set)
3789
 *
3790
 * Returns the nodes in @nodes that follow @node in document order,
3791
 *         @nodes if @node is NULL or an empty node-set if @nodes
3792
 *         doesn't contain @node
3793
 */
3794
xmlNodeSetPtr
3795
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3796
0
    int i, l;
3797
0
    xmlNodePtr cur;
3798
0
    xmlNodeSetPtr ret;
3799
3800
0
    if (node == NULL)
3801
0
  return(nodes);
3802
3803
0
    ret = xmlXPathNodeSetCreate(NULL);
3804
0
    if (ret == NULL)
3805
0
        return(ret);
3806
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3807
0
  (!xmlXPathNodeSetContains(nodes, node)))
3808
0
  return(ret);
3809
3810
0
    l = xmlXPathNodeSetGetLength(nodes);
3811
0
    for (i = l - 1; i >= 0; i--) {
3812
0
  cur = xmlXPathNodeSetItem(nodes, i);
3813
0
  if (cur == node)
3814
0
      break;
3815
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3816
0
            xmlXPathFreeNodeSet(ret);
3817
0
      return(NULL);
3818
0
        }
3819
0
    }
3820
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3821
0
    return(ret);
3822
0
}
3823
3824
/**
3825
 * xmlXPathNodeTrailing:
3826
 * @nodes:  a node-set
3827
 * @node:  a node
3828
 *
3829
 * Implements the EXSLT - Sets trailing() function:
3830
 *    node-set set:trailing (node-set, node-set)
3831
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3832
 * is called.
3833
 *
3834
 * Returns the nodes in @nodes that follow @node in document order,
3835
 *         @nodes if @node is NULL or an empty node-set if @nodes
3836
 *         doesn't contain @node
3837
 */
3838
xmlNodeSetPtr
3839
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3840
0
    xmlXPathNodeSetSort(nodes);
3841
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3842
0
}
3843
3844
/**
3845
 * xmlXPathTrailingSorted:
3846
 * @nodes1:  a node-set, sorted by document order
3847
 * @nodes2:  a node-set, sorted by document order
3848
 *
3849
 * Implements the EXSLT - Sets trailing() function:
3850
 *    node-set set:trailing (node-set, node-set)
3851
 *
3852
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3853
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3854
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3855
 */
3856
xmlNodeSetPtr
3857
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3858
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3859
0
  return(nodes1);
3860
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3861
0
              xmlXPathNodeSetItem(nodes2, 0)));
3862
0
}
3863
3864
/**
3865
 * xmlXPathTrailing:
3866
 * @nodes1:  a node-set
3867
 * @nodes2:  a node-set
3868
 *
3869
 * Implements the EXSLT - Sets trailing() function:
3870
 *    node-set set:trailing (node-set, node-set)
3871
 * @nodes1 and @nodes2 are sorted by document order, then
3872
 * #xmlXPathTrailingSorted is called.
3873
 *
3874
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3875
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3876
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3877
 */
3878
xmlNodeSetPtr
3879
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3880
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3881
0
  return(nodes1);
3882
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3883
0
  return(xmlXPathNodeSetCreate(NULL));
3884
0
    xmlXPathNodeSetSort(nodes1);
3885
0
    xmlXPathNodeSetSort(nodes2);
3886
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3887
0
              xmlXPathNodeSetItem(nodes2, 0)));
3888
0
}
3889
3890
/************************************************************************
3891
 *                  *
3892
 *    Routines to handle extra functions      *
3893
 *                  *
3894
 ************************************************************************/
3895
3896
/**
3897
 * xmlXPathRegisterFunc:
3898
 * @ctxt:  the XPath context
3899
 * @name:  the function name
3900
 * @f:  the function implementation or NULL
3901
 *
3902
 * Register a new function. If @f is NULL it unregisters the function
3903
 *
3904
 * Returns 0 in case of success, -1 in case of error
3905
 */
3906
int
3907
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3908
0
         xmlXPathFunction f) {
3909
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3910
0
}
3911
3912
/**
3913
 * xmlXPathRegisterFuncNS:
3914
 * @ctxt:  the XPath context
3915
 * @name:  the function name
3916
 * @ns_uri:  the function namespace URI
3917
 * @f:  the function implementation or NULL
3918
 *
3919
 * Register a new function. If @f is NULL it unregisters the function
3920
 *
3921
 * Returns 0 in case of success, -1 in case of error
3922
 */
3923
int
3924
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3925
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
3926
0
    int ret;
3927
3928
0
    if (ctxt == NULL)
3929
0
  return(-1);
3930
0
    if (name == NULL)
3931
0
  return(-1);
3932
3933
0
    if (ctxt->funcHash == NULL)
3934
0
  ctxt->funcHash = xmlHashCreate(0);
3935
0
    if (ctxt->funcHash == NULL) {
3936
0
        xmlXPathErrMemory(ctxt);
3937
0
  return(-1);
3938
0
    }
3939
0
    if (f == NULL)
3940
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3941
0
XML_IGNORE_FPTR_CAST_WARNINGS
3942
0
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3943
0
XML_POP_WARNINGS
3944
0
    if (ret < 0) {
3945
0
        xmlXPathErrMemory(ctxt);
3946
0
        return(-1);
3947
0
    }
3948
3949
0
    return(0);
3950
0
}
3951
3952
/**
3953
 * xmlXPathRegisterFuncLookup:
3954
 * @ctxt:  the XPath context
3955
 * @f:  the lookup function
3956
 * @funcCtxt:  the lookup data
3957
 *
3958
 * Registers an external mechanism to do function lookup.
3959
 */
3960
void
3961
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3962
          xmlXPathFuncLookupFunc f,
3963
0
          void *funcCtxt) {
3964
0
    if (ctxt == NULL)
3965
0
  return;
3966
0
    ctxt->funcLookupFunc = f;
3967
0
    ctxt->funcLookupData = funcCtxt;
3968
0
}
3969
3970
/**
3971
 * xmlXPathFunctionLookup:
3972
 * @ctxt:  the XPath context
3973
 * @name:  the function name
3974
 *
3975
 * Search in the Function array of the context for the given
3976
 * function.
3977
 *
3978
 * Returns the xmlXPathFunction or NULL if not found
3979
 */
3980
xmlXPathFunction
3981
0
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3982
0
    if (ctxt == NULL)
3983
0
  return (NULL);
3984
3985
0
    if (ctxt->funcLookupFunc != NULL) {
3986
0
  xmlXPathFunction ret;
3987
0
  xmlXPathFuncLookupFunc f;
3988
3989
0
  f = ctxt->funcLookupFunc;
3990
0
  ret = f(ctxt->funcLookupData, name, NULL);
3991
0
  if (ret != NULL)
3992
0
      return(ret);
3993
0
    }
3994
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3995
0
}
3996
3997
/**
3998
 * xmlXPathFunctionLookupNS:
3999
 * @ctxt:  the XPath context
4000
 * @name:  the function name
4001
 * @ns_uri:  the function namespace URI
4002
 *
4003
 * Search in the Function array of the context for the given
4004
 * function.
4005
 *
4006
 * Returns the xmlXPathFunction or NULL if not found
4007
 */
4008
xmlXPathFunction
4009
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4010
0
       const xmlChar *ns_uri) {
4011
0
    xmlXPathFunction ret;
4012
4013
0
    if (ctxt == NULL)
4014
0
  return(NULL);
4015
0
    if (name == NULL)
4016
0
  return(NULL);
4017
4018
0
    if (ctxt->funcLookupFunc != NULL) {
4019
0
  xmlXPathFuncLookupFunc f;
4020
4021
0
  f = ctxt->funcLookupFunc;
4022
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
4023
0
  if (ret != NULL)
4024
0
      return(ret);
4025
0
    }
4026
4027
0
    if (ctxt->funcHash == NULL)
4028
0
  return(NULL);
4029
4030
0
XML_IGNORE_FPTR_CAST_WARNINGS
4031
0
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4032
0
XML_POP_WARNINGS
4033
0
    return(ret);
4034
0
}
4035
4036
/**
4037
 * xmlXPathRegisteredFuncsCleanup:
4038
 * @ctxt:  the XPath context
4039
 *
4040
 * Cleanup the XPath context data associated to registered functions
4041
 */
4042
void
4043
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4044
0
    if (ctxt == NULL)
4045
0
  return;
4046
4047
0
    xmlHashFree(ctxt->funcHash, NULL);
4048
0
    ctxt->funcHash = NULL;
4049
0
}
4050
4051
/************************************************************************
4052
 *                  *
4053
 *      Routines to handle Variables      *
4054
 *                  *
4055
 ************************************************************************/
4056
4057
/**
4058
 * xmlXPathRegisterVariable:
4059
 * @ctxt:  the XPath context
4060
 * @name:  the variable name
4061
 * @value:  the variable value or NULL
4062
 *
4063
 * Register a new variable value. If @value is NULL it unregisters
4064
 * the variable
4065
 *
4066
 * Returns 0 in case of success, -1 in case of error
4067
 */
4068
int
4069
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4070
0
       xmlXPathObjectPtr value) {
4071
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4072
0
}
4073
4074
/**
4075
 * xmlXPathRegisterVariableNS:
4076
 * @ctxt:  the XPath context
4077
 * @name:  the variable name
4078
 * @ns_uri:  the variable namespace URI
4079
 * @value:  the variable value or NULL
4080
 *
4081
 * Register a new variable value. If @value is NULL it unregisters
4082
 * the variable
4083
 *
4084
 * Returns 0 in case of success, -1 in case of error
4085
 */
4086
int
4087
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4088
         const xmlChar *ns_uri,
4089
0
         xmlXPathObjectPtr value) {
4090
0
    if (ctxt == NULL)
4091
0
  return(-1);
4092
0
    if (name == NULL)
4093
0
  return(-1);
4094
4095
0
    if (ctxt->varHash == NULL)
4096
0
  ctxt->varHash = xmlHashCreate(0);
4097
0
    if (ctxt->varHash == NULL)
4098
0
  return(-1);
4099
0
    if (value == NULL)
4100
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4101
0
                             xmlXPathFreeObjectEntry));
4102
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4103
0
             (void *) value, xmlXPathFreeObjectEntry));
4104
0
}
4105
4106
/**
4107
 * xmlXPathRegisterVariableLookup:
4108
 * @ctxt:  the XPath context
4109
 * @f:  the lookup function
4110
 * @data:  the lookup data
4111
 *
4112
 * register an external mechanism to do variable lookup
4113
 */
4114
void
4115
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4116
0
   xmlXPathVariableLookupFunc f, void *data) {
4117
0
    if (ctxt == NULL)
4118
0
  return;
4119
0
    ctxt->varLookupFunc = f;
4120
0
    ctxt->varLookupData = data;
4121
0
}
4122
4123
/**
4124
 * xmlXPathVariableLookup:
4125
 * @ctxt:  the XPath context
4126
 * @name:  the variable name
4127
 *
4128
 * Search in the Variable array of the context for the given
4129
 * variable value.
4130
 *
4131
 * Returns a copy of the value or NULL if not found
4132
 */
4133
xmlXPathObjectPtr
4134
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4135
0
    if (ctxt == NULL)
4136
0
  return(NULL);
4137
4138
0
    if (ctxt->varLookupFunc != NULL) {
4139
0
  xmlXPathObjectPtr ret;
4140
4141
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4142
0
          (ctxt->varLookupData, name, NULL);
4143
0
  return(ret);
4144
0
    }
4145
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4146
0
}
4147
4148
/**
4149
 * xmlXPathVariableLookupNS:
4150
 * @ctxt:  the XPath context
4151
 * @name:  the variable name
4152
 * @ns_uri:  the variable namespace URI
4153
 *
4154
 * Search in the Variable array of the context for the given
4155
 * variable value.
4156
 *
4157
 * Returns the a copy of the value or NULL if not found
4158
 */
4159
xmlXPathObjectPtr
4160
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4161
0
       const xmlChar *ns_uri) {
4162
0
    if (ctxt == NULL)
4163
0
  return(NULL);
4164
4165
0
    if (ctxt->varLookupFunc != NULL) {
4166
0
  xmlXPathObjectPtr ret;
4167
4168
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4169
0
          (ctxt->varLookupData, name, ns_uri);
4170
0
  if (ret != NULL) return(ret);
4171
0
    }
4172
4173
0
    if (ctxt->varHash == NULL)
4174
0
  return(NULL);
4175
0
    if (name == NULL)
4176
0
  return(NULL);
4177
4178
0
    return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4179
0
}
4180
4181
/**
4182
 * xmlXPathRegisteredVariablesCleanup:
4183
 * @ctxt:  the XPath context
4184
 *
4185
 * Cleanup the XPath context data associated to registered variables
4186
 */
4187
void
4188
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4189
0
    if (ctxt == NULL)
4190
0
  return;
4191
4192
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4193
0
    ctxt->varHash = NULL;
4194
0
}
4195
4196
/**
4197
 * xmlXPathRegisterNs:
4198
 * @ctxt:  the XPath context
4199
 * @prefix:  the namespace prefix cannot be NULL or empty string
4200
 * @ns_uri:  the namespace name
4201
 *
4202
 * Register a new namespace. If @ns_uri is NULL it unregisters
4203
 * the namespace
4204
 *
4205
 * Returns 0 in case of success, -1 in case of error
4206
 */
4207
int
4208
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4209
0
         const xmlChar *ns_uri) {
4210
0
    xmlChar *copy;
4211
4212
0
    if (ctxt == NULL)
4213
0
  return(-1);
4214
0
    if (prefix == NULL)
4215
0
  return(-1);
4216
0
    if (prefix[0] == 0)
4217
0
  return(-1);
4218
4219
0
    if (ctxt->nsHash == NULL)
4220
0
  ctxt->nsHash = xmlHashCreate(10);
4221
0
    if (ctxt->nsHash == NULL) {
4222
0
        xmlXPathErrMemory(ctxt);
4223
0
  return(-1);
4224
0
    }
4225
0
    if (ns_uri == NULL)
4226
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4227
0
                            xmlHashDefaultDeallocator));
4228
4229
0
    copy = xmlStrdup(ns_uri);
4230
0
    if (copy == NULL) {
4231
0
        xmlXPathErrMemory(ctxt);
4232
0
        return(-1);
4233
0
    }
4234
0
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4235
0
                           xmlHashDefaultDeallocator) < 0) {
4236
0
        xmlXPathErrMemory(ctxt);
4237
0
        xmlFree(copy);
4238
0
        return(-1);
4239
0
    }
4240
4241
0
    return(0);
4242
0
}
4243
4244
/**
4245
 * xmlXPathNsLookup:
4246
 * @ctxt:  the XPath context
4247
 * @prefix:  the namespace prefix value
4248
 *
4249
 * Search in the namespace declaration array of the context for the given
4250
 * namespace name associated to the given prefix
4251
 *
4252
 * Returns the value or NULL if not found
4253
 */
4254
const xmlChar *
4255
0
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4256
0
    if (ctxt == NULL)
4257
0
  return(NULL);
4258
0
    if (prefix == NULL)
4259
0
  return(NULL);
4260
4261
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4262
0
  return(XML_XML_NAMESPACE);
4263
4264
0
    if (ctxt->namespaces != NULL) {
4265
0
  int i;
4266
4267
0
  for (i = 0;i < ctxt->nsNr;i++) {
4268
0
      if ((ctxt->namespaces[i] != NULL) &&
4269
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4270
0
    return(ctxt->namespaces[i]->href);
4271
0
  }
4272
0
    }
4273
4274
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4275
0
}
4276
4277
/**
4278
 * xmlXPathRegisteredNsCleanup:
4279
 * @ctxt:  the XPath context
4280
 *
4281
 * Cleanup the XPath context data associated to registered variables
4282
 */
4283
void
4284
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4285
0
    if (ctxt == NULL)
4286
0
  return;
4287
4288
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4289
0
    ctxt->nsHash = NULL;
4290
0
}
4291
4292
/************************************************************************
4293
 *                  *
4294
 *      Routines to handle Values     *
4295
 *                  *
4296
 ************************************************************************/
4297
4298
/* Allocations are terrible, one needs to optimize all this !!! */
4299
4300
/**
4301
 * xmlXPathNewFloat:
4302
 * @val:  the double value
4303
 *
4304
 * Create a new xmlXPathObjectPtr of type double and of value @val
4305
 *
4306
 * Returns the newly created object.
4307
 */
4308
xmlXPathObjectPtr
4309
0
xmlXPathNewFloat(double val) {
4310
0
    xmlXPathObjectPtr ret;
4311
4312
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4313
0
    if (ret == NULL)
4314
0
  return(NULL);
4315
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4316
0
    ret->type = XPATH_NUMBER;
4317
0
    ret->floatval = val;
4318
0
    return(ret);
4319
0
}
4320
4321
/**
4322
 * xmlXPathNewBoolean:
4323
 * @val:  the boolean value
4324
 *
4325
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4326
 *
4327
 * Returns the newly created object.
4328
 */
4329
xmlXPathObjectPtr
4330
0
xmlXPathNewBoolean(int val) {
4331
0
    xmlXPathObjectPtr ret;
4332
4333
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4334
0
    if (ret == NULL)
4335
0
  return(NULL);
4336
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4337
0
    ret->type = XPATH_BOOLEAN;
4338
0
    ret->boolval = (val != 0);
4339
0
    return(ret);
4340
0
}
4341
4342
/**
4343
 * xmlXPathNewString:
4344
 * @val:  the xmlChar * value
4345
 *
4346
 * Create a new xmlXPathObjectPtr of type string and of value @val
4347
 *
4348
 * Returns the newly created object.
4349
 */
4350
xmlXPathObjectPtr
4351
0
xmlXPathNewString(const xmlChar *val) {
4352
0
    xmlXPathObjectPtr ret;
4353
4354
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4355
0
    if (ret == NULL)
4356
0
  return(NULL);
4357
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4358
0
    ret->type = XPATH_STRING;
4359
0
    if (val == NULL)
4360
0
        val = BAD_CAST "";
4361
0
    ret->stringval = xmlStrdup(val);
4362
0
    if (ret->stringval == NULL) {
4363
0
        xmlFree(ret);
4364
0
        return(NULL);
4365
0
    }
4366
0
    return(ret);
4367
0
}
4368
4369
/**
4370
 * xmlXPathWrapString:
4371
 * @val:  the xmlChar * value
4372
 *
4373
 * Wraps the @val string into an XPath object.
4374
 *
4375
 * Returns the newly created object.
4376
 *
4377
 * Frees @val in case of error.
4378
 */
4379
xmlXPathObjectPtr
4380
0
xmlXPathWrapString (xmlChar *val) {
4381
0
    xmlXPathObjectPtr ret;
4382
4383
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4384
0
    if (ret == NULL) {
4385
0
        xmlFree(val);
4386
0
  return(NULL);
4387
0
    }
4388
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4389
0
    ret->type = XPATH_STRING;
4390
0
    ret->stringval = val;
4391
0
    return(ret);
4392
0
}
4393
4394
/**
4395
 * xmlXPathNewCString:
4396
 * @val:  the char * value
4397
 *
4398
 * Create a new xmlXPathObjectPtr of type string and of value @val
4399
 *
4400
 * Returns the newly created object.
4401
 */
4402
xmlXPathObjectPtr
4403
0
xmlXPathNewCString(const char *val) {
4404
0
    return(xmlXPathNewString(BAD_CAST val));
4405
0
}
4406
4407
/**
4408
 * xmlXPathWrapCString:
4409
 * @val:  the char * value
4410
 *
4411
 * Wraps a string into an XPath object.
4412
 *
4413
 * Returns the newly created object.
4414
 */
4415
xmlXPathObjectPtr
4416
0
xmlXPathWrapCString (char * val) {
4417
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4418
0
}
4419
4420
/**
4421
 * xmlXPathWrapExternal:
4422
 * @val:  the user data
4423
 *
4424
 * Wraps the @val data into an XPath object.
4425
 *
4426
 * Returns the newly created object.
4427
 */
4428
xmlXPathObjectPtr
4429
0
xmlXPathWrapExternal (void *val) {
4430
0
    xmlXPathObjectPtr ret;
4431
4432
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4433
0
    if (ret == NULL)
4434
0
  return(NULL);
4435
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4436
0
    ret->type = XPATH_USERS;
4437
0
    ret->user = val;
4438
0
    return(ret);
4439
0
}
4440
4441
/**
4442
 * xmlXPathObjectCopy:
4443
 * @val:  the original object
4444
 *
4445
 * allocate a new copy of a given object
4446
 *
4447
 * Returns the newly created object.
4448
 */
4449
xmlXPathObjectPtr
4450
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4451
0
    xmlXPathObjectPtr ret;
4452
4453
0
    if (val == NULL)
4454
0
  return(NULL);
4455
4456
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4457
0
    if (ret == NULL)
4458
0
  return(NULL);
4459
0
    memcpy(ret, val , sizeof(xmlXPathObject));
4460
0
    switch (val->type) {
4461
0
  case XPATH_BOOLEAN:
4462
0
  case XPATH_NUMBER:
4463
#ifdef LIBXML_XPTR_LOCS_ENABLED
4464
  case XPATH_POINT:
4465
  case XPATH_RANGE:
4466
#endif /* LIBXML_XPTR_LOCS_ENABLED */
4467
0
      break;
4468
0
  case XPATH_STRING:
4469
0
      ret->stringval = xmlStrdup(val->stringval);
4470
0
            if (ret->stringval == NULL) {
4471
0
                xmlFree(ret);
4472
0
                return(NULL);
4473
0
            }
4474
0
      break;
4475
0
  case XPATH_XSLT_TREE:
4476
#if 0
4477
/*
4478
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4479
  this previous handling is no longer correct, and can cause some serious
4480
  problems (ref. bug 145547)
4481
*/
4482
      if ((val->nodesetval != NULL) &&
4483
    (val->nodesetval->nodeTab != NULL)) {
4484
    xmlNodePtr cur, tmp;
4485
    xmlDocPtr top;
4486
4487
    ret->boolval = 1;
4488
    top =  xmlNewDoc(NULL);
4489
    top->name = (char *)
4490
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
4491
    ret->user = top;
4492
    if (top != NULL) {
4493
        top->doc = top;
4494
        cur = val->nodesetval->nodeTab[0]->children;
4495
        while (cur != NULL) {
4496
      tmp = xmlDocCopyNode(cur, top, 1);
4497
      xmlAddChild((xmlNodePtr) top, tmp);
4498
      cur = cur->next;
4499
        }
4500
    }
4501
4502
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4503
      } else
4504
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4505
      /* Deallocate the copied tree value */
4506
      break;
4507
#endif
4508
0
  case XPATH_NODESET:
4509
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4510
0
            if (ret->nodesetval == NULL) {
4511
0
                xmlFree(ret);
4512
0
                return(NULL);
4513
0
            }
4514
      /* Do not deallocate the copied tree value */
4515
0
      ret->boolval = 0;
4516
0
      break;
4517
#ifdef LIBXML_XPTR_LOCS_ENABLED
4518
  case XPATH_LOCATIONSET:
4519
  {
4520
      xmlLocationSetPtr loc = val->user;
4521
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4522
      break;
4523
  }
4524
#endif
4525
0
        case XPATH_USERS:
4526
0
      ret->user = val->user;
4527
0
      break;
4528
0
        default:
4529
0
            xmlFree(ret);
4530
0
            ret = NULL;
4531
0
      break;
4532
0
    }
4533
0
    return(ret);
4534
0
}
4535
4536
/**
4537
 * xmlXPathFreeObject:
4538
 * @obj:  the object to free
4539
 *
4540
 * Free up an xmlXPathObjectPtr object.
4541
 */
4542
void
4543
0
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4544
0
    if (obj == NULL) return;
4545
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4546
0
        if (obj->nodesetval != NULL)
4547
0
            xmlXPathFreeNodeSet(obj->nodesetval);
4548
#ifdef LIBXML_XPTR_LOCS_ENABLED
4549
    } else if (obj->type == XPATH_LOCATIONSET) {
4550
  if (obj->user != NULL)
4551
      xmlXPtrFreeLocationSet(obj->user);
4552
#endif
4553
0
    } else if (obj->type == XPATH_STRING) {
4554
0
  if (obj->stringval != NULL)
4555
0
      xmlFree(obj->stringval);
4556
0
    }
4557
0
    xmlFree(obj);
4558
0
}
4559
4560
static void
4561
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4562
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4563
0
}
4564
4565
/**
4566
 * xmlXPathReleaseObject:
4567
 * @obj:  the xmlXPathObjectPtr to free or to cache
4568
 *
4569
 * Depending on the state of the cache this frees the given
4570
 * XPath object or stores it in the cache.
4571
 */
4572
static void
4573
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4574
0
{
4575
0
    if (obj == NULL)
4576
0
  return;
4577
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4578
0
   xmlXPathFreeObject(obj);
4579
0
    } else {
4580
0
  xmlXPathContextCachePtr cache =
4581
0
      (xmlXPathContextCachePtr) ctxt->cache;
4582
4583
0
  switch (obj->type) {
4584
0
      case XPATH_NODESET:
4585
0
      case XPATH_XSLT_TREE:
4586
0
    if (obj->nodesetval != NULL) {
4587
0
        if ((obj->nodesetval->nodeMax <= 40) &&
4588
0
      (cache->numNodeset < cache->maxNodeset)) {
4589
0
                        obj->stringval = (void *) cache->nodesetObjs;
4590
0
                        cache->nodesetObjs = obj;
4591
0
                        cache->numNodeset += 1;
4592
0
      goto obj_cached;
4593
0
        } else {
4594
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4595
0
      obj->nodesetval = NULL;
4596
0
        }
4597
0
    }
4598
0
    break;
4599
0
      case XPATH_STRING:
4600
0
    if (obj->stringval != NULL)
4601
0
        xmlFree(obj->stringval);
4602
0
                obj->stringval = NULL;
4603
0
    break;
4604
0
      case XPATH_BOOLEAN:
4605
0
      case XPATH_NUMBER:
4606
0
    break;
4607
#ifdef LIBXML_XPTR_LOCS_ENABLED
4608
      case XPATH_LOCATIONSET:
4609
    if (obj->user != NULL) {
4610
        xmlXPtrFreeLocationSet(obj->user);
4611
    }
4612
    goto free_obj;
4613
#endif
4614
0
      default:
4615
0
    goto free_obj;
4616
0
  }
4617
4618
  /*
4619
  * Fallback to adding to the misc-objects slot.
4620
  */
4621
0
        if (cache->numMisc >= cache->maxMisc)
4622
0
      goto free_obj;
4623
0
        obj->stringval = (void *) cache->miscObjs;
4624
0
        cache->miscObjs = obj;
4625
0
        cache->numMisc += 1;
4626
4627
0
obj_cached:
4628
0
        obj->boolval = 0;
4629
0
  if (obj->nodesetval != NULL) {
4630
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
4631
4632
      /*
4633
      * Due to those nasty ns-nodes, we need to traverse
4634
      * the list and free the ns-nodes.
4635
      */
4636
0
      if (tmpset->nodeNr > 0) {
4637
0
    int i;
4638
0
    xmlNodePtr node;
4639
4640
0
    for (i = 0; i < tmpset->nodeNr; i++) {
4641
0
        node = tmpset->nodeTab[i];
4642
0
        if ((node != NULL) &&
4643
0
      (node->type == XML_NAMESPACE_DECL))
4644
0
        {
4645
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4646
0
        }
4647
0
    }
4648
0
      }
4649
0
      tmpset->nodeNr = 0;
4650
0
        }
4651
4652
0
  return;
4653
4654
0
free_obj:
4655
  /*
4656
  * Cache is full; free the object.
4657
  */
4658
0
  if (obj->nodesetval != NULL)
4659
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4660
0
  xmlFree(obj);
4661
0
    }
4662
0
    return;
4663
0
}
4664
4665
4666
/************************************************************************
4667
 *                  *
4668
 *      Type Casting Routines       *
4669
 *                  *
4670
 ************************************************************************/
4671
4672
/**
4673
 * xmlXPathCastBooleanToString:
4674
 * @val:  a boolean
4675
 *
4676
 * Converts a boolean to its string value.
4677
 *
4678
 * Returns a newly allocated string.
4679
 */
4680
xmlChar *
4681
0
xmlXPathCastBooleanToString (int val) {
4682
0
    xmlChar *ret;
4683
0
    if (val)
4684
0
  ret = xmlStrdup((const xmlChar *) "true");
4685
0
    else
4686
0
  ret = xmlStrdup((const xmlChar *) "false");
4687
0
    return(ret);
4688
0
}
4689
4690
/**
4691
 * xmlXPathCastNumberToString:
4692
 * @val:  a number
4693
 *
4694
 * Converts a number to its string value.
4695
 *
4696
 * Returns a newly allocated string.
4697
 */
4698
xmlChar *
4699
0
xmlXPathCastNumberToString (double val) {
4700
0
    xmlChar *ret;
4701
0
    switch (xmlXPathIsInf(val)) {
4702
0
    case 1:
4703
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
4704
0
  break;
4705
0
    case -1:
4706
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4707
0
  break;
4708
0
    default:
4709
0
  if (xmlXPathIsNaN(val)) {
4710
0
      ret = xmlStrdup((const xmlChar *) "NaN");
4711
0
  } else if (val == 0) {
4712
            /* Omit sign for negative zero. */
4713
0
      ret = xmlStrdup((const xmlChar *) "0");
4714
0
  } else {
4715
      /* could be improved */
4716
0
      char buf[100];
4717
0
      xmlXPathFormatNumber(val, buf, 99);
4718
0
      buf[99] = 0;
4719
0
      ret = xmlStrdup((const xmlChar *) buf);
4720
0
  }
4721
0
    }
4722
0
    return(ret);
4723
0
}
4724
4725
/**
4726
 * xmlXPathCastNodeToString:
4727
 * @node:  a node
4728
 *
4729
 * Converts a node to its string value.
4730
 *
4731
 * Returns a newly allocated string.
4732
 */
4733
xmlChar *
4734
0
xmlXPathCastNodeToString (xmlNodePtr node) {
4735
0
    return(xmlNodeGetContent(node));
4736
0
}
4737
4738
/**
4739
 * xmlXPathCastNodeSetToString:
4740
 * @ns:  a node-set
4741
 *
4742
 * Converts a node-set to its string value.
4743
 *
4744
 * Returns a newly allocated string.
4745
 */
4746
xmlChar *
4747
0
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4748
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4749
0
  return(xmlStrdup((const xmlChar *) ""));
4750
4751
0
    if (ns->nodeNr > 1)
4752
0
  xmlXPathNodeSetSort(ns);
4753
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4754
0
}
4755
4756
/**
4757
 * xmlXPathCastToString:
4758
 * @val:  an XPath object
4759
 *
4760
 * Converts an existing object to its string() equivalent
4761
 *
4762
 * Returns the allocated string value of the object, NULL in case of error.
4763
 *         It's up to the caller to free the string memory with xmlFree().
4764
 */
4765
xmlChar *
4766
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
4767
0
    xmlChar *ret = NULL;
4768
4769
0
    if (val == NULL)
4770
0
  return(xmlStrdup((const xmlChar *) ""));
4771
0
    switch (val->type) {
4772
0
  case XPATH_UNDEFINED:
4773
0
      ret = xmlStrdup((const xmlChar *) "");
4774
0
      break;
4775
0
        case XPATH_NODESET:
4776
0
        case XPATH_XSLT_TREE:
4777
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4778
0
      break;
4779
0
  case XPATH_STRING:
4780
0
      return(xmlStrdup(val->stringval));
4781
0
        case XPATH_BOOLEAN:
4782
0
      ret = xmlXPathCastBooleanToString(val->boolval);
4783
0
      break;
4784
0
  case XPATH_NUMBER: {
4785
0
      ret = xmlXPathCastNumberToString(val->floatval);
4786
0
      break;
4787
0
  }
4788
0
  case XPATH_USERS:
4789
#ifdef LIBXML_XPTR_LOCS_ENABLED
4790
  case XPATH_POINT:
4791
  case XPATH_RANGE:
4792
  case XPATH_LOCATIONSET:
4793
#endif /* LIBXML_XPTR_LOCS_ENABLED */
4794
      /* TODO */
4795
0
      ret = xmlStrdup((const xmlChar *) "");
4796
0
      break;
4797
0
    }
4798
0
    return(ret);
4799
0
}
4800
4801
/**
4802
 * xmlXPathConvertString:
4803
 * @val:  an XPath object
4804
 *
4805
 * Converts an existing object to its string() equivalent
4806
 *
4807
 * Returns the new object, the old one is freed (or the operation
4808
 *         is done directly on @val)
4809
 */
4810
xmlXPathObjectPtr
4811
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
4812
0
    xmlChar *res = NULL;
4813
4814
0
    if (val == NULL)
4815
0
  return(xmlXPathNewCString(""));
4816
4817
0
    switch (val->type) {
4818
0
    case XPATH_UNDEFINED:
4819
0
  break;
4820
0
    case XPATH_NODESET:
4821
0
    case XPATH_XSLT_TREE:
4822
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4823
0
  break;
4824
0
    case XPATH_STRING:
4825
0
  return(val);
4826
0
    case XPATH_BOOLEAN:
4827
0
  res = xmlXPathCastBooleanToString(val->boolval);
4828
0
  break;
4829
0
    case XPATH_NUMBER:
4830
0
  res = xmlXPathCastNumberToString(val->floatval);
4831
0
  break;
4832
0
    case XPATH_USERS:
4833
#ifdef LIBXML_XPTR_LOCS_ENABLED
4834
    case XPATH_POINT:
4835
    case XPATH_RANGE:
4836
    case XPATH_LOCATIONSET:
4837
#endif /* LIBXML_XPTR_LOCS_ENABLED */
4838
  /* TODO */
4839
0
  break;
4840
0
    }
4841
0
    xmlXPathFreeObject(val);
4842
0
    if (res == NULL)
4843
0
  return(xmlXPathNewCString(""));
4844
0
    return(xmlXPathWrapString(res));
4845
0
}
4846
4847
/**
4848
 * xmlXPathCastBooleanToNumber:
4849
 * @val:  a boolean
4850
 *
4851
 * Converts a boolean to its number value
4852
 *
4853
 * Returns the number value
4854
 */
4855
double
4856
0
xmlXPathCastBooleanToNumber(int val) {
4857
0
    if (val)
4858
0
  return(1.0);
4859
0
    return(0.0);
4860
0
}
4861
4862
/**
4863
 * xmlXPathCastStringToNumber:
4864
 * @val:  a string
4865
 *
4866
 * Converts a string to its number value
4867
 *
4868
 * Returns the number value
4869
 */
4870
double
4871
0
xmlXPathCastStringToNumber(const xmlChar * val) {
4872
0
    return(xmlXPathStringEvalNumber(val));
4873
0
}
4874
4875
/**
4876
 * xmlXPathNodeToNumberInternal:
4877
 * @node:  a node
4878
 *
4879
 * Converts a node to its number value
4880
 *
4881
 * Returns the number value
4882
 */
4883
static double
4884
0
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4885
0
    xmlChar *strval;
4886
0
    double ret;
4887
4888
0
    if (node == NULL)
4889
0
  return(xmlXPathNAN);
4890
0
    strval = xmlXPathCastNodeToString(node);
4891
0
    if (strval == NULL) {
4892
0
        xmlXPathPErrMemory(ctxt);
4893
0
  return(xmlXPathNAN);
4894
0
    }
4895
0
    ret = xmlXPathCastStringToNumber(strval);
4896
0
    xmlFree(strval);
4897
4898
0
    return(ret);
4899
0
}
4900
4901
/**
4902
 * xmlXPathCastNodeToNumber:
4903
 * @node:  a node
4904
 *
4905
 * Converts a node to its number value
4906
 *
4907
 * Returns the number value
4908
 */
4909
double
4910
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
4911
0
    return(xmlXPathNodeToNumberInternal(NULL, node));
4912
0
}
4913
4914
/**
4915
 * xmlXPathCastNodeSetToNumber:
4916
 * @ns:  a node-set
4917
 *
4918
 * Converts a node-set to its number value
4919
 *
4920
 * Returns the number value
4921
 */
4922
double
4923
0
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4924
0
    xmlChar *str;
4925
0
    double ret;
4926
4927
0
    if (ns == NULL)
4928
0
  return(xmlXPathNAN);
4929
0
    str = xmlXPathCastNodeSetToString(ns);
4930
0
    ret = xmlXPathCastStringToNumber(str);
4931
0
    xmlFree(str);
4932
0
    return(ret);
4933
0
}
4934
4935
/**
4936
 * xmlXPathCastToNumber:
4937
 * @val:  an XPath object
4938
 *
4939
 * Converts an XPath object to its number value
4940
 *
4941
 * Returns the number value
4942
 */
4943
double
4944
0
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4945
0
    return(xmlXPathCastToNumberInternal(NULL, val));
4946
0
}
4947
4948
/**
4949
 * xmlXPathConvertNumber:
4950
 * @val:  an XPath object
4951
 *
4952
 * Converts an existing object to its number() equivalent
4953
 *
4954
 * Returns the new object, the old one is freed (or the operation
4955
 *         is done directly on @val)
4956
 */
4957
xmlXPathObjectPtr
4958
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4959
0
    xmlXPathObjectPtr ret;
4960
4961
0
    if (val == NULL)
4962
0
  return(xmlXPathNewFloat(0.0));
4963
0
    if (val->type == XPATH_NUMBER)
4964
0
  return(val);
4965
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4966
0
    xmlXPathFreeObject(val);
4967
0
    return(ret);
4968
0
}
4969
4970
/**
4971
 * xmlXPathCastNumberToBoolean:
4972
 * @val:  a number
4973
 *
4974
 * Converts a number to its boolean value
4975
 *
4976
 * Returns the boolean value
4977
 */
4978
int
4979
0
xmlXPathCastNumberToBoolean (double val) {
4980
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
4981
0
   return(0);
4982
0
     return(1);
4983
0
}
4984
4985
/**
4986
 * xmlXPathCastStringToBoolean:
4987
 * @val:  a string
4988
 *
4989
 * Converts a string to its boolean value
4990
 *
4991
 * Returns the boolean value
4992
 */
4993
int
4994
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
4995
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
4996
0
  return(0);
4997
0
    return(1);
4998
0
}
4999
5000
/**
5001
 * xmlXPathCastNodeSetToBoolean:
5002
 * @ns:  a node-set
5003
 *
5004
 * Converts a node-set to its boolean value
5005
 *
5006
 * Returns the boolean value
5007
 */
5008
int
5009
0
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5010
0
    if ((ns == NULL) || (ns->nodeNr == 0))
5011
0
  return(0);
5012
0
    return(1);
5013
0
}
5014
5015
/**
5016
 * xmlXPathCastToBoolean:
5017
 * @val:  an XPath object
5018
 *
5019
 * Converts an XPath object to its boolean value
5020
 *
5021
 * Returns the boolean value
5022
 */
5023
int
5024
0
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5025
0
    int ret = 0;
5026
5027
0
    if (val == NULL)
5028
0
  return(0);
5029
0
    switch (val->type) {
5030
0
    case XPATH_UNDEFINED:
5031
0
  ret = 0;
5032
0
  break;
5033
0
    case XPATH_NODESET:
5034
0
    case XPATH_XSLT_TREE:
5035
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5036
0
  break;
5037
0
    case XPATH_STRING:
5038
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
5039
0
  break;
5040
0
    case XPATH_NUMBER:
5041
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
5042
0
  break;
5043
0
    case XPATH_BOOLEAN:
5044
0
  ret = val->boolval;
5045
0
  break;
5046
0
    case XPATH_USERS:
5047
#ifdef LIBXML_XPTR_LOCS_ENABLED
5048
    case XPATH_POINT:
5049
    case XPATH_RANGE:
5050
    case XPATH_LOCATIONSET:
5051
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5052
  /* TODO */
5053
0
  ret = 0;
5054
0
  break;
5055
0
    }
5056
0
    return(ret);
5057
0
}
5058
5059
5060
/**
5061
 * xmlXPathConvertBoolean:
5062
 * @val:  an XPath object
5063
 *
5064
 * Converts an existing object to its boolean() equivalent
5065
 *
5066
 * Returns the new object, the old one is freed (or the operation
5067
 *         is done directly on @val)
5068
 */
5069
xmlXPathObjectPtr
5070
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5071
0
    xmlXPathObjectPtr ret;
5072
5073
0
    if (val == NULL)
5074
0
  return(xmlXPathNewBoolean(0));
5075
0
    if (val->type == XPATH_BOOLEAN)
5076
0
  return(val);
5077
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5078
0
    xmlXPathFreeObject(val);
5079
0
    return(ret);
5080
0
}
5081
5082
/************************************************************************
5083
 *                  *
5084
 *    Routines to handle XPath contexts     *
5085
 *                  *
5086
 ************************************************************************/
5087
5088
/**
5089
 * xmlXPathNewContext:
5090
 * @doc:  the XML document
5091
 *
5092
 * Create a new xmlXPathContext
5093
 *
5094
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5095
 */
5096
xmlXPathContextPtr
5097
0
xmlXPathNewContext(xmlDocPtr doc) {
5098
0
    xmlXPathContextPtr ret;
5099
5100
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5101
0
    if (ret == NULL)
5102
0
  return(NULL);
5103
0
    memset(ret, 0 , sizeof(xmlXPathContext));
5104
0
    ret->doc = doc;
5105
0
    ret->node = NULL;
5106
5107
0
    ret->varHash = NULL;
5108
5109
0
    ret->nb_types = 0;
5110
0
    ret->max_types = 0;
5111
0
    ret->types = NULL;
5112
5113
0
    ret->nb_axis = 0;
5114
0
    ret->max_axis = 0;
5115
0
    ret->axis = NULL;
5116
5117
0
    ret->nsHash = NULL;
5118
0
    ret->user = NULL;
5119
5120
0
    ret->contextSize = -1;
5121
0
    ret->proximityPosition = -1;
5122
5123
#ifdef XP_DEFAULT_CACHE_ON
5124
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5125
  xmlXPathFreeContext(ret);
5126
  return(NULL);
5127
    }
5128
#endif
5129
5130
0
    xmlXPathRegisterAllFunctions(ret);
5131
5132
0
    if (ret->lastError.code != XML_ERR_OK) {
5133
0
  xmlXPathFreeContext(ret);
5134
0
  return(NULL);
5135
0
    }
5136
5137
0
    return(ret);
5138
0
}
5139
5140
/**
5141
 * xmlXPathFreeContext:
5142
 * @ctxt:  the context to free
5143
 *
5144
 * Free up an xmlXPathContext
5145
 */
5146
void
5147
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5148
0
    if (ctxt == NULL) return;
5149
5150
0
    if (ctxt->cache != NULL)
5151
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5152
0
    xmlXPathRegisteredNsCleanup(ctxt);
5153
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
5154
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
5155
0
    xmlResetError(&ctxt->lastError);
5156
0
    xmlFree(ctxt);
5157
0
}
5158
5159
/**
5160
 * xmlXPathSetErrorHandler:
5161
 * @ctxt:  the XPath context
5162
 * @handler:  error handler
5163
 * @data:  user data which will be passed to the handler
5164
 *
5165
 * Register a callback function that will be called on errors and
5166
 * warnings. If handler is NULL, the error handler will be deactivated.
5167
 *
5168
 * Available since 2.13.0.
5169
 */
5170
void
5171
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
5172
0
                        xmlStructuredErrorFunc handler, void *data) {
5173
0
    if (ctxt == NULL)
5174
0
        return;
5175
5176
0
    ctxt->error = handler;
5177
0
    ctxt->userData = data;
5178
0
}
5179
5180
/************************************************************************
5181
 *                  *
5182
 *    Routines to handle XPath parser contexts    *
5183
 *                  *
5184
 ************************************************************************/
5185
5186
/**
5187
 * xmlXPathNewParserContext:
5188
 * @str:  the XPath expression
5189
 * @ctxt:  the XPath context
5190
 *
5191
 * Create a new xmlXPathParserContext
5192
 *
5193
 * Returns the xmlXPathParserContext just allocated.
5194
 */
5195
xmlXPathParserContextPtr
5196
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5197
0
    xmlXPathParserContextPtr ret;
5198
5199
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5200
0
    if (ret == NULL) {
5201
0
        xmlXPathErrMemory(ctxt);
5202
0
  return(NULL);
5203
0
    }
5204
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
5205
0
    ret->cur = ret->base = str;
5206
0
    ret->context = ctxt;
5207
5208
0
    ret->comp = xmlXPathNewCompExpr();
5209
0
    if (ret->comp == NULL) {
5210
0
        xmlXPathErrMemory(ctxt);
5211
0
  xmlFree(ret->valueTab);
5212
0
  xmlFree(ret);
5213
0
  return(NULL);
5214
0
    }
5215
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5216
0
        ret->comp->dict = ctxt->dict;
5217
0
  xmlDictReference(ret->comp->dict);
5218
0
    }
5219
5220
0
    return(ret);
5221
0
}
5222
5223
/**
5224
 * xmlXPathCompParserContext:
5225
 * @comp:  the XPath compiled expression
5226
 * @ctxt:  the XPath context
5227
 *
5228
 * Create a new xmlXPathParserContext when processing a compiled expression
5229
 *
5230
 * Returns the xmlXPathParserContext just allocated.
5231
 */
5232
static xmlXPathParserContextPtr
5233
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5234
0
    xmlXPathParserContextPtr ret;
5235
5236
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5237
0
    if (ret == NULL) {
5238
0
        xmlXPathErrMemory(ctxt);
5239
0
  return(NULL);
5240
0
    }
5241
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
5242
5243
    /* Allocate the value stack */
5244
0
    ret->valueTab = (xmlXPathObjectPtr *)
5245
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5246
0
    if (ret->valueTab == NULL) {
5247
0
  xmlFree(ret);
5248
0
  xmlXPathErrMemory(ctxt);
5249
0
  return(NULL);
5250
0
    }
5251
0
    ret->valueNr = 0;
5252
0
    ret->valueMax = 10;
5253
0
    ret->value = NULL;
5254
5255
0
    ret->context = ctxt;
5256
0
    ret->comp = comp;
5257
5258
0
    return(ret);
5259
0
}
5260
5261
/**
5262
 * xmlXPathFreeParserContext:
5263
 * @ctxt:  the context to free
5264
 *
5265
 * Free up an xmlXPathParserContext
5266
 */
5267
void
5268
0
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5269
0
    int i;
5270
5271
0
    if (ctxt->valueTab != NULL) {
5272
0
        for (i = 0; i < ctxt->valueNr; i++) {
5273
0
            if (ctxt->context)
5274
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5275
0
            else
5276
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
5277
0
        }
5278
0
        xmlFree(ctxt->valueTab);
5279
0
    }
5280
0
    if (ctxt->comp != NULL) {
5281
#ifdef XPATH_STREAMING
5282
  if (ctxt->comp->stream != NULL) {
5283
      xmlFreePatternList(ctxt->comp->stream);
5284
      ctxt->comp->stream = NULL;
5285
  }
5286
#endif
5287
0
  xmlXPathFreeCompExpr(ctxt->comp);
5288
0
    }
5289
0
    xmlFree(ctxt);
5290
0
}
5291
5292
/************************************************************************
5293
 *                  *
5294
 *    The implicit core function library      *
5295
 *                  *
5296
 ************************************************************************/
5297
5298
/**
5299
 * xmlXPathNodeValHash:
5300
 * @node:  a node pointer
5301
 *
5302
 * Function computing the beginning of the string value of the node,
5303
 * used to speed up comparisons
5304
 *
5305
 * Returns an int usable as a hash
5306
 */
5307
static unsigned int
5308
0
xmlXPathNodeValHash(xmlNodePtr node) {
5309
0
    int len = 2;
5310
0
    const xmlChar * string = NULL;
5311
0
    xmlNodePtr tmp = NULL;
5312
0
    unsigned int ret = 0;
5313
5314
0
    if (node == NULL)
5315
0
  return(0);
5316
5317
0
    if (node->type == XML_DOCUMENT_NODE) {
5318
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
5319
0
  if (tmp == NULL)
5320
0
      node = node->children;
5321
0
  else
5322
0
      node = tmp;
5323
5324
0
  if (node == NULL)
5325
0
      return(0);
5326
0
    }
5327
5328
0
    switch (node->type) {
5329
0
  case XML_COMMENT_NODE:
5330
0
  case XML_PI_NODE:
5331
0
  case XML_CDATA_SECTION_NODE:
5332
0
  case XML_TEXT_NODE:
5333
0
      string = node->content;
5334
0
      if (string == NULL)
5335
0
    return(0);
5336
0
      if (string[0] == 0)
5337
0
    return(0);
5338
0
      return(string[0] + (string[1] << 8));
5339
0
  case XML_NAMESPACE_DECL:
5340
0
      string = ((xmlNsPtr)node)->href;
5341
0
      if (string == NULL)
5342
0
    return(0);
5343
0
      if (string[0] == 0)
5344
0
    return(0);
5345
0
      return(string[0] + (string[1] << 8));
5346
0
  case XML_ATTRIBUTE_NODE:
5347
0
      tmp = ((xmlAttrPtr) node)->children;
5348
0
      break;
5349
0
  case XML_ELEMENT_NODE:
5350
0
      tmp = node->children;
5351
0
      break;
5352
0
  default:
5353
0
      return(0);
5354
0
    }
5355
0
    while (tmp != NULL) {
5356
0
  switch (tmp->type) {
5357
0
      case XML_CDATA_SECTION_NODE:
5358
0
      case XML_TEXT_NODE:
5359
0
    string = tmp->content;
5360
0
    break;
5361
0
      default:
5362
0
                string = NULL;
5363
0
    break;
5364
0
  }
5365
0
  if ((string != NULL) && (string[0] != 0)) {
5366
0
      if (len == 1) {
5367
0
    return(ret + (string[0] << 8));
5368
0
      }
5369
0
      if (string[1] == 0) {
5370
0
    len = 1;
5371
0
    ret = string[0];
5372
0
      } else {
5373
0
    return(string[0] + (string[1] << 8));
5374
0
      }
5375
0
  }
5376
  /*
5377
   * Skip to next node
5378
   */
5379
0
        if ((tmp->children != NULL) &&
5380
0
            (tmp->type != XML_DTD_NODE) &&
5381
0
            (tmp->type != XML_ENTITY_REF_NODE) &&
5382
0
            (tmp->children->type != XML_ENTITY_DECL)) {
5383
0
            tmp = tmp->children;
5384
0
            continue;
5385
0
  }
5386
0
  if (tmp == node)
5387
0
      break;
5388
5389
0
  if (tmp->next != NULL) {
5390
0
      tmp = tmp->next;
5391
0
      continue;
5392
0
  }
5393
5394
0
  do {
5395
0
      tmp = tmp->parent;
5396
0
      if (tmp == NULL)
5397
0
    break;
5398
0
      if (tmp == node) {
5399
0
    tmp = NULL;
5400
0
    break;
5401
0
      }
5402
0
      if (tmp->next != NULL) {
5403
0
    tmp = tmp->next;
5404
0
    break;
5405
0
      }
5406
0
  } while (tmp != NULL);
5407
0
    }
5408
0
    return(ret);
5409
0
}
5410
5411
/**
5412
 * xmlXPathStringHash:
5413
 * @string:  a string
5414
 *
5415
 * Function computing the beginning of the string value of the node,
5416
 * used to speed up comparisons
5417
 *
5418
 * Returns an int usable as a hash
5419
 */
5420
static unsigned int
5421
0
xmlXPathStringHash(const xmlChar * string) {
5422
0
    if (string == NULL)
5423
0
  return(0);
5424
0
    if (string[0] == 0)
5425
0
  return(0);
5426
0
    return(string[0] + (string[1] << 8));
5427
0
}
5428
5429
/**
5430
 * xmlXPathCompareNodeSetFloat:
5431
 * @ctxt:  the XPath Parser context
5432
 * @inf:  less than (1) or greater than (0)
5433
 * @strict:  is the comparison strict
5434
 * @arg:  the node set
5435
 * @f:  the value
5436
 *
5437
 * Implement the compare operation between a nodeset and a number
5438
 *     @ns < @val    (1, 1, ...
5439
 *     @ns <= @val   (1, 0, ...
5440
 *     @ns > @val    (0, 1, ...
5441
 *     @ns >= @val   (0, 0, ...
5442
 *
5443
 * If one object to be compared is a node-set and the other is a number,
5444
 * then the comparison will be true if and only if there is a node in the
5445
 * node-set such that the result of performing the comparison on the number
5446
 * to be compared and on the result of converting the string-value of that
5447
 * node to a number using the number function is true.
5448
 *
5449
 * Returns 0 or 1 depending on the results of the test.
5450
 */
5451
static int
5452
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5453
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5454
0
    int i, ret = 0;
5455
0
    xmlNodeSetPtr ns;
5456
0
    xmlChar *str2;
5457
5458
0
    if ((f == NULL) || (arg == NULL) ||
5459
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5460
0
  xmlXPathReleaseObject(ctxt->context, arg);
5461
0
  xmlXPathReleaseObject(ctxt->context, f);
5462
0
        return(0);
5463
0
    }
5464
0
    ns = arg->nodesetval;
5465
0
    if (ns != NULL) {
5466
0
  for (i = 0;i < ns->nodeNr;i++) {
5467
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5468
0
       if (str2 != NULL) {
5469
0
     valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5470
0
     xmlFree(str2);
5471
0
     xmlXPathNumberFunction(ctxt, 1);
5472
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5473
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5474
0
     if (ret)
5475
0
         break;
5476
0
       } else {
5477
0
                 xmlXPathPErrMemory(ctxt);
5478
0
             }
5479
0
  }
5480
0
    }
5481
0
    xmlXPathReleaseObject(ctxt->context, arg);
5482
0
    xmlXPathReleaseObject(ctxt->context, f);
5483
0
    return(ret);
5484
0
}
5485
5486
/**
5487
 * xmlXPathCompareNodeSetString:
5488
 * @ctxt:  the XPath Parser context
5489
 * @inf:  less than (1) or greater than (0)
5490
 * @strict:  is the comparison strict
5491
 * @arg:  the node set
5492
 * @s:  the value
5493
 *
5494
 * Implement the compare operation between a nodeset and a string
5495
 *     @ns < @val    (1, 1, ...
5496
 *     @ns <= @val   (1, 0, ...
5497
 *     @ns > @val    (0, 1, ...
5498
 *     @ns >= @val   (0, 0, ...
5499
 *
5500
 * If one object to be compared is a node-set and the other is a string,
5501
 * then the comparison will be true if and only if there is a node in
5502
 * the node-set such that the result of performing the comparison on the
5503
 * string-value of the node and the other string is true.
5504
 *
5505
 * Returns 0 or 1 depending on the results of the test.
5506
 */
5507
static int
5508
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5509
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5510
0
    int i, ret = 0;
5511
0
    xmlNodeSetPtr ns;
5512
0
    xmlChar *str2;
5513
5514
0
    if ((s == NULL) || (arg == NULL) ||
5515
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5516
0
  xmlXPathReleaseObject(ctxt->context, arg);
5517
0
  xmlXPathReleaseObject(ctxt->context, s);
5518
0
        return(0);
5519
0
    }
5520
0
    ns = arg->nodesetval;
5521
0
    if (ns != NULL) {
5522
0
  for (i = 0;i < ns->nodeNr;i++) {
5523
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5524
0
       if (str2 != NULL) {
5525
0
     valuePush(ctxt,
5526
0
         xmlXPathCacheNewString(ctxt, str2));
5527
0
     xmlFree(str2);
5528
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5529
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5530
0
     if (ret)
5531
0
         break;
5532
0
       } else {
5533
0
                 xmlXPathPErrMemory(ctxt);
5534
0
             }
5535
0
  }
5536
0
    }
5537
0
    xmlXPathReleaseObject(ctxt->context, arg);
5538
0
    xmlXPathReleaseObject(ctxt->context, s);
5539
0
    return(ret);
5540
0
}
5541
5542
/**
5543
 * xmlXPathCompareNodeSets:
5544
 * @inf:  less than (1) or greater than (0)
5545
 * @strict:  is the comparison strict
5546
 * @arg1:  the first node set object
5547
 * @arg2:  the second node set object
5548
 *
5549
 * Implement the compare operation on nodesets:
5550
 *
5551
 * If both objects to be compared are node-sets, then the comparison
5552
 * will be true if and only if there is a node in the first node-set
5553
 * and a node in the second node-set such that the result of performing
5554
 * the comparison on the string-values of the two nodes is true.
5555
 * ....
5556
 * When neither object to be compared is a node-set and the operator
5557
 * is <=, <, >= or >, then the objects are compared by converting both
5558
 * objects to numbers and comparing the numbers according to IEEE 754.
5559
 * ....
5560
 * The number function converts its argument to a number as follows:
5561
 *  - a string that consists of optional whitespace followed by an
5562
 *    optional minus sign followed by a Number followed by whitespace
5563
 *    is converted to the IEEE 754 number that is nearest (according
5564
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5565
 *    represented by the string; any other string is converted to NaN
5566
 *
5567
 * Conclusion all nodes need to be converted first to their string value
5568
 * and then the comparison must be done when possible
5569
 */
5570
static int
5571
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5572
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5573
0
    int i, j, init = 0;
5574
0
    double val1;
5575
0
    double *values2;
5576
0
    int ret = 0;
5577
0
    xmlNodeSetPtr ns1;
5578
0
    xmlNodeSetPtr ns2;
5579
5580
0
    if ((arg1 == NULL) ||
5581
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5582
0
  xmlXPathFreeObject(arg2);
5583
0
        return(0);
5584
0
    }
5585
0
    if ((arg2 == NULL) ||
5586
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5587
0
  xmlXPathFreeObject(arg1);
5588
0
  xmlXPathFreeObject(arg2);
5589
0
        return(0);
5590
0
    }
5591
5592
0
    ns1 = arg1->nodesetval;
5593
0
    ns2 = arg2->nodesetval;
5594
5595
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5596
0
  xmlXPathFreeObject(arg1);
5597
0
  xmlXPathFreeObject(arg2);
5598
0
  return(0);
5599
0
    }
5600
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5601
0
  xmlXPathFreeObject(arg1);
5602
0
  xmlXPathFreeObject(arg2);
5603
0
  return(0);
5604
0
    }
5605
5606
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5607
0
    if (values2 == NULL) {
5608
0
        xmlXPathPErrMemory(ctxt);
5609
0
  xmlXPathFreeObject(arg1);
5610
0
  xmlXPathFreeObject(arg2);
5611
0
  return(0);
5612
0
    }
5613
0
    for (i = 0;i < ns1->nodeNr;i++) {
5614
0
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5615
0
  if (xmlXPathIsNaN(val1))
5616
0
      continue;
5617
0
  for (j = 0;j < ns2->nodeNr;j++) {
5618
0
      if (init == 0) {
5619
0
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5620
0
                                                          ns2->nodeTab[j]);
5621
0
      }
5622
0
      if (xmlXPathIsNaN(values2[j]))
5623
0
    continue;
5624
0
      if (inf && strict)
5625
0
    ret = (val1 < values2[j]);
5626
0
      else if (inf && !strict)
5627
0
    ret = (val1 <= values2[j]);
5628
0
      else if (!inf && strict)
5629
0
    ret = (val1 > values2[j]);
5630
0
      else if (!inf && !strict)
5631
0
    ret = (val1 >= values2[j]);
5632
0
      if (ret)
5633
0
    break;
5634
0
  }
5635
0
  if (ret)
5636
0
      break;
5637
0
  init = 1;
5638
0
    }
5639
0
    xmlFree(values2);
5640
0
    xmlXPathFreeObject(arg1);
5641
0
    xmlXPathFreeObject(arg2);
5642
0
    return(ret);
5643
0
}
5644
5645
/**
5646
 * xmlXPathCompareNodeSetValue:
5647
 * @ctxt:  the XPath Parser context
5648
 * @inf:  less than (1) or greater than (0)
5649
 * @strict:  is the comparison strict
5650
 * @arg:  the node set
5651
 * @val:  the value
5652
 *
5653
 * Implement the compare operation between a nodeset and a value
5654
 *     @ns < @val    (1, 1, ...
5655
 *     @ns <= @val   (1, 0, ...
5656
 *     @ns > @val    (0, 1, ...
5657
 *     @ns >= @val   (0, 0, ...
5658
 *
5659
 * If one object to be compared is a node-set and the other is a boolean,
5660
 * then the comparison will be true if and only if the result of performing
5661
 * the comparison on the boolean and on the result of converting
5662
 * the node-set to a boolean using the boolean function is true.
5663
 *
5664
 * Returns 0 or 1 depending on the results of the test.
5665
 */
5666
static int
5667
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5668
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5669
0
    if ((val == NULL) || (arg == NULL) ||
5670
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5671
0
        return(0);
5672
5673
0
    switch(val->type) {
5674
0
        case XPATH_NUMBER:
5675
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5676
0
        case XPATH_NODESET:
5677
0
        case XPATH_XSLT_TREE:
5678
0
      return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5679
0
        case XPATH_STRING:
5680
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5681
0
        case XPATH_BOOLEAN:
5682
0
      valuePush(ctxt, arg);
5683
0
      xmlXPathBooleanFunction(ctxt, 1);
5684
0
      valuePush(ctxt, val);
5685
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
5686
0
  default:
5687
0
            xmlXPathReleaseObject(ctxt->context, arg);
5688
0
            xmlXPathReleaseObject(ctxt->context, val);
5689
0
            XP_ERROR0(XPATH_INVALID_TYPE);
5690
0
    }
5691
0
    return(0);
5692
0
}
5693
5694
/**
5695
 * xmlXPathEqualNodeSetString:
5696
 * @arg:  the nodeset object argument
5697
 * @str:  the string to compare to.
5698
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
5699
 *
5700
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5701
 * If one object to be compared is a node-set and the other is a string,
5702
 * then the comparison will be true if and only if there is a node in
5703
 * the node-set such that the result of performing the comparison on the
5704
 * string-value of the node and the other string is true.
5705
 *
5706
 * Returns 0 or 1 depending on the results of the test.
5707
 */
5708
static int
5709
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5710
                           xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5711
0
{
5712
0
    int i;
5713
0
    xmlNodeSetPtr ns;
5714
0
    xmlChar *str2;
5715
0
    unsigned int hash;
5716
5717
0
    if ((str == NULL) || (arg == NULL) ||
5718
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5719
0
        return (0);
5720
0
    ns = arg->nodesetval;
5721
    /*
5722
     * A NULL nodeset compared with a string is always false
5723
     * (since there is no node equal, and no node not equal)
5724
     */
5725
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5726
0
        return (0);
5727
0
    hash = xmlXPathStringHash(str);
5728
0
    for (i = 0; i < ns->nodeNr; i++) {
5729
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5730
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5731
0
            if (str2 == NULL) {
5732
0
                xmlXPathPErrMemory(ctxt);
5733
0
                return(0);
5734
0
            }
5735
0
            if (xmlStrEqual(str, str2)) {
5736
0
                xmlFree(str2);
5737
0
    if (neq)
5738
0
        continue;
5739
0
                return (1);
5740
0
            } else if (neq) {
5741
0
    xmlFree(str2);
5742
0
    return (1);
5743
0
      }
5744
0
            xmlFree(str2);
5745
0
        } else if (neq)
5746
0
      return (1);
5747
0
    }
5748
0
    return (0);
5749
0
}
5750
5751
/**
5752
 * xmlXPathEqualNodeSetFloat:
5753
 * @arg:  the nodeset object argument
5754
 * @f:  the float to compare to
5755
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
5756
 *
5757
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5758
 * If one object to be compared is a node-set and the other is a number,
5759
 * then the comparison will be true if and only if there is a node in
5760
 * the node-set such that the result of performing the comparison on the
5761
 * number to be compared and on the result of converting the string-value
5762
 * of that node to a number using the number function is true.
5763
 *
5764
 * Returns 0 or 1 depending on the results of the test.
5765
 */
5766
static int
5767
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5768
0
    xmlXPathObjectPtr arg, double f, int neq) {
5769
0
  int i, ret=0;
5770
0
  xmlNodeSetPtr ns;
5771
0
  xmlChar *str2;
5772
0
  xmlXPathObjectPtr val;
5773
0
  double v;
5774
5775
0
    if ((arg == NULL) ||
5776
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5777
0
        return(0);
5778
5779
0
    ns = arg->nodesetval;
5780
0
    if (ns != NULL) {
5781
0
  for (i=0;i<ns->nodeNr;i++) {
5782
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5783
0
      if (str2 != NULL) {
5784
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5785
0
    xmlFree(str2);
5786
0
    xmlXPathNumberFunction(ctxt, 1);
5787
0
                CHECK_ERROR0;
5788
0
    val = valuePop(ctxt);
5789
0
    v = val->floatval;
5790
0
    xmlXPathReleaseObject(ctxt->context, val);
5791
0
    if (!xmlXPathIsNaN(v)) {
5792
0
        if ((!neq) && (v==f)) {
5793
0
      ret = 1;
5794
0
      break;
5795
0
        } else if ((neq) && (v!=f)) {
5796
0
      ret = 1;
5797
0
      break;
5798
0
        }
5799
0
    } else { /* NaN is unequal to any value */
5800
0
        if (neq)
5801
0
      ret = 1;
5802
0
    }
5803
0
      } else {
5804
0
                xmlXPathPErrMemory(ctxt);
5805
0
            }
5806
0
  }
5807
0
    }
5808
5809
0
    return(ret);
5810
0
}
5811
5812
5813
/**
5814
 * xmlXPathEqualNodeSets:
5815
 * @arg1:  first nodeset object argument
5816
 * @arg2:  second nodeset object argument
5817
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
5818
 *
5819
 * Implement the equal / not equal operation on XPath nodesets:
5820
 * @arg1 == @arg2  or  @arg1 != @arg2
5821
 * If both objects to be compared are node-sets, then the comparison
5822
 * will be true if and only if there is a node in the first node-set and
5823
 * a node in the second node-set such that the result of performing the
5824
 * comparison on the string-values of the two nodes is true.
5825
 *
5826
 * (needless to say, this is a costly operation)
5827
 *
5828
 * Returns 0 or 1 depending on the results of the test.
5829
 */
5830
static int
5831
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5832
0
                      xmlXPathObjectPtr arg2, int neq) {
5833
0
    int i, j;
5834
0
    unsigned int *hashs1;
5835
0
    unsigned int *hashs2;
5836
0
    xmlChar **values1;
5837
0
    xmlChar **values2;
5838
0
    int ret = 0;
5839
0
    xmlNodeSetPtr ns1;
5840
0
    xmlNodeSetPtr ns2;
5841
5842
0
    if ((arg1 == NULL) ||
5843
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5844
0
        return(0);
5845
0
    if ((arg2 == NULL) ||
5846
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5847
0
        return(0);
5848
5849
0
    ns1 = arg1->nodesetval;
5850
0
    ns2 = arg2->nodesetval;
5851
5852
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5853
0
  return(0);
5854
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5855
0
  return(0);
5856
5857
    /*
5858
     * for equal, check if there is a node pertaining to both sets
5859
     */
5860
0
    if (neq == 0)
5861
0
  for (i = 0;i < ns1->nodeNr;i++)
5862
0
      for (j = 0;j < ns2->nodeNr;j++)
5863
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5864
0
        return(1);
5865
5866
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5867
0
    if (values1 == NULL) {
5868
0
        xmlXPathPErrMemory(ctxt);
5869
0
  return(0);
5870
0
    }
5871
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5872
0
    if (hashs1 == NULL) {
5873
0
        xmlXPathPErrMemory(ctxt);
5874
0
  xmlFree(values1);
5875
0
  return(0);
5876
0
    }
5877
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5878
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5879
0
    if (values2 == NULL) {
5880
0
        xmlXPathPErrMemory(ctxt);
5881
0
  xmlFree(hashs1);
5882
0
  xmlFree(values1);
5883
0
  return(0);
5884
0
    }
5885
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5886
0
    if (hashs2 == NULL) {
5887
0
        xmlXPathPErrMemory(ctxt);
5888
0
  xmlFree(hashs1);
5889
0
  xmlFree(values1);
5890
0
  xmlFree(values2);
5891
0
  return(0);
5892
0
    }
5893
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5894
0
    for (i = 0;i < ns1->nodeNr;i++) {
5895
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5896
0
  for (j = 0;j < ns2->nodeNr;j++) {
5897
0
      if (i == 0)
5898
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5899
0
      if (hashs1[i] != hashs2[j]) {
5900
0
    if (neq) {
5901
0
        ret = 1;
5902
0
        break;
5903
0
    }
5904
0
      }
5905
0
      else {
5906
0
    if (values1[i] == NULL) {
5907
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5908
0
                    if (values1[i] == NULL)
5909
0
                        xmlXPathPErrMemory(ctxt);
5910
0
                }
5911
0
    if (values2[j] == NULL) {
5912
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5913
0
                    if (values2[j] == NULL)
5914
0
                        xmlXPathPErrMemory(ctxt);
5915
0
                }
5916
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5917
0
    if (ret)
5918
0
        break;
5919
0
      }
5920
0
  }
5921
0
  if (ret)
5922
0
      break;
5923
0
    }
5924
0
    for (i = 0;i < ns1->nodeNr;i++)
5925
0
  if (values1[i] != NULL)
5926
0
      xmlFree(values1[i]);
5927
0
    for (j = 0;j < ns2->nodeNr;j++)
5928
0
  if (values2[j] != NULL)
5929
0
      xmlFree(values2[j]);
5930
0
    xmlFree(values1);
5931
0
    xmlFree(values2);
5932
0
    xmlFree(hashs1);
5933
0
    xmlFree(hashs2);
5934
0
    return(ret);
5935
0
}
5936
5937
static int
5938
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5939
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5940
0
    int ret = 0;
5941
    /*
5942
     *At this point we are assured neither arg1 nor arg2
5943
     *is a nodeset, so we can just pick the appropriate routine.
5944
     */
5945
0
    switch (arg1->type) {
5946
0
        case XPATH_UNDEFINED:
5947
0
      break;
5948
0
        case XPATH_BOOLEAN:
5949
0
      switch (arg2->type) {
5950
0
          case XPATH_UNDEFINED:
5951
0
        break;
5952
0
    case XPATH_BOOLEAN:
5953
0
        ret = (arg1->boolval == arg2->boolval);
5954
0
        break;
5955
0
    case XPATH_NUMBER:
5956
0
        ret = (arg1->boolval ==
5957
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
5958
0
        break;
5959
0
    case XPATH_STRING:
5960
0
        if ((arg2->stringval == NULL) ||
5961
0
      (arg2->stringval[0] == 0)) ret = 0;
5962
0
        else
5963
0
      ret = 1;
5964
0
        ret = (arg1->boolval == ret);
5965
0
        break;
5966
0
    case XPATH_USERS:
5967
#ifdef LIBXML_XPTR_LOCS_ENABLED
5968
    case XPATH_POINT:
5969
    case XPATH_RANGE:
5970
    case XPATH_LOCATIONSET:
5971
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5972
        /* TODO */
5973
0
        break;
5974
0
    case XPATH_NODESET:
5975
0
    case XPATH_XSLT_TREE:
5976
0
        break;
5977
0
      }
5978
0
      break;
5979
0
        case XPATH_NUMBER:
5980
0
      switch (arg2->type) {
5981
0
          case XPATH_UNDEFINED:
5982
0
        break;
5983
0
    case XPATH_BOOLEAN:
5984
0
        ret = (arg2->boolval==
5985
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
5986
0
        break;
5987
0
    case XPATH_STRING:
5988
0
        valuePush(ctxt, arg2);
5989
0
        xmlXPathNumberFunction(ctxt, 1);
5990
0
        arg2 = valuePop(ctxt);
5991
0
                    if (ctxt->error)
5992
0
                        break;
5993
                    /* Falls through. */
5994
0
    case XPATH_NUMBER:
5995
        /* Hand check NaN and Infinity equalities */
5996
0
        if (xmlXPathIsNaN(arg1->floatval) ||
5997
0
          xmlXPathIsNaN(arg2->floatval)) {
5998
0
            ret = 0;
5999
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6000
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
6001
0
          ret = 1;
6002
0
      else
6003
0
          ret = 0;
6004
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6005
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
6006
0
          ret = 1;
6007
0
      else
6008
0
          ret = 0;
6009
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6010
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
6011
0
          ret = 1;
6012
0
      else
6013
0
          ret = 0;
6014
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6015
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
6016
0
          ret = 1;
6017
0
      else
6018
0
          ret = 0;
6019
0
        } else {
6020
0
            ret = (arg1->floatval == arg2->floatval);
6021
0
        }
6022
0
        break;
6023
0
    case XPATH_USERS:
6024
#ifdef LIBXML_XPTR_LOCS_ENABLED
6025
    case XPATH_POINT:
6026
    case XPATH_RANGE:
6027
    case XPATH_LOCATIONSET:
6028
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6029
        /* TODO */
6030
0
        break;
6031
0
    case XPATH_NODESET:
6032
0
    case XPATH_XSLT_TREE:
6033
0
        break;
6034
0
      }
6035
0
      break;
6036
0
        case XPATH_STRING:
6037
0
      switch (arg2->type) {
6038
0
          case XPATH_UNDEFINED:
6039
0
        break;
6040
0
    case XPATH_BOOLEAN:
6041
0
        if ((arg1->stringval == NULL) ||
6042
0
      (arg1->stringval[0] == 0)) ret = 0;
6043
0
        else
6044
0
      ret = 1;
6045
0
        ret = (arg2->boolval == ret);
6046
0
        break;
6047
0
    case XPATH_STRING:
6048
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6049
0
        break;
6050
0
    case XPATH_NUMBER:
6051
0
        valuePush(ctxt, arg1);
6052
0
        xmlXPathNumberFunction(ctxt, 1);
6053
0
        arg1 = valuePop(ctxt);
6054
0
                    if (ctxt->error)
6055
0
                        break;
6056
        /* Hand check NaN and Infinity equalities */
6057
0
        if (xmlXPathIsNaN(arg1->floatval) ||
6058
0
          xmlXPathIsNaN(arg2->floatval)) {
6059
0
            ret = 0;
6060
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6061
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
6062
0
          ret = 1;
6063
0
      else
6064
0
          ret = 0;
6065
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6066
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
6067
0
          ret = 1;
6068
0
      else
6069
0
          ret = 0;
6070
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6071
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
6072
0
          ret = 1;
6073
0
      else
6074
0
          ret = 0;
6075
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6076
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
6077
0
          ret = 1;
6078
0
      else
6079
0
          ret = 0;
6080
0
        } else {
6081
0
            ret = (arg1->floatval == arg2->floatval);
6082
0
        }
6083
0
        break;
6084
0
    case XPATH_USERS:
6085
#ifdef LIBXML_XPTR_LOCS_ENABLED
6086
    case XPATH_POINT:
6087
    case XPATH_RANGE:
6088
    case XPATH_LOCATIONSET:
6089
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6090
        /* TODO */
6091
0
        break;
6092
0
    case XPATH_NODESET:
6093
0
    case XPATH_XSLT_TREE:
6094
0
        break;
6095
0
      }
6096
0
      break;
6097
0
        case XPATH_USERS:
6098
#ifdef LIBXML_XPTR_LOCS_ENABLED
6099
  case XPATH_POINT:
6100
  case XPATH_RANGE:
6101
  case XPATH_LOCATIONSET:
6102
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6103
      /* TODO */
6104
0
      break;
6105
0
  case XPATH_NODESET:
6106
0
  case XPATH_XSLT_TREE:
6107
0
      break;
6108
0
    }
6109
0
    xmlXPathReleaseObject(ctxt->context, arg1);
6110
0
    xmlXPathReleaseObject(ctxt->context, arg2);
6111
0
    return(ret);
6112
0
}
6113
6114
/**
6115
 * xmlXPathEqualValues:
6116
 * @ctxt:  the XPath Parser context
6117
 *
6118
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6119
 *
6120
 * Returns 0 or 1 depending on the results of the test.
6121
 */
6122
int
6123
0
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6124
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
6125
0
    int ret = 0;
6126
6127
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6128
0
    arg2 = valuePop(ctxt);
6129
0
    arg1 = valuePop(ctxt);
6130
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6131
0
  if (arg1 != NULL)
6132
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6133
0
  else
6134
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6135
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6136
0
    }
6137
6138
0
    if (arg1 == arg2) {
6139
0
  xmlXPathFreeObject(arg1);
6140
0
        return(1);
6141
0
    }
6142
6143
    /*
6144
     *If either argument is a nodeset, it's a 'special case'
6145
     */
6146
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6147
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6148
  /*
6149
   *Hack it to assure arg1 is the nodeset
6150
   */
6151
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6152
0
    argtmp = arg2;
6153
0
    arg2 = arg1;
6154
0
    arg1 = argtmp;
6155
0
  }
6156
0
  switch (arg2->type) {
6157
0
      case XPATH_UNDEFINED:
6158
0
    break;
6159
0
      case XPATH_NODESET:
6160
0
      case XPATH_XSLT_TREE:
6161
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
6162
0
    break;
6163
0
      case XPATH_BOOLEAN:
6164
0
    if ((arg1->nodesetval == NULL) ||
6165
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
6166
0
    else
6167
0
        ret = 1;
6168
0
    ret = (ret == arg2->boolval);
6169
0
    break;
6170
0
      case XPATH_NUMBER:
6171
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6172
0
    break;
6173
0
      case XPATH_STRING:
6174
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6175
0
                                                 arg2->stringval, 0);
6176
0
    break;
6177
0
      case XPATH_USERS:
6178
#ifdef LIBXML_XPTR_LOCS_ENABLED
6179
      case XPATH_POINT:
6180
      case XPATH_RANGE:
6181
      case XPATH_LOCATIONSET:
6182
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6183
    /* TODO */
6184
0
    break;
6185
0
  }
6186
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6187
0
  xmlXPathReleaseObject(ctxt->context, arg2);
6188
0
  return(ret);
6189
0
    }
6190
6191
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6192
0
}
6193
6194
/**
6195
 * xmlXPathNotEqualValues:
6196
 * @ctxt:  the XPath Parser context
6197
 *
6198
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6199
 *
6200
 * Returns 0 or 1 depending on the results of the test.
6201
 */
6202
int
6203
0
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6204
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
6205
0
    int ret = 0;
6206
6207
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6208
0
    arg2 = valuePop(ctxt);
6209
0
    arg1 = valuePop(ctxt);
6210
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6211
0
  if (arg1 != NULL)
6212
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6213
0
  else
6214
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6215
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6216
0
    }
6217
6218
0
    if (arg1 == arg2) {
6219
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6220
0
        return(0);
6221
0
    }
6222
6223
    /*
6224
     *If either argument is a nodeset, it's a 'special case'
6225
     */
6226
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6227
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6228
  /*
6229
   *Hack it to assure arg1 is the nodeset
6230
   */
6231
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6232
0
    argtmp = arg2;
6233
0
    arg2 = arg1;
6234
0
    arg1 = argtmp;
6235
0
  }
6236
0
  switch (arg2->type) {
6237
0
      case XPATH_UNDEFINED:
6238
0
    break;
6239
0
      case XPATH_NODESET:
6240
0
      case XPATH_XSLT_TREE:
6241
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6242
0
    break;
6243
0
      case XPATH_BOOLEAN:
6244
0
    if ((arg1->nodesetval == NULL) ||
6245
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
6246
0
    else
6247
0
        ret = 1;
6248
0
    ret = (ret != arg2->boolval);
6249
0
    break;
6250
0
      case XPATH_NUMBER:
6251
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6252
0
    break;
6253
0
      case XPATH_STRING:
6254
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6255
0
                                                 arg2->stringval, 1);
6256
0
    break;
6257
0
      case XPATH_USERS:
6258
#ifdef LIBXML_XPTR_LOCS_ENABLED
6259
      case XPATH_POINT:
6260
      case XPATH_RANGE:
6261
      case XPATH_LOCATIONSET:
6262
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6263
    /* TODO */
6264
0
    break;
6265
0
  }
6266
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6267
0
  xmlXPathReleaseObject(ctxt->context, arg2);
6268
0
  return(ret);
6269
0
    }
6270
6271
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6272
0
}
6273
6274
/**
6275
 * xmlXPathCompareValues:
6276
 * @ctxt:  the XPath Parser context
6277
 * @inf:  less than (1) or greater than (0)
6278
 * @strict:  is the comparison strict
6279
 *
6280
 * Implement the compare operation on XPath objects:
6281
 *     @arg1 < @arg2    (1, 1, ...
6282
 *     @arg1 <= @arg2   (1, 0, ...
6283
 *     @arg1 > @arg2    (0, 1, ...
6284
 *     @arg1 >= @arg2   (0, 0, ...
6285
 *
6286
 * When neither object to be compared is a node-set and the operator is
6287
 * <=, <, >=, >, then the objects are compared by converted both objects
6288
 * to numbers and comparing the numbers according to IEEE 754. The <
6289
 * comparison will be true if and only if the first number is less than the
6290
 * second number. The <= comparison will be true if and only if the first
6291
 * number is less than or equal to the second number. The > comparison
6292
 * will be true if and only if the first number is greater than the second
6293
 * number. The >= comparison will be true if and only if the first number
6294
 * is greater than or equal to the second number.
6295
 *
6296
 * Returns 1 if the comparison succeeded, 0 if it failed
6297
 */
6298
int
6299
0
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6300
0
    int ret = 0, arg1i = 0, arg2i = 0;
6301
0
    xmlXPathObjectPtr arg1, arg2;
6302
6303
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6304
0
    arg2 = valuePop(ctxt);
6305
0
    arg1 = valuePop(ctxt);
6306
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6307
0
  if (arg1 != NULL)
6308
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6309
0
  else
6310
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6311
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6312
0
    }
6313
6314
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6315
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6316
  /*
6317
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6318
   * are not freed from within this routine; they will be freed from the
6319
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6320
   */
6321
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6322
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6323
0
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6324
0
  } else {
6325
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6326
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6327
0
                                arg1, arg2);
6328
0
      } else {
6329
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6330
0
                                arg2, arg1);
6331
0
      }
6332
0
  }
6333
0
  return(ret);
6334
0
    }
6335
6336
0
    if (arg1->type != XPATH_NUMBER) {
6337
0
  valuePush(ctxt, arg1);
6338
0
  xmlXPathNumberFunction(ctxt, 1);
6339
0
  arg1 = valuePop(ctxt);
6340
0
    }
6341
0
    if (arg2->type != XPATH_NUMBER) {
6342
0
  valuePush(ctxt, arg2);
6343
0
  xmlXPathNumberFunction(ctxt, 1);
6344
0
  arg2 = valuePop(ctxt);
6345
0
    }
6346
0
    if (ctxt->error)
6347
0
        goto error;
6348
    /*
6349
     * Add tests for infinity and nan
6350
     * => feedback on 3.4 for Inf and NaN
6351
     */
6352
    /* Hand check NaN and Infinity comparisons */
6353
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6354
0
  ret=0;
6355
0
    } else {
6356
0
  arg1i=xmlXPathIsInf(arg1->floatval);
6357
0
  arg2i=xmlXPathIsInf(arg2->floatval);
6358
0
  if (inf && strict) {
6359
0
      if ((arg1i == -1 && arg2i != -1) ||
6360
0
    (arg2i == 1 && arg1i != 1)) {
6361
0
    ret = 1;
6362
0
      } else if (arg1i == 0 && arg2i == 0) {
6363
0
    ret = (arg1->floatval < arg2->floatval);
6364
0
      } else {
6365
0
    ret = 0;
6366
0
      }
6367
0
  }
6368
0
  else if (inf && !strict) {
6369
0
      if (arg1i == -1 || arg2i == 1) {
6370
0
    ret = 1;
6371
0
      } else if (arg1i == 0 && arg2i == 0) {
6372
0
    ret = (arg1->floatval <= arg2->floatval);
6373
0
      } else {
6374
0
    ret = 0;
6375
0
      }
6376
0
  }
6377
0
  else if (!inf && strict) {
6378
0
      if ((arg1i == 1 && arg2i != 1) ||
6379
0
    (arg2i == -1 && arg1i != -1)) {
6380
0
    ret = 1;
6381
0
      } else if (arg1i == 0 && arg2i == 0) {
6382
0
    ret = (arg1->floatval > arg2->floatval);
6383
0
      } else {
6384
0
    ret = 0;
6385
0
      }
6386
0
  }
6387
0
  else if (!inf && !strict) {
6388
0
      if (arg1i == 1 || arg2i == -1) {
6389
0
    ret = 1;
6390
0
      } else if (arg1i == 0 && arg2i == 0) {
6391
0
    ret = (arg1->floatval >= arg2->floatval);
6392
0
      } else {
6393
0
    ret = 0;
6394
0
      }
6395
0
  }
6396
0
    }
6397
0
error:
6398
0
    xmlXPathReleaseObject(ctxt->context, arg1);
6399
0
    xmlXPathReleaseObject(ctxt->context, arg2);
6400
0
    return(ret);
6401
0
}
6402
6403
/**
6404
 * xmlXPathValueFlipSign:
6405
 * @ctxt:  the XPath Parser context
6406
 *
6407
 * Implement the unary - operation on an XPath object
6408
 * The numeric operators convert their operands to numbers as if
6409
 * by calling the number function.
6410
 */
6411
void
6412
0
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6413
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6414
0
    CAST_TO_NUMBER;
6415
0
    CHECK_TYPE(XPATH_NUMBER);
6416
0
    ctxt->value->floatval = -ctxt->value->floatval;
6417
0
}
6418
6419
/**
6420
 * xmlXPathAddValues:
6421
 * @ctxt:  the XPath Parser context
6422
 *
6423
 * Implement the add operation on XPath objects:
6424
 * The numeric operators convert their operands to numbers as if
6425
 * by calling the number function.
6426
 */
6427
void
6428
0
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6429
0
    xmlXPathObjectPtr arg;
6430
0
    double val;
6431
6432
0
    arg = valuePop(ctxt);
6433
0
    if (arg == NULL)
6434
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6435
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6436
0
    xmlXPathReleaseObject(ctxt->context, arg);
6437
0
    CAST_TO_NUMBER;
6438
0
    CHECK_TYPE(XPATH_NUMBER);
6439
0
    ctxt->value->floatval += val;
6440
0
}
6441
6442
/**
6443
 * xmlXPathSubValues:
6444
 * @ctxt:  the XPath Parser context
6445
 *
6446
 * Implement the subtraction operation on XPath objects:
6447
 * The numeric operators convert their operands to numbers as if
6448
 * by calling the number function.
6449
 */
6450
void
6451
0
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6452
0
    xmlXPathObjectPtr arg;
6453
0
    double val;
6454
6455
0
    arg = valuePop(ctxt);
6456
0
    if (arg == NULL)
6457
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6458
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6459
0
    xmlXPathReleaseObject(ctxt->context, arg);
6460
0
    CAST_TO_NUMBER;
6461
0
    CHECK_TYPE(XPATH_NUMBER);
6462
0
    ctxt->value->floatval -= val;
6463
0
}
6464
6465
/**
6466
 * xmlXPathMultValues:
6467
 * @ctxt:  the XPath Parser context
6468
 *
6469
 * Implement the multiply operation on XPath objects:
6470
 * The numeric operators convert their operands to numbers as if
6471
 * by calling the number function.
6472
 */
6473
void
6474
0
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6475
0
    xmlXPathObjectPtr arg;
6476
0
    double val;
6477
6478
0
    arg = valuePop(ctxt);
6479
0
    if (arg == NULL)
6480
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6481
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6482
0
    xmlXPathReleaseObject(ctxt->context, arg);
6483
0
    CAST_TO_NUMBER;
6484
0
    CHECK_TYPE(XPATH_NUMBER);
6485
0
    ctxt->value->floatval *= val;
6486
0
}
6487
6488
/**
6489
 * xmlXPathDivValues:
6490
 * @ctxt:  the XPath Parser context
6491
 *
6492
 * Implement the div operation on XPath objects @arg1 / @arg2:
6493
 * The numeric operators convert their operands to numbers as if
6494
 * by calling the number function.
6495
 */
6496
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6497
void
6498
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6499
0
    xmlXPathObjectPtr arg;
6500
0
    double val;
6501
6502
0
    arg = valuePop(ctxt);
6503
0
    if (arg == NULL)
6504
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6505
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6506
0
    xmlXPathReleaseObject(ctxt->context, arg);
6507
0
    CAST_TO_NUMBER;
6508
0
    CHECK_TYPE(XPATH_NUMBER);
6509
0
    ctxt->value->floatval /= val;
6510
0
}
6511
6512
/**
6513
 * xmlXPathModValues:
6514
 * @ctxt:  the XPath Parser context
6515
 *
6516
 * Implement the mod operation on XPath objects: @arg1 / @arg2
6517
 * The numeric operators convert their operands to numbers as if
6518
 * by calling the number function.
6519
 */
6520
void
6521
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6522
0
    xmlXPathObjectPtr arg;
6523
0
    double arg1, arg2;
6524
6525
0
    arg = valuePop(ctxt);
6526
0
    if (arg == NULL)
6527
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6528
0
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6529
0
    xmlXPathReleaseObject(ctxt->context, arg);
6530
0
    CAST_TO_NUMBER;
6531
0
    CHECK_TYPE(XPATH_NUMBER);
6532
0
    arg1 = ctxt->value->floatval;
6533
0
    if (arg2 == 0)
6534
0
  ctxt->value->floatval = xmlXPathNAN;
6535
0
    else {
6536
0
  ctxt->value->floatval = fmod(arg1, arg2);
6537
0
    }
6538
0
}
6539
6540
/************************************************************************
6541
 *                  *
6542
 *    The traversal functions         *
6543
 *                  *
6544
 ************************************************************************/
6545
6546
/*
6547
 * A traversal function enumerates nodes along an axis.
6548
 * Initially it must be called with NULL, and it indicates
6549
 * termination on the axis by returning NULL.
6550
 */
6551
typedef xmlNodePtr (*xmlXPathTraversalFunction)
6552
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6553
6554
/*
6555
 * xmlXPathTraversalFunctionExt:
6556
 * A traversal function enumerates nodes along an axis.
6557
 * Initially it must be called with NULL, and it indicates
6558
 * termination on the axis by returning NULL.
6559
 * The context node of the traversal is specified via @contextNode.
6560
 */
6561
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6562
                    (xmlNodePtr cur, xmlNodePtr contextNode);
6563
6564
/*
6565
 * xmlXPathNodeSetMergeFunction:
6566
 * Used for merging node sets in xmlXPathCollectAndTest().
6567
 */
6568
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6569
        (xmlNodeSetPtr, xmlNodeSetPtr);
6570
6571
6572
/**
6573
 * xmlXPathNextSelf:
6574
 * @ctxt:  the XPath Parser context
6575
 * @cur:  the current node in the traversal
6576
 *
6577
 * Traversal function for the "self" direction
6578
 * The self axis contains just the context node itself
6579
 *
6580
 * Returns the next element following that axis
6581
 */
6582
xmlNodePtr
6583
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6584
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6585
0
    if (cur == NULL)
6586
0
        return(ctxt->context->node);
6587
0
    return(NULL);
6588
0
}
6589
6590
/**
6591
 * xmlXPathNextChild:
6592
 * @ctxt:  the XPath Parser context
6593
 * @cur:  the current node in the traversal
6594
 *
6595
 * Traversal function for the "child" direction
6596
 * The child axis contains the children of the context node in document order.
6597
 *
6598
 * Returns the next element following that axis
6599
 */
6600
xmlNodePtr
6601
0
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6602
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6603
0
    if (cur == NULL) {
6604
0
  if (ctxt->context->node == NULL) return(NULL);
6605
0
  switch (ctxt->context->node->type) {
6606
0
            case XML_ELEMENT_NODE:
6607
0
            case XML_TEXT_NODE:
6608
0
            case XML_CDATA_SECTION_NODE:
6609
0
            case XML_ENTITY_REF_NODE:
6610
0
            case XML_ENTITY_NODE:
6611
0
            case XML_PI_NODE:
6612
0
            case XML_COMMENT_NODE:
6613
0
            case XML_NOTATION_NODE:
6614
0
            case XML_DTD_NODE:
6615
0
    return(ctxt->context->node->children);
6616
0
            case XML_DOCUMENT_NODE:
6617
0
            case XML_DOCUMENT_TYPE_NODE:
6618
0
            case XML_DOCUMENT_FRAG_NODE:
6619
0
            case XML_HTML_DOCUMENT_NODE:
6620
0
    return(((xmlDocPtr) ctxt->context->node)->children);
6621
0
      case XML_ELEMENT_DECL:
6622
0
      case XML_ATTRIBUTE_DECL:
6623
0
      case XML_ENTITY_DECL:
6624
0
            case XML_ATTRIBUTE_NODE:
6625
0
      case XML_NAMESPACE_DECL:
6626
0
      case XML_XINCLUDE_START:
6627
0
      case XML_XINCLUDE_END:
6628
0
    return(NULL);
6629
0
  }
6630
0
  return(NULL);
6631
0
    }
6632
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
6633
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
6634
0
  return(NULL);
6635
0
    return(cur->next);
6636
0
}
6637
6638
/**
6639
 * xmlXPathNextChildElement:
6640
 * @ctxt:  the XPath Parser context
6641
 * @cur:  the current node in the traversal
6642
 *
6643
 * Traversal function for the "child" direction and nodes of type element.
6644
 * The child axis contains the children of the context node in document order.
6645
 *
6646
 * Returns the next element following that axis
6647
 */
6648
static xmlNodePtr
6649
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6650
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6651
0
    if (cur == NULL) {
6652
0
  cur = ctxt->context->node;
6653
0
  if (cur == NULL) return(NULL);
6654
  /*
6655
  * Get the first element child.
6656
  */
6657
0
  switch (cur->type) {
6658
0
            case XML_ELEMENT_NODE:
6659
0
      case XML_DOCUMENT_FRAG_NODE:
6660
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6661
0
            case XML_ENTITY_NODE:
6662
0
    cur = cur->children;
6663
0
    if (cur != NULL) {
6664
0
        if (cur->type == XML_ELEMENT_NODE)
6665
0
      return(cur);
6666
0
        do {
6667
0
      cur = cur->next;
6668
0
        } while ((cur != NULL) &&
6669
0
      (cur->type != XML_ELEMENT_NODE));
6670
0
        return(cur);
6671
0
    }
6672
0
    return(NULL);
6673
0
            case XML_DOCUMENT_NODE:
6674
0
            case XML_HTML_DOCUMENT_NODE:
6675
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6676
0
      default:
6677
0
    return(NULL);
6678
0
  }
6679
0
  return(NULL);
6680
0
    }
6681
    /*
6682
    * Get the next sibling element node.
6683
    */
6684
0
    switch (cur->type) {
6685
0
  case XML_ELEMENT_NODE:
6686
0
  case XML_TEXT_NODE:
6687
0
  case XML_ENTITY_REF_NODE:
6688
0
  case XML_ENTITY_NODE:
6689
0
  case XML_CDATA_SECTION_NODE:
6690
0
  case XML_PI_NODE:
6691
0
  case XML_COMMENT_NODE:
6692
0
  case XML_XINCLUDE_END:
6693
0
      break;
6694
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6695
0
  default:
6696
0
      return(NULL);
6697
0
    }
6698
0
    if (cur->next != NULL) {
6699
0
  if (cur->next->type == XML_ELEMENT_NODE)
6700
0
      return(cur->next);
6701
0
  cur = cur->next;
6702
0
  do {
6703
0
      cur = cur->next;
6704
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6705
0
  return(cur);
6706
0
    }
6707
0
    return(NULL);
6708
0
}
6709
6710
#if 0
6711
/**
6712
 * xmlXPathNextDescendantOrSelfElemParent:
6713
 * @ctxt:  the XPath Parser context
6714
 * @cur:  the current node in the traversal
6715
 *
6716
 * Traversal function for the "descendant-or-self" axis.
6717
 * Additionally it returns only nodes which can be parents of
6718
 * element nodes.
6719
 *
6720
 *
6721
 * Returns the next element following that axis
6722
 */
6723
static xmlNodePtr
6724
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
6725
               xmlNodePtr contextNode)
6726
{
6727
    if (cur == NULL) {
6728
  if (contextNode == NULL)
6729
      return(NULL);
6730
  switch (contextNode->type) {
6731
      case XML_ELEMENT_NODE:
6732
      case XML_XINCLUDE_START:
6733
      case XML_DOCUMENT_FRAG_NODE:
6734
      case XML_DOCUMENT_NODE:
6735
      case XML_HTML_DOCUMENT_NODE:
6736
    return(contextNode);
6737
      default:
6738
    return(NULL);
6739
  }
6740
  return(NULL);
6741
    } else {
6742
  xmlNodePtr start = cur;
6743
6744
  while (cur != NULL) {
6745
      switch (cur->type) {
6746
    case XML_ELEMENT_NODE:
6747
    /* TODO: OK to have XInclude here? */
6748
    case XML_XINCLUDE_START:
6749
    case XML_DOCUMENT_FRAG_NODE:
6750
        if (cur != start)
6751
      return(cur);
6752
        if (cur->children != NULL) {
6753
      cur = cur->children;
6754
      continue;
6755
        }
6756
        break;
6757
    /* Not sure if we need those here. */
6758
    case XML_DOCUMENT_NODE:
6759
    case XML_HTML_DOCUMENT_NODE:
6760
        if (cur != start)
6761
      return(cur);
6762
        return(xmlDocGetRootElement((xmlDocPtr) cur));
6763
    default:
6764
        break;
6765
      }
6766
6767
next_sibling:
6768
      if ((cur == NULL) || (cur == contextNode))
6769
    return(NULL);
6770
      if (cur->next != NULL) {
6771
    cur = cur->next;
6772
      } else {
6773
    cur = cur->parent;
6774
    goto next_sibling;
6775
      }
6776
  }
6777
    }
6778
    return(NULL);
6779
}
6780
#endif
6781
6782
/**
6783
 * xmlXPathNextDescendant:
6784
 * @ctxt:  the XPath Parser context
6785
 * @cur:  the current node in the traversal
6786
 *
6787
 * Traversal function for the "descendant" direction
6788
 * the descendant axis contains the descendants of the context node in document
6789
 * order; a descendant is a child or a child of a child and so on.
6790
 *
6791
 * Returns the next element following that axis
6792
 */
6793
xmlNodePtr
6794
0
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6795
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6796
0
    if (cur == NULL) {
6797
0
  if (ctxt->context->node == NULL)
6798
0
      return(NULL);
6799
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6800
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6801
0
      return(NULL);
6802
6803
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6804
0
      return(ctxt->context->doc->children);
6805
0
        return(ctxt->context->node->children);
6806
0
    }
6807
6808
0
    if (cur->type == XML_NAMESPACE_DECL)
6809
0
        return(NULL);
6810
0
    if (cur->children != NULL) {
6811
  /*
6812
   * Do not descend on entities declarations
6813
   */
6814
0
  if (cur->children->type != XML_ENTITY_DECL) {
6815
0
      cur = cur->children;
6816
      /*
6817
       * Skip DTDs
6818
       */
6819
0
      if (cur->type != XML_DTD_NODE)
6820
0
    return(cur);
6821
0
  }
6822
0
    }
6823
6824
0
    if (cur == ctxt->context->node) return(NULL);
6825
6826
0
    while (cur->next != NULL) {
6827
0
  cur = cur->next;
6828
0
  if ((cur->type != XML_ENTITY_DECL) &&
6829
0
      (cur->type != XML_DTD_NODE))
6830
0
      return(cur);
6831
0
    }
6832
6833
0
    do {
6834
0
        cur = cur->parent;
6835
0
  if (cur == NULL) break;
6836
0
  if (cur == ctxt->context->node) return(NULL);
6837
0
  if (cur->next != NULL) {
6838
0
      cur = cur->next;
6839
0
      return(cur);
6840
0
  }
6841
0
    } while (cur != NULL);
6842
0
    return(cur);
6843
0
}
6844
6845
/**
6846
 * xmlXPathNextDescendantOrSelf:
6847
 * @ctxt:  the XPath Parser context
6848
 * @cur:  the current node in the traversal
6849
 *
6850
 * Traversal function for the "descendant-or-self" direction
6851
 * the descendant-or-self axis contains the context node and the descendants
6852
 * of the context node in document order; thus the context node is the first
6853
 * node on the axis, and the first child of the context node is the second node
6854
 * on the axis
6855
 *
6856
 * Returns the next element following that axis
6857
 */
6858
xmlNodePtr
6859
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6860
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6861
0
    if (cur == NULL)
6862
0
        return(ctxt->context->node);
6863
6864
0
    if (ctxt->context->node == NULL)
6865
0
        return(NULL);
6866
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6867
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6868
0
        return(NULL);
6869
6870
0
    return(xmlXPathNextDescendant(ctxt, cur));
6871
0
}
6872
6873
/**
6874
 * xmlXPathNextParent:
6875
 * @ctxt:  the XPath Parser context
6876
 * @cur:  the current node in the traversal
6877
 *
6878
 * Traversal function for the "parent" direction
6879
 * The parent axis contains the parent of the context node, if there is one.
6880
 *
6881
 * Returns the next element following that axis
6882
 */
6883
xmlNodePtr
6884
0
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6885
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6886
    /*
6887
     * the parent of an attribute or namespace node is the element
6888
     * to which the attribute or namespace node is attached
6889
     * Namespace handling !!!
6890
     */
6891
0
    if (cur == NULL) {
6892
0
  if (ctxt->context->node == NULL) return(NULL);
6893
0
  switch (ctxt->context->node->type) {
6894
0
            case XML_ELEMENT_NODE:
6895
0
            case XML_TEXT_NODE:
6896
0
            case XML_CDATA_SECTION_NODE:
6897
0
            case XML_ENTITY_REF_NODE:
6898
0
            case XML_ENTITY_NODE:
6899
0
            case XML_PI_NODE:
6900
0
            case XML_COMMENT_NODE:
6901
0
            case XML_NOTATION_NODE:
6902
0
            case XML_DTD_NODE:
6903
0
      case XML_ELEMENT_DECL:
6904
0
      case XML_ATTRIBUTE_DECL:
6905
0
      case XML_XINCLUDE_START:
6906
0
      case XML_XINCLUDE_END:
6907
0
      case XML_ENTITY_DECL:
6908
0
    if (ctxt->context->node->parent == NULL)
6909
0
        return((xmlNodePtr) ctxt->context->doc);
6910
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6911
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6912
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6913
0
         BAD_CAST "fake node libxslt"))))
6914
0
        return(NULL);
6915
0
    return(ctxt->context->node->parent);
6916
0
            case XML_ATTRIBUTE_NODE: {
6917
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6918
6919
0
    return(att->parent);
6920
0
      }
6921
0
            case XML_DOCUMENT_NODE:
6922
0
            case XML_DOCUMENT_TYPE_NODE:
6923
0
            case XML_DOCUMENT_FRAG_NODE:
6924
0
            case XML_HTML_DOCUMENT_NODE:
6925
0
                return(NULL);
6926
0
      case XML_NAMESPACE_DECL: {
6927
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6928
6929
0
    if ((ns->next != NULL) &&
6930
0
        (ns->next->type != XML_NAMESPACE_DECL))
6931
0
        return((xmlNodePtr) ns->next);
6932
0
                return(NULL);
6933
0
      }
6934
0
  }
6935
0
    }
6936
0
    return(NULL);
6937
0
}
6938
6939
/**
6940
 * xmlXPathNextAncestor:
6941
 * @ctxt:  the XPath Parser context
6942
 * @cur:  the current node in the traversal
6943
 *
6944
 * Traversal function for the "ancestor" direction
6945
 * the ancestor axis contains the ancestors of the context node; the ancestors
6946
 * of the context node consist of the parent of context node and the parent's
6947
 * parent and so on; the nodes are ordered in reverse document order; thus the
6948
 * parent is the first node on the axis, and the parent's parent is the second
6949
 * node on the axis
6950
 *
6951
 * Returns the next element following that axis
6952
 */
6953
xmlNodePtr
6954
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6955
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6956
    /*
6957
     * the parent of an attribute or namespace node is the element
6958
     * to which the attribute or namespace node is attached
6959
     * !!!!!!!!!!!!!
6960
     */
6961
0
    if (cur == NULL) {
6962
0
  if (ctxt->context->node == NULL) return(NULL);
6963
0
  switch (ctxt->context->node->type) {
6964
0
            case XML_ELEMENT_NODE:
6965
0
            case XML_TEXT_NODE:
6966
0
            case XML_CDATA_SECTION_NODE:
6967
0
            case XML_ENTITY_REF_NODE:
6968
0
            case XML_ENTITY_NODE:
6969
0
            case XML_PI_NODE:
6970
0
            case XML_COMMENT_NODE:
6971
0
      case XML_DTD_NODE:
6972
0
      case XML_ELEMENT_DECL:
6973
0
      case XML_ATTRIBUTE_DECL:
6974
0
      case XML_ENTITY_DECL:
6975
0
            case XML_NOTATION_NODE:
6976
0
      case XML_XINCLUDE_START:
6977
0
      case XML_XINCLUDE_END:
6978
0
    if (ctxt->context->node->parent == NULL)
6979
0
        return((xmlNodePtr) ctxt->context->doc);
6980
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6981
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6982
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6983
0
         BAD_CAST "fake node libxslt"))))
6984
0
        return(NULL);
6985
0
    return(ctxt->context->node->parent);
6986
0
            case XML_ATTRIBUTE_NODE: {
6987
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6988
6989
0
    return(tmp->parent);
6990
0
      }
6991
0
            case XML_DOCUMENT_NODE:
6992
0
            case XML_DOCUMENT_TYPE_NODE:
6993
0
            case XML_DOCUMENT_FRAG_NODE:
6994
0
            case XML_HTML_DOCUMENT_NODE:
6995
0
                return(NULL);
6996
0
      case XML_NAMESPACE_DECL: {
6997
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6998
6999
0
    if ((ns->next != NULL) &&
7000
0
        (ns->next->type != XML_NAMESPACE_DECL))
7001
0
        return((xmlNodePtr) ns->next);
7002
    /* Bad, how did that namespace end up here ? */
7003
0
                return(NULL);
7004
0
      }
7005
0
  }
7006
0
  return(NULL);
7007
0
    }
7008
0
    if (cur == ctxt->context->doc->children)
7009
0
  return((xmlNodePtr) ctxt->context->doc);
7010
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7011
0
  return(NULL);
7012
0
    switch (cur->type) {
7013
0
  case XML_ELEMENT_NODE:
7014
0
  case XML_TEXT_NODE:
7015
0
  case XML_CDATA_SECTION_NODE:
7016
0
  case XML_ENTITY_REF_NODE:
7017
0
  case XML_ENTITY_NODE:
7018
0
  case XML_PI_NODE:
7019
0
  case XML_COMMENT_NODE:
7020
0
  case XML_NOTATION_NODE:
7021
0
  case XML_DTD_NODE:
7022
0
        case XML_ELEMENT_DECL:
7023
0
        case XML_ATTRIBUTE_DECL:
7024
0
        case XML_ENTITY_DECL:
7025
0
  case XML_XINCLUDE_START:
7026
0
  case XML_XINCLUDE_END:
7027
0
      if (cur->parent == NULL)
7028
0
    return(NULL);
7029
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
7030
0
    ((cur->parent->name[0] == ' ') ||
7031
0
     (xmlStrEqual(cur->parent->name,
7032
0
            BAD_CAST "fake node libxslt"))))
7033
0
    return(NULL);
7034
0
      return(cur->parent);
7035
0
  case XML_ATTRIBUTE_NODE: {
7036
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
7037
7038
0
      return(att->parent);
7039
0
  }
7040
0
  case XML_NAMESPACE_DECL: {
7041
0
      xmlNsPtr ns = (xmlNsPtr) cur;
7042
7043
0
      if ((ns->next != NULL) &&
7044
0
          (ns->next->type != XML_NAMESPACE_DECL))
7045
0
          return((xmlNodePtr) ns->next);
7046
      /* Bad, how did that namespace end up here ? */
7047
0
            return(NULL);
7048
0
  }
7049
0
  case XML_DOCUMENT_NODE:
7050
0
  case XML_DOCUMENT_TYPE_NODE:
7051
0
  case XML_DOCUMENT_FRAG_NODE:
7052
0
  case XML_HTML_DOCUMENT_NODE:
7053
0
      return(NULL);
7054
0
    }
7055
0
    return(NULL);
7056
0
}
7057
7058
/**
7059
 * xmlXPathNextAncestorOrSelf:
7060
 * @ctxt:  the XPath Parser context
7061
 * @cur:  the current node in the traversal
7062
 *
7063
 * Traversal function for the "ancestor-or-self" direction
7064
 * he ancestor-or-self axis contains the context node and ancestors of
7065
 * the context node in reverse document order; thus the context node is
7066
 * the first node on the axis, and the context node's parent the second;
7067
 * parent here is defined the same as with the parent axis.
7068
 *
7069
 * Returns the next element following that axis
7070
 */
7071
xmlNodePtr
7072
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7073
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7074
0
    if (cur == NULL)
7075
0
        return(ctxt->context->node);
7076
0
    return(xmlXPathNextAncestor(ctxt, cur));
7077
0
}
7078
7079
/**
7080
 * xmlXPathNextFollowingSibling:
7081
 * @ctxt:  the XPath Parser context
7082
 * @cur:  the current node in the traversal
7083
 *
7084
 * Traversal function for the "following-sibling" direction
7085
 * The following-sibling axis contains the following siblings of the context
7086
 * node in document order.
7087
 *
7088
 * Returns the next element following that axis
7089
 */
7090
xmlNodePtr
7091
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7092
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7093
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7094
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
7095
0
  return(NULL);
7096
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7097
0
        return(NULL);
7098
0
    if (cur == NULL)
7099
0
        return(ctxt->context->node->next);
7100
0
    return(cur->next);
7101
0
}
7102
7103
/**
7104
 * xmlXPathNextPrecedingSibling:
7105
 * @ctxt:  the XPath Parser context
7106
 * @cur:  the current node in the traversal
7107
 *
7108
 * Traversal function for the "preceding-sibling" direction
7109
 * The preceding-sibling axis contains the preceding siblings of the context
7110
 * node in reverse document order; the first preceding sibling is first on the
7111
 * axis; the sibling preceding that node is the second on the axis and so on.
7112
 *
7113
 * Returns the next element following that axis
7114
 */
7115
xmlNodePtr
7116
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7117
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7118
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7119
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
7120
0
  return(NULL);
7121
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7122
0
        return(NULL);
7123
0
    if (cur == NULL)
7124
0
        return(ctxt->context->node->prev);
7125
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7126
0
  cur = cur->prev;
7127
0
  if (cur == NULL)
7128
0
      return(ctxt->context->node->prev);
7129
0
    }
7130
0
    return(cur->prev);
7131
0
}
7132
7133
/**
7134
 * xmlXPathNextFollowing:
7135
 * @ctxt:  the XPath Parser context
7136
 * @cur:  the current node in the traversal
7137
 *
7138
 * Traversal function for the "following" direction
7139
 * The following axis contains all nodes in the same document as the context
7140
 * node that are after the context node in document order, excluding any
7141
 * descendants and excluding attribute nodes and namespace nodes; the nodes
7142
 * are ordered in document order
7143
 *
7144
 * Returns the next element following that axis
7145
 */
7146
xmlNodePtr
7147
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7148
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7149
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
7150
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7151
0
        return(cur->children);
7152
7153
0
    if (cur == NULL) {
7154
0
        cur = ctxt->context->node;
7155
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7156
0
            cur = cur->parent;
7157
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7158
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7159
7160
0
            if ((ns->next == NULL) ||
7161
0
                (ns->next->type == XML_NAMESPACE_DECL))
7162
0
                return (NULL);
7163
0
            cur = (xmlNodePtr) ns->next;
7164
0
        }
7165
0
    }
7166
0
    if (cur == NULL) return(NULL) ; /* ERROR */
7167
0
    if (cur->next != NULL) return(cur->next) ;
7168
0
    do {
7169
0
        cur = cur->parent;
7170
0
        if (cur == NULL) break;
7171
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7172
0
        if (cur->next != NULL) return(cur->next);
7173
0
    } while (cur != NULL);
7174
0
    return(cur);
7175
0
}
7176
7177
/*
7178
 * xmlXPathIsAncestor:
7179
 * @ancestor:  the ancestor node
7180
 * @node:  the current node
7181
 *
7182
 * Check that @ancestor is a @node's ancestor
7183
 *
7184
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7185
 */
7186
static int
7187
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7188
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
7189
0
    if (node->type == XML_NAMESPACE_DECL)
7190
0
        return(0);
7191
0
    if (ancestor->type == XML_NAMESPACE_DECL)
7192
0
        return(0);
7193
    /* nodes need to be in the same document */
7194
0
    if (ancestor->doc != node->doc) return(0);
7195
    /* avoid searching if ancestor or node is the root node */
7196
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
7197
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
7198
0
    while (node->parent != NULL) {
7199
0
        if (node->parent == ancestor)
7200
0
            return(1);
7201
0
  node = node->parent;
7202
0
    }
7203
0
    return(0);
7204
0
}
7205
7206
/**
7207
 * xmlXPathNextPreceding:
7208
 * @ctxt:  the XPath Parser context
7209
 * @cur:  the current node in the traversal
7210
 *
7211
 * Traversal function for the "preceding" direction
7212
 * the preceding axis contains all nodes in the same document as the context
7213
 * node that are before the context node in document order, excluding any
7214
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7215
 * ordered in reverse document order
7216
 *
7217
 * Returns the next element following that axis
7218
 */
7219
xmlNodePtr
7220
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7221
0
{
7222
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7223
0
    if (cur == NULL) {
7224
0
        cur = ctxt->context->node;
7225
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7226
0
            cur = cur->parent;
7227
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7228
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7229
7230
0
            if ((ns->next == NULL) ||
7231
0
                (ns->next->type == XML_NAMESPACE_DECL))
7232
0
                return (NULL);
7233
0
            cur = (xmlNodePtr) ns->next;
7234
0
        }
7235
0
    }
7236
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7237
0
  return (NULL);
7238
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7239
0
  cur = cur->prev;
7240
0
    do {
7241
0
        if (cur->prev != NULL) {
7242
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7243
0
            return (cur);
7244
0
        }
7245
7246
0
        cur = cur->parent;
7247
0
        if (cur == NULL)
7248
0
            return (NULL);
7249
0
        if (cur == ctxt->context->doc->children)
7250
0
            return (NULL);
7251
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7252
0
    return (cur);
7253
0
}
7254
7255
/**
7256
 * xmlXPathNextPrecedingInternal:
7257
 * @ctxt:  the XPath Parser context
7258
 * @cur:  the current node in the traversal
7259
 *
7260
 * Traversal function for the "preceding" direction
7261
 * the preceding axis contains all nodes in the same document as the context
7262
 * node that are before the context node in document order, excluding any
7263
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7264
 * ordered in reverse document order
7265
 * This is a faster implementation but internal only since it requires a
7266
 * state kept in the parser context: ctxt->ancestor.
7267
 *
7268
 * Returns the next element following that axis
7269
 */
7270
static xmlNodePtr
7271
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7272
                              xmlNodePtr cur)
7273
0
{
7274
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7275
0
    if (cur == NULL) {
7276
0
        cur = ctxt->context->node;
7277
0
        if (cur == NULL)
7278
0
            return (NULL);
7279
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7280
0
            cur = cur->parent;
7281
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7282
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7283
7284
0
            if ((ns->next == NULL) ||
7285
0
                (ns->next->type == XML_NAMESPACE_DECL))
7286
0
                return (NULL);
7287
0
            cur = (xmlNodePtr) ns->next;
7288
0
        }
7289
0
        ctxt->ancestor = cur->parent;
7290
0
    }
7291
0
    if (cur->type == XML_NAMESPACE_DECL)
7292
0
        return(NULL);
7293
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7294
0
  cur = cur->prev;
7295
0
    while (cur->prev == NULL) {
7296
0
        cur = cur->parent;
7297
0
        if (cur == NULL)
7298
0
            return (NULL);
7299
0
        if (cur == ctxt->context->doc->children)
7300
0
            return (NULL);
7301
0
        if (cur != ctxt->ancestor)
7302
0
            return (cur);
7303
0
        ctxt->ancestor = cur->parent;
7304
0
    }
7305
0
    cur = cur->prev;
7306
0
    while (cur->last != NULL)
7307
0
        cur = cur->last;
7308
0
    return (cur);
7309
0
}
7310
7311
/**
7312
 * xmlXPathNextNamespace:
7313
 * @ctxt:  the XPath Parser context
7314
 * @cur:  the current attribute in the traversal
7315
 *
7316
 * Traversal function for the "namespace" direction
7317
 * the namespace axis contains the namespace nodes of the context node;
7318
 * the order of nodes on this axis is implementation-defined; the axis will
7319
 * be empty unless the context node is an element
7320
 *
7321
 * We keep the XML namespace node at the end of the list.
7322
 *
7323
 * Returns the next element following that axis
7324
 */
7325
xmlNodePtr
7326
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7327
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7328
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7329
0
    if (cur == NULL) {
7330
0
        if (ctxt->context->tmpNsList != NULL)
7331
0
      xmlFree(ctxt->context->tmpNsList);
7332
0
  ctxt->context->tmpNsNr = 0;
7333
0
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7334
0
                             &ctxt->context->tmpNsList) < 0) {
7335
0
            xmlXPathPErrMemory(ctxt);
7336
0
            return(NULL);
7337
0
        }
7338
0
        if (ctxt->context->tmpNsList != NULL) {
7339
0
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7340
0
                ctxt->context->tmpNsNr++;
7341
0
            }
7342
0
        }
7343
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
7344
0
    }
7345
0
    if (ctxt->context->tmpNsNr > 0) {
7346
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7347
0
    } else {
7348
0
  if (ctxt->context->tmpNsList != NULL)
7349
0
      xmlFree(ctxt->context->tmpNsList);
7350
0
  ctxt->context->tmpNsList = NULL;
7351
0
  return(NULL);
7352
0
    }
7353
0
}
7354
7355
/**
7356
 * xmlXPathNextAttribute:
7357
 * @ctxt:  the XPath Parser context
7358
 * @cur:  the current attribute in the traversal
7359
 *
7360
 * Traversal function for the "attribute" direction
7361
 * TODO: support DTD inherited default attributes
7362
 *
7363
 * Returns the next element following that axis
7364
 */
7365
xmlNodePtr
7366
0
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7367
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7368
0
    if (ctxt->context->node == NULL)
7369
0
  return(NULL);
7370
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
7371
0
  return(NULL);
7372
0
    if (cur == NULL) {
7373
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7374
0
      return(NULL);
7375
0
        return((xmlNodePtr)ctxt->context->node->properties);
7376
0
    }
7377
0
    return((xmlNodePtr)cur->next);
7378
0
}
7379
7380
/************************************************************************
7381
 *                  *
7382
 *    NodeTest Functions          *
7383
 *                  *
7384
 ************************************************************************/
7385
7386
#define IS_FUNCTION     200
7387
7388
7389
/************************************************************************
7390
 *                  *
7391
 *    Implicit tree core function library     *
7392
 *                  *
7393
 ************************************************************************/
7394
7395
/**
7396
 * xmlXPathRoot:
7397
 * @ctxt:  the XPath Parser context
7398
 *
7399
 * Initialize the context to the root of the document
7400
 */
7401
void
7402
0
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7403
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
7404
0
  return;
7405
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7406
0
                                            (xmlNodePtr) ctxt->context->doc));
7407
0
}
7408
7409
/************************************************************************
7410
 *                  *
7411
 *    The explicit core function library      *
7412
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7413
 *                  *
7414
 ************************************************************************/
7415
7416
7417
/**
7418
 * xmlXPathLastFunction:
7419
 * @ctxt:  the XPath Parser context
7420
 * @nargs:  the number of arguments
7421
 *
7422
 * Implement the last() XPath function
7423
 *    number last()
7424
 * The last function returns the number of nodes in the context node list.
7425
 */
7426
void
7427
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7428
0
    CHECK_ARITY(0);
7429
0
    if (ctxt->context->contextSize >= 0) {
7430
0
  valuePush(ctxt,
7431
0
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7432
0
    } else {
7433
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7434
0
    }
7435
0
}
7436
7437
/**
7438
 * xmlXPathPositionFunction:
7439
 * @ctxt:  the XPath Parser context
7440
 * @nargs:  the number of arguments
7441
 *
7442
 * Implement the position() XPath function
7443
 *    number position()
7444
 * The position function returns the position of the context node in the
7445
 * context node list. The first position is 1, and so the last position
7446
 * will be equal to last().
7447
 */
7448
void
7449
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7450
0
    CHECK_ARITY(0);
7451
0
    if (ctxt->context->proximityPosition >= 0) {
7452
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7453
0
            (double) ctxt->context->proximityPosition));
7454
0
    } else {
7455
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7456
0
    }
7457
0
}
7458
7459
/**
7460
 * xmlXPathCountFunction:
7461
 * @ctxt:  the XPath Parser context
7462
 * @nargs:  the number of arguments
7463
 *
7464
 * Implement the count() XPath function
7465
 *    number count(node-set)
7466
 */
7467
void
7468
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7469
0
    xmlXPathObjectPtr cur;
7470
7471
0
    CHECK_ARITY(1);
7472
0
    if ((ctxt->value == NULL) ||
7473
0
  ((ctxt->value->type != XPATH_NODESET) &&
7474
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7475
0
  XP_ERROR(XPATH_INVALID_TYPE);
7476
0
    cur = valuePop(ctxt);
7477
7478
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
7479
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7480
0
    else
7481
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7482
0
      (double) cur->nodesetval->nodeNr));
7483
0
    xmlXPathReleaseObject(ctxt->context, cur);
7484
0
}
7485
7486
/**
7487
 * xmlXPathGetElementsByIds:
7488
 * @doc:  the document
7489
 * @ids:  a whitespace separated list of IDs
7490
 *
7491
 * Selects elements by their unique ID.
7492
 *
7493
 * Returns a node-set of selected elements.
7494
 */
7495
static xmlNodeSetPtr
7496
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7497
0
    xmlNodeSetPtr ret;
7498
0
    const xmlChar *cur = ids;
7499
0
    xmlChar *ID;
7500
0
    xmlAttrPtr attr;
7501
0
    xmlNodePtr elem = NULL;
7502
7503
0
    if (ids == NULL) return(NULL);
7504
7505
0
    ret = xmlXPathNodeSetCreate(NULL);
7506
0
    if (ret == NULL)
7507
0
        return(ret);
7508
7509
0
    while (IS_BLANK_CH(*cur)) cur++;
7510
0
    while (*cur != 0) {
7511
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7512
0
      cur++;
7513
7514
0
        ID = xmlStrndup(ids, cur - ids);
7515
0
  if (ID == NULL) {
7516
0
            xmlXPathFreeNodeSet(ret);
7517
0
            return(NULL);
7518
0
        }
7519
        /*
7520
         * We used to check the fact that the value passed
7521
         * was an NCName, but this generated much troubles for
7522
         * me and Aleksey Sanin, people blatantly violated that
7523
         * constraint, like Visa3D spec.
7524
         * if (xmlValidateNCName(ID, 1) == 0)
7525
         */
7526
0
        attr = xmlGetID(doc, ID);
7527
0
        xmlFree(ID);
7528
0
        if (attr != NULL) {
7529
0
            if (attr->type == XML_ATTRIBUTE_NODE)
7530
0
                elem = attr->parent;
7531
0
            else if (attr->type == XML_ELEMENT_NODE)
7532
0
                elem = (xmlNodePtr) attr;
7533
0
            else
7534
0
                elem = NULL;
7535
0
            if (elem != NULL) {
7536
0
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7537
0
                    xmlXPathFreeNodeSet(ret);
7538
0
                    return(NULL);
7539
0
                }
7540
0
            }
7541
0
        }
7542
7543
0
  while (IS_BLANK_CH(*cur)) cur++;
7544
0
  ids = cur;
7545
0
    }
7546
0
    return(ret);
7547
0
}
7548
7549
/**
7550
 * xmlXPathIdFunction:
7551
 * @ctxt:  the XPath Parser context
7552
 * @nargs:  the number of arguments
7553
 *
7554
 * Implement the id() XPath function
7555
 *    node-set id(object)
7556
 * The id function selects elements by their unique ID
7557
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7558
 * then the result is the union of the result of applying id to the
7559
 * string value of each of the nodes in the argument node-set. When the
7560
 * argument to id is of any other type, the argument is converted to a
7561
 * string as if by a call to the string function; the string is split
7562
 * into a whitespace-separated list of tokens (whitespace is any sequence
7563
 * of characters matching the production S); the result is a node-set
7564
 * containing the elements in the same document as the context node that
7565
 * have a unique ID equal to any of the tokens in the list.
7566
 */
7567
void
7568
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7569
0
    xmlChar *tokens;
7570
0
    xmlNodeSetPtr ret;
7571
0
    xmlXPathObjectPtr obj;
7572
7573
0
    CHECK_ARITY(1);
7574
0
    obj = valuePop(ctxt);
7575
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7576
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7577
0
  xmlNodeSetPtr ns;
7578
0
  int i;
7579
7580
0
  ret = xmlXPathNodeSetCreate(NULL);
7581
0
        if (ret == NULL)
7582
0
            xmlXPathPErrMemory(ctxt);
7583
7584
0
  if (obj->nodesetval != NULL) {
7585
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7586
0
    tokens =
7587
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7588
0
                if (tokens == NULL)
7589
0
                    xmlXPathPErrMemory(ctxt);
7590
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7591
0
                if (ns == NULL)
7592
0
                    xmlXPathPErrMemory(ctxt);
7593
0
    ret = xmlXPathNodeSetMerge(ret, ns);
7594
0
                if (ret == NULL)
7595
0
                    xmlXPathPErrMemory(ctxt);
7596
0
    xmlXPathFreeNodeSet(ns);
7597
0
    if (tokens != NULL)
7598
0
        xmlFree(tokens);
7599
0
      }
7600
0
  }
7601
0
  xmlXPathReleaseObject(ctxt->context, obj);
7602
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7603
0
  return;
7604
0
    }
7605
0
    tokens = xmlXPathCastToString(obj);
7606
0
    if (tokens == NULL)
7607
0
        xmlXPathPErrMemory(ctxt);
7608
0
    xmlXPathReleaseObject(ctxt->context, obj);
7609
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7610
0
    if (ret == NULL)
7611
0
        xmlXPathPErrMemory(ctxt);
7612
0
    xmlFree(tokens);
7613
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7614
0
    return;
7615
0
}
7616
7617
/**
7618
 * xmlXPathLocalNameFunction:
7619
 * @ctxt:  the XPath Parser context
7620
 * @nargs:  the number of arguments
7621
 *
7622
 * Implement the local-name() XPath function
7623
 *    string local-name(node-set?)
7624
 * The local-name function returns a string containing the local part
7625
 * of the name of the node in the argument node-set that is first in
7626
 * document order. If the node-set is empty or the first node has no
7627
 * name, an empty string is returned. If the argument is omitted it
7628
 * defaults to the context node.
7629
 */
7630
void
7631
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7632
0
    xmlXPathObjectPtr cur;
7633
7634
0
    if (ctxt == NULL) return;
7635
7636
0
    if (nargs == 0) {
7637
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7638
0
  nargs = 1;
7639
0
    }
7640
7641
0
    CHECK_ARITY(1);
7642
0
    if ((ctxt->value == NULL) ||
7643
0
  ((ctxt->value->type != XPATH_NODESET) &&
7644
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7645
0
  XP_ERROR(XPATH_INVALID_TYPE);
7646
0
    cur = valuePop(ctxt);
7647
7648
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7649
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7650
0
    } else {
7651
0
  int i = 0; /* Should be first in document order !!!!! */
7652
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7653
0
  case XML_ELEMENT_NODE:
7654
0
  case XML_ATTRIBUTE_NODE:
7655
0
  case XML_PI_NODE:
7656
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7657
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7658
0
      else
7659
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7660
0
      cur->nodesetval->nodeTab[i]->name));
7661
0
      break;
7662
0
  case XML_NAMESPACE_DECL:
7663
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7664
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7665
0
      break;
7666
0
  default:
7667
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7668
0
  }
7669
0
    }
7670
0
    xmlXPathReleaseObject(ctxt->context, cur);
7671
0
}
7672
7673
/**
7674
 * xmlXPathNamespaceURIFunction:
7675
 * @ctxt:  the XPath Parser context
7676
 * @nargs:  the number of arguments
7677
 *
7678
 * Implement the namespace-uri() XPath function
7679
 *    string namespace-uri(node-set?)
7680
 * The namespace-uri function returns a string containing the
7681
 * namespace URI of the expanded name of the node in the argument
7682
 * node-set that is first in document order. If the node-set is empty,
7683
 * the first node has no name, or the expanded name has no namespace
7684
 * URI, an empty string is returned. If the argument is omitted it
7685
 * defaults to the context node.
7686
 */
7687
void
7688
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7689
0
    xmlXPathObjectPtr cur;
7690
7691
0
    if (ctxt == NULL) return;
7692
7693
0
    if (nargs == 0) {
7694
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7695
0
  nargs = 1;
7696
0
    }
7697
0
    CHECK_ARITY(1);
7698
0
    if ((ctxt->value == NULL) ||
7699
0
  ((ctxt->value->type != XPATH_NODESET) &&
7700
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7701
0
  XP_ERROR(XPATH_INVALID_TYPE);
7702
0
    cur = valuePop(ctxt);
7703
7704
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7705
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7706
0
    } else {
7707
0
  int i = 0; /* Should be first in document order !!!!! */
7708
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7709
0
  case XML_ELEMENT_NODE:
7710
0
  case XML_ATTRIBUTE_NODE:
7711
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7712
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7713
0
      else
7714
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7715
0
        cur->nodesetval->nodeTab[i]->ns->href));
7716
0
      break;
7717
0
  default:
7718
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7719
0
  }
7720
0
    }
7721
0
    xmlXPathReleaseObject(ctxt->context, cur);
7722
0
}
7723
7724
/**
7725
 * xmlXPathNameFunction:
7726
 * @ctxt:  the XPath Parser context
7727
 * @nargs:  the number of arguments
7728
 *
7729
 * Implement the name() XPath function
7730
 *    string name(node-set?)
7731
 * The name function returns a string containing a QName representing
7732
 * the name of the node in the argument node-set that is first in document
7733
 * order. The QName must represent the name with respect to the namespace
7734
 * declarations in effect on the node whose name is being represented.
7735
 * Typically, this will be the form in which the name occurred in the XML
7736
 * source. This need not be the case if there are namespace declarations
7737
 * in effect on the node that associate multiple prefixes with the same
7738
 * namespace. However, an implementation may include information about
7739
 * the original prefix in its representation of nodes; in this case, an
7740
 * implementation can ensure that the returned string is always the same
7741
 * as the QName used in the XML source. If the argument it omitted it
7742
 * defaults to the context node.
7743
 * Libxml keep the original prefix so the "real qualified name" used is
7744
 * returned.
7745
 */
7746
static void
7747
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7748
0
{
7749
0
    xmlXPathObjectPtr cur;
7750
7751
0
    if (nargs == 0) {
7752
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7753
0
        nargs = 1;
7754
0
    }
7755
7756
0
    CHECK_ARITY(1);
7757
0
    if ((ctxt->value == NULL) ||
7758
0
        ((ctxt->value->type != XPATH_NODESET) &&
7759
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
7760
0
        XP_ERROR(XPATH_INVALID_TYPE);
7761
0
    cur = valuePop(ctxt);
7762
7763
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7764
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7765
0
    } else {
7766
0
        int i = 0;              /* Should be first in document order !!!!! */
7767
7768
0
        switch (cur->nodesetval->nodeTab[i]->type) {
7769
0
            case XML_ELEMENT_NODE:
7770
0
            case XML_ATTRIBUTE_NODE:
7771
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7772
0
        valuePush(ctxt,
7773
0
      xmlXPathCacheNewCString(ctxt, ""));
7774
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7775
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7776
0
        valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7777
0
          cur->nodesetval->nodeTab[i]->name));
7778
0
    } else {
7779
0
        xmlChar *fullname;
7780
7781
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7782
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
7783
0
             NULL, 0);
7784
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7785
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7786
0
        if (fullname == NULL)
7787
0
                        xmlXPathPErrMemory(ctxt);
7788
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7789
0
                }
7790
0
                break;
7791
0
            default:
7792
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7793
0
        cur->nodesetval->nodeTab[i]));
7794
0
                xmlXPathLocalNameFunction(ctxt, 1);
7795
0
        }
7796
0
    }
7797
0
    xmlXPathReleaseObject(ctxt->context, cur);
7798
0
}
7799
7800
7801
/**
7802
 * xmlXPathStringFunction:
7803
 * @ctxt:  the XPath Parser context
7804
 * @nargs:  the number of arguments
7805
 *
7806
 * Implement the string() XPath function
7807
 *    string string(object?)
7808
 * The string function converts an object to a string as follows:
7809
 *    - A node-set is converted to a string by returning the value of
7810
 *      the node in the node-set that is first in document order.
7811
 *      If the node-set is empty, an empty string is returned.
7812
 *    - A number is converted to a string as follows
7813
 *      + NaN is converted to the string NaN
7814
 *      + positive zero is converted to the string 0
7815
 *      + negative zero is converted to the string 0
7816
 *      + positive infinity is converted to the string Infinity
7817
 *      + negative infinity is converted to the string -Infinity
7818
 *      + if the number is an integer, the number is represented in
7819
 *        decimal form as a Number with no decimal point and no leading
7820
 *        zeros, preceded by a minus sign (-) if the number is negative
7821
 *      + otherwise, the number is represented in decimal form as a
7822
 *        Number including a decimal point with at least one digit
7823
 *        before the decimal point and at least one digit after the
7824
 *        decimal point, preceded by a minus sign (-) if the number
7825
 *        is negative; there must be no leading zeros before the decimal
7826
 *        point apart possibly from the one required digit immediately
7827
 *        before the decimal point; beyond the one required digit
7828
 *        after the decimal point there must be as many, but only as
7829
 *        many, more digits as are needed to uniquely distinguish the
7830
 *        number from all other IEEE 754 numeric values.
7831
 *    - The boolean false value is converted to the string false.
7832
 *      The boolean true value is converted to the string true.
7833
 *
7834
 * If the argument is omitted, it defaults to a node-set with the
7835
 * context node as its only member.
7836
 */
7837
void
7838
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7839
0
    xmlXPathObjectPtr cur;
7840
0
    xmlChar *stringval;
7841
7842
0
    if (ctxt == NULL) return;
7843
0
    if (nargs == 0) {
7844
0
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7845
0
        if (stringval == NULL)
7846
0
            xmlXPathPErrMemory(ctxt);
7847
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7848
0
  return;
7849
0
    }
7850
7851
0
    CHECK_ARITY(1);
7852
0
    cur = valuePop(ctxt);
7853
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7854
0
    if (cur->type != XPATH_STRING) {
7855
0
        stringval = xmlXPathCastToString(cur);
7856
0
        if (stringval == NULL)
7857
0
            xmlXPathPErrMemory(ctxt);
7858
0
        xmlXPathReleaseObject(ctxt->context, cur);
7859
0
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7860
0
    }
7861
0
    valuePush(ctxt, cur);
7862
0
}
7863
7864
/**
7865
 * xmlXPathStringLengthFunction:
7866
 * @ctxt:  the XPath Parser context
7867
 * @nargs:  the number of arguments
7868
 *
7869
 * Implement the string-length() XPath function
7870
 *    number string-length(string?)
7871
 * The string-length returns the number of characters in the string
7872
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7873
 * the context node converted to a string, in other words the value
7874
 * of the context node.
7875
 */
7876
void
7877
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7878
0
    xmlXPathObjectPtr cur;
7879
7880
0
    if (nargs == 0) {
7881
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
7882
0
      return;
7883
0
  if (ctxt->context->node == NULL) {
7884
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7885
0
  } else {
7886
0
      xmlChar *content;
7887
7888
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
7889
0
            if (content == NULL)
7890
0
                xmlXPathPErrMemory(ctxt);
7891
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7892
0
    xmlUTF8Strlen(content)));
7893
0
      xmlFree(content);
7894
0
  }
7895
0
  return;
7896
0
    }
7897
0
    CHECK_ARITY(1);
7898
0
    CAST_TO_STRING;
7899
0
    CHECK_TYPE(XPATH_STRING);
7900
0
    cur = valuePop(ctxt);
7901
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7902
0
  xmlUTF8Strlen(cur->stringval)));
7903
0
    xmlXPathReleaseObject(ctxt->context, cur);
7904
0
}
7905
7906
/**
7907
 * xmlXPathConcatFunction:
7908
 * @ctxt:  the XPath Parser context
7909
 * @nargs:  the number of arguments
7910
 *
7911
 * Implement the concat() XPath function
7912
 *    string concat(string, string, string*)
7913
 * The concat function returns the concatenation of its arguments.
7914
 */
7915
void
7916
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7917
0
    xmlXPathObjectPtr cur, newobj;
7918
0
    xmlChar *tmp;
7919
7920
0
    if (ctxt == NULL) return;
7921
0
    if (nargs < 2) {
7922
0
  CHECK_ARITY(2);
7923
0
    }
7924
7925
0
    CAST_TO_STRING;
7926
0
    cur = valuePop(ctxt);
7927
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7928
0
  xmlXPathReleaseObject(ctxt->context, cur);
7929
0
  return;
7930
0
    }
7931
0
    nargs--;
7932
7933
0
    while (nargs > 0) {
7934
0
  CAST_TO_STRING;
7935
0
  newobj = valuePop(ctxt);
7936
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7937
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7938
0
      xmlXPathReleaseObject(ctxt->context, cur);
7939
0
      XP_ERROR(XPATH_INVALID_TYPE);
7940
0
  }
7941
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7942
0
        if (tmp == NULL)
7943
0
            xmlXPathPErrMemory(ctxt);
7944
0
  newobj->stringval = cur->stringval;
7945
0
  cur->stringval = tmp;
7946
0
  xmlXPathReleaseObject(ctxt->context, newobj);
7947
0
  nargs--;
7948
0
    }
7949
0
    valuePush(ctxt, cur);
7950
0
}
7951
7952
/**
7953
 * xmlXPathContainsFunction:
7954
 * @ctxt:  the XPath Parser context
7955
 * @nargs:  the number of arguments
7956
 *
7957
 * Implement the contains() XPath function
7958
 *    boolean contains(string, string)
7959
 * The contains function returns true if the first argument string
7960
 * contains the second argument string, and otherwise returns false.
7961
 */
7962
void
7963
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7964
0
    xmlXPathObjectPtr hay, needle;
7965
7966
0
    CHECK_ARITY(2);
7967
0
    CAST_TO_STRING;
7968
0
    CHECK_TYPE(XPATH_STRING);
7969
0
    needle = valuePop(ctxt);
7970
0
    CAST_TO_STRING;
7971
0
    hay = valuePop(ctxt);
7972
7973
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7974
0
  xmlXPathReleaseObject(ctxt->context, hay);
7975
0
  xmlXPathReleaseObject(ctxt->context, needle);
7976
0
  XP_ERROR(XPATH_INVALID_TYPE);
7977
0
    }
7978
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7979
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7980
0
    else
7981
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7982
0
    xmlXPathReleaseObject(ctxt->context, hay);
7983
0
    xmlXPathReleaseObject(ctxt->context, needle);
7984
0
}
7985
7986
/**
7987
 * xmlXPathStartsWithFunction:
7988
 * @ctxt:  the XPath Parser context
7989
 * @nargs:  the number of arguments
7990
 *
7991
 * Implement the starts-with() XPath function
7992
 *    boolean starts-with(string, string)
7993
 * The starts-with function returns true if the first argument string
7994
 * starts with the second argument string, and otherwise returns false.
7995
 */
7996
void
7997
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7998
0
    xmlXPathObjectPtr hay, needle;
7999
0
    int n;
8000
8001
0
    CHECK_ARITY(2);
8002
0
    CAST_TO_STRING;
8003
0
    CHECK_TYPE(XPATH_STRING);
8004
0
    needle = valuePop(ctxt);
8005
0
    CAST_TO_STRING;
8006
0
    hay = valuePop(ctxt);
8007
8008
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8009
0
  xmlXPathReleaseObject(ctxt->context, hay);
8010
0
  xmlXPathReleaseObject(ctxt->context, needle);
8011
0
  XP_ERROR(XPATH_INVALID_TYPE);
8012
0
    }
8013
0
    n = xmlStrlen(needle->stringval);
8014
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
8015
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8016
0
    else
8017
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8018
0
    xmlXPathReleaseObject(ctxt->context, hay);
8019
0
    xmlXPathReleaseObject(ctxt->context, needle);
8020
0
}
8021
8022
/**
8023
 * xmlXPathSubstringFunction:
8024
 * @ctxt:  the XPath Parser context
8025
 * @nargs:  the number of arguments
8026
 *
8027
 * Implement the substring() XPath function
8028
 *    string substring(string, number, number?)
8029
 * The substring function returns the substring of the first argument
8030
 * starting at the position specified in the second argument with
8031
 * length specified in the third argument. For example,
8032
 * substring("12345",2,3) returns "234". If the third argument is not
8033
 * specified, it returns the substring starting at the position specified
8034
 * in the second argument and continuing to the end of the string. For
8035
 * example, substring("12345",2) returns "2345".  More precisely, each
8036
 * character in the string (see [3.6 Strings]) is considered to have a
8037
 * numeric position: the position of the first character is 1, the position
8038
 * of the second character is 2 and so on. The returned substring contains
8039
 * those characters for which the position of the character is greater than
8040
 * or equal to the second argument and, if the third argument is specified,
8041
 * less than the sum of the second and third arguments; the comparisons
8042
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8043
 *  - substring("12345", 1.5, 2.6) returns "234"
8044
 *  - substring("12345", 0, 3) returns "12"
8045
 *  - substring("12345", 0 div 0, 3) returns ""
8046
 *  - substring("12345", 1, 0 div 0) returns ""
8047
 *  - substring("12345", -42, 1 div 0) returns "12345"
8048
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
8049
 */
8050
void
8051
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8052
0
    xmlXPathObjectPtr str, start, len;
8053
0
    double le=0, in;
8054
0
    int i = 1, j = INT_MAX;
8055
8056
0
    if (nargs < 2) {
8057
0
  CHECK_ARITY(2);
8058
0
    }
8059
0
    if (nargs > 3) {
8060
0
  CHECK_ARITY(3);
8061
0
    }
8062
    /*
8063
     * take care of possible last (position) argument
8064
    */
8065
0
    if (nargs == 3) {
8066
0
  CAST_TO_NUMBER;
8067
0
  CHECK_TYPE(XPATH_NUMBER);
8068
0
  len = valuePop(ctxt);
8069
0
  le = len->floatval;
8070
0
  xmlXPathReleaseObject(ctxt->context, len);
8071
0
    }
8072
8073
0
    CAST_TO_NUMBER;
8074
0
    CHECK_TYPE(XPATH_NUMBER);
8075
0
    start = valuePop(ctxt);
8076
0
    in = start->floatval;
8077
0
    xmlXPathReleaseObject(ctxt->context, start);
8078
0
    CAST_TO_STRING;
8079
0
    CHECK_TYPE(XPATH_STRING);
8080
0
    str = valuePop(ctxt);
8081
8082
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8083
0
        i = INT_MAX;
8084
0
    } else if (in >= 1.0) {
8085
0
        i = (int)in;
8086
0
        if (in - floor(in) >= 0.5)
8087
0
            i += 1;
8088
0
    }
8089
8090
0
    if (nargs == 3) {
8091
0
        double rin, rle, end;
8092
8093
0
        rin = floor(in);
8094
0
        if (in - rin >= 0.5)
8095
0
            rin += 1.0;
8096
8097
0
        rle = floor(le);
8098
0
        if (le - rle >= 0.5)
8099
0
            rle += 1.0;
8100
8101
0
        end = rin + rle;
8102
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8103
0
            j = 1;
8104
0
        } else if (end < INT_MAX) {
8105
0
            j = (int)end;
8106
0
        }
8107
0
    }
8108
8109
0
    i -= 1;
8110
0
    j -= 1;
8111
8112
0
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
8113
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
8114
0
        if (ret == NULL)
8115
0
            xmlXPathPErrMemory(ctxt);
8116
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
8117
0
  xmlFree(ret);
8118
0
    } else {
8119
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
8120
0
    }
8121
8122
0
    xmlXPathReleaseObject(ctxt->context, str);
8123
0
}
8124
8125
/**
8126
 * xmlXPathSubstringBeforeFunction:
8127
 * @ctxt:  the XPath Parser context
8128
 * @nargs:  the number of arguments
8129
 *
8130
 * Implement the substring-before() XPath function
8131
 *    string substring-before(string, string)
8132
 * The substring-before function returns the substring of the first
8133
 * argument string that precedes the first occurrence of the second
8134
 * argument string in the first argument string, or the empty string
8135
 * if the first argument string does not contain the second argument
8136
 * string. For example, substring-before("1999/04/01","/") returns 1999.
8137
 */
8138
void
8139
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8140
0
    xmlXPathObjectPtr str = NULL;
8141
0
    xmlXPathObjectPtr find = NULL;
8142
0
    const xmlChar *point;
8143
0
    xmlChar *result;
8144
8145
0
    CHECK_ARITY(2);
8146
0
    CAST_TO_STRING;
8147
0
    find = valuePop(ctxt);
8148
0
    CAST_TO_STRING;
8149
0
    str = valuePop(ctxt);
8150
0
    if (ctxt->error != 0)
8151
0
        goto error;
8152
8153
0
    point = xmlStrstr(str->stringval, find->stringval);
8154
0
    if (point == NULL) {
8155
0
        result = xmlStrdup(BAD_CAST "");
8156
0
    } else {
8157
0
        result = xmlStrndup(str->stringval, point - str->stringval);
8158
0
    }
8159
0
    if (result == NULL) {
8160
0
        xmlXPathPErrMemory(ctxt);
8161
0
        goto error;
8162
0
    }
8163
0
    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8164
8165
0
error:
8166
0
    xmlXPathReleaseObject(ctxt->context, str);
8167
0
    xmlXPathReleaseObject(ctxt->context, find);
8168
0
}
8169
8170
/**
8171
 * xmlXPathSubstringAfterFunction:
8172
 * @ctxt:  the XPath Parser context
8173
 * @nargs:  the number of arguments
8174
 *
8175
 * Implement the substring-after() XPath function
8176
 *    string substring-after(string, string)
8177
 * The substring-after function returns the substring of the first
8178
 * argument string that follows the first occurrence of the second
8179
 * argument string in the first argument string, or the empty string
8180
 * if the first argument string does not contain the second argument
8181
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8182
 * and substring-after("1999/04/01","19") returns 99/04/01.
8183
 */
8184
void
8185
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8186
0
    xmlXPathObjectPtr str = NULL;
8187
0
    xmlXPathObjectPtr find = NULL;
8188
0
    const xmlChar *point;
8189
0
    xmlChar *result;
8190
8191
0
    CHECK_ARITY(2);
8192
0
    CAST_TO_STRING;
8193
0
    find = valuePop(ctxt);
8194
0
    CAST_TO_STRING;
8195
0
    str = valuePop(ctxt);
8196
0
    if (ctxt->error != 0)
8197
0
        goto error;
8198
8199
0
    point = xmlStrstr(str->stringval, find->stringval);
8200
0
    if (point == NULL) {
8201
0
        result = xmlStrdup(BAD_CAST "");
8202
0
    } else {
8203
0
        result = xmlStrdup(point + xmlStrlen(find->stringval));
8204
0
    }
8205
0
    if (result == NULL) {
8206
0
        xmlXPathPErrMemory(ctxt);
8207
0
        goto error;
8208
0
    }
8209
0
    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
8210
8211
0
error:
8212
0
    xmlXPathReleaseObject(ctxt->context, str);
8213
0
    xmlXPathReleaseObject(ctxt->context, find);
8214
0
}
8215
8216
/**
8217
 * xmlXPathNormalizeFunction:
8218
 * @ctxt:  the XPath Parser context
8219
 * @nargs:  the number of arguments
8220
 *
8221
 * Implement the normalize-space() XPath function
8222
 *    string normalize-space(string?)
8223
 * The normalize-space function returns the argument string with white
8224
 * space normalized by stripping leading and trailing whitespace
8225
 * and replacing sequences of whitespace characters by a single
8226
 * space. Whitespace characters are the same allowed by the S production
8227
 * in XML. If the argument is omitted, it defaults to the context
8228
 * node converted to a string, in other words the value of the context node.
8229
 */
8230
void
8231
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8232
0
    xmlChar *source, *target;
8233
0
    int blank;
8234
8235
0
    if (ctxt == NULL) return;
8236
0
    if (nargs == 0) {
8237
        /* Use current context node */
8238
0
        source = xmlXPathCastNodeToString(ctxt->context->node);
8239
0
        if (source == NULL)
8240
0
            xmlXPathPErrMemory(ctxt);
8241
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
8242
0
        nargs = 1;
8243
0
    }
8244
8245
0
    CHECK_ARITY(1);
8246
0
    CAST_TO_STRING;
8247
0
    CHECK_TYPE(XPATH_STRING);
8248
0
    source = ctxt->value->stringval;
8249
0
    if (source == NULL)
8250
0
        return;
8251
0
    target = source;
8252
8253
    /* Skip leading whitespaces */
8254
0
    while (IS_BLANK_CH(*source))
8255
0
        source++;
8256
8257
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8258
0
    blank = 0;
8259
0
    while (*source) {
8260
0
        if (IS_BLANK_CH(*source)) {
8261
0
      blank = 1;
8262
0
        } else {
8263
0
            if (blank) {
8264
0
                *target++ = 0x20;
8265
0
                blank = 0;
8266
0
            }
8267
0
            *target++ = *source;
8268
0
        }
8269
0
        source++;
8270
0
    }
8271
0
    *target = 0;
8272
0
}
8273
8274
/**
8275
 * xmlXPathTranslateFunction:
8276
 * @ctxt:  the XPath Parser context
8277
 * @nargs:  the number of arguments
8278
 *
8279
 * Implement the translate() XPath function
8280
 *    string translate(string, string, string)
8281
 * The translate function returns the first argument string with
8282
 * occurrences of characters in the second argument string replaced
8283
 * by the character at the corresponding position in the third argument
8284
 * string. For example, translate("bar","abc","ABC") returns the string
8285
 * BAr. If there is a character in the second argument string with no
8286
 * character at a corresponding position in the third argument string
8287
 * (because the second argument string is longer than the third argument
8288
 * string), then occurrences of that character in the first argument
8289
 * string are removed. For example, translate("--aaa--","abc-","ABC")
8290
 * returns "AAA". If a character occurs more than once in second
8291
 * argument string, then the first occurrence determines the replacement
8292
 * character. If the third argument string is longer than the second
8293
 * argument string, then excess characters are ignored.
8294
 */
8295
void
8296
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8297
0
    xmlXPathObjectPtr str = NULL;
8298
0
    xmlXPathObjectPtr from = NULL;
8299
0
    xmlXPathObjectPtr to = NULL;
8300
0
    xmlBufPtr target;
8301
0
    int offset, max;
8302
0
    int ch;
8303
0
    const xmlChar *point;
8304
0
    xmlChar *cptr, *content;
8305
8306
0
    CHECK_ARITY(3);
8307
8308
0
    CAST_TO_STRING;
8309
0
    to = valuePop(ctxt);
8310
0
    CAST_TO_STRING;
8311
0
    from = valuePop(ctxt);
8312
0
    CAST_TO_STRING;
8313
0
    str = valuePop(ctxt);
8314
0
    if (ctxt->error != 0)
8315
0
        goto error;
8316
8317
    /*
8318
     * Account for quadratic runtime
8319
     */
8320
0
    if (ctxt->context->opLimit != 0) {
8321
0
        unsigned long f1 = xmlStrlen(from->stringval);
8322
0
        unsigned long f2 = xmlStrlen(str->stringval);
8323
8324
0
        if ((f1 > 0) && (f2 > 0)) {
8325
0
            unsigned long p;
8326
8327
0
            f1 = f1 / 10 + 1;
8328
0
            f2 = f2 / 10 + 1;
8329
0
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
8330
0
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
8331
0
                goto error;
8332
0
        }
8333
0
    }
8334
8335
0
    target = xmlBufCreateSize(64);
8336
0
    if (target == NULL) {
8337
0
        xmlXPathPErrMemory(ctxt);
8338
0
        goto error;
8339
0
    }
8340
8341
0
    max = xmlUTF8Strlen(to->stringval);
8342
0
    for (cptr = str->stringval; (ch=*cptr); ) {
8343
0
        offset = xmlUTF8Strloc(from->stringval, cptr);
8344
0
        if (offset >= 0) {
8345
0
            if (offset < max) {
8346
0
                point = xmlUTF8Strpos(to->stringval, offset);
8347
0
                if (point)
8348
0
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8349
0
            }
8350
0
        } else
8351
0
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8352
8353
        /* Step to next character in input */
8354
0
        cptr++;
8355
0
        if ( ch & 0x80 ) {
8356
            /* if not simple ascii, verify proper format */
8357
0
            if ( (ch & 0xc0) != 0xc0 ) {
8358
0
                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8359
0
                break;
8360
0
            }
8361
            /* then skip over remaining bytes for this char */
8362
0
            while ( (ch <<= 1) & 0x80 )
8363
0
                if ( (*cptr++ & 0xc0) != 0x80 ) {
8364
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8365
0
                    break;
8366
0
                }
8367
0
            if (ch & 0x80) /* must have had error encountered */
8368
0
                break;
8369
0
        }
8370
0
    }
8371
8372
0
    content = xmlBufDetach(target);
8373
0
    if (content == NULL)
8374
0
        xmlXPathPErrMemory(ctxt);
8375
0
    else
8376
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8377
0
    xmlBufFree(target);
8378
0
error:
8379
0
    xmlXPathReleaseObject(ctxt->context, str);
8380
0
    xmlXPathReleaseObject(ctxt->context, from);
8381
0
    xmlXPathReleaseObject(ctxt->context, to);
8382
0
}
8383
8384
/**
8385
 * xmlXPathBooleanFunction:
8386
 * @ctxt:  the XPath Parser context
8387
 * @nargs:  the number of arguments
8388
 *
8389
 * Implement the boolean() XPath function
8390
 *    boolean boolean(object)
8391
 * The boolean function converts its argument to a boolean as follows:
8392
 *    - a number is true if and only if it is neither positive or
8393
 *      negative zero nor NaN
8394
 *    - a node-set is true if and only if it is non-empty
8395
 *    - a string is true if and only if its length is non-zero
8396
 */
8397
void
8398
0
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8399
0
    xmlXPathObjectPtr cur;
8400
8401
0
    CHECK_ARITY(1);
8402
0
    cur = valuePop(ctxt);
8403
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8404
0
    if (cur->type != XPATH_BOOLEAN) {
8405
0
        int boolval = xmlXPathCastToBoolean(cur);
8406
8407
0
        xmlXPathReleaseObject(ctxt->context, cur);
8408
0
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8409
0
    }
8410
0
    valuePush(ctxt, cur);
8411
0
}
8412
8413
/**
8414
 * xmlXPathNotFunction:
8415
 * @ctxt:  the XPath Parser context
8416
 * @nargs:  the number of arguments
8417
 *
8418
 * Implement the not() XPath function
8419
 *    boolean not(boolean)
8420
 * The not function returns true if its argument is false,
8421
 * and false otherwise.
8422
 */
8423
void
8424
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8425
0
    CHECK_ARITY(1);
8426
0
    CAST_TO_BOOLEAN;
8427
0
    CHECK_TYPE(XPATH_BOOLEAN);
8428
0
    ctxt->value->boolval = ! ctxt->value->boolval;
8429
0
}
8430
8431
/**
8432
 * xmlXPathTrueFunction:
8433
 * @ctxt:  the XPath Parser context
8434
 * @nargs:  the number of arguments
8435
 *
8436
 * Implement the true() XPath function
8437
 *    boolean true()
8438
 */
8439
void
8440
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8441
0
    CHECK_ARITY(0);
8442
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8443
0
}
8444
8445
/**
8446
 * xmlXPathFalseFunction:
8447
 * @ctxt:  the XPath Parser context
8448
 * @nargs:  the number of arguments
8449
 *
8450
 * Implement the false() XPath function
8451
 *    boolean false()
8452
 */
8453
void
8454
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8455
0
    CHECK_ARITY(0);
8456
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8457
0
}
8458
8459
/**
8460
 * xmlXPathLangFunction:
8461
 * @ctxt:  the XPath Parser context
8462
 * @nargs:  the number of arguments
8463
 *
8464
 * Implement the lang() XPath function
8465
 *    boolean lang(string)
8466
 * The lang function returns true or false depending on whether the
8467
 * language of the context node as specified by xml:lang attributes
8468
 * is the same as or is a sublanguage of the language specified by
8469
 * the argument string. The language of the context node is determined
8470
 * by the value of the xml:lang attribute on the context node, or, if
8471
 * the context node has no xml:lang attribute, by the value of the
8472
 * xml:lang attribute on the nearest ancestor of the context node that
8473
 * has an xml:lang attribute. If there is no such attribute, then lang
8474
 * returns false. If there is such an attribute, then lang returns
8475
 * true if the attribute value is equal to the argument ignoring case,
8476
 * or if there is some suffix starting with - such that the attribute
8477
 * value is equal to the argument ignoring that suffix of the attribute
8478
 * value and ignoring case.
8479
 */
8480
void
8481
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8482
0
    xmlXPathObjectPtr val;
8483
0
    xmlNodePtr cur;
8484
0
    xmlChar *theLang;
8485
0
    const xmlChar *lang;
8486
0
    int ret = 0;
8487
0
    int i;
8488
8489
0
    CHECK_ARITY(1);
8490
0
    CAST_TO_STRING;
8491
0
    CHECK_TYPE(XPATH_STRING);
8492
0
    val = valuePop(ctxt);
8493
0
    lang = val->stringval;
8494
0
    cur = ctxt->context->node;
8495
0
    while (cur != NULL) {
8496
0
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8497
0
                                &theLang) < 0)
8498
0
            xmlXPathPErrMemory(ctxt);
8499
0
        if (theLang != NULL)
8500
0
            break;
8501
0
        cur = cur->parent;
8502
0
    }
8503
0
    if ((theLang != NULL) && (lang != NULL)) {
8504
0
        for (i = 0;lang[i] != 0;i++)
8505
0
            if (toupper(lang[i]) != toupper(theLang[i]))
8506
0
                goto not_equal;
8507
0
        if ((theLang[i] == 0) || (theLang[i] == '-'))
8508
0
            ret = 1;
8509
0
    }
8510
0
not_equal:
8511
0
    if (theLang != NULL)
8512
0
  xmlFree((void *)theLang);
8513
8514
0
    xmlXPathReleaseObject(ctxt->context, val);
8515
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8516
0
}
8517
8518
/**
8519
 * xmlXPathNumberFunction:
8520
 * @ctxt:  the XPath Parser context
8521
 * @nargs:  the number of arguments
8522
 *
8523
 * Implement the number() XPath function
8524
 *    number number(object?)
8525
 */
8526
void
8527
0
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8528
0
    xmlXPathObjectPtr cur;
8529
0
    double res;
8530
8531
0
    if (ctxt == NULL) return;
8532
0
    if (nargs == 0) {
8533
0
  if (ctxt->context->node == NULL) {
8534
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8535
0
  } else {
8536
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8537
0
            if (content == NULL)
8538
0
                xmlXPathPErrMemory(ctxt);
8539
8540
0
      res = xmlXPathStringEvalNumber(content);
8541
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8542
0
      xmlFree(content);
8543
0
  }
8544
0
  return;
8545
0
    }
8546
8547
0
    CHECK_ARITY(1);
8548
0
    cur = valuePop(ctxt);
8549
0
    if (cur->type != XPATH_NUMBER) {
8550
0
        double floatval;
8551
8552
0
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8553
0
        xmlXPathReleaseObject(ctxt->context, cur);
8554
0
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8555
0
    }
8556
0
    valuePush(ctxt, cur);
8557
0
}
8558
8559
/**
8560
 * xmlXPathSumFunction:
8561
 * @ctxt:  the XPath Parser context
8562
 * @nargs:  the number of arguments
8563
 *
8564
 * Implement the sum() XPath function
8565
 *    number sum(node-set)
8566
 * The sum function returns the sum of the values of the nodes in
8567
 * the argument node-set.
8568
 */
8569
void
8570
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8571
0
    xmlXPathObjectPtr cur;
8572
0
    int i;
8573
0
    double res = 0.0;
8574
8575
0
    CHECK_ARITY(1);
8576
0
    if ((ctxt->value == NULL) ||
8577
0
  ((ctxt->value->type != XPATH_NODESET) &&
8578
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8579
0
  XP_ERROR(XPATH_INVALID_TYPE);
8580
0
    cur = valuePop(ctxt);
8581
8582
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8583
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8584
0
      res += xmlXPathNodeToNumberInternal(ctxt,
8585
0
                                                cur->nodesetval->nodeTab[i]);
8586
0
  }
8587
0
    }
8588
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8589
0
    xmlXPathReleaseObject(ctxt->context, cur);
8590
0
}
8591
8592
/**
8593
 * xmlXPathFloorFunction:
8594
 * @ctxt:  the XPath Parser context
8595
 * @nargs:  the number of arguments
8596
 *
8597
 * Implement the floor() XPath function
8598
 *    number floor(number)
8599
 * The floor function returns the largest (closest to positive infinity)
8600
 * number that is not greater than the argument and that is an integer.
8601
 */
8602
void
8603
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8604
0
    CHECK_ARITY(1);
8605
0
    CAST_TO_NUMBER;
8606
0
    CHECK_TYPE(XPATH_NUMBER);
8607
8608
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
8609
0
}
8610
8611
/**
8612
 * xmlXPathCeilingFunction:
8613
 * @ctxt:  the XPath Parser context
8614
 * @nargs:  the number of arguments
8615
 *
8616
 * Implement the ceiling() XPath function
8617
 *    number ceiling(number)
8618
 * The ceiling function returns the smallest (closest to negative infinity)
8619
 * number that is not less than the argument and that is an integer.
8620
 */
8621
void
8622
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8623
0
    CHECK_ARITY(1);
8624
0
    CAST_TO_NUMBER;
8625
0
    CHECK_TYPE(XPATH_NUMBER);
8626
8627
#ifdef _AIX
8628
    /* Work around buggy ceil() function on AIX */
8629
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8630
#else
8631
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8632
0
#endif
8633
0
}
8634
8635
/**
8636
 * xmlXPathRoundFunction:
8637
 * @ctxt:  the XPath Parser context
8638
 * @nargs:  the number of arguments
8639
 *
8640
 * Implement the round() XPath function
8641
 *    number round(number)
8642
 * The round function returns the number that is closest to the
8643
 * argument and that is an integer. If there are two such numbers,
8644
 * then the one that is closest to positive infinity is returned.
8645
 */
8646
void
8647
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8648
0
    double f;
8649
8650
0
    CHECK_ARITY(1);
8651
0
    CAST_TO_NUMBER;
8652
0
    CHECK_TYPE(XPATH_NUMBER);
8653
8654
0
    f = ctxt->value->floatval;
8655
8656
0
    if ((f >= -0.5) && (f < 0.5)) {
8657
        /* Handles negative zero. */
8658
0
        ctxt->value->floatval *= 0.0;
8659
0
    }
8660
0
    else {
8661
0
        double rounded = floor(f);
8662
0
        if (f - rounded >= 0.5)
8663
0
            rounded += 1.0;
8664
0
        ctxt->value->floatval = rounded;
8665
0
    }
8666
0
}
8667
8668
/************************************************************************
8669
 *                  *
8670
 *      The Parser          *
8671
 *                  *
8672
 ************************************************************************/
8673
8674
/*
8675
 * a few forward declarations since we use a recursive call based
8676
 * implementation.
8677
 */
8678
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8679
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8680
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8681
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8682
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8683
                                    int qualified);
8684
8685
/**
8686
 * xmlXPathCurrentChar:
8687
 * @ctxt:  the XPath parser context
8688
 * @cur:  pointer to the beginning of the char
8689
 * @len:  pointer to the length of the char read
8690
 *
8691
 * The current char value, if using UTF-8 this may actually span multiple
8692
 * bytes in the input buffer.
8693
 *
8694
 * Returns the current char value and its length
8695
 */
8696
8697
static int
8698
0
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8699
0
    unsigned char c;
8700
0
    unsigned int val;
8701
0
    const xmlChar *cur;
8702
8703
0
    if (ctxt == NULL)
8704
0
  return(0);
8705
0
    cur = ctxt->cur;
8706
8707
    /*
8708
     * We are supposed to handle UTF8, check it's valid
8709
     * From rfc2044: encoding of the Unicode values on UTF-8:
8710
     *
8711
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
8712
     * 0000 0000-0000 007F   0xxxxxxx
8713
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
8714
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
8715
     *
8716
     * Check for the 0x110000 limit too
8717
     */
8718
0
    c = *cur;
8719
0
    if (c & 0x80) {
8720
0
  if ((cur[1] & 0xc0) != 0x80)
8721
0
      goto encoding_error;
8722
0
  if ((c & 0xe0) == 0xe0) {
8723
8724
0
      if ((cur[2] & 0xc0) != 0x80)
8725
0
    goto encoding_error;
8726
0
      if ((c & 0xf0) == 0xf0) {
8727
0
    if (((c & 0xf8) != 0xf0) ||
8728
0
        ((cur[3] & 0xc0) != 0x80))
8729
0
        goto encoding_error;
8730
    /* 4-byte code */
8731
0
    *len = 4;
8732
0
    val = (cur[0] & 0x7) << 18;
8733
0
    val |= (cur[1] & 0x3f) << 12;
8734
0
    val |= (cur[2] & 0x3f) << 6;
8735
0
    val |= cur[3] & 0x3f;
8736
0
      } else {
8737
        /* 3-byte code */
8738
0
    *len = 3;
8739
0
    val = (cur[0] & 0xf) << 12;
8740
0
    val |= (cur[1] & 0x3f) << 6;
8741
0
    val |= cur[2] & 0x3f;
8742
0
      }
8743
0
  } else {
8744
    /* 2-byte code */
8745
0
      *len = 2;
8746
0
      val = (cur[0] & 0x1f) << 6;
8747
0
      val |= cur[1] & 0x3f;
8748
0
  }
8749
0
  if (!IS_CHAR(val)) {
8750
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8751
0
  }
8752
0
  return(val);
8753
0
    } else {
8754
  /* 1-byte code */
8755
0
  *len = 1;
8756
0
  return(*cur);
8757
0
    }
8758
0
encoding_error:
8759
    /*
8760
     * If we detect an UTF8 error that probably means that the
8761
     * input encoding didn't get properly advertised in the
8762
     * declaration header. Report the error and switch the encoding
8763
     * to ISO-Latin-1 (if you don't like this policy, just declare the
8764
     * encoding !)
8765
     */
8766
0
    *len = 0;
8767
0
    XP_ERROR0(XPATH_ENCODING_ERROR);
8768
0
}
8769
8770
/**
8771
 * xmlXPathParseNCName:
8772
 * @ctxt:  the XPath Parser context
8773
 *
8774
 * parse an XML namespace non qualified name.
8775
 *
8776
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8777
 *
8778
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8779
 *                       CombiningChar | Extender
8780
 *
8781
 * Returns the namespace name or NULL
8782
 */
8783
8784
xmlChar *
8785
0
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8786
0
    const xmlChar *in;
8787
0
    xmlChar *ret;
8788
0
    int count = 0;
8789
8790
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8791
    /*
8792
     * Accelerator for simple ASCII names
8793
     */
8794
0
    in = ctxt->cur;
8795
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
8796
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
8797
0
  (*in == '_')) {
8798
0
  in++;
8799
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
8800
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
8801
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
8802
0
         (*in == '_') || (*in == '.') ||
8803
0
         (*in == '-'))
8804
0
      in++;
8805
0
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8806
0
            (*in == '[') || (*in == ']') || (*in == ':') ||
8807
0
            (*in == '@') || (*in == '*')) {
8808
0
      count = in - ctxt->cur;
8809
0
      if (count == 0)
8810
0
    return(NULL);
8811
0
      ret = xmlStrndup(ctxt->cur, count);
8812
0
            if (ret == NULL)
8813
0
                xmlXPathPErrMemory(ctxt);
8814
0
      ctxt->cur = in;
8815
0
      return(ret);
8816
0
  }
8817
0
    }
8818
0
    return(xmlXPathParseNameComplex(ctxt, 0));
8819
0
}
8820
8821
8822
/**
8823
 * xmlXPathParseQName:
8824
 * @ctxt:  the XPath Parser context
8825
 * @prefix:  a xmlChar **
8826
 *
8827
 * parse an XML qualified name
8828
 *
8829
 * [NS 5] QName ::= (Prefix ':')? LocalPart
8830
 *
8831
 * [NS 6] Prefix ::= NCName
8832
 *
8833
 * [NS 7] LocalPart ::= NCName
8834
 *
8835
 * Returns the function returns the local part, and prefix is updated
8836
 *   to get the Prefix if any.
8837
 */
8838
8839
static xmlChar *
8840
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8841
0
    xmlChar *ret = NULL;
8842
8843
0
    *prefix = NULL;
8844
0
    ret = xmlXPathParseNCName(ctxt);
8845
0
    if (ret && CUR == ':') {
8846
0
        *prefix = ret;
8847
0
  NEXT;
8848
0
  ret = xmlXPathParseNCName(ctxt);
8849
0
    }
8850
0
    return(ret);
8851
0
}
8852
8853
/**
8854
 * xmlXPathParseName:
8855
 * @ctxt:  the XPath Parser context
8856
 *
8857
 * parse an XML name
8858
 *
8859
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8860
 *                  CombiningChar | Extender
8861
 *
8862
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8863
 *
8864
 * Returns the namespace name or NULL
8865
 */
8866
8867
xmlChar *
8868
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8869
0
    const xmlChar *in;
8870
0
    xmlChar *ret;
8871
0
    size_t count = 0;
8872
8873
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8874
    /*
8875
     * Accelerator for simple ASCII names
8876
     */
8877
0
    in = ctxt->cur;
8878
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
8879
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
8880
0
  (*in == '_') || (*in == ':')) {
8881
0
  in++;
8882
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
8883
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
8884
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
8885
0
         (*in == '_') || (*in == '-') ||
8886
0
         (*in == ':') || (*in == '.'))
8887
0
      in++;
8888
0
  if ((*in > 0) && (*in < 0x80)) {
8889
0
      count = in - ctxt->cur;
8890
0
            if (count > XML_MAX_NAME_LENGTH) {
8891
0
                ctxt->cur = in;
8892
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
8893
0
            }
8894
0
      ret = xmlStrndup(ctxt->cur, count);
8895
0
            if (ret == NULL)
8896
0
                xmlXPathPErrMemory(ctxt);
8897
0
      ctxt->cur = in;
8898
0
      return(ret);
8899
0
  }
8900
0
    }
8901
0
    return(xmlXPathParseNameComplex(ctxt, 1));
8902
0
}
8903
8904
static xmlChar *
8905
0
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8906
0
    xmlChar *ret;
8907
0
    xmlChar buf[XML_MAX_NAMELEN + 5];
8908
0
    int len = 0, l;
8909
0
    int c;
8910
8911
    /*
8912
     * Handler for more complex cases
8913
     */
8914
0
    c = CUR_CHAR(l);
8915
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8916
0
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8917
0
        (c == '*') || /* accelerators */
8918
0
  (!IS_LETTER(c) && (c != '_') &&
8919
0
         ((!qualified) || (c != ':')))) {
8920
0
  return(NULL);
8921
0
    }
8922
8923
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8924
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8925
0
            (c == '.') || (c == '-') ||
8926
0
      (c == '_') || ((qualified) && (c == ':')) ||
8927
0
      (IS_COMBINING(c)) ||
8928
0
      (IS_EXTENDER(c)))) {
8929
0
  COPY_BUF(l,buf,len,c);
8930
0
  NEXTL(l);
8931
0
  c = CUR_CHAR(l);
8932
0
  if (len >= XML_MAX_NAMELEN) {
8933
      /*
8934
       * Okay someone managed to make a huge name, so he's ready to pay
8935
       * for the processing speed.
8936
       */
8937
0
      xmlChar *buffer;
8938
0
      int max = len * 2;
8939
8940
0
            if (len > XML_MAX_NAME_LENGTH) {
8941
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
8942
0
            }
8943
0
      buffer = (xmlChar *) xmlMallocAtomic(max);
8944
0
      if (buffer == NULL) {
8945
0
                xmlXPathPErrMemory(ctxt);
8946
0
                return(NULL);
8947
0
      }
8948
0
      memcpy(buffer, buf, len);
8949
0
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8950
0
       (c == '.') || (c == '-') ||
8951
0
       (c == '_') || ((qualified) && (c == ':')) ||
8952
0
       (IS_COMBINING(c)) ||
8953
0
       (IS_EXTENDER(c))) {
8954
0
    if (len + 10 > max) {
8955
0
                    xmlChar *tmp;
8956
0
                    if (max > XML_MAX_NAME_LENGTH) {
8957
0
                        xmlFree(buffer);
8958
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
8959
0
                    }
8960
0
        max *= 2;
8961
0
        tmp = (xmlChar *) xmlRealloc(buffer, max);
8962
0
        if (tmp == NULL) {
8963
0
                        xmlFree(buffer);
8964
0
                        xmlXPathPErrMemory(ctxt);
8965
0
                        return(NULL);
8966
0
        }
8967
0
                    buffer = tmp;
8968
0
    }
8969
0
    COPY_BUF(l,buffer,len,c);
8970
0
    NEXTL(l);
8971
0
    c = CUR_CHAR(l);
8972
0
      }
8973
0
      buffer[len] = 0;
8974
0
      return(buffer);
8975
0
  }
8976
0
    }
8977
0
    if (len == 0)
8978
0
  return(NULL);
8979
0
    ret = xmlStrndup(buf, len);
8980
0
    if (ret == NULL)
8981
0
        xmlXPathPErrMemory(ctxt);
8982
0
    return(ret);
8983
0
}
8984
8985
0
#define MAX_FRAC 20
8986
8987
/**
8988
 * xmlXPathStringEvalNumber:
8989
 * @str:  A string to scan
8990
 *
8991
 *  [30a]  Float  ::= Number ('e' Digits?)?
8992
 *
8993
 *  [30]   Number ::=   Digits ('.' Digits?)?
8994
 *                    | '.' Digits
8995
 *  [31]   Digits ::=   [0-9]+
8996
 *
8997
 * Compile a Number in the string
8998
 * In complement of the Number expression, this function also handles
8999
 * negative values : '-' Number.
9000
 *
9001
 * Returns the double value.
9002
 */
9003
double
9004
0
xmlXPathStringEvalNumber(const xmlChar *str) {
9005
0
    const xmlChar *cur = str;
9006
0
    double ret;
9007
0
    int ok = 0;
9008
0
    int isneg = 0;
9009
0
    int exponent = 0;
9010
0
    int is_exponent_negative = 0;
9011
0
#ifdef __GNUC__
9012
0
    unsigned long tmp = 0;
9013
0
    double temp;
9014
0
#endif
9015
0
    if (cur == NULL) return(0);
9016
0
    while (IS_BLANK_CH(*cur)) cur++;
9017
0
    if (*cur == '-') {
9018
0
  isneg = 1;
9019
0
  cur++;
9020
0
    }
9021
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9022
0
        return(xmlXPathNAN);
9023
0
    }
9024
9025
0
#ifdef __GNUC__
9026
    /*
9027
     * tmp/temp is a workaround against a gcc compiler bug
9028
     * http://veillard.com/gcc.bug
9029
     */
9030
0
    ret = 0;
9031
0
    while ((*cur >= '0') && (*cur <= '9')) {
9032
0
  ret = ret * 10;
9033
0
  tmp = (*cur - '0');
9034
0
  ok = 1;
9035
0
  cur++;
9036
0
  temp = (double) tmp;
9037
0
  ret = ret + temp;
9038
0
    }
9039
#else
9040
    ret = 0;
9041
    while ((*cur >= '0') && (*cur <= '9')) {
9042
  ret = ret * 10 + (*cur - '0');
9043
  ok = 1;
9044
  cur++;
9045
    }
9046
#endif
9047
9048
0
    if (*cur == '.') {
9049
0
  int v, frac = 0, max;
9050
0
  double fraction = 0;
9051
9052
0
        cur++;
9053
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9054
0
      return(xmlXPathNAN);
9055
0
  }
9056
0
        while (*cur == '0') {
9057
0
      frac = frac + 1;
9058
0
      cur++;
9059
0
        }
9060
0
        max = frac + MAX_FRAC;
9061
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9062
0
      v = (*cur - '0');
9063
0
      fraction = fraction * 10 + v;
9064
0
      frac = frac + 1;
9065
0
      cur++;
9066
0
  }
9067
0
  fraction /= pow(10.0, frac);
9068
0
  ret = ret + fraction;
9069
0
  while ((*cur >= '0') && (*cur <= '9'))
9070
0
      cur++;
9071
0
    }
9072
0
    if ((*cur == 'e') || (*cur == 'E')) {
9073
0
      cur++;
9074
0
      if (*cur == '-') {
9075
0
  is_exponent_negative = 1;
9076
0
  cur++;
9077
0
      } else if (*cur == '+') {
9078
0
        cur++;
9079
0
      }
9080
0
      while ((*cur >= '0') && (*cur <= '9')) {
9081
0
        if (exponent < 1000000)
9082
0
    exponent = exponent * 10 + (*cur - '0');
9083
0
  cur++;
9084
0
      }
9085
0
    }
9086
0
    while (IS_BLANK_CH(*cur)) cur++;
9087
0
    if (*cur != 0) return(xmlXPathNAN);
9088
0
    if (isneg) ret = -ret;
9089
0
    if (is_exponent_negative) exponent = -exponent;
9090
0
    ret *= pow(10.0, (double)exponent);
9091
0
    return(ret);
9092
0
}
9093
9094
/**
9095
 * xmlXPathCompNumber:
9096
 * @ctxt:  the XPath Parser context
9097
 *
9098
 *  [30]   Number ::=   Digits ('.' Digits?)?
9099
 *                    | '.' Digits
9100
 *  [31]   Digits ::=   [0-9]+
9101
 *
9102
 * Compile a Number, then push it on the stack
9103
 *
9104
 */
9105
static void
9106
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9107
0
{
9108
0
    double ret = 0.0;
9109
0
    int ok = 0;
9110
0
    int exponent = 0;
9111
0
    int is_exponent_negative = 0;
9112
0
    xmlXPathObjectPtr num;
9113
0
#ifdef __GNUC__
9114
0
    unsigned long tmp = 0;
9115
0
    double temp;
9116
0
#endif
9117
9118
0
    CHECK_ERROR;
9119
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9120
0
        XP_ERROR(XPATH_NUMBER_ERROR);
9121
0
    }
9122
0
#ifdef __GNUC__
9123
    /*
9124
     * tmp/temp is a workaround against a gcc compiler bug
9125
     * http://veillard.com/gcc.bug
9126
     */
9127
0
    ret = 0;
9128
0
    while ((CUR >= '0') && (CUR <= '9')) {
9129
0
  ret = ret * 10;
9130
0
  tmp = (CUR - '0');
9131
0
        ok = 1;
9132
0
        NEXT;
9133
0
  temp = (double) tmp;
9134
0
  ret = ret + temp;
9135
0
    }
9136
#else
9137
    ret = 0;
9138
    while ((CUR >= '0') && (CUR <= '9')) {
9139
  ret = ret * 10 + (CUR - '0');
9140
  ok = 1;
9141
  NEXT;
9142
    }
9143
#endif
9144
0
    if (CUR == '.') {
9145
0
  int v, frac = 0, max;
9146
0
  double fraction = 0;
9147
9148
0
        NEXT;
9149
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9150
0
            XP_ERROR(XPATH_NUMBER_ERROR);
9151
0
        }
9152
0
        while (CUR == '0') {
9153
0
            frac = frac + 1;
9154
0
            NEXT;
9155
0
        }
9156
0
        max = frac + MAX_FRAC;
9157
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9158
0
      v = (CUR - '0');
9159
0
      fraction = fraction * 10 + v;
9160
0
      frac = frac + 1;
9161
0
            NEXT;
9162
0
        }
9163
0
        fraction /= pow(10.0, frac);
9164
0
        ret = ret + fraction;
9165
0
        while ((CUR >= '0') && (CUR <= '9'))
9166
0
            NEXT;
9167
0
    }
9168
0
    if ((CUR == 'e') || (CUR == 'E')) {
9169
0
        NEXT;
9170
0
        if (CUR == '-') {
9171
0
            is_exponent_negative = 1;
9172
0
            NEXT;
9173
0
        } else if (CUR == '+') {
9174
0
      NEXT;
9175
0
  }
9176
0
        while ((CUR >= '0') && (CUR <= '9')) {
9177
0
            if (exponent < 1000000)
9178
0
                exponent = exponent * 10 + (CUR - '0');
9179
0
            NEXT;
9180
0
        }
9181
0
        if (is_exponent_negative)
9182
0
            exponent = -exponent;
9183
0
        ret *= pow(10.0, (double) exponent);
9184
0
    }
9185
0
    num = xmlXPathCacheNewFloat(ctxt, ret);
9186
0
    if (num == NULL) {
9187
0
  ctxt->error = XPATH_MEMORY_ERROR;
9188
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9189
0
                              NULL) == -1) {
9190
0
        xmlXPathReleaseObject(ctxt->context, num);
9191
0
    }
9192
0
}
9193
9194
/**
9195
 * xmlXPathParseLiteral:
9196
 * @ctxt:  the XPath Parser context
9197
 *
9198
 * Parse a Literal
9199
 *
9200
 *  [29]   Literal ::=   '"' [^"]* '"'
9201
 *                    | "'" [^']* "'"
9202
 *
9203
 * Returns the value found or NULL in case of error
9204
 */
9205
static xmlChar *
9206
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9207
0
    const xmlChar *q;
9208
0
    xmlChar *ret = NULL;
9209
0
    int quote;
9210
9211
0
    if (CUR == '"') {
9212
0
        quote = '"';
9213
0
    } else if (CUR == '\'') {
9214
0
        quote = '\'';
9215
0
    } else {
9216
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9217
0
    }
9218
9219
0
    NEXT;
9220
0
    q = CUR_PTR;
9221
0
    while (CUR != quote) {
9222
0
        int ch;
9223
0
        int len = 4;
9224
9225
0
        if (CUR == 0)
9226
0
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9227
0
        ch = xmlGetUTF8Char(CUR_PTR, &len);
9228
0
        if ((ch < 0) || (IS_CHAR(ch) == 0))
9229
0
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
9230
0
        CUR_PTR += len;
9231
0
    }
9232
0
    ret = xmlStrndup(q, CUR_PTR - q);
9233
0
    if (ret == NULL)
9234
0
        xmlXPathPErrMemory(ctxt);
9235
0
    NEXT;
9236
0
    return(ret);
9237
0
}
9238
9239
/**
9240
 * xmlXPathCompLiteral:
9241
 * @ctxt:  the XPath Parser context
9242
 *
9243
 * Parse a Literal and push it on the stack.
9244
 *
9245
 *  [29]   Literal ::=   '"' [^"]* '"'
9246
 *                    | "'" [^']* "'"
9247
 *
9248
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
9249
 */
9250
static void
9251
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9252
0
    xmlChar *ret = NULL;
9253
0
    xmlXPathObjectPtr lit;
9254
9255
0
    ret = xmlXPathParseLiteral(ctxt);
9256
0
    if (ret == NULL)
9257
0
        return;
9258
0
    lit = xmlXPathCacheNewString(ctxt, ret);
9259
0
    if (lit == NULL) {
9260
0
        ctxt->error = XPATH_MEMORY_ERROR;
9261
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9262
0
                              NULL) == -1) {
9263
0
        xmlXPathReleaseObject(ctxt->context, lit);
9264
0
    }
9265
0
    xmlFree(ret);
9266
0
}
9267
9268
/**
9269
 * xmlXPathCompVariableReference:
9270
 * @ctxt:  the XPath Parser context
9271
 *
9272
 * Parse a VariableReference, evaluate it and push it on the stack.
9273
 *
9274
 * The variable bindings consist of a mapping from variable names
9275
 * to variable values. The value of a variable is an object, which can be
9276
 * of any of the types that are possible for the value of an expression,
9277
 * and may also be of additional types not specified here.
9278
 *
9279
 * Early evaluation is possible since:
9280
 * The variable bindings [...] used to evaluate a subexpression are
9281
 * always the same as those used to evaluate the containing expression.
9282
 *
9283
 *  [36]   VariableReference ::=   '$' QName
9284
 */
9285
static void
9286
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9287
0
    xmlChar *name;
9288
0
    xmlChar *prefix;
9289
9290
0
    SKIP_BLANKS;
9291
0
    if (CUR != '$') {
9292
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9293
0
    }
9294
0
    NEXT;
9295
0
    name = xmlXPathParseQName(ctxt, &prefix);
9296
0
    if (name == NULL) {
9297
0
        xmlFree(prefix);
9298
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9299
0
    }
9300
0
    ctxt->comp->last = -1;
9301
0
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9302
0
        xmlFree(prefix);
9303
0
        xmlFree(name);
9304
0
    }
9305
0
    SKIP_BLANKS;
9306
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9307
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9308
0
    }
9309
0
}
9310
9311
/**
9312
 * xmlXPathIsNodeType:
9313
 * @name:  a name string
9314
 *
9315
 * Is the name given a NodeType one.
9316
 *
9317
 *  [38]   NodeType ::=   'comment'
9318
 *                    | 'text'
9319
 *                    | 'processing-instruction'
9320
 *                    | 'node'
9321
 *
9322
 * Returns 1 if true 0 otherwise
9323
 */
9324
int
9325
0
xmlXPathIsNodeType(const xmlChar *name) {
9326
0
    if (name == NULL)
9327
0
  return(0);
9328
9329
0
    if (xmlStrEqual(name, BAD_CAST "node"))
9330
0
  return(1);
9331
0
    if (xmlStrEqual(name, BAD_CAST "text"))
9332
0
  return(1);
9333
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
9334
0
  return(1);
9335
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9336
0
  return(1);
9337
0
    return(0);
9338
0
}
9339
9340
/**
9341
 * xmlXPathCompFunctionCall:
9342
 * @ctxt:  the XPath Parser context
9343
 *
9344
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9345
 *  [17]   Argument ::=   Expr
9346
 *
9347
 * Compile a function call, the evaluation of all arguments are
9348
 * pushed on the stack
9349
 */
9350
static void
9351
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9352
0
    xmlChar *name;
9353
0
    xmlChar *prefix;
9354
0
    int nbargs = 0;
9355
0
    int sort = 1;
9356
9357
0
    name = xmlXPathParseQName(ctxt, &prefix);
9358
0
    if (name == NULL) {
9359
0
  xmlFree(prefix);
9360
0
  XP_ERROR(XPATH_EXPR_ERROR);
9361
0
    }
9362
0
    SKIP_BLANKS;
9363
9364
0
    if (CUR != '(') {
9365
0
  xmlFree(name);
9366
0
  xmlFree(prefix);
9367
0
  XP_ERROR(XPATH_EXPR_ERROR);
9368
0
    }
9369
0
    NEXT;
9370
0
    SKIP_BLANKS;
9371
9372
    /*
9373
    * Optimization for count(): we don't need the node-set to be sorted.
9374
    */
9375
0
    if ((prefix == NULL) && (name[0] == 'c') &&
9376
0
  xmlStrEqual(name, BAD_CAST "count"))
9377
0
    {
9378
0
  sort = 0;
9379
0
    }
9380
0
    ctxt->comp->last = -1;
9381
0
    if (CUR != ')') {
9382
0
  while (CUR != 0) {
9383
0
      int op1 = ctxt->comp->last;
9384
0
      ctxt->comp->last = -1;
9385
0
      xmlXPathCompileExpr(ctxt, sort);
9386
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
9387
0
    xmlFree(name);
9388
0
    xmlFree(prefix);
9389
0
    return;
9390
0
      }
9391
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9392
0
      nbargs++;
9393
0
      if (CUR == ')') break;
9394
0
      if (CUR != ',') {
9395
0
    xmlFree(name);
9396
0
    xmlFree(prefix);
9397
0
    XP_ERROR(XPATH_EXPR_ERROR);
9398
0
      }
9399
0
      NEXT;
9400
0
      SKIP_BLANKS;
9401
0
  }
9402
0
    }
9403
0
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9404
0
        xmlFree(prefix);
9405
0
        xmlFree(name);
9406
0
    }
9407
0
    NEXT;
9408
0
    SKIP_BLANKS;
9409
0
}
9410
9411
/**
9412
 * xmlXPathCompPrimaryExpr:
9413
 * @ctxt:  the XPath Parser context
9414
 *
9415
 *  [15]   PrimaryExpr ::=   VariableReference
9416
 *                | '(' Expr ')'
9417
 *                | Literal
9418
 *                | Number
9419
 *                | FunctionCall
9420
 *
9421
 * Compile a primary expression.
9422
 */
9423
static void
9424
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9425
0
    SKIP_BLANKS;
9426
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9427
0
    else if (CUR == '(') {
9428
0
  NEXT;
9429
0
  SKIP_BLANKS;
9430
0
  xmlXPathCompileExpr(ctxt, 1);
9431
0
  CHECK_ERROR;
9432
0
  if (CUR != ')') {
9433
0
      XP_ERROR(XPATH_EXPR_ERROR);
9434
0
  }
9435
0
  NEXT;
9436
0
  SKIP_BLANKS;
9437
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9438
0
  xmlXPathCompNumber(ctxt);
9439
0
    } else if ((CUR == '\'') || (CUR == '"')) {
9440
0
  xmlXPathCompLiteral(ctxt);
9441
0
    } else {
9442
0
  xmlXPathCompFunctionCall(ctxt);
9443
0
    }
9444
0
    SKIP_BLANKS;
9445
0
}
9446
9447
/**
9448
 * xmlXPathCompFilterExpr:
9449
 * @ctxt:  the XPath Parser context
9450
 *
9451
 *  [20]   FilterExpr ::=   PrimaryExpr
9452
 *               | FilterExpr Predicate
9453
 *
9454
 * Compile a filter expression.
9455
 * Square brackets are used to filter expressions in the same way that
9456
 * they are used in location paths. It is an error if the expression to
9457
 * be filtered does not evaluate to a node-set. The context node list
9458
 * used for evaluating the expression in square brackets is the node-set
9459
 * to be filtered listed in document order.
9460
 */
9461
9462
static void
9463
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9464
0
    xmlXPathCompPrimaryExpr(ctxt);
9465
0
    CHECK_ERROR;
9466
0
    SKIP_BLANKS;
9467
9468
0
    while (CUR == '[') {
9469
0
  xmlXPathCompPredicate(ctxt, 1);
9470
0
  SKIP_BLANKS;
9471
0
    }
9472
9473
9474
0
}
9475
9476
/**
9477
 * xmlXPathScanName:
9478
 * @ctxt:  the XPath Parser context
9479
 *
9480
 * Trickery: parse an XML name but without consuming the input flow
9481
 * Needed to avoid insanity in the parser state.
9482
 *
9483
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9484
 *                  CombiningChar | Extender
9485
 *
9486
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9487
 *
9488
 * [6] Names ::= Name (S Name)*
9489
 *
9490
 * Returns the Name parsed or NULL
9491
 */
9492
9493
static xmlChar *
9494
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9495
0
    int l;
9496
0
    int c;
9497
0
    const xmlChar *cur;
9498
0
    xmlChar *ret;
9499
9500
0
    cur = ctxt->cur;
9501
9502
0
    c = CUR_CHAR(l);
9503
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9504
0
  (!IS_LETTER(c) && (c != '_') &&
9505
0
         (c != ':'))) {
9506
0
  return(NULL);
9507
0
    }
9508
9509
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9510
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9511
0
            (c == '.') || (c == '-') ||
9512
0
      (c == '_') || (c == ':') ||
9513
0
      (IS_COMBINING(c)) ||
9514
0
      (IS_EXTENDER(c)))) {
9515
0
  NEXTL(l);
9516
0
  c = CUR_CHAR(l);
9517
0
    }
9518
0
    ret = xmlStrndup(cur, ctxt->cur - cur);
9519
0
    if (ret == NULL)
9520
0
        xmlXPathPErrMemory(ctxt);
9521
0
    ctxt->cur = cur;
9522
0
    return(ret);
9523
0
}
9524
9525
/**
9526
 * xmlXPathCompPathExpr:
9527
 * @ctxt:  the XPath Parser context
9528
 *
9529
 *  [19]   PathExpr ::=   LocationPath
9530
 *               | FilterExpr
9531
 *               | FilterExpr '/' RelativeLocationPath
9532
 *               | FilterExpr '//' RelativeLocationPath
9533
 *
9534
 * Compile a path expression.
9535
 * The / operator and // operators combine an arbitrary expression
9536
 * and a relative location path. It is an error if the expression
9537
 * does not evaluate to a node-set.
9538
 * The / operator does composition in the same way as when / is
9539
 * used in a location path. As in location paths, // is short for
9540
 * /descendant-or-self::node()/.
9541
 */
9542
9543
static void
9544
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9545
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
9546
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
9547
9548
0
    SKIP_BLANKS;
9549
0
    if ((CUR == '$') || (CUR == '(') ||
9550
0
  (IS_ASCII_DIGIT(CUR)) ||
9551
0
        (CUR == '\'') || (CUR == '"') ||
9552
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9553
0
  lc = 0;
9554
0
    } else if (CUR == '*') {
9555
  /* relative or absolute location path */
9556
0
  lc = 1;
9557
0
    } else if (CUR == '/') {
9558
  /* relative or absolute location path */
9559
0
  lc = 1;
9560
0
    } else if (CUR == '@') {
9561
  /* relative abbreviated attribute location path */
9562
0
  lc = 1;
9563
0
    } else if (CUR == '.') {
9564
  /* relative abbreviated attribute location path */
9565
0
  lc = 1;
9566
0
    } else {
9567
  /*
9568
   * Problem is finding if we have a name here whether it's:
9569
   *   - a nodetype
9570
   *   - a function call in which case it's followed by '('
9571
   *   - an axis in which case it's followed by ':'
9572
   *   - a element name
9573
   * We do an a priori analysis here rather than having to
9574
   * maintain parsed token content through the recursive function
9575
   * calls. This looks uglier but makes the code easier to
9576
   * read/write/debug.
9577
   */
9578
0
  SKIP_BLANKS;
9579
0
  name = xmlXPathScanName(ctxt);
9580
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9581
0
      lc = 1;
9582
0
      xmlFree(name);
9583
0
  } else if (name != NULL) {
9584
0
      int len =xmlStrlen(name);
9585
9586
9587
0
      while (NXT(len) != 0) {
9588
0
    if (NXT(len) == '/') {
9589
        /* element name */
9590
0
        lc = 1;
9591
0
        break;
9592
0
    } else if (IS_BLANK_CH(NXT(len))) {
9593
        /* ignore blanks */
9594
0
        ;
9595
0
    } else if (NXT(len) == ':') {
9596
0
        lc = 1;
9597
0
        break;
9598
0
    } else if ((NXT(len) == '(')) {
9599
        /* Node Type or Function */
9600
0
        if (xmlXPathIsNodeType(name)) {
9601
0
      lc = 1;
9602
#ifdef LIBXML_XPTR_LOCS_ENABLED
9603
                    } else if (ctxt->xptr &&
9604
                               xmlStrEqual(name, BAD_CAST "range-to")) {
9605
                        lc = 1;
9606
#endif
9607
0
        } else {
9608
0
      lc = 0;
9609
0
        }
9610
0
                    break;
9611
0
    } else if ((NXT(len) == '[')) {
9612
        /* element name */
9613
0
        lc = 1;
9614
0
        break;
9615
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9616
0
         (NXT(len) == '=')) {
9617
0
        lc = 1;
9618
0
        break;
9619
0
    } else {
9620
0
        lc = 1;
9621
0
        break;
9622
0
    }
9623
0
    len++;
9624
0
      }
9625
0
      if (NXT(len) == 0) {
9626
    /* element name */
9627
0
    lc = 1;
9628
0
      }
9629
0
      xmlFree(name);
9630
0
  } else {
9631
      /* make sure all cases are covered explicitly */
9632
0
      XP_ERROR(XPATH_EXPR_ERROR);
9633
0
  }
9634
0
    }
9635
9636
0
    if (lc) {
9637
0
  if (CUR == '/') {
9638
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9639
0
  } else {
9640
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9641
0
  }
9642
0
  xmlXPathCompLocationPath(ctxt);
9643
0
    } else {
9644
0
  xmlXPathCompFilterExpr(ctxt);
9645
0
  CHECK_ERROR;
9646
0
  if ((CUR == '/') && (NXT(1) == '/')) {
9647
0
      SKIP(2);
9648
0
      SKIP_BLANKS;
9649
9650
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9651
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9652
9653
0
      xmlXPathCompRelativeLocationPath(ctxt);
9654
0
  } else if (CUR == '/') {
9655
0
      xmlXPathCompRelativeLocationPath(ctxt);
9656
0
  }
9657
0
    }
9658
0
    SKIP_BLANKS;
9659
0
}
9660
9661
/**
9662
 * xmlXPathCompUnionExpr:
9663
 * @ctxt:  the XPath Parser context
9664
 *
9665
 *  [18]   UnionExpr ::=   PathExpr
9666
 *               | UnionExpr '|' PathExpr
9667
 *
9668
 * Compile an union expression.
9669
 */
9670
9671
static void
9672
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9673
0
    xmlXPathCompPathExpr(ctxt);
9674
0
    CHECK_ERROR;
9675
0
    SKIP_BLANKS;
9676
0
    while (CUR == '|') {
9677
0
  int op1 = ctxt->comp->last;
9678
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9679
9680
0
  NEXT;
9681
0
  SKIP_BLANKS;
9682
0
  xmlXPathCompPathExpr(ctxt);
9683
9684
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9685
9686
0
  SKIP_BLANKS;
9687
0
    }
9688
0
}
9689
9690
/**
9691
 * xmlXPathCompUnaryExpr:
9692
 * @ctxt:  the XPath Parser context
9693
 *
9694
 *  [27]   UnaryExpr ::=   UnionExpr
9695
 *                   | '-' UnaryExpr
9696
 *
9697
 * Compile an unary expression.
9698
 */
9699
9700
static void
9701
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9702
0
    int minus = 0;
9703
0
    int found = 0;
9704
9705
0
    SKIP_BLANKS;
9706
0
    while (CUR == '-') {
9707
0
        minus = 1 - minus;
9708
0
  found = 1;
9709
0
  NEXT;
9710
0
  SKIP_BLANKS;
9711
0
    }
9712
9713
0
    xmlXPathCompUnionExpr(ctxt);
9714
0
    CHECK_ERROR;
9715
0
    if (found) {
9716
0
  if (minus)
9717
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9718
0
  else
9719
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9720
0
    }
9721
0
}
9722
9723
/**
9724
 * xmlXPathCompMultiplicativeExpr:
9725
 * @ctxt:  the XPath Parser context
9726
 *
9727
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
9728
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
9729
 *                   | MultiplicativeExpr 'div' UnaryExpr
9730
 *                   | MultiplicativeExpr 'mod' UnaryExpr
9731
 *  [34]   MultiplyOperator ::=   '*'
9732
 *
9733
 * Compile an Additive expression.
9734
 */
9735
9736
static void
9737
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9738
0
    xmlXPathCompUnaryExpr(ctxt);
9739
0
    CHECK_ERROR;
9740
0
    SKIP_BLANKS;
9741
0
    while ((CUR == '*') ||
9742
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9743
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9744
0
  int op = -1;
9745
0
  int op1 = ctxt->comp->last;
9746
9747
0
        if (CUR == '*') {
9748
0
      op = 0;
9749
0
      NEXT;
9750
0
  } else if (CUR == 'd') {
9751
0
      op = 1;
9752
0
      SKIP(3);
9753
0
  } else if (CUR == 'm') {
9754
0
      op = 2;
9755
0
      SKIP(3);
9756
0
  }
9757
0
  SKIP_BLANKS;
9758
0
        xmlXPathCompUnaryExpr(ctxt);
9759
0
  CHECK_ERROR;
9760
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9761
0
  SKIP_BLANKS;
9762
0
    }
9763
0
}
9764
9765
/**
9766
 * xmlXPathCompAdditiveExpr:
9767
 * @ctxt:  the XPath Parser context
9768
 *
9769
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
9770
 *                   | AdditiveExpr '+' MultiplicativeExpr
9771
 *                   | AdditiveExpr '-' MultiplicativeExpr
9772
 *
9773
 * Compile an Additive expression.
9774
 */
9775
9776
static void
9777
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9778
9779
0
    xmlXPathCompMultiplicativeExpr(ctxt);
9780
0
    CHECK_ERROR;
9781
0
    SKIP_BLANKS;
9782
0
    while ((CUR == '+') || (CUR == '-')) {
9783
0
  int plus;
9784
0
  int op1 = ctxt->comp->last;
9785
9786
0
        if (CUR == '+') plus = 1;
9787
0
  else plus = 0;
9788
0
  NEXT;
9789
0
  SKIP_BLANKS;
9790
0
        xmlXPathCompMultiplicativeExpr(ctxt);
9791
0
  CHECK_ERROR;
9792
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9793
0
  SKIP_BLANKS;
9794
0
    }
9795
0
}
9796
9797
/**
9798
 * xmlXPathCompRelationalExpr:
9799
 * @ctxt:  the XPath Parser context
9800
 *
9801
 *  [24]   RelationalExpr ::=   AdditiveExpr
9802
 *                 | RelationalExpr '<' AdditiveExpr
9803
 *                 | RelationalExpr '>' AdditiveExpr
9804
 *                 | RelationalExpr '<=' AdditiveExpr
9805
 *                 | RelationalExpr '>=' AdditiveExpr
9806
 *
9807
 *  A <= B > C is allowed ? Answer from James, yes with
9808
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9809
 *  which is basically what got implemented.
9810
 *
9811
 * Compile a Relational expression, then push the result
9812
 * on the stack
9813
 */
9814
9815
static void
9816
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9817
0
    xmlXPathCompAdditiveExpr(ctxt);
9818
0
    CHECK_ERROR;
9819
0
    SKIP_BLANKS;
9820
0
    while ((CUR == '<') || (CUR == '>')) {
9821
0
  int inf, strict;
9822
0
  int op1 = ctxt->comp->last;
9823
9824
0
        if (CUR == '<') inf = 1;
9825
0
  else inf = 0;
9826
0
  if (NXT(1) == '=') strict = 0;
9827
0
  else strict = 1;
9828
0
  NEXT;
9829
0
  if (!strict) NEXT;
9830
0
  SKIP_BLANKS;
9831
0
        xmlXPathCompAdditiveExpr(ctxt);
9832
0
  CHECK_ERROR;
9833
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9834
0
  SKIP_BLANKS;
9835
0
    }
9836
0
}
9837
9838
/**
9839
 * xmlXPathCompEqualityExpr:
9840
 * @ctxt:  the XPath Parser context
9841
 *
9842
 *  [23]   EqualityExpr ::=   RelationalExpr
9843
 *                 | EqualityExpr '=' RelationalExpr
9844
 *                 | EqualityExpr '!=' RelationalExpr
9845
 *
9846
 *  A != B != C is allowed ? Answer from James, yes with
9847
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
9848
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
9849
 *  which is basically what got implemented.
9850
 *
9851
 * Compile an Equality expression.
9852
 *
9853
 */
9854
static void
9855
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9856
0
    xmlXPathCompRelationalExpr(ctxt);
9857
0
    CHECK_ERROR;
9858
0
    SKIP_BLANKS;
9859
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9860
0
  int eq;
9861
0
  int op1 = ctxt->comp->last;
9862
9863
0
        if (CUR == '=') eq = 1;
9864
0
  else eq = 0;
9865
0
  NEXT;
9866
0
  if (!eq) NEXT;
9867
0
  SKIP_BLANKS;
9868
0
        xmlXPathCompRelationalExpr(ctxt);
9869
0
  CHECK_ERROR;
9870
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9871
0
  SKIP_BLANKS;
9872
0
    }
9873
0
}
9874
9875
/**
9876
 * xmlXPathCompAndExpr:
9877
 * @ctxt:  the XPath Parser context
9878
 *
9879
 *  [22]   AndExpr ::=   EqualityExpr
9880
 *                 | AndExpr 'and' EqualityExpr
9881
 *
9882
 * Compile an AND expression.
9883
 *
9884
 */
9885
static void
9886
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9887
0
    xmlXPathCompEqualityExpr(ctxt);
9888
0
    CHECK_ERROR;
9889
0
    SKIP_BLANKS;
9890
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9891
0
  int op1 = ctxt->comp->last;
9892
0
        SKIP(3);
9893
0
  SKIP_BLANKS;
9894
0
        xmlXPathCompEqualityExpr(ctxt);
9895
0
  CHECK_ERROR;
9896
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9897
0
  SKIP_BLANKS;
9898
0
    }
9899
0
}
9900
9901
/**
9902
 * xmlXPathCompileExpr:
9903
 * @ctxt:  the XPath Parser context
9904
 *
9905
 *  [14]   Expr ::=   OrExpr
9906
 *  [21]   OrExpr ::=   AndExpr
9907
 *                 | OrExpr 'or' AndExpr
9908
 *
9909
 * Parse and compile an expression
9910
 */
9911
static void
9912
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9913
0
    xmlXPathContextPtr xpctxt = ctxt->context;
9914
9915
0
    if (xpctxt != NULL) {
9916
0
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9917
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9918
        /*
9919
         * Parsing a single '(' pushes about 10 functions on the call stack
9920
         * before recursing!
9921
         */
9922
0
        xpctxt->depth += 10;
9923
0
    }
9924
9925
0
    xmlXPathCompAndExpr(ctxt);
9926
0
    CHECK_ERROR;
9927
0
    SKIP_BLANKS;
9928
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9929
0
  int op1 = ctxt->comp->last;
9930
0
        SKIP(2);
9931
0
  SKIP_BLANKS;
9932
0
        xmlXPathCompAndExpr(ctxt);
9933
0
  CHECK_ERROR;
9934
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9935
0
  SKIP_BLANKS;
9936
0
    }
9937
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9938
  /* more ops could be optimized too */
9939
  /*
9940
  * This is the main place to eliminate sorting for
9941
  * operations which don't require a sorted node-set.
9942
  * E.g. count().
9943
  */
9944
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9945
0
    }
9946
9947
0
    if (xpctxt != NULL)
9948
0
        xpctxt->depth -= 10;
9949
0
}
9950
9951
/**
9952
 * xmlXPathCompPredicate:
9953
 * @ctxt:  the XPath Parser context
9954
 * @filter:  act as a filter
9955
 *
9956
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
9957
 *  [9]   PredicateExpr ::=   Expr
9958
 *
9959
 * Compile a predicate expression
9960
 */
9961
static void
9962
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9963
0
    int op1 = ctxt->comp->last;
9964
9965
0
    SKIP_BLANKS;
9966
0
    if (CUR != '[') {
9967
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9968
0
    }
9969
0
    NEXT;
9970
0
    SKIP_BLANKS;
9971
9972
0
    ctxt->comp->last = -1;
9973
    /*
9974
    * This call to xmlXPathCompileExpr() will deactivate sorting
9975
    * of the predicate result.
9976
    * TODO: Sorting is still activated for filters, since I'm not
9977
    *  sure if needed. Normally sorting should not be needed, since
9978
    *  a filter can only diminish the number of items in a sequence,
9979
    *  but won't change its order; so if the initial sequence is sorted,
9980
    *  subsequent sorting is not needed.
9981
    */
9982
0
    if (! filter)
9983
0
  xmlXPathCompileExpr(ctxt, 0);
9984
0
    else
9985
0
  xmlXPathCompileExpr(ctxt, 1);
9986
0
    CHECK_ERROR;
9987
9988
0
    if (CUR != ']') {
9989
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9990
0
    }
9991
9992
0
    if (filter)
9993
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9994
0
    else
9995
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9996
9997
0
    NEXT;
9998
0
    SKIP_BLANKS;
9999
0
}
10000
10001
/**
10002
 * xmlXPathCompNodeTest:
10003
 * @ctxt:  the XPath Parser context
10004
 * @test:  pointer to a xmlXPathTestVal
10005
 * @type:  pointer to a xmlXPathTypeVal
10006
 * @prefix:  placeholder for a possible name prefix
10007
 *
10008
 * [7] NodeTest ::=   NameTest
10009
 *        | NodeType '(' ')'
10010
 *        | 'processing-instruction' '(' Literal ')'
10011
 *
10012
 * [37] NameTest ::=  '*'
10013
 *        | NCName ':' '*'
10014
 *        | QName
10015
 * [38] NodeType ::= 'comment'
10016
 *       | 'text'
10017
 *       | 'processing-instruction'
10018
 *       | 'node'
10019
 *
10020
 * Returns the name found and updates @test, @type and @prefix appropriately
10021
 */
10022
static xmlChar *
10023
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10024
               xmlXPathTypeVal *type, xmlChar **prefix,
10025
0
         xmlChar *name) {
10026
0
    int blanks;
10027
10028
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10029
0
  return(NULL);
10030
0
    }
10031
0
    *type = (xmlXPathTypeVal) 0;
10032
0
    *test = (xmlXPathTestVal) 0;
10033
0
    *prefix = NULL;
10034
0
    SKIP_BLANKS;
10035
10036
0
    if ((name == NULL) && (CUR == '*')) {
10037
  /*
10038
   * All elements
10039
   */
10040
0
  NEXT;
10041
0
  *test = NODE_TEST_ALL;
10042
0
  return(NULL);
10043
0
    }
10044
10045
0
    if (name == NULL)
10046
0
  name = xmlXPathParseNCName(ctxt);
10047
0
    if (name == NULL) {
10048
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
10049
0
    }
10050
10051
0
    blanks = IS_BLANK_CH(CUR);
10052
0
    SKIP_BLANKS;
10053
0
    if (CUR == '(') {
10054
0
  NEXT;
10055
  /*
10056
   * NodeType or PI search
10057
   */
10058
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
10059
0
      *type = NODE_TYPE_COMMENT;
10060
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
10061
0
      *type = NODE_TYPE_NODE;
10062
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10063
0
      *type = NODE_TYPE_PI;
10064
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
10065
0
      *type = NODE_TYPE_TEXT;
10066
0
  else {
10067
0
      if (name != NULL)
10068
0
    xmlFree(name);
10069
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
10070
0
  }
10071
10072
0
  *test = NODE_TEST_TYPE;
10073
10074
0
  SKIP_BLANKS;
10075
0
  if (*type == NODE_TYPE_PI) {
10076
      /*
10077
       * Specific case: search a PI by name.
10078
       */
10079
0
      if (name != NULL)
10080
0
    xmlFree(name);
10081
0
      name = NULL;
10082
0
      if (CUR != ')') {
10083
0
    name = xmlXPathParseLiteral(ctxt);
10084
0
    *test = NODE_TEST_PI;
10085
0
    SKIP_BLANKS;
10086
0
      }
10087
0
  }
10088
0
  if (CUR != ')') {
10089
0
      if (name != NULL)
10090
0
    xmlFree(name);
10091
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10092
0
  }
10093
0
  NEXT;
10094
0
  return(name);
10095
0
    }
10096
0
    *test = NODE_TEST_NAME;
10097
0
    if ((!blanks) && (CUR == ':')) {
10098
0
  NEXT;
10099
10100
  /*
10101
   * Since currently the parser context don't have a
10102
   * namespace list associated:
10103
   * The namespace name for this prefix can be computed
10104
   * only at evaluation time. The compilation is done
10105
   * outside of any context.
10106
   */
10107
#if 0
10108
  *prefix = xmlXPathNsLookup(ctxt->context, name);
10109
  if (name != NULL)
10110
      xmlFree(name);
10111
  if (*prefix == NULL) {
10112
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10113
  }
10114
#else
10115
0
  *prefix = name;
10116
0
#endif
10117
10118
0
  if (CUR == '*') {
10119
      /*
10120
       * All elements
10121
       */
10122
0
      NEXT;
10123
0
      *test = NODE_TEST_ALL;
10124
0
      return(NULL);
10125
0
  }
10126
10127
0
  name = xmlXPathParseNCName(ctxt);
10128
0
  if (name == NULL) {
10129
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
10130
0
  }
10131
0
    }
10132
0
    return(name);
10133
0
}
10134
10135
/**
10136
 * xmlXPathIsAxisName:
10137
 * @name:  a preparsed name token
10138
 *
10139
 * [6] AxisName ::=   'ancestor'
10140
 *                  | 'ancestor-or-self'
10141
 *                  | 'attribute'
10142
 *                  | 'child'
10143
 *                  | 'descendant'
10144
 *                  | 'descendant-or-self'
10145
 *                  | 'following'
10146
 *                  | 'following-sibling'
10147
 *                  | 'namespace'
10148
 *                  | 'parent'
10149
 *                  | 'preceding'
10150
 *                  | 'preceding-sibling'
10151
 *                  | 'self'
10152
 *
10153
 * Returns the axis or 0
10154
 */
10155
static xmlXPathAxisVal
10156
0
xmlXPathIsAxisName(const xmlChar *name) {
10157
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10158
0
    switch (name[0]) {
10159
0
  case 'a':
10160
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
10161
0
    ret = AXIS_ANCESTOR;
10162
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10163
0
    ret = AXIS_ANCESTOR_OR_SELF;
10164
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
10165
0
    ret = AXIS_ATTRIBUTE;
10166
0
      break;
10167
0
  case 'c':
10168
0
      if (xmlStrEqual(name, BAD_CAST "child"))
10169
0
    ret = AXIS_CHILD;
10170
0
      break;
10171
0
  case 'd':
10172
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
10173
0
    ret = AXIS_DESCENDANT;
10174
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10175
0
    ret = AXIS_DESCENDANT_OR_SELF;
10176
0
      break;
10177
0
  case 'f':
10178
0
      if (xmlStrEqual(name, BAD_CAST "following"))
10179
0
    ret = AXIS_FOLLOWING;
10180
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10181
0
    ret = AXIS_FOLLOWING_SIBLING;
10182
0
      break;
10183
0
  case 'n':
10184
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
10185
0
    ret = AXIS_NAMESPACE;
10186
0
      break;
10187
0
  case 'p':
10188
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
10189
0
    ret = AXIS_PARENT;
10190
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
10191
0
    ret = AXIS_PRECEDING;
10192
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10193
0
    ret = AXIS_PRECEDING_SIBLING;
10194
0
      break;
10195
0
  case 's':
10196
0
      if (xmlStrEqual(name, BAD_CAST "self"))
10197
0
    ret = AXIS_SELF;
10198
0
      break;
10199
0
    }
10200
0
    return(ret);
10201
0
}
10202
10203
/**
10204
 * xmlXPathCompStep:
10205
 * @ctxt:  the XPath Parser context
10206
 *
10207
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
10208
 *                  | AbbreviatedStep
10209
 *
10210
 * [12] AbbreviatedStep ::=   '.' | '..'
10211
 *
10212
 * [5] AxisSpecifier ::= AxisName '::'
10213
 *                  | AbbreviatedAxisSpecifier
10214
 *
10215
 * [13] AbbreviatedAxisSpecifier ::= '@'?
10216
 *
10217
 * Modified for XPtr range support as:
10218
 *
10219
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10220
 *                     | AbbreviatedStep
10221
 *                     | 'range-to' '(' Expr ')' Predicate*
10222
 *
10223
 * Compile one step in a Location Path
10224
 * A location step of . is short for self::node(). This is
10225
 * particularly useful in conjunction with //. For example, the
10226
 * location path .//para is short for
10227
 * self::node()/descendant-or-self::node()/child::para
10228
 * and so will select all para descendant elements of the context
10229
 * node.
10230
 * Similarly, a location step of .. is short for parent::node().
10231
 * For example, ../title is short for parent::node()/child::title
10232
 * and so will select the title children of the parent of the context
10233
 * node.
10234
 */
10235
static void
10236
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10237
#ifdef LIBXML_XPTR_LOCS_ENABLED
10238
    int rangeto = 0;
10239
    int op2 = -1;
10240
#endif
10241
10242
0
    SKIP_BLANKS;
10243
0
    if ((CUR == '.') && (NXT(1) == '.')) {
10244
0
  SKIP(2);
10245
0
  SKIP_BLANKS;
10246
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10247
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10248
0
    } else if (CUR == '.') {
10249
0
  NEXT;
10250
0
  SKIP_BLANKS;
10251
0
    } else {
10252
0
  xmlChar *name = NULL;
10253
0
  xmlChar *prefix = NULL;
10254
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
10255
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10256
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10257
0
  int op1;
10258
10259
  /*
10260
   * The modification needed for XPointer change to the production
10261
   */
10262
#ifdef LIBXML_XPTR_LOCS_ENABLED
10263
  if (ctxt->xptr) {
10264
      name = xmlXPathParseNCName(ctxt);
10265
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10266
                op2 = ctxt->comp->last;
10267
    xmlFree(name);
10268
    SKIP_BLANKS;
10269
    if (CUR != '(') {
10270
        XP_ERROR(XPATH_EXPR_ERROR);
10271
    }
10272
    NEXT;
10273
    SKIP_BLANKS;
10274
10275
    xmlXPathCompileExpr(ctxt, 1);
10276
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10277
    CHECK_ERROR;
10278
10279
    SKIP_BLANKS;
10280
    if (CUR != ')') {
10281
        XP_ERROR(XPATH_EXPR_ERROR);
10282
    }
10283
    NEXT;
10284
    rangeto = 1;
10285
    goto eval_predicates;
10286
      }
10287
  }
10288
#endif
10289
0
  if (CUR == '*') {
10290
0
      axis = AXIS_CHILD;
10291
0
  } else {
10292
0
      if (name == NULL)
10293
0
    name = xmlXPathParseNCName(ctxt);
10294
0
      if (name != NULL) {
10295
0
    axis = xmlXPathIsAxisName(name);
10296
0
    if (axis != 0) {
10297
0
        SKIP_BLANKS;
10298
0
        if ((CUR == ':') && (NXT(1) == ':')) {
10299
0
      SKIP(2);
10300
0
      xmlFree(name);
10301
0
      name = NULL;
10302
0
        } else {
10303
      /* an element name can conflict with an axis one :-\ */
10304
0
      axis = AXIS_CHILD;
10305
0
        }
10306
0
    } else {
10307
0
        axis = AXIS_CHILD;
10308
0
    }
10309
0
      } else if (CUR == '@') {
10310
0
    NEXT;
10311
0
    axis = AXIS_ATTRIBUTE;
10312
0
      } else {
10313
0
    axis = AXIS_CHILD;
10314
0
      }
10315
0
  }
10316
10317
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
10318
0
            xmlFree(name);
10319
0
            return;
10320
0
        }
10321
10322
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10323
0
  if (test == 0)
10324
0
      return;
10325
10326
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
10327
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10328
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10329
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10330
0
      }
10331
0
  }
10332
10333
#ifdef LIBXML_XPTR_LOCS_ENABLED
10334
eval_predicates:
10335
#endif
10336
0
  op1 = ctxt->comp->last;
10337
0
  ctxt->comp->last = -1;
10338
10339
0
  SKIP_BLANKS;
10340
0
  while (CUR == '[') {
10341
0
      xmlXPathCompPredicate(ctxt, 0);
10342
0
  }
10343
10344
#ifdef LIBXML_XPTR_LOCS_ENABLED
10345
  if (rangeto) {
10346
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10347
  } else
10348
#endif
10349
0
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10350
0
                           test, type, (void *)prefix, (void *)name) == -1) {
10351
0
            xmlFree(prefix);
10352
0
            xmlFree(name);
10353
0
        }
10354
0
    }
10355
0
}
10356
10357
/**
10358
 * xmlXPathCompRelativeLocationPath:
10359
 * @ctxt:  the XPath Parser context
10360
 *
10361
 *  [3]   RelativeLocationPath ::=   Step
10362
 *                     | RelativeLocationPath '/' Step
10363
 *                     | AbbreviatedRelativeLocationPath
10364
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
10365
 *
10366
 * Compile a relative location path.
10367
 */
10368
static void
10369
xmlXPathCompRelativeLocationPath
10370
0
(xmlXPathParserContextPtr ctxt) {
10371
0
    SKIP_BLANKS;
10372
0
    if ((CUR == '/') && (NXT(1) == '/')) {
10373
0
  SKIP(2);
10374
0
  SKIP_BLANKS;
10375
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10376
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10377
0
    } else if (CUR == '/') {
10378
0
      NEXT;
10379
0
  SKIP_BLANKS;
10380
0
    }
10381
0
    xmlXPathCompStep(ctxt);
10382
0
    CHECK_ERROR;
10383
0
    SKIP_BLANKS;
10384
0
    while (CUR == '/') {
10385
0
  if ((CUR == '/') && (NXT(1) == '/')) {
10386
0
      SKIP(2);
10387
0
      SKIP_BLANKS;
10388
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10389
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10390
0
      xmlXPathCompStep(ctxt);
10391
0
  } else if (CUR == '/') {
10392
0
      NEXT;
10393
0
      SKIP_BLANKS;
10394
0
      xmlXPathCompStep(ctxt);
10395
0
  }
10396
0
  SKIP_BLANKS;
10397
0
    }
10398
0
}
10399
10400
/**
10401
 * xmlXPathCompLocationPath:
10402
 * @ctxt:  the XPath Parser context
10403
 *
10404
 *  [1]   LocationPath ::=   RelativeLocationPath
10405
 *                     | AbsoluteLocationPath
10406
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
10407
 *                     | AbbreviatedAbsoluteLocationPath
10408
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
10409
 *                           '//' RelativeLocationPath
10410
 *
10411
 * Compile a location path
10412
 *
10413
 * // is short for /descendant-or-self::node()/. For example,
10414
 * //para is short for /descendant-or-self::node()/child::para and
10415
 * so will select any para element in the document (even a para element
10416
 * that is a document element will be selected by //para since the
10417
 * document element node is a child of the root node); div//para is
10418
 * short for div/descendant-or-self::node()/child::para and so will
10419
 * select all para descendants of div children.
10420
 */
10421
static void
10422
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10423
0
    SKIP_BLANKS;
10424
0
    if (CUR != '/') {
10425
0
        xmlXPathCompRelativeLocationPath(ctxt);
10426
0
    } else {
10427
0
  while (CUR == '/') {
10428
0
      if ((CUR == '/') && (NXT(1) == '/')) {
10429
0
    SKIP(2);
10430
0
    SKIP_BLANKS;
10431
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10432
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10433
0
    xmlXPathCompRelativeLocationPath(ctxt);
10434
0
      } else if (CUR == '/') {
10435
0
    NEXT;
10436
0
    SKIP_BLANKS;
10437
0
    if ((CUR != 0 ) &&
10438
0
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10439
0
         (CUR == '@') || (CUR == '*')))
10440
0
        xmlXPathCompRelativeLocationPath(ctxt);
10441
0
      }
10442
0
      CHECK_ERROR;
10443
0
  }
10444
0
    }
10445
0
}
10446
10447
/************************************************************************
10448
 *                  *
10449
 *    XPath precompiled expression evaluation     *
10450
 *                  *
10451
 ************************************************************************/
10452
10453
static int
10454
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10455
10456
/**
10457
 * xmlXPathNodeSetFilter:
10458
 * @ctxt:  the XPath Parser context
10459
 * @set: the node set to filter
10460
 * @filterOpIndex: the index of the predicate/filter op
10461
 * @minPos: minimum position in the filtered set (1-based)
10462
 * @maxPos: maximum position in the filtered set (1-based)
10463
 * @hasNsNodes: true if the node set may contain namespace nodes
10464
 *
10465
 * Filter a node set, keeping only nodes for which the predicate expression
10466
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10467
 * filtered result.
10468
 */
10469
static void
10470
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10471
          xmlNodeSetPtr set,
10472
          int filterOpIndex,
10473
                      int minPos, int maxPos,
10474
          int hasNsNodes)
10475
0
{
10476
0
    xmlXPathContextPtr xpctxt;
10477
0
    xmlNodePtr oldnode;
10478
0
    xmlDocPtr olddoc;
10479
0
    xmlXPathStepOpPtr filterOp;
10480
0
    int oldcs, oldpp;
10481
0
    int i, j, pos;
10482
10483
0
    if ((set == NULL) || (set->nodeNr == 0))
10484
0
        return;
10485
10486
    /*
10487
    * Check if the node set contains a sufficient number of nodes for
10488
    * the requested range.
10489
    */
10490
0
    if (set->nodeNr < minPos) {
10491
0
        xmlXPathNodeSetClear(set, hasNsNodes);
10492
0
        return;
10493
0
    }
10494
10495
0
    xpctxt = ctxt->context;
10496
0
    oldnode = xpctxt->node;
10497
0
    olddoc = xpctxt->doc;
10498
0
    oldcs = xpctxt->contextSize;
10499
0
    oldpp = xpctxt->proximityPosition;
10500
0
    filterOp = &ctxt->comp->steps[filterOpIndex];
10501
10502
0
    xpctxt->contextSize = set->nodeNr;
10503
10504
0
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10505
0
        xmlNodePtr node = set->nodeTab[i];
10506
0
        int res;
10507
10508
0
        xpctxt->node = node;
10509
0
        xpctxt->proximityPosition = i + 1;
10510
10511
        /*
10512
        * Also set the xpath document in case things like
10513
        * key() are evaluated in the predicate.
10514
        *
10515
        * TODO: Get real doc for namespace nodes.
10516
        */
10517
0
        if ((node->type != XML_NAMESPACE_DECL) &&
10518
0
            (node->doc != NULL))
10519
0
            xpctxt->doc = node->doc;
10520
10521
0
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10522
10523
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
10524
0
            break;
10525
0
        if (res < 0) {
10526
            /* Shouldn't happen */
10527
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10528
0
            break;
10529
0
        }
10530
10531
0
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10532
0
            if (i != j) {
10533
0
                set->nodeTab[j] = node;
10534
0
                set->nodeTab[i] = NULL;
10535
0
            }
10536
10537
0
            j += 1;
10538
0
        } else {
10539
            /* Remove the entry from the initial node set. */
10540
0
            set->nodeTab[i] = NULL;
10541
0
            if (node->type == XML_NAMESPACE_DECL)
10542
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10543
0
        }
10544
10545
0
        if (res != 0) {
10546
0
            if (pos == maxPos) {
10547
0
                i += 1;
10548
0
                break;
10549
0
            }
10550
10551
0
            pos += 1;
10552
0
        }
10553
0
    }
10554
10555
    /* Free remaining nodes. */
10556
0
    if (hasNsNodes) {
10557
0
        for (; i < set->nodeNr; i++) {
10558
0
            xmlNodePtr node = set->nodeTab[i];
10559
0
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10560
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10561
0
        }
10562
0
    }
10563
10564
0
    set->nodeNr = j;
10565
10566
    /* If too many elements were removed, shrink table to preserve memory. */
10567
0
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10568
0
        (set->nodeNr < set->nodeMax / 2)) {
10569
0
        xmlNodePtr *tmp;
10570
0
        int nodeMax = set->nodeNr;
10571
10572
0
        if (nodeMax < XML_NODESET_DEFAULT)
10573
0
            nodeMax = XML_NODESET_DEFAULT;
10574
0
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10575
0
                nodeMax * sizeof(xmlNodePtr));
10576
0
        if (tmp == NULL) {
10577
0
            xmlXPathPErrMemory(ctxt);
10578
0
        } else {
10579
0
            set->nodeTab = tmp;
10580
0
            set->nodeMax = nodeMax;
10581
0
        }
10582
0
    }
10583
10584
0
    xpctxt->node = oldnode;
10585
0
    xpctxt->doc = olddoc;
10586
0
    xpctxt->contextSize = oldcs;
10587
0
    xpctxt->proximityPosition = oldpp;
10588
0
}
10589
10590
#ifdef LIBXML_XPTR_LOCS_ENABLED
10591
/**
10592
 * xmlXPathLocationSetFilter:
10593
 * @ctxt:  the XPath Parser context
10594
 * @locset: the location set to filter
10595
 * @filterOpIndex: the index of the predicate/filter op
10596
 * @minPos: minimum position in the filtered set (1-based)
10597
 * @maxPos: maximum position in the filtered set (1-based)
10598
 *
10599
 * Filter a location set, keeping only nodes for which the predicate
10600
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
10601
 * in the filtered result.
10602
 */
10603
static void
10604
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10605
              xmlLocationSetPtr locset,
10606
              int filterOpIndex,
10607
                          int minPos, int maxPos)
10608
{
10609
    xmlXPathContextPtr xpctxt;
10610
    xmlNodePtr oldnode;
10611
    xmlDocPtr olddoc;
10612
    xmlXPathStepOpPtr filterOp;
10613
    int oldcs, oldpp;
10614
    int i, j, pos;
10615
10616
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10617
        return;
10618
10619
    xpctxt = ctxt->context;
10620
    oldnode = xpctxt->node;
10621
    olddoc = xpctxt->doc;
10622
    oldcs = xpctxt->contextSize;
10623
    oldpp = xpctxt->proximityPosition;
10624
    filterOp = &ctxt->comp->steps[filterOpIndex];
10625
10626
    xpctxt->contextSize = locset->locNr;
10627
10628
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10629
        xmlNodePtr contextNode = locset->locTab[i]->user;
10630
        int res;
10631
10632
        xpctxt->node = contextNode;
10633
        xpctxt->proximityPosition = i + 1;
10634
10635
        /*
10636
        * Also set the xpath document in case things like
10637
        * key() are evaluated in the predicate.
10638
        *
10639
        * TODO: Get real doc for namespace nodes.
10640
        */
10641
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
10642
            (contextNode->doc != NULL))
10643
            xpctxt->doc = contextNode->doc;
10644
10645
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10646
10647
        if (ctxt->error != XPATH_EXPRESSION_OK)
10648
            break;
10649
        if (res < 0) {
10650
            /* Shouldn't happen */
10651
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10652
            break;
10653
        }
10654
10655
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10656
            if (i != j) {
10657
                locset->locTab[j] = locset->locTab[i];
10658
                locset->locTab[i] = NULL;
10659
            }
10660
10661
            j += 1;
10662
        } else {
10663
            /* Remove the entry from the initial location set. */
10664
            xmlXPathFreeObject(locset->locTab[i]);
10665
            locset->locTab[i] = NULL;
10666
        }
10667
10668
        if (res != 0) {
10669
            if (pos == maxPos) {
10670
                i += 1;
10671
                break;
10672
            }
10673
10674
            pos += 1;
10675
        }
10676
    }
10677
10678
    /* Free remaining nodes. */
10679
    for (; i < locset->locNr; i++)
10680
        xmlXPathFreeObject(locset->locTab[i]);
10681
10682
    locset->locNr = j;
10683
10684
    /* If too many elements were removed, shrink table to preserve memory. */
10685
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
10686
        (locset->locNr < locset->locMax / 2)) {
10687
        xmlXPathObjectPtr *tmp;
10688
        int locMax = locset->locNr;
10689
10690
        if (locMax < XML_NODESET_DEFAULT)
10691
            locMax = XML_NODESET_DEFAULT;
10692
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10693
                locMax * sizeof(xmlXPathObjectPtr));
10694
        if (tmp == NULL) {
10695
            xmlXPathPErrMemory(ctxt);
10696
        } else {
10697
            locset->locTab = tmp;
10698
            locset->locMax = locMax;
10699
        }
10700
    }
10701
10702
    xpctxt->node = oldnode;
10703
    xpctxt->doc = olddoc;
10704
    xpctxt->contextSize = oldcs;
10705
    xpctxt->proximityPosition = oldpp;
10706
}
10707
#endif /* LIBXML_XPTR_LOCS_ENABLED */
10708
10709
/**
10710
 * xmlXPathCompOpEvalPredicate:
10711
 * @ctxt:  the XPath Parser context
10712
 * @op: the predicate op
10713
 * @set: the node set to filter
10714
 * @minPos: minimum position in the filtered set (1-based)
10715
 * @maxPos: maximum position in the filtered set (1-based)
10716
 * @hasNsNodes: true if the node set may contain namespace nodes
10717
 *
10718
 * Filter a node set, keeping only nodes for which the sequence of predicate
10719
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10720
 * in the filtered result.
10721
 */
10722
static void
10723
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10724
          xmlXPathStepOpPtr op,
10725
          xmlNodeSetPtr set,
10726
                            int minPos, int maxPos,
10727
          int hasNsNodes)
10728
0
{
10729
0
    if (op->ch1 != -1) {
10730
0
  xmlXPathCompExprPtr comp = ctxt->comp;
10731
  /*
10732
  * Process inner predicates first.
10733
  */
10734
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10735
0
            XP_ERROR(XPATH_INVALID_OPERAND);
10736
0
  }
10737
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10738
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10739
0
        ctxt->context->depth += 1;
10740
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10741
0
                                    1, set->nodeNr, hasNsNodes);
10742
0
        ctxt->context->depth -= 1;
10743
0
  CHECK_ERROR;
10744
0
    }
10745
10746
0
    if (op->ch2 != -1)
10747
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10748
0
}
10749
10750
static int
10751
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10752
          xmlXPathStepOpPtr op,
10753
          int *maxPos)
10754
0
{
10755
10756
0
    xmlXPathStepOpPtr exprOp;
10757
10758
    /*
10759
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10760
    */
10761
10762
    /*
10763
    * If not -1, then ch1 will point to:
10764
    * 1) For predicates (XPATH_OP_PREDICATE):
10765
    *    - an inner predicate operator
10766
    * 2) For filters (XPATH_OP_FILTER):
10767
    *    - an inner filter operator OR
10768
    *    - an expression selecting the node set.
10769
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
10770
    */
10771
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10772
0
  return(0);
10773
10774
0
    if (op->ch2 != -1) {
10775
0
  exprOp = &ctxt->comp->steps[op->ch2];
10776
0
    } else
10777
0
  return(0);
10778
10779
0
    if ((exprOp != NULL) &&
10780
0
  (exprOp->op == XPATH_OP_VALUE) &&
10781
0
  (exprOp->value4 != NULL) &&
10782
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10783
0
    {
10784
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10785
10786
  /*
10787
  * We have a "[n]" predicate here.
10788
  * TODO: Unfortunately this simplistic test here is not
10789
  * able to detect a position() predicate in compound
10790
  * expressions like "[@attr = 'a" and position() = 1],
10791
  * and even not the usage of position() in
10792
  * "[position() = 1]"; thus - obviously - a position-range,
10793
  * like it "[position() < 5]", is also not detected.
10794
  * Maybe we could rewrite the AST to ease the optimization.
10795
  */
10796
10797
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10798
0
      *maxPos = (int) floatval;
10799
0
            if (floatval == (double) *maxPos)
10800
0
                return(1);
10801
0
        }
10802
0
    }
10803
0
    return(0);
10804
0
}
10805
10806
static int
10807
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10808
                           xmlXPathStepOpPtr op,
10809
         xmlNodePtr * first, xmlNodePtr * last,
10810
         int toBool)
10811
0
{
10812
10813
0
#define XP_TEST_HIT \
10814
0
    if (hasAxisRange != 0) { \
10815
0
  if (++pos == maxPos) { \
10816
0
      if (addNode(seq, cur) < 0) \
10817
0
          xmlXPathPErrMemory(ctxt); \
10818
0
      goto axis_range_end; } \
10819
0
    } else { \
10820
0
  if (addNode(seq, cur) < 0) \
10821
0
      xmlXPathPErrMemory(ctxt); \
10822
0
  if (breakOnFirstHit) goto first_hit; }
10823
10824
0
#define XP_TEST_HIT_NS \
10825
0
    if (hasAxisRange != 0) { \
10826
0
  if (++pos == maxPos) { \
10827
0
      hasNsNodes = 1; \
10828
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10829
0
          xmlXPathPErrMemory(ctxt); \
10830
0
  goto axis_range_end; } \
10831
0
    } else { \
10832
0
  hasNsNodes = 1; \
10833
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10834
0
      xmlXPathPErrMemory(ctxt); \
10835
0
  if (breakOnFirstHit) goto first_hit; }
10836
10837
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10838
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10839
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10840
0
    const xmlChar *prefix = op->value4;
10841
0
    const xmlChar *name = op->value5;
10842
0
    const xmlChar *URI = NULL;
10843
10844
0
    int total = 0, hasNsNodes = 0;
10845
    /* The popped object holding the context nodes */
10846
0
    xmlXPathObjectPtr obj;
10847
    /* The set of context nodes for the node tests */
10848
0
    xmlNodeSetPtr contextSeq;
10849
0
    int contextIdx;
10850
0
    xmlNodePtr contextNode;
10851
    /* The final resulting node set wrt to all context nodes */
10852
0
    xmlNodeSetPtr outSeq;
10853
    /*
10854
    * The temporary resulting node set wrt 1 context node.
10855
    * Used to feed predicate evaluation.
10856
    */
10857
0
    xmlNodeSetPtr seq;
10858
0
    xmlNodePtr cur;
10859
    /* First predicate operator */
10860
0
    xmlXPathStepOpPtr predOp;
10861
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
10862
0
    int hasPredicateRange, hasAxisRange, pos;
10863
0
    int breakOnFirstHit;
10864
10865
0
    xmlXPathTraversalFunction next = NULL;
10866
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10867
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
10868
0
    xmlNodePtr oldContextNode;
10869
0
    xmlXPathContextPtr xpctxt = ctxt->context;
10870
10871
10872
0
    CHECK_TYPE0(XPATH_NODESET);
10873
0
    obj = valuePop(ctxt);
10874
    /*
10875
    * Setup namespaces.
10876
    */
10877
0
    if (prefix != NULL) {
10878
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
10879
0
        if (URI == NULL) {
10880
0
      xmlXPathReleaseObject(xpctxt, obj);
10881
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10882
0
  }
10883
0
    }
10884
    /*
10885
    * Setup axis.
10886
    *
10887
    * MAYBE FUTURE TODO: merging optimizations:
10888
    * - If the nodes to be traversed wrt to the initial nodes and
10889
    *   the current axis cannot overlap, then we could avoid searching
10890
    *   for duplicates during the merge.
10891
    *   But the question is how/when to evaluate if they cannot overlap.
10892
    *   Example: if we know that for two initial nodes, the one is
10893
    *   not in the ancestor-or-self axis of the other, then we could safely
10894
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10895
    *   the descendant-or-self axis.
10896
    */
10897
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
10898
0
    switch (axis) {
10899
0
        case AXIS_ANCESTOR:
10900
0
            first = NULL;
10901
0
            next = xmlXPathNextAncestor;
10902
0
            break;
10903
0
        case AXIS_ANCESTOR_OR_SELF:
10904
0
            first = NULL;
10905
0
            next = xmlXPathNextAncestorOrSelf;
10906
0
            break;
10907
0
        case AXIS_ATTRIBUTE:
10908
0
            first = NULL;
10909
0
      last = NULL;
10910
0
            next = xmlXPathNextAttribute;
10911
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10912
0
            break;
10913
0
        case AXIS_CHILD:
10914
0
      last = NULL;
10915
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10916
0
    (type == NODE_TYPE_NODE))
10917
0
      {
10918
    /*
10919
    * Optimization if an element node type is 'element'.
10920
    */
10921
0
    next = xmlXPathNextChildElement;
10922
0
      } else
10923
0
    next = xmlXPathNextChild;
10924
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10925
0
            break;
10926
0
        case AXIS_DESCENDANT:
10927
0
      last = NULL;
10928
0
            next = xmlXPathNextDescendant;
10929
0
            break;
10930
0
        case AXIS_DESCENDANT_OR_SELF:
10931
0
      last = NULL;
10932
0
            next = xmlXPathNextDescendantOrSelf;
10933
0
            break;
10934
0
        case AXIS_FOLLOWING:
10935
0
      last = NULL;
10936
0
            next = xmlXPathNextFollowing;
10937
0
            break;
10938
0
        case AXIS_FOLLOWING_SIBLING:
10939
0
      last = NULL;
10940
0
            next = xmlXPathNextFollowingSibling;
10941
0
            break;
10942
0
        case AXIS_NAMESPACE:
10943
0
            first = NULL;
10944
0
      last = NULL;
10945
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10946
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10947
0
            break;
10948
0
        case AXIS_PARENT:
10949
0
            first = NULL;
10950
0
            next = xmlXPathNextParent;
10951
0
            break;
10952
0
        case AXIS_PRECEDING:
10953
0
            first = NULL;
10954
0
            next = xmlXPathNextPrecedingInternal;
10955
0
            break;
10956
0
        case AXIS_PRECEDING_SIBLING:
10957
0
            first = NULL;
10958
0
            next = xmlXPathNextPrecedingSibling;
10959
0
            break;
10960
0
        case AXIS_SELF:
10961
0
            first = NULL;
10962
0
      last = NULL;
10963
0
            next = xmlXPathNextSelf;
10964
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10965
0
            break;
10966
0
    }
10967
10968
0
    if (next == NULL) {
10969
0
  xmlXPathReleaseObject(xpctxt, obj);
10970
0
        return(0);
10971
0
    }
10972
0
    contextSeq = obj->nodesetval;
10973
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10974
0
        valuePush(ctxt, obj);
10975
0
        return(0);
10976
0
    }
10977
    /*
10978
    * Predicate optimization ---------------------------------------------
10979
    * If this step has a last predicate, which contains a position(),
10980
    * then we'll optimize (although not exactly "position()", but only
10981
    * the  short-hand form, i.e., "[n]".
10982
    *
10983
    * Example - expression "/foo[parent::bar][1]":
10984
    *
10985
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
10986
    *   ROOT                               -- op->ch1
10987
    *   PREDICATE                          -- op->ch2 (predOp)
10988
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
10989
    *       SORT
10990
    *         COLLECT  'parent' 'name' 'node' bar
10991
    *           NODE
10992
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
10993
    *
10994
    */
10995
0
    maxPos = 0;
10996
0
    predOp = NULL;
10997
0
    hasPredicateRange = 0;
10998
0
    hasAxisRange = 0;
10999
0
    if (op->ch2 != -1) {
11000
  /*
11001
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
11002
  */
11003
0
  predOp = &ctxt->comp->steps[op->ch2];
11004
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
11005
0
      if (predOp->ch1 != -1) {
11006
    /*
11007
    * Use the next inner predicate operator.
11008
    */
11009
0
    predOp = &ctxt->comp->steps[predOp->ch1];
11010
0
    hasPredicateRange = 1;
11011
0
      } else {
11012
    /*
11013
    * There's no other predicate than the [n] predicate.
11014
    */
11015
0
    predOp = NULL;
11016
0
    hasAxisRange = 1;
11017
0
      }
11018
0
  }
11019
0
    }
11020
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11021
    /*
11022
    * Axis traversal -----------------------------------------------------
11023
    */
11024
    /*
11025
     * 2.3 Node Tests
11026
     *  - For the attribute axis, the principal node type is attribute.
11027
     *  - For the namespace axis, the principal node type is namespace.
11028
     *  - For other axes, the principal node type is element.
11029
     *
11030
     * A node test * is true for any node of the
11031
     * principal node type. For example, child::* will
11032
     * select all element children of the context node
11033
     */
11034
0
    oldContextNode = xpctxt->node;
11035
0
    addNode = xmlXPathNodeSetAddUnique;
11036
0
    outSeq = NULL;
11037
0
    seq = NULL;
11038
0
    contextNode = NULL;
11039
0
    contextIdx = 0;
11040
11041
11042
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11043
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
11044
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
11045
11046
0
  if (seq == NULL) {
11047
0
      seq = xmlXPathNodeSetCreate(NULL);
11048
0
      if (seq == NULL) {
11049
0
                xmlXPathPErrMemory(ctxt);
11050
0
    total = 0;
11051
0
    goto error;
11052
0
      }
11053
0
  }
11054
  /*
11055
  * Traverse the axis and test the nodes.
11056
  */
11057
0
  pos = 0;
11058
0
  cur = NULL;
11059
0
  hasNsNodes = 0;
11060
0
        do {
11061
0
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
11062
0
                goto error;
11063
11064
0
            cur = next(ctxt, cur);
11065
0
            if (cur == NULL)
11066
0
                break;
11067
11068
      /*
11069
      * QUESTION TODO: What does the "first" and "last" stuff do?
11070
      */
11071
0
            if ((first != NULL) && (*first != NULL)) {
11072
0
    if (*first == cur)
11073
0
        break;
11074
0
    if (((total % 256) == 0) &&
11075
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11076
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
11077
#else
11078
        (xmlXPathCmpNodes(*first, cur) >= 0))
11079
#endif
11080
0
    {
11081
0
        break;
11082
0
    }
11083
0
      }
11084
0
      if ((last != NULL) && (*last != NULL)) {
11085
0
    if (*last == cur)
11086
0
        break;
11087
0
    if (((total % 256) == 0) &&
11088
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11089
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
11090
#else
11091
        (xmlXPathCmpNodes(cur, *last) >= 0))
11092
#endif
11093
0
    {
11094
0
        break;
11095
0
    }
11096
0
      }
11097
11098
0
            total++;
11099
11100
0
      switch (test) {
11101
0
                case NODE_TEST_NONE:
11102
0
        total = 0;
11103
0
        goto error;
11104
0
                case NODE_TEST_TYPE:
11105
0
        if (type == NODE_TYPE_NODE) {
11106
0
      switch (cur->type) {
11107
0
          case XML_DOCUMENT_NODE:
11108
0
          case XML_HTML_DOCUMENT_NODE:
11109
0
          case XML_ELEMENT_NODE:
11110
0
          case XML_ATTRIBUTE_NODE:
11111
0
          case XML_PI_NODE:
11112
0
          case XML_COMMENT_NODE:
11113
0
          case XML_CDATA_SECTION_NODE:
11114
0
          case XML_TEXT_NODE:
11115
0
        XP_TEST_HIT
11116
0
        break;
11117
0
          case XML_NAMESPACE_DECL: {
11118
0
        if (axis == AXIS_NAMESPACE) {
11119
0
            XP_TEST_HIT_NS
11120
0
        } else {
11121
0
                              hasNsNodes = 1;
11122
0
            XP_TEST_HIT
11123
0
        }
11124
0
        break;
11125
0
                            }
11126
0
          default:
11127
0
        break;
11128
0
      }
11129
0
        } else if (cur->type == (xmlElementType) type) {
11130
0
      if (cur->type == XML_NAMESPACE_DECL)
11131
0
          XP_TEST_HIT_NS
11132
0
      else
11133
0
          XP_TEST_HIT
11134
0
        } else if ((type == NODE_TYPE_TEXT) &&
11135
0
       (cur->type == XML_CDATA_SECTION_NODE))
11136
0
        {
11137
0
      XP_TEST_HIT
11138
0
        }
11139
0
        break;
11140
0
                case NODE_TEST_PI:
11141
0
                    if ((cur->type == XML_PI_NODE) &&
11142
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
11143
0
        {
11144
0
      XP_TEST_HIT
11145
0
                    }
11146
0
                    break;
11147
0
                case NODE_TEST_ALL:
11148
0
                    if (axis == AXIS_ATTRIBUTE) {
11149
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
11150
0
      {
11151
0
                            if (prefix == NULL)
11152
0
          {
11153
0
        XP_TEST_HIT
11154
0
                            } else if ((cur->ns != NULL) &&
11155
0
        (xmlStrEqual(URI, cur->ns->href)))
11156
0
          {
11157
0
        XP_TEST_HIT
11158
0
                            }
11159
0
                        }
11160
0
                    } else if (axis == AXIS_NAMESPACE) {
11161
0
                        if (cur->type == XML_NAMESPACE_DECL)
11162
0
      {
11163
0
          XP_TEST_HIT_NS
11164
0
                        }
11165
0
                    } else {
11166
0
                        if (cur->type == XML_ELEMENT_NODE) {
11167
0
                            if (prefix == NULL)
11168
0
          {
11169
0
        XP_TEST_HIT
11170
11171
0
                            } else if ((cur->ns != NULL) &&
11172
0
        (xmlStrEqual(URI, cur->ns->href)))
11173
0
          {
11174
0
        XP_TEST_HIT
11175
0
                            }
11176
0
                        }
11177
0
                    }
11178
0
                    break;
11179
0
                case NODE_TEST_NS:{
11180
                        /* TODO */
11181
0
                        break;
11182
0
                    }
11183
0
                case NODE_TEST_NAME:
11184
0
                    if (axis == AXIS_ATTRIBUTE) {
11185
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
11186
0
          break;
11187
0
        } else if (axis == AXIS_NAMESPACE) {
11188
0
                        if (cur->type != XML_NAMESPACE_DECL)
11189
0
          break;
11190
0
        } else {
11191
0
            if (cur->type != XML_ELEMENT_NODE)
11192
0
          break;
11193
0
        }
11194
0
                    switch (cur->type) {
11195
0
                        case XML_ELEMENT_NODE:
11196
0
                            if (xmlStrEqual(name, cur->name)) {
11197
0
                                if (prefix == NULL) {
11198
0
                                    if (cur->ns == NULL)
11199
0
            {
11200
0
          XP_TEST_HIT
11201
0
                                    }
11202
0
                                } else {
11203
0
                                    if ((cur->ns != NULL) &&
11204
0
                                        (xmlStrEqual(URI, cur->ns->href)))
11205
0
            {
11206
0
          XP_TEST_HIT
11207
0
                                    }
11208
0
                                }
11209
0
                            }
11210
0
                            break;
11211
0
                        case XML_ATTRIBUTE_NODE:{
11212
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
11213
11214
0
                                if (xmlStrEqual(name, attr->name)) {
11215
0
                                    if (prefix == NULL) {
11216
0
                                        if ((attr->ns == NULL) ||
11217
0
                                            (attr->ns->prefix == NULL))
11218
0
          {
11219
0
              XP_TEST_HIT
11220
0
                                        }
11221
0
                                    } else {
11222
0
                                        if ((attr->ns != NULL) &&
11223
0
                                            (xmlStrEqual(URI,
11224
0
                attr->ns->href)))
11225
0
          {
11226
0
              XP_TEST_HIT
11227
0
                                        }
11228
0
                                    }
11229
0
                                }
11230
0
                                break;
11231
0
                            }
11232
0
                        case XML_NAMESPACE_DECL:
11233
0
                            if (cur->type == XML_NAMESPACE_DECL) {
11234
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
11235
11236
0
                                if ((ns->prefix != NULL) && (name != NULL)
11237
0
                                    && (xmlStrEqual(ns->prefix, name)))
11238
0
        {
11239
0
            XP_TEST_HIT_NS
11240
0
                                }
11241
0
                            }
11242
0
                            break;
11243
0
                        default:
11244
0
                            break;
11245
0
                    }
11246
0
                    break;
11247
0
      } /* switch(test) */
11248
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11249
11250
0
  goto apply_predicates;
11251
11252
0
axis_range_end: /* ----------------------------------------------------- */
11253
  /*
11254
  * We have a "/foo[n]", and position() = n was reached.
11255
  * Note that we can have as well "/foo/::parent::foo[1]", so
11256
  * a duplicate-aware merge is still needed.
11257
  * Merge with the result.
11258
  */
11259
0
  if (outSeq == NULL) {
11260
0
      outSeq = seq;
11261
0
      seq = NULL;
11262
0
  } else {
11263
0
      outSeq = mergeAndClear(outSeq, seq);
11264
0
            if (outSeq == NULL)
11265
0
                xmlXPathPErrMemory(ctxt);
11266
0
        }
11267
  /*
11268
  * Break if only a true/false result was requested.
11269
  */
11270
0
  if (toBool)
11271
0
      break;
11272
0
  continue;
11273
11274
0
first_hit: /* ---------------------------------------------------------- */
11275
  /*
11276
  * Break if only a true/false result was requested and
11277
  * no predicates existed and a node test succeeded.
11278
  */
11279
0
  if (outSeq == NULL) {
11280
0
      outSeq = seq;
11281
0
      seq = NULL;
11282
0
  } else {
11283
0
      outSeq = mergeAndClear(outSeq, seq);
11284
0
            if (outSeq == NULL)
11285
0
                xmlXPathPErrMemory(ctxt);
11286
0
        }
11287
0
  break;
11288
11289
0
apply_predicates: /* --------------------------------------------------- */
11290
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
11291
0
      goto error;
11292
11293
        /*
11294
  * Apply predicates.
11295
  */
11296
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
11297
      /*
11298
      * E.g. when we have a "/foo[some expression][n]".
11299
      */
11300
      /*
11301
      * QUESTION TODO: The old predicate evaluation took into
11302
      *  account location-sets.
11303
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11304
      *  Do we expect such a set here?
11305
      *  All what I learned now from the evaluation semantics
11306
      *  does not indicate that a location-set will be processed
11307
      *  here, so this looks OK.
11308
      */
11309
      /*
11310
      * Iterate over all predicates, starting with the outermost
11311
      * predicate.
11312
      * TODO: Problem: we cannot execute the inner predicates first
11313
      *  since we cannot go back *up* the operator tree!
11314
      *  Options we have:
11315
      *  1) Use of recursive functions (like is it currently done
11316
      *     via xmlXPathCompOpEval())
11317
      *  2) Add a predicate evaluation information stack to the
11318
      *     context struct
11319
      *  3) Change the way the operators are linked; we need a
11320
      *     "parent" field on xmlXPathStepOp
11321
      *
11322
      * For the moment, I'll try to solve this with a recursive
11323
      * function: xmlXPathCompOpEvalPredicate().
11324
      */
11325
0
      if (hasPredicateRange != 0)
11326
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11327
0
              hasNsNodes);
11328
0
      else
11329
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11330
0
              hasNsNodes);
11331
11332
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
11333
0
    total = 0;
11334
0
    goto error;
11335
0
      }
11336
0
        }
11337
11338
0
        if (seq->nodeNr > 0) {
11339
      /*
11340
      * Add to result set.
11341
      */
11342
0
      if (outSeq == NULL) {
11343
0
    outSeq = seq;
11344
0
    seq = NULL;
11345
0
      } else {
11346
0
    outSeq = mergeAndClear(outSeq, seq);
11347
0
                if (outSeq == NULL)
11348
0
                    xmlXPathPErrMemory(ctxt);
11349
0
      }
11350
11351
0
            if (toBool)
11352
0
                break;
11353
0
  }
11354
0
    }
11355
11356
0
error:
11357
0
    if ((obj->boolval) && (obj->user != NULL)) {
11358
  /*
11359
  * QUESTION TODO: What does this do and why?
11360
  * TODO: Do we have to do this also for the "error"
11361
  * cleanup further down?
11362
  */
11363
0
  ctxt->value->boolval = 1;
11364
0
  ctxt->value->user = obj->user;
11365
0
  obj->user = NULL;
11366
0
  obj->boolval = 0;
11367
0
    }
11368
0
    xmlXPathReleaseObject(xpctxt, obj);
11369
11370
    /*
11371
    * Ensure we return at least an empty set.
11372
    */
11373
0
    if (outSeq == NULL) {
11374
0
  if ((seq != NULL) && (seq->nodeNr == 0)) {
11375
0
      outSeq = seq;
11376
0
        } else {
11377
0
      outSeq = xmlXPathNodeSetCreate(NULL);
11378
0
            if (outSeq == NULL)
11379
0
                xmlXPathPErrMemory(ctxt);
11380
0
        }
11381
0
    }
11382
0
    if ((seq != NULL) && (seq != outSeq)) {
11383
0
   xmlXPathFreeNodeSet(seq);
11384
0
    }
11385
    /*
11386
    * Hand over the result. Better to push the set also in
11387
    * case of errors.
11388
    */
11389
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
11390
    /*
11391
    * Reset the context node.
11392
    */
11393
0
    xpctxt->node = oldContextNode;
11394
    /*
11395
    * When traversing the namespace axis in "toBool" mode, it's
11396
    * possible that tmpNsList wasn't freed.
11397
    */
11398
0
    if (xpctxt->tmpNsList != NULL) {
11399
0
        xmlFree(xpctxt->tmpNsList);
11400
0
        xpctxt->tmpNsList = NULL;
11401
0
    }
11402
11403
0
    return(total);
11404
0
}
11405
11406
static int
11407
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11408
            xmlXPathStepOpPtr op, xmlNodePtr * first);
11409
11410
/**
11411
 * xmlXPathCompOpEvalFirst:
11412
 * @ctxt:  the XPath parser context with the compiled expression
11413
 * @op:  an XPath compiled operation
11414
 * @first:  the first elem found so far
11415
 *
11416
 * Evaluate the Precompiled XPath operation searching only the first
11417
 * element in document order
11418
 *
11419
 * Returns the number of examined objects.
11420
 */
11421
static int
11422
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11423
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
11424
0
{
11425
0
    int total = 0, cur;
11426
0
    xmlXPathCompExprPtr comp;
11427
0
    xmlXPathObjectPtr arg1, arg2;
11428
11429
0
    CHECK_ERROR0;
11430
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11431
0
        return(0);
11432
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11433
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11434
0
    ctxt->context->depth += 1;
11435
0
    comp = ctxt->comp;
11436
0
    switch (op->op) {
11437
0
        case XPATH_OP_END:
11438
0
            break;
11439
0
        case XPATH_OP_UNION:
11440
0
            total =
11441
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11442
0
                                        first);
11443
0
      CHECK_ERROR0;
11444
0
            if ((ctxt->value != NULL)
11445
0
                && (ctxt->value->type == XPATH_NODESET)
11446
0
                && (ctxt->value->nodesetval != NULL)
11447
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
11448
                /*
11449
                 * limit tree traversing to first node in the result
11450
                 */
11451
    /*
11452
    * OPTIMIZE TODO: This implicitly sorts
11453
    *  the result, even if not needed. E.g. if the argument
11454
    *  of the count() function, no sorting is needed.
11455
    * OPTIMIZE TODO: How do we know if the node-list wasn't
11456
    *  already sorted?
11457
    */
11458
0
    if (ctxt->value->nodesetval->nodeNr > 1)
11459
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
11460
0
                *first = ctxt->value->nodesetval->nodeTab[0];
11461
0
            }
11462
0
            cur =
11463
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11464
0
                                        first);
11465
0
      CHECK_ERROR0;
11466
11467
0
            arg2 = valuePop(ctxt);
11468
0
            arg1 = valuePop(ctxt);
11469
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11470
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11471
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11472
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11473
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11474
0
            }
11475
0
            if ((ctxt->context->opLimit != 0) &&
11476
0
                (((arg1->nodesetval != NULL) &&
11477
0
                  (xmlXPathCheckOpLimit(ctxt,
11478
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11479
0
                 ((arg2->nodesetval != NULL) &&
11480
0
                  (xmlXPathCheckOpLimit(ctxt,
11481
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11482
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11483
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11484
0
                break;
11485
0
            }
11486
11487
0
            if ((arg2->nodesetval != NULL) &&
11488
0
                (arg2->nodesetval->nodeNr != 0)) {
11489
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11490
0
                                                        arg2->nodesetval);
11491
0
                if (arg1->nodesetval == NULL)
11492
0
                    xmlXPathPErrMemory(ctxt);
11493
0
            }
11494
0
            valuePush(ctxt, arg1);
11495
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11496
            /* optimizer */
11497
0
      if (total > cur)
11498
0
    xmlXPathCompSwap(op);
11499
0
            total += cur;
11500
0
            break;
11501
0
        case XPATH_OP_ROOT:
11502
0
            xmlXPathRoot(ctxt);
11503
0
            break;
11504
0
        case XPATH_OP_NODE:
11505
0
            if (op->ch1 != -1)
11506
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11507
0
      CHECK_ERROR0;
11508
0
            if (op->ch2 != -1)
11509
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11510
0
      CHECK_ERROR0;
11511
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11512
0
    ctxt->context->node));
11513
0
            break;
11514
0
        case XPATH_OP_COLLECT:{
11515
0
                if (op->ch1 == -1)
11516
0
                    break;
11517
11518
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11519
0
    CHECK_ERROR0;
11520
11521
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11522
0
                break;
11523
0
            }
11524
0
        case XPATH_OP_VALUE:
11525
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11526
0
            break;
11527
0
        case XPATH_OP_SORT:
11528
0
            if (op->ch1 != -1)
11529
0
                total +=
11530
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11531
0
                                            first);
11532
0
      CHECK_ERROR0;
11533
0
            if ((ctxt->value != NULL)
11534
0
                && (ctxt->value->type == XPATH_NODESET)
11535
0
                && (ctxt->value->nodesetval != NULL)
11536
0
    && (ctxt->value->nodesetval->nodeNr > 1))
11537
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11538
0
            break;
11539
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
11540
0
  case XPATH_OP_FILTER:
11541
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11542
0
            break;
11543
0
#endif
11544
0
        default:
11545
0
            total += xmlXPathCompOpEval(ctxt, op);
11546
0
            break;
11547
0
    }
11548
11549
0
    ctxt->context->depth -= 1;
11550
0
    return(total);
11551
0
}
11552
11553
/**
11554
 * xmlXPathCompOpEvalLast:
11555
 * @ctxt:  the XPath parser context with the compiled expression
11556
 * @op:  an XPath compiled operation
11557
 * @last:  the last elem found so far
11558
 *
11559
 * Evaluate the Precompiled XPath operation searching only the last
11560
 * element in document order
11561
 *
11562
 * Returns the number of nodes traversed
11563
 */
11564
static int
11565
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11566
                       xmlNodePtr * last)
11567
0
{
11568
0
    int total = 0, cur;
11569
0
    xmlXPathCompExprPtr comp;
11570
0
    xmlXPathObjectPtr arg1, arg2;
11571
11572
0
    CHECK_ERROR0;
11573
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11574
0
        return(0);
11575
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11576
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11577
0
    ctxt->context->depth += 1;
11578
0
    comp = ctxt->comp;
11579
0
    switch (op->op) {
11580
0
        case XPATH_OP_END:
11581
0
            break;
11582
0
        case XPATH_OP_UNION:
11583
0
            total =
11584
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11585
0
      CHECK_ERROR0;
11586
0
            if ((ctxt->value != NULL)
11587
0
                && (ctxt->value->type == XPATH_NODESET)
11588
0
                && (ctxt->value->nodesetval != NULL)
11589
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
11590
                /*
11591
                 * limit tree traversing to first node in the result
11592
                 */
11593
0
    if (ctxt->value->nodesetval->nodeNr > 1)
11594
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
11595
0
                *last =
11596
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
11597
0
                                                     nodesetval->nodeNr -
11598
0
                                                     1];
11599
0
            }
11600
0
            cur =
11601
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11602
0
      CHECK_ERROR0;
11603
0
            if ((ctxt->value != NULL)
11604
0
                && (ctxt->value->type == XPATH_NODESET)
11605
0
                && (ctxt->value->nodesetval != NULL)
11606
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11607
0
            }
11608
11609
0
            arg2 = valuePop(ctxt);
11610
0
            arg1 = valuePop(ctxt);
11611
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11612
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11613
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11614
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11615
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11616
0
            }
11617
0
            if ((ctxt->context->opLimit != 0) &&
11618
0
                (((arg1->nodesetval != NULL) &&
11619
0
                  (xmlXPathCheckOpLimit(ctxt,
11620
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11621
0
                 ((arg2->nodesetval != NULL) &&
11622
0
                  (xmlXPathCheckOpLimit(ctxt,
11623
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11624
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11625
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11626
0
                break;
11627
0
            }
11628
11629
0
            if ((arg2->nodesetval != NULL) &&
11630
0
                (arg2->nodesetval->nodeNr != 0)) {
11631
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11632
0
                                                        arg2->nodesetval);
11633
0
                if (arg1->nodesetval == NULL)
11634
0
                    xmlXPathPErrMemory(ctxt);
11635
0
            }
11636
0
            valuePush(ctxt, arg1);
11637
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11638
            /* optimizer */
11639
0
      if (total > cur)
11640
0
    xmlXPathCompSwap(op);
11641
0
            total += cur;
11642
0
            break;
11643
0
        case XPATH_OP_ROOT:
11644
0
            xmlXPathRoot(ctxt);
11645
0
            break;
11646
0
        case XPATH_OP_NODE:
11647
0
            if (op->ch1 != -1)
11648
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11649
0
      CHECK_ERROR0;
11650
0
            if (op->ch2 != -1)
11651
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11652
0
      CHECK_ERROR0;
11653
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11654
0
    ctxt->context->node));
11655
0
            break;
11656
0
        case XPATH_OP_COLLECT:{
11657
0
                if (op->ch1 == -1)
11658
0
                    break;
11659
11660
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11661
0
    CHECK_ERROR0;
11662
11663
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11664
0
                break;
11665
0
            }
11666
0
        case XPATH_OP_VALUE:
11667
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11668
0
            break;
11669
0
        case XPATH_OP_SORT:
11670
0
            if (op->ch1 != -1)
11671
0
                total +=
11672
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11673
0
                                           last);
11674
0
      CHECK_ERROR0;
11675
0
            if ((ctxt->value != NULL)
11676
0
                && (ctxt->value->type == XPATH_NODESET)
11677
0
                && (ctxt->value->nodesetval != NULL)
11678
0
    && (ctxt->value->nodesetval->nodeNr > 1))
11679
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11680
0
            break;
11681
0
        default:
11682
0
            total += xmlXPathCompOpEval(ctxt, op);
11683
0
            break;
11684
0
    }
11685
11686
0
    ctxt->context->depth -= 1;
11687
0
    return (total);
11688
0
}
11689
11690
#ifdef XP_OPTIMIZED_FILTER_FIRST
11691
static int
11692
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11693
            xmlXPathStepOpPtr op, xmlNodePtr * first)
11694
0
{
11695
0
    int total = 0;
11696
0
    xmlXPathCompExprPtr comp;
11697
0
    xmlXPathObjectPtr obj;
11698
0
    xmlNodeSetPtr set;
11699
11700
0
    CHECK_ERROR0;
11701
0
    comp = ctxt->comp;
11702
    /*
11703
    * Optimization for ()[last()] selection i.e. the last elem
11704
    */
11705
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
11706
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11707
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11708
0
  int f = comp->steps[op->ch2].ch1;
11709
11710
0
  if ((f != -1) &&
11711
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11712
0
      (comp->steps[f].value5 == NULL) &&
11713
0
      (comp->steps[f].value == 0) &&
11714
0
      (comp->steps[f].value4 != NULL) &&
11715
0
      (xmlStrEqual
11716
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
11717
0
      xmlNodePtr last = NULL;
11718
11719
0
      total +=
11720
0
    xmlXPathCompOpEvalLast(ctxt,
11721
0
        &comp->steps[op->ch1],
11722
0
        &last);
11723
0
      CHECK_ERROR0;
11724
      /*
11725
      * The nodeset should be in document order,
11726
      * Keep only the last value
11727
      */
11728
0
      if ((ctxt->value != NULL) &&
11729
0
    (ctxt->value->type == XPATH_NODESET) &&
11730
0
    (ctxt->value->nodesetval != NULL) &&
11731
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
11732
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
11733
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11734
0
    *first = *(ctxt->value->nodesetval->nodeTab);
11735
0
      }
11736
0
      return (total);
11737
0
  }
11738
0
    }
11739
11740
0
    if (op->ch1 != -1)
11741
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11742
0
    CHECK_ERROR0;
11743
0
    if (op->ch2 == -1)
11744
0
  return (total);
11745
0
    if (ctxt->value == NULL)
11746
0
  return (total);
11747
11748
#ifdef LIBXML_XPTR_LOCS_ENABLED
11749
    /*
11750
    * Hum are we filtering the result of an XPointer expression
11751
    */
11752
    if (ctxt->value->type == XPATH_LOCATIONSET) {
11753
        xmlLocationSetPtr locset = ctxt->value->user;
11754
11755
        if (locset != NULL) {
11756
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
11757
            if (locset->locNr > 0)
11758
                *first = (xmlNodePtr) locset->locTab[0]->user;
11759
        }
11760
11761
  return (total);
11762
    }
11763
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11764
11765
    /*
11766
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11767
     * the stack. We have to temporarily remove the nodeset object from the
11768
     * stack to avoid freeing it prematurely.
11769
     */
11770
0
    CHECK_TYPE0(XPATH_NODESET);
11771
0
    obj = valuePop(ctxt);
11772
0
    set = obj->nodesetval;
11773
0
    if (set != NULL) {
11774
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11775
0
        if (set->nodeNr > 0)
11776
0
            *first = set->nodeTab[0];
11777
0
    }
11778
0
    valuePush(ctxt, obj);
11779
11780
0
    return (total);
11781
0
}
11782
#endif /* XP_OPTIMIZED_FILTER_FIRST */
11783
11784
/**
11785
 * xmlXPathCompOpEval:
11786
 * @ctxt:  the XPath parser context with the compiled expression
11787
 * @op:  an XPath compiled operation
11788
 *
11789
 * Evaluate the Precompiled XPath operation
11790
 * Returns the number of nodes traversed
11791
 */
11792
static int
11793
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11794
0
{
11795
0
    int total = 0;
11796
0
    int equal, ret;
11797
0
    xmlXPathCompExprPtr comp;
11798
0
    xmlXPathObjectPtr arg1, arg2;
11799
11800
0
    CHECK_ERROR0;
11801
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11802
0
        return(0);
11803
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11804
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11805
0
    ctxt->context->depth += 1;
11806
0
    comp = ctxt->comp;
11807
0
    switch (op->op) {
11808
0
        case XPATH_OP_END:
11809
0
            break;
11810
0
        case XPATH_OP_AND:
11811
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11812
0
      CHECK_ERROR0;
11813
0
            xmlXPathBooleanFunction(ctxt, 1);
11814
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11815
0
                break;
11816
0
            arg2 = valuePop(ctxt);
11817
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11818
0
      if (ctxt->error) {
11819
0
    xmlXPathFreeObject(arg2);
11820
0
    break;
11821
0
      }
11822
0
            xmlXPathBooleanFunction(ctxt, 1);
11823
0
            if (ctxt->value != NULL)
11824
0
                ctxt->value->boolval &= arg2->boolval;
11825
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11826
0
            break;
11827
0
        case XPATH_OP_OR:
11828
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11829
0
      CHECK_ERROR0;
11830
0
            xmlXPathBooleanFunction(ctxt, 1);
11831
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11832
0
                break;
11833
0
            arg2 = valuePop(ctxt);
11834
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11835
0
      if (ctxt->error) {
11836
0
    xmlXPathFreeObject(arg2);
11837
0
    break;
11838
0
      }
11839
0
            xmlXPathBooleanFunction(ctxt, 1);
11840
0
            if (ctxt->value != NULL)
11841
0
                ctxt->value->boolval |= arg2->boolval;
11842
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11843
0
            break;
11844
0
        case XPATH_OP_EQUAL:
11845
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11846
0
      CHECK_ERROR0;
11847
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11848
0
      CHECK_ERROR0;
11849
0
      if (op->value)
11850
0
    equal = xmlXPathEqualValues(ctxt);
11851
0
      else
11852
0
    equal = xmlXPathNotEqualValues(ctxt);
11853
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11854
0
            break;
11855
0
        case XPATH_OP_CMP:
11856
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11857
0
      CHECK_ERROR0;
11858
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11859
0
      CHECK_ERROR0;
11860
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11861
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11862
0
            break;
11863
0
        case XPATH_OP_PLUS:
11864
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11865
0
      CHECK_ERROR0;
11866
0
            if (op->ch2 != -1) {
11867
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11868
0
      }
11869
0
      CHECK_ERROR0;
11870
0
            if (op->value == 0)
11871
0
                xmlXPathSubValues(ctxt);
11872
0
            else if (op->value == 1)
11873
0
                xmlXPathAddValues(ctxt);
11874
0
            else if (op->value == 2)
11875
0
                xmlXPathValueFlipSign(ctxt);
11876
0
            else if (op->value == 3) {
11877
0
                CAST_TO_NUMBER;
11878
0
                CHECK_TYPE0(XPATH_NUMBER);
11879
0
            }
11880
0
            break;
11881
0
        case XPATH_OP_MULT:
11882
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11883
0
      CHECK_ERROR0;
11884
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11885
0
      CHECK_ERROR0;
11886
0
            if (op->value == 0)
11887
0
                xmlXPathMultValues(ctxt);
11888
0
            else if (op->value == 1)
11889
0
                xmlXPathDivValues(ctxt);
11890
0
            else if (op->value == 2)
11891
0
                xmlXPathModValues(ctxt);
11892
0
            break;
11893
0
        case XPATH_OP_UNION:
11894
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11895
0
      CHECK_ERROR0;
11896
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11897
0
      CHECK_ERROR0;
11898
11899
0
            arg2 = valuePop(ctxt);
11900
0
            arg1 = valuePop(ctxt);
11901
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11902
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11903
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11904
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11905
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11906
0
            }
11907
0
            if ((ctxt->context->opLimit != 0) &&
11908
0
                (((arg1->nodesetval != NULL) &&
11909
0
                  (xmlXPathCheckOpLimit(ctxt,
11910
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11911
0
                 ((arg2->nodesetval != NULL) &&
11912
0
                  (xmlXPathCheckOpLimit(ctxt,
11913
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11914
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11915
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11916
0
                break;
11917
0
            }
11918
11919
0
      if (((arg2->nodesetval != NULL) &&
11920
0
     (arg2->nodesetval->nodeNr != 0)))
11921
0
      {
11922
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11923
0
              arg2->nodesetval);
11924
0
                if (arg1->nodesetval == NULL)
11925
0
                    xmlXPathPErrMemory(ctxt);
11926
0
      }
11927
11928
0
            valuePush(ctxt, arg1);
11929
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11930
0
            break;
11931
0
        case XPATH_OP_ROOT:
11932
0
            xmlXPathRoot(ctxt);
11933
0
            break;
11934
0
        case XPATH_OP_NODE:
11935
0
            if (op->ch1 != -1)
11936
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11937
0
      CHECK_ERROR0;
11938
0
            if (op->ch2 != -1)
11939
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11940
0
      CHECK_ERROR0;
11941
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11942
0
                                                    ctxt->context->node));
11943
0
            break;
11944
0
        case XPATH_OP_COLLECT:{
11945
0
                if (op->ch1 == -1)
11946
0
                    break;
11947
11948
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11949
0
    CHECK_ERROR0;
11950
11951
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11952
0
                break;
11953
0
            }
11954
0
        case XPATH_OP_VALUE:
11955
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11956
0
            break;
11957
0
        case XPATH_OP_VARIABLE:{
11958
0
    xmlXPathObjectPtr val;
11959
11960
0
                if (op->ch1 != -1)
11961
0
                    total +=
11962
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11963
0
                if (op->value5 == NULL) {
11964
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
11965
0
        if (val == NULL)
11966
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11967
0
                    valuePush(ctxt, val);
11968
0
    } else {
11969
0
                    const xmlChar *URI;
11970
11971
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
11972
0
                    if (URI == NULL) {
11973
0
                        XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11974
0
                        break;
11975
0
                    }
11976
0
        val = xmlXPathVariableLookupNS(ctxt->context,
11977
0
                                                       op->value4, URI);
11978
0
        if (val == NULL)
11979
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11980
0
                    valuePush(ctxt, val);
11981
0
                }
11982
0
                break;
11983
0
            }
11984
0
        case XPATH_OP_FUNCTION:{
11985
0
                xmlXPathFunction func;
11986
0
                const xmlChar *oldFunc, *oldFuncURI;
11987
0
    int i;
11988
0
                int frame;
11989
11990
0
                frame = ctxt->valueNr;
11991
0
                if (op->ch1 != -1) {
11992
0
                    total +=
11993
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11994
0
                    if (ctxt->error != XPATH_EXPRESSION_OK)
11995
0
                        break;
11996
0
                }
11997
0
    if (ctxt->valueNr < frame + op->value)
11998
0
        XP_ERROR0(XPATH_INVALID_OPERAND);
11999
0
    for (i = 0; i < op->value; i++) {
12000
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
12001
0
      XP_ERROR0(XPATH_INVALID_OPERAND);
12002
0
                }
12003
0
                if (op->cache != NULL)
12004
0
                    func = op->cache;
12005
0
                else {
12006
0
                    const xmlChar *URI = NULL;
12007
12008
0
                    if (op->value5 == NULL)
12009
0
                        func =
12010
0
                            xmlXPathFunctionLookup(ctxt->context,
12011
0
                                                   op->value4);
12012
0
                    else {
12013
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
12014
0
                        if (URI == NULL)
12015
0
                            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12016
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
12017
0
                                                        op->value4, URI);
12018
0
                    }
12019
0
                    if (func == NULL)
12020
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12021
0
                    op->cache = func;
12022
0
                    op->cacheURI = (void *) URI;
12023
0
                }
12024
0
                oldFunc = ctxt->context->function;
12025
0
                oldFuncURI = ctxt->context->functionURI;
12026
0
                ctxt->context->function = op->value4;
12027
0
                ctxt->context->functionURI = op->cacheURI;
12028
0
                func(ctxt, op->value);
12029
0
                ctxt->context->function = oldFunc;
12030
0
                ctxt->context->functionURI = oldFuncURI;
12031
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12032
0
                    (ctxt->valueNr != frame + 1))
12033
0
                    XP_ERROR0(XPATH_STACK_ERROR);
12034
0
                break;
12035
0
            }
12036
0
        case XPATH_OP_ARG:
12037
0
            if (op->ch1 != -1) {
12038
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12039
0
          CHECK_ERROR0;
12040
0
            }
12041
0
            if (op->ch2 != -1) {
12042
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12043
0
          CHECK_ERROR0;
12044
0
      }
12045
0
            break;
12046
0
        case XPATH_OP_PREDICATE:
12047
0
        case XPATH_OP_FILTER:{
12048
0
                xmlXPathObjectPtr obj;
12049
0
                xmlNodeSetPtr set;
12050
12051
                /*
12052
                 * Optimization for ()[1] selection i.e. the first elem
12053
                 */
12054
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
12055
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12056
        /*
12057
        * FILTER TODO: Can we assume that the inner processing
12058
        *  will result in an ordered list if we have an
12059
        *  XPATH_OP_FILTER?
12060
        *  What about an additional field or flag on
12061
        *  xmlXPathObject like @sorted ? This way we wouldn't need
12062
        *  to assume anything, so it would be more robust and
12063
        *  easier to optimize.
12064
        */
12065
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12066
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12067
#else
12068
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12069
#endif
12070
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12071
0
                    xmlXPathObjectPtr val;
12072
12073
0
                    val = comp->steps[op->ch2].value4;
12074
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12075
0
                        (val->floatval == 1.0)) {
12076
0
                        xmlNodePtr first = NULL;
12077
12078
0
                        total +=
12079
0
                            xmlXPathCompOpEvalFirst(ctxt,
12080
0
                                                    &comp->steps[op->ch1],
12081
0
                                                    &first);
12082
0
      CHECK_ERROR0;
12083
                        /*
12084
                         * The nodeset should be in document order,
12085
                         * Keep only the first value
12086
                         */
12087
0
                        if ((ctxt->value != NULL) &&
12088
0
                            (ctxt->value->type == XPATH_NODESET) &&
12089
0
                            (ctxt->value->nodesetval != NULL) &&
12090
0
                            (ctxt->value->nodesetval->nodeNr > 1))
12091
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12092
0
                                                        1, 1);
12093
0
                        break;
12094
0
                    }
12095
0
                }
12096
                /*
12097
                 * Optimization for ()[last()] selection i.e. the last elem
12098
                 */
12099
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
12100
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12101
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12102
0
                    int f = comp->steps[op->ch2].ch1;
12103
12104
0
                    if ((f != -1) &&
12105
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12106
0
                        (comp->steps[f].value5 == NULL) &&
12107
0
                        (comp->steps[f].value == 0) &&
12108
0
                        (comp->steps[f].value4 != NULL) &&
12109
0
                        (xmlStrEqual
12110
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
12111
0
                        xmlNodePtr last = NULL;
12112
12113
0
                        total +=
12114
0
                            xmlXPathCompOpEvalLast(ctxt,
12115
0
                                                   &comp->steps[op->ch1],
12116
0
                                                   &last);
12117
0
      CHECK_ERROR0;
12118
                        /*
12119
                         * The nodeset should be in document order,
12120
                         * Keep only the last value
12121
                         */
12122
0
                        if ((ctxt->value != NULL) &&
12123
0
                            (ctxt->value->type == XPATH_NODESET) &&
12124
0
                            (ctxt->value->nodesetval != NULL) &&
12125
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
12126
0
                            (ctxt->value->nodesetval->nodeNr > 1))
12127
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12128
0
                        break;
12129
0
                    }
12130
0
                }
12131
    /*
12132
    * Process inner predicates first.
12133
    * Example "index[parent::book][1]":
12134
    * ...
12135
    *   PREDICATE   <-- we are here "[1]"
12136
    *     PREDICATE <-- process "[parent::book]" first
12137
    *       SORT
12138
    *         COLLECT  'parent' 'name' 'node' book
12139
    *           NODE
12140
    *     ELEM Object is a number : 1
12141
    */
12142
0
                if (op->ch1 != -1)
12143
0
                    total +=
12144
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12145
0
    CHECK_ERROR0;
12146
0
                if (op->ch2 == -1)
12147
0
                    break;
12148
0
                if (ctxt->value == NULL)
12149
0
                    break;
12150
12151
#ifdef LIBXML_XPTR_LOCS_ENABLED
12152
                /*
12153
                 * Hum are we filtering the result of an XPointer expression
12154
                 */
12155
                if (ctxt->value->type == XPATH_LOCATIONSET) {
12156
                    xmlLocationSetPtr locset = ctxt->value->user;
12157
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12158
                                              1, locset->locNr);
12159
                    break;
12160
                }
12161
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12162
12163
                /*
12164
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
12165
                 * nodes from the stack. We have to temporarily remove the
12166
                 * nodeset object from the stack to avoid freeing it
12167
                 * prematurely.
12168
                 */
12169
0
                CHECK_TYPE0(XPATH_NODESET);
12170
0
                obj = valuePop(ctxt);
12171
0
                set = obj->nodesetval;
12172
0
                if (set != NULL)
12173
0
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12174
0
                                          1, set->nodeNr, 1);
12175
0
                valuePush(ctxt, obj);
12176
0
                break;
12177
0
            }
12178
0
        case XPATH_OP_SORT:
12179
0
            if (op->ch1 != -1)
12180
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12181
0
      CHECK_ERROR0;
12182
0
            if ((ctxt->value != NULL) &&
12183
0
                (ctxt->value->type == XPATH_NODESET) &&
12184
0
                (ctxt->value->nodesetval != NULL) &&
12185
0
    (ctxt->value->nodesetval->nodeNr > 1))
12186
0
      {
12187
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12188
0
      }
12189
0
            break;
12190
#ifdef LIBXML_XPTR_LOCS_ENABLED
12191
        case XPATH_OP_RANGETO:{
12192
                xmlXPathObjectPtr range;
12193
                xmlXPathObjectPtr res, obj;
12194
                xmlXPathObjectPtr tmp;
12195
                xmlLocationSetPtr newlocset = NULL;
12196
        xmlLocationSetPtr oldlocset;
12197
                xmlNodeSetPtr oldset;
12198
                xmlNodePtr oldnode = ctxt->context->node;
12199
                int oldcs = ctxt->context->contextSize;
12200
                int oldpp = ctxt->context->proximityPosition;
12201
                int i, j;
12202
12203
                if (op->ch1 != -1) {
12204
                    total +=
12205
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12206
                    CHECK_ERROR0;
12207
                }
12208
                if (ctxt->value == NULL) {
12209
                    XP_ERROR0(XPATH_INVALID_OPERAND);
12210
                }
12211
                if (op->ch2 == -1)
12212
                    break;
12213
12214
                if (ctxt->value->type == XPATH_LOCATIONSET) {
12215
                    /*
12216
                     * Extract the old locset, and then evaluate the result of the
12217
                     * expression for all the element in the locset. use it to grow
12218
                     * up a new locset.
12219
                     */
12220
                    CHECK_TYPE0(XPATH_LOCATIONSET);
12221
12222
                    if ((ctxt->value->user == NULL) ||
12223
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12224
                        break;
12225
12226
                    obj = valuePop(ctxt);
12227
                    oldlocset = obj->user;
12228
12229
                    newlocset = xmlXPtrLocationSetCreate(NULL);
12230
12231
                    for (i = 0; i < oldlocset->locNr; i++) {
12232
                        /*
12233
                         * Run the evaluation with a node list made of a
12234
                         * single item in the nodelocset.
12235
                         */
12236
                        ctxt->context->node = oldlocset->locTab[i]->user;
12237
                        ctxt->context->contextSize = oldlocset->locNr;
12238
                        ctxt->context->proximityPosition = i + 1;
12239
                        tmp = xmlXPathCacheNewNodeSet(ctxt,
12240
                                                      ctxt->context->node);
12241
                        valuePush(ctxt, tmp);
12242
12243
                        if (op->ch2 != -1)
12244
                            total +=
12245
                                xmlXPathCompOpEval(ctxt,
12246
                                                   &comp->steps[op->ch2]);
12247
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12248
                            xmlXPtrFreeLocationSet(newlocset);
12249
                            goto rangeto_error;
12250
      }
12251
12252
                        res = valuePop(ctxt);
12253
      if (res->type == XPATH_LOCATIONSET) {
12254
          xmlLocationSetPtr rloc =
12255
              (xmlLocationSetPtr)res->user;
12256
          for (j=0; j<rloc->locNr; j++) {
12257
              range = xmlXPtrNewRange(
12258
          oldlocset->locTab[i]->user,
12259
          oldlocset->locTab[i]->index,
12260
          rloc->locTab[j]->user2,
12261
          rloc->locTab[j]->index2);
12262
        if (range != NULL) {
12263
            xmlXPtrLocationSetAdd(newlocset, range);
12264
        }
12265
          }
12266
      } else {
12267
          range = xmlXPtrNewRangeNodeObject(
12268
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
12269
                            if (range != NULL) {
12270
                                xmlXPtrLocationSetAdd(newlocset,range);
12271
          }
12272
                        }
12273
12274
                        /*
12275
                         * Cleanup
12276
                         */
12277
                        if (res != NULL) {
12278
          xmlXPathReleaseObject(ctxt->context, res);
12279
      }
12280
                        if (ctxt->value == tmp) {
12281
                            res = valuePop(ctxt);
12282
          xmlXPathReleaseObject(ctxt->context, res);
12283
                        }
12284
                    }
12285
    } else {  /* Not a location set */
12286
                    CHECK_TYPE0(XPATH_NODESET);
12287
                    obj = valuePop(ctxt);
12288
                    oldset = obj->nodesetval;
12289
12290
                    newlocset = xmlXPtrLocationSetCreate(NULL);
12291
12292
                    if (oldset != NULL) {
12293
                        for (i = 0; i < oldset->nodeNr; i++) {
12294
                            /*
12295
                             * Run the evaluation with a node list made of a single item
12296
                             * in the nodeset.
12297
                             */
12298
                            ctxt->context->node = oldset->nodeTab[i];
12299
          /*
12300
          * OPTIMIZE TODO: Avoid recreation for every iteration.
12301
          */
12302
                            tmp = xmlXPathCacheNewNodeSet(ctxt,
12303
                                                          ctxt->context->node);
12304
                            valuePush(ctxt, tmp);
12305
12306
                            if (op->ch2 != -1)
12307
                                total +=
12308
                                    xmlXPathCompOpEval(ctxt,
12309
                                                   &comp->steps[op->ch2]);
12310
          if (ctxt->error != XPATH_EXPRESSION_OK) {
12311
                                xmlXPtrFreeLocationSet(newlocset);
12312
                                goto rangeto_error;
12313
          }
12314
12315
                            res = valuePop(ctxt);
12316
                            range =
12317
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12318
                                                      res);
12319
                            if (range != NULL) {
12320
                                xmlXPtrLocationSetAdd(newlocset, range);
12321
                            }
12322
12323
                            /*
12324
                             * Cleanup
12325
                             */
12326
                            if (res != NULL) {
12327
        xmlXPathReleaseObject(ctxt->context, res);
12328
          }
12329
                            if (ctxt->value == tmp) {
12330
                                res = valuePop(ctxt);
12331
        xmlXPathReleaseObject(ctxt->context, res);
12332
                            }
12333
                        }
12334
                    }
12335
                }
12336
12337
                /*
12338
                 * The result is used as the new evaluation set.
12339
                 */
12340
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12341
rangeto_error:
12342
    xmlXPathReleaseObject(ctxt->context, obj);
12343
                ctxt->context->node = oldnode;
12344
                ctxt->context->contextSize = oldcs;
12345
                ctxt->context->proximityPosition = oldpp;
12346
                break;
12347
            }
12348
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12349
0
        default:
12350
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
12351
0
            break;
12352
0
    }
12353
12354
0
    ctxt->context->depth -= 1;
12355
0
    return (total);
12356
0
}
12357
12358
/**
12359
 * xmlXPathCompOpEvalToBoolean:
12360
 * @ctxt:  the XPath parser context
12361
 *
12362
 * Evaluates if the expression evaluates to true.
12363
 *
12364
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
12365
 */
12366
static int
12367
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12368
          xmlXPathStepOpPtr op,
12369
          int isPredicate)
12370
0
{
12371
0
    xmlXPathObjectPtr resObj = NULL;
12372
12373
0
start:
12374
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12375
0
        return(0);
12376
    /* comp = ctxt->comp; */
12377
0
    switch (op->op) {
12378
0
        case XPATH_OP_END:
12379
0
            return (0);
12380
0
  case XPATH_OP_VALUE:
12381
0
      resObj = (xmlXPathObjectPtr) op->value4;
12382
0
      if (isPredicate)
12383
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12384
0
      return(xmlXPathCastToBoolean(resObj));
12385
0
  case XPATH_OP_SORT:
12386
      /*
12387
      * We don't need sorting for boolean results. Skip this one.
12388
      */
12389
0
            if (op->ch1 != -1) {
12390
0
    op = &ctxt->comp->steps[op->ch1];
12391
0
    goto start;
12392
0
      }
12393
0
      return(0);
12394
0
  case XPATH_OP_COLLECT:
12395
0
      if (op->ch1 == -1)
12396
0
    return(0);
12397
12398
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12399
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12400
0
    return(-1);
12401
12402
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12403
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12404
0
    return(-1);
12405
12406
0
      resObj = valuePop(ctxt);
12407
0
      if (resObj == NULL)
12408
0
    return(-1);
12409
0
      break;
12410
0
  default:
12411
      /*
12412
      * Fallback to call xmlXPathCompOpEval().
12413
      */
12414
0
      xmlXPathCompOpEval(ctxt, op);
12415
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12416
0
    return(-1);
12417
12418
0
      resObj = valuePop(ctxt);
12419
0
      if (resObj == NULL)
12420
0
    return(-1);
12421
0
      break;
12422
0
    }
12423
12424
0
    if (resObj) {
12425
0
  int res;
12426
12427
0
  if (resObj->type == XPATH_BOOLEAN) {
12428
0
      res = resObj->boolval;
12429
0
  } else if (isPredicate) {
12430
      /*
12431
      * For predicates a result of type "number" is handled
12432
      * differently:
12433
      * SPEC XPath 1.0:
12434
      * "If the result is a number, the result will be converted
12435
      *  to true if the number is equal to the context position
12436
      *  and will be converted to false otherwise;"
12437
      */
12438
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12439
0
  } else {
12440
0
      res = xmlXPathCastToBoolean(resObj);
12441
0
  }
12442
0
  xmlXPathReleaseObject(ctxt->context, resObj);
12443
0
  return(res);
12444
0
    }
12445
12446
0
    return(0);
12447
0
}
12448
12449
#ifdef XPATH_STREAMING
12450
/**
12451
 * xmlXPathRunStreamEval:
12452
 * @pctxt:  the XPath parser context with the compiled expression
12453
 *
12454
 * Evaluate the Precompiled Streamable XPath expression in the given context.
12455
 */
12456
static int
12457
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
12458
          xmlXPathObjectPtr *resultSeq, int toBool)
12459
{
12460
    int max_depth, min_depth;
12461
    int from_root;
12462
    int ret, depth;
12463
    int eval_all_nodes;
12464
    xmlNodePtr cur = NULL, limit = NULL;
12465
    xmlStreamCtxtPtr patstream = NULL;
12466
    xmlXPathContextPtr ctxt = pctxt->context;
12467
12468
    if ((ctxt == NULL) || (comp == NULL))
12469
        return(-1);
12470
    max_depth = xmlPatternMaxDepth(comp);
12471
    if (max_depth == -1)
12472
        return(-1);
12473
    if (max_depth == -2)
12474
        max_depth = 10000;
12475
    min_depth = xmlPatternMinDepth(comp);
12476
    if (min_depth == -1)
12477
        return(-1);
12478
    from_root = xmlPatternFromRoot(comp);
12479
    if (from_root < 0)
12480
        return(-1);
12481
#if 0
12482
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12483
#endif
12484
12485
    if (! toBool) {
12486
  if (resultSeq == NULL)
12487
      return(-1);
12488
  *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
12489
  if (*resultSeq == NULL)
12490
      return(-1);
12491
    }
12492
12493
    /*
12494
     * handle the special cases of "/" amd "." being matched
12495
     */
12496
    if (min_depth == 0) {
12497
        int res;
12498
12499
  if (from_root) {
12500
      /* Select "/" */
12501
      if (toBool)
12502
    return(1);
12503
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12504
                                           (xmlNodePtr) ctxt->doc);
12505
  } else {
12506
      /* Select "self::node()" */
12507
      if (toBool)
12508
    return(1);
12509
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12510
                                           ctxt->node);
12511
  }
12512
12513
        if (res < 0)
12514
            xmlXPathPErrMemory(pctxt);
12515
    }
12516
    if (max_depth == 0) {
12517
  return(0);
12518
    }
12519
12520
    if (from_root) {
12521
        cur = (xmlNodePtr)ctxt->doc;
12522
    } else if (ctxt->node != NULL) {
12523
        switch (ctxt->node->type) {
12524
            case XML_ELEMENT_NODE:
12525
            case XML_DOCUMENT_NODE:
12526
            case XML_DOCUMENT_FRAG_NODE:
12527
            case XML_HTML_DOCUMENT_NODE:
12528
          cur = ctxt->node;
12529
    break;
12530
            case XML_ATTRIBUTE_NODE:
12531
            case XML_TEXT_NODE:
12532
            case XML_CDATA_SECTION_NODE:
12533
            case XML_ENTITY_REF_NODE:
12534
            case XML_ENTITY_NODE:
12535
            case XML_PI_NODE:
12536
            case XML_COMMENT_NODE:
12537
            case XML_NOTATION_NODE:
12538
            case XML_DTD_NODE:
12539
            case XML_DOCUMENT_TYPE_NODE:
12540
            case XML_ELEMENT_DECL:
12541
            case XML_ATTRIBUTE_DECL:
12542
            case XML_ENTITY_DECL:
12543
            case XML_NAMESPACE_DECL:
12544
            case XML_XINCLUDE_START:
12545
            case XML_XINCLUDE_END:
12546
    break;
12547
  }
12548
  limit = cur;
12549
    }
12550
    if (cur == NULL) {
12551
        return(0);
12552
    }
12553
12554
    patstream = xmlPatternGetStreamCtxt(comp);
12555
    if (patstream == NULL) {
12556
        xmlXPathPErrMemory(pctxt);
12557
  return(-1);
12558
    }
12559
12560
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12561
12562
    if (from_root) {
12563
  ret = xmlStreamPush(patstream, NULL, NULL);
12564
  if (ret < 0) {
12565
  } else if (ret == 1) {
12566
      if (toBool)
12567
    goto return_1;
12568
      if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
12569
                xmlXPathPErrMemory(pctxt);
12570
  }
12571
    }
12572
    depth = 0;
12573
    goto scan_children;
12574
next_node:
12575
    do {
12576
        if (ctxt->opLimit != 0) {
12577
            if (ctxt->opCount >= ctxt->opLimit) {
12578
                xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
12579
                xmlFreeStreamCtxt(patstream);
12580
                return(-1);
12581
            }
12582
            ctxt->opCount++;
12583
        }
12584
12585
  switch (cur->type) {
12586
      case XML_ELEMENT_NODE:
12587
      case XML_TEXT_NODE:
12588
      case XML_CDATA_SECTION_NODE:
12589
      case XML_COMMENT_NODE:
12590
      case XML_PI_NODE:
12591
    if (cur->type == XML_ELEMENT_NODE) {
12592
        ret = xmlStreamPush(patstream, cur->name,
12593
        (cur->ns ? cur->ns->href : NULL));
12594
    } else if (eval_all_nodes)
12595
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12596
    else
12597
        break;
12598
12599
    if (ret < 0) {
12600
        xmlXPathPErrMemory(pctxt);
12601
    } else if (ret == 1) {
12602
        if (toBool)
12603
      goto return_1;
12604
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12605
                                                 cur) < 0)
12606
                        xmlXPathPErrMemory(pctxt);
12607
    }
12608
    if ((cur->children == NULL) || (depth >= max_depth)) {
12609
        ret = xmlStreamPop(patstream);
12610
        while (cur->next != NULL) {
12611
      cur = cur->next;
12612
      if ((cur->type != XML_ENTITY_DECL) &&
12613
          (cur->type != XML_DTD_NODE))
12614
          goto next_node;
12615
        }
12616
    }
12617
      default:
12618
    break;
12619
  }
12620
12621
scan_children:
12622
  if (cur->type == XML_NAMESPACE_DECL) break;
12623
  if ((cur->children != NULL) && (depth < max_depth)) {
12624
      /*
12625
       * Do not descend on entities declarations
12626
       */
12627
      if (cur->children->type != XML_ENTITY_DECL) {
12628
    cur = cur->children;
12629
    depth++;
12630
    /*
12631
     * Skip DTDs
12632
     */
12633
    if (cur->type != XML_DTD_NODE)
12634
        continue;
12635
      }
12636
  }
12637
12638
  if (cur == limit)
12639
      break;
12640
12641
  while (cur->next != NULL) {
12642
      cur = cur->next;
12643
      if ((cur->type != XML_ENTITY_DECL) &&
12644
    (cur->type != XML_DTD_NODE))
12645
    goto next_node;
12646
  }
12647
12648
  do {
12649
      cur = cur->parent;
12650
      depth--;
12651
      if ((cur == NULL) || (cur == limit) ||
12652
                (cur->type == XML_DOCUMENT_NODE))
12653
          goto done;
12654
      if (cur->type == XML_ELEMENT_NODE) {
12655
    ret = xmlStreamPop(patstream);
12656
      } else if ((eval_all_nodes) &&
12657
    ((cur->type == XML_TEXT_NODE) ||
12658
     (cur->type == XML_CDATA_SECTION_NODE) ||
12659
     (cur->type == XML_COMMENT_NODE) ||
12660
     (cur->type == XML_PI_NODE)))
12661
      {
12662
    ret = xmlStreamPop(patstream);
12663
      }
12664
      if (cur->next != NULL) {
12665
    cur = cur->next;
12666
    break;
12667
      }
12668
  } while (cur != NULL);
12669
12670
    } while ((cur != NULL) && (depth >= 0));
12671
12672
done:
12673
12674
    if (patstream)
12675
  xmlFreeStreamCtxt(patstream);
12676
    return(0);
12677
12678
return_1:
12679
    if (patstream)
12680
  xmlFreeStreamCtxt(patstream);
12681
    return(1);
12682
}
12683
#endif /* XPATH_STREAMING */
12684
12685
/**
12686
 * xmlXPathRunEval:
12687
 * @ctxt:  the XPath parser context with the compiled expression
12688
 * @toBool:  evaluate to a boolean result
12689
 *
12690
 * Evaluate the Precompiled XPath expression in the given context.
12691
 */
12692
static int
12693
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12694
0
{
12695
0
    xmlXPathCompExprPtr comp;
12696
0
    int oldDepth;
12697
12698
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
12699
0
  return(-1);
12700
12701
0
    if (ctxt->valueTab == NULL) {
12702
  /* Allocate the value stack */
12703
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
12704
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12705
0
  if (ctxt->valueTab == NULL) {
12706
0
      xmlXPathPErrMemory(ctxt);
12707
0
      return(-1);
12708
0
  }
12709
0
  ctxt->valueNr = 0;
12710
0
  ctxt->valueMax = 10;
12711
0
  ctxt->value = NULL;
12712
0
    }
12713
#ifdef XPATH_STREAMING
12714
    if (ctxt->comp->stream) {
12715
  int res;
12716
12717
  if (toBool) {
12718
      /*
12719
      * Evaluation to boolean result.
12720
      */
12721
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12722
      if (res != -1)
12723
    return(res);
12724
  } else {
12725
      xmlXPathObjectPtr resObj = NULL;
12726
12727
      /*
12728
      * Evaluation to a sequence.
12729
      */
12730
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12731
12732
      if ((res != -1) && (resObj != NULL)) {
12733
    valuePush(ctxt, resObj);
12734
    return(0);
12735
      }
12736
      if (resObj != NULL)
12737
    xmlXPathReleaseObject(ctxt->context, resObj);
12738
  }
12739
  /*
12740
  * QUESTION TODO: This falls back to normal XPath evaluation
12741
  * if res == -1. Is this intended?
12742
  */
12743
    }
12744
#endif
12745
0
    comp = ctxt->comp;
12746
0
    if (comp->last < 0) {
12747
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12748
0
  return(-1);
12749
0
    }
12750
0
    oldDepth = ctxt->context->depth;
12751
0
    if (toBool)
12752
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
12753
0
      &comp->steps[comp->last], 0));
12754
0
    else
12755
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12756
0
    ctxt->context->depth = oldDepth;
12757
12758
0
    return(0);
12759
0
}
12760
12761
/************************************************************************
12762
 *                  *
12763
 *      Public interfaces       *
12764
 *                  *
12765
 ************************************************************************/
12766
12767
/**
12768
 * xmlXPathEvalPredicate:
12769
 * @ctxt:  the XPath context
12770
 * @res:  the Predicate Expression evaluation result
12771
 *
12772
 * Evaluate a predicate result for the current node.
12773
 * A PredicateExpr is evaluated by evaluating the Expr and converting
12774
 * the result to a boolean. If the result is a number, the result will
12775
 * be converted to true if the number is equal to the position of the
12776
 * context node in the context node list (as returned by the position
12777
 * function) and will be converted to false otherwise; if the result
12778
 * is not a number, then the result will be converted as if by a call
12779
 * to the boolean function.
12780
 *
12781
 * Returns 1 if predicate is true, 0 otherwise
12782
 */
12783
int
12784
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12785
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
12786
0
    switch (res->type) {
12787
0
        case XPATH_BOOLEAN:
12788
0
      return(res->boolval);
12789
0
        case XPATH_NUMBER:
12790
0
      return(res->floatval == ctxt->proximityPosition);
12791
0
        case XPATH_NODESET:
12792
0
        case XPATH_XSLT_TREE:
12793
0
      if (res->nodesetval == NULL)
12794
0
    return(0);
12795
0
      return(res->nodesetval->nodeNr != 0);
12796
0
        case XPATH_STRING:
12797
0
      return((res->stringval != NULL) &&
12798
0
             (xmlStrlen(res->stringval) != 0));
12799
0
        default:
12800
0
      break;
12801
0
    }
12802
0
    return(0);
12803
0
}
12804
12805
/**
12806
 * xmlXPathEvaluatePredicateResult:
12807
 * @ctxt:  the XPath Parser context
12808
 * @res:  the Predicate Expression evaluation result
12809
 *
12810
 * Evaluate a predicate result for the current node.
12811
 * A PredicateExpr is evaluated by evaluating the Expr and converting
12812
 * the result to a boolean. If the result is a number, the result will
12813
 * be converted to true if the number is equal to the position of the
12814
 * context node in the context node list (as returned by the position
12815
 * function) and will be converted to false otherwise; if the result
12816
 * is not a number, then the result will be converted as if by a call
12817
 * to the boolean function.
12818
 *
12819
 * Returns 1 if predicate is true, 0 otherwise
12820
 */
12821
int
12822
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12823
0
                                xmlXPathObjectPtr res) {
12824
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
12825
0
    switch (res->type) {
12826
0
        case XPATH_BOOLEAN:
12827
0
      return(res->boolval);
12828
0
        case XPATH_NUMBER:
12829
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12830
      return((res->floatval == ctxt->context->proximityPosition) &&
12831
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12832
#else
12833
0
      return(res->floatval == ctxt->context->proximityPosition);
12834
0
#endif
12835
0
        case XPATH_NODESET:
12836
0
        case XPATH_XSLT_TREE:
12837
0
      if (res->nodesetval == NULL)
12838
0
    return(0);
12839
0
      return(res->nodesetval->nodeNr != 0);
12840
0
        case XPATH_STRING:
12841
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
12842
#ifdef LIBXML_XPTR_LOCS_ENABLED
12843
  case XPATH_LOCATIONSET:{
12844
      xmlLocationSetPtr ptr = res->user;
12845
      if (ptr == NULL)
12846
          return(0);
12847
      return (ptr->locNr != 0);
12848
      }
12849
#endif
12850
0
        default:
12851
0
      break;
12852
0
    }
12853
0
    return(0);
12854
0
}
12855
12856
#ifdef XPATH_STREAMING
12857
/**
12858
 * xmlXPathTryStreamCompile:
12859
 * @ctxt: an XPath context
12860
 * @str:  the XPath expression
12861
 *
12862
 * Try to compile the XPath expression as a streamable subset.
12863
 *
12864
 * Returns the compiled expression or NULL if failed to compile.
12865
 */
12866
static xmlXPathCompExprPtr
12867
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12868
    /*
12869
     * Optimization: use streaming patterns when the XPath expression can
12870
     * be compiled to a stream lookup
12871
     */
12872
    xmlPatternPtr stream;
12873
    xmlXPathCompExprPtr comp;
12874
    xmlDictPtr dict = NULL;
12875
    const xmlChar **namespaces = NULL;
12876
    xmlNsPtr ns;
12877
    int i, j;
12878
12879
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12880
        (!xmlStrchr(str, '@'))) {
12881
  const xmlChar *tmp;
12882
        int res;
12883
12884
  /*
12885
   * We don't try to handle expressions using the verbose axis
12886
   * specifiers ("::"), just the simplified form at this point.
12887
   * Additionally, if there is no list of namespaces available and
12888
   *  there's a ":" in the expression, indicating a prefixed QName,
12889
   *  then we won't try to compile either. xmlPatterncompile() needs
12890
   *  to have a list of namespaces at compilation time in order to
12891
   *  compile prefixed name tests.
12892
   */
12893
  tmp = xmlStrchr(str, ':');
12894
  if ((tmp != NULL) &&
12895
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12896
      return(NULL);
12897
12898
  if (ctxt != NULL) {
12899
      dict = ctxt->dict;
12900
      if (ctxt->nsNr > 0) {
12901
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12902
    if (namespaces == NULL) {
12903
        xmlXPathErrMemory(ctxt);
12904
        return(NULL);
12905
    }
12906
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12907
        ns = ctxt->namespaces[j];
12908
        namespaces[i++] = ns->href;
12909
        namespaces[i++] = ns->prefix;
12910
    }
12911
    namespaces[i++] = NULL;
12912
    namespaces[i] = NULL;
12913
      }
12914
  }
12915
12916
  res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12917
                                    &stream);
12918
  if (namespaces != NULL) {
12919
      xmlFree((xmlChar **)namespaces);
12920
  }
12921
        if (res < 0) {
12922
            xmlXPathErrMemory(ctxt);
12923
            return(NULL);
12924
        }
12925
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12926
      comp = xmlXPathNewCompExpr();
12927
      if (comp == NULL) {
12928
    xmlXPathErrMemory(ctxt);
12929
          xmlFreePattern(stream);
12930
    return(NULL);
12931
      }
12932
      comp->stream = stream;
12933
      comp->dict = dict;
12934
      if (comp->dict)
12935
    xmlDictReference(comp->dict);
12936
      return(comp);
12937
  }
12938
  xmlFreePattern(stream);
12939
    }
12940
    return(NULL);
12941
}
12942
#endif /* XPATH_STREAMING */
12943
12944
static void
12945
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12946
                           xmlXPathStepOpPtr op)
12947
0
{
12948
0
    xmlXPathCompExprPtr comp = pctxt->comp;
12949
0
    xmlXPathContextPtr ctxt;
12950
12951
    /*
12952
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12953
    * internal representation.
12954
    */
12955
12956
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12957
0
        (op->ch1 != -1) &&
12958
0
        (op->ch2 == -1 /* no predicate */))
12959
0
    {
12960
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12961
12962
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12963
0
            ((xmlXPathAxisVal) prevop->value ==
12964
0
                AXIS_DESCENDANT_OR_SELF) &&
12965
0
            (prevop->ch2 == -1) &&
12966
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12967
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12968
0
        {
12969
            /*
12970
            * This is a "descendant-or-self::node()" without predicates.
12971
            * Try to eliminate it.
12972
            */
12973
12974
0
            switch ((xmlXPathAxisVal) op->value) {
12975
0
                case AXIS_CHILD:
12976
0
                case AXIS_DESCENDANT:
12977
                    /*
12978
                    * Convert "descendant-or-self::node()/child::" or
12979
                    * "descendant-or-self::node()/descendant::" to
12980
                    * "descendant::"
12981
                    */
12982
0
                    op->ch1   = prevop->ch1;
12983
0
                    op->value = AXIS_DESCENDANT;
12984
0
                    break;
12985
0
                case AXIS_SELF:
12986
0
                case AXIS_DESCENDANT_OR_SELF:
12987
                    /*
12988
                    * Convert "descendant-or-self::node()/self::" or
12989
                    * "descendant-or-self::node()/descendant-or-self::" to
12990
                    * to "descendant-or-self::"
12991
                    */
12992
0
                    op->ch1   = prevop->ch1;
12993
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
12994
0
                    break;
12995
0
                default:
12996
0
                    break;
12997
0
            }
12998
0
  }
12999
0
    }
13000
13001
    /* OP_VALUE has invalid ch1. */
13002
0
    if (op->op == XPATH_OP_VALUE)
13003
0
        return;
13004
13005
    /* Recurse */
13006
0
    ctxt = pctxt->context;
13007
0
    if (ctxt != NULL) {
13008
0
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
13009
0
            return;
13010
0
        ctxt->depth += 1;
13011
0
    }
13012
0
    if (op->ch1 != -1)
13013
0
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
13014
0
    if (op->ch2 != -1)
13015
0
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
13016
0
    if (ctxt != NULL)
13017
0
        ctxt->depth -= 1;
13018
0
}
13019
13020
/**
13021
 * xmlXPathCtxtCompile:
13022
 * @ctxt: an XPath context
13023
 * @str:  the XPath expression
13024
 *
13025
 * Compile an XPath expression
13026
 *
13027
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13028
 *         the caller has to free the object.
13029
 */
13030
xmlXPathCompExprPtr
13031
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13032
0
    xmlXPathParserContextPtr pctxt;
13033
0
    xmlXPathCompExprPtr comp;
13034
0
    int oldDepth = 0;
13035
13036
#ifdef XPATH_STREAMING
13037
    comp = xmlXPathTryStreamCompile(ctxt, str);
13038
    if (comp != NULL)
13039
        return(comp);
13040
#endif
13041
13042
0
    xmlInitParser();
13043
13044
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
13045
0
    if (pctxt == NULL)
13046
0
        return NULL;
13047
0
    if (ctxt != NULL)
13048
0
        oldDepth = ctxt->depth;
13049
0
    xmlXPathCompileExpr(pctxt, 1);
13050
0
    if (ctxt != NULL)
13051
0
        ctxt->depth = oldDepth;
13052
13053
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
13054
0
    {
13055
0
        xmlXPathFreeParserContext(pctxt);
13056
0
        return(NULL);
13057
0
    }
13058
13059
0
    if (*pctxt->cur != 0) {
13060
  /*
13061
   * aleksey: in some cases this line prints *second* error message
13062
   * (see bug #78858) and probably this should be fixed.
13063
   * However, we are not sure that all error messages are printed
13064
   * out in other places. It's not critical so we leave it as-is for now
13065
   */
13066
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13067
0
  comp = NULL;
13068
0
    } else {
13069
0
  comp = pctxt->comp;
13070
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
13071
0
            if (ctxt != NULL)
13072
0
                oldDepth = ctxt->depth;
13073
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13074
0
            if (ctxt != NULL)
13075
0
                ctxt->depth = oldDepth;
13076
0
  }
13077
0
  pctxt->comp = NULL;
13078
0
    }
13079
0
    xmlXPathFreeParserContext(pctxt);
13080
13081
0
    if (comp != NULL) {
13082
0
  comp->expr = xmlStrdup(str);
13083
0
    }
13084
0
    return(comp);
13085
0
}
13086
13087
/**
13088
 * xmlXPathCompile:
13089
 * @str:  the XPath expression
13090
 *
13091
 * Compile an XPath expression
13092
 *
13093
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13094
 *         the caller has to free the object.
13095
 */
13096
xmlXPathCompExprPtr
13097
0
xmlXPathCompile(const xmlChar *str) {
13098
0
    return(xmlXPathCtxtCompile(NULL, str));
13099
0
}
13100
13101
/**
13102
 * xmlXPathCompiledEvalInternal:
13103
 * @comp:  the compiled XPath expression
13104
 * @ctxt:  the XPath context
13105
 * @resObj: the resulting XPath object or NULL
13106
 * @toBool: 1 if only a boolean result is requested
13107
 *
13108
 * Evaluate the Precompiled XPath expression in the given context.
13109
 * The caller has to free @resObj.
13110
 *
13111
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13112
 *         the caller has to free the object.
13113
 */
13114
static int
13115
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13116
           xmlXPathContextPtr ctxt,
13117
           xmlXPathObjectPtr *resObjPtr,
13118
           int toBool)
13119
0
{
13120
0
    xmlXPathParserContextPtr pctxt;
13121
0
    xmlXPathObjectPtr resObj = NULL;
13122
#ifndef LIBXML_THREAD_ENABLED
13123
    static int reentance = 0;
13124
#endif
13125
0
    int res;
13126
13127
0
    if (comp == NULL)
13128
0
  return(-1);
13129
0
    xmlInitParser();
13130
13131
0
    xmlResetError(&ctxt->lastError);
13132
13133
#ifndef LIBXML_THREAD_ENABLED
13134
    reentance++;
13135
    if (reentance > 1)
13136
  xmlXPathDisableOptimizer = 1;
13137
#endif
13138
13139
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
13140
0
    if (pctxt == NULL)
13141
0
        return(-1);
13142
0
    res = xmlXPathRunEval(pctxt, toBool);
13143
13144
0
    if (pctxt->error == XPATH_EXPRESSION_OK) {
13145
0
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
13146
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
13147
0
        else if (!toBool)
13148
0
            resObj = valuePop(pctxt);
13149
0
    }
13150
13151
0
    if (resObjPtr)
13152
0
        *resObjPtr = resObj;
13153
0
    else
13154
0
        xmlXPathReleaseObject(ctxt, resObj);
13155
13156
0
    pctxt->comp = NULL;
13157
0
    xmlXPathFreeParserContext(pctxt);
13158
#ifndef LIBXML_THREAD_ENABLED
13159
    reentance--;
13160
#endif
13161
13162
0
    return(res);
13163
0
}
13164
13165
/**
13166
 * xmlXPathCompiledEval:
13167
 * @comp:  the compiled XPath expression
13168
 * @ctx:  the XPath context
13169
 *
13170
 * Evaluate the Precompiled XPath expression in the given context.
13171
 *
13172
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13173
 *         the caller has to free the object.
13174
 */
13175
xmlXPathObjectPtr
13176
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13177
0
{
13178
0
    xmlXPathObjectPtr res = NULL;
13179
13180
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13181
0
    return(res);
13182
0
}
13183
13184
/**
13185
 * xmlXPathCompiledEvalToBoolean:
13186
 * @comp:  the compiled XPath expression
13187
 * @ctxt:  the XPath context
13188
 *
13189
 * Applies the XPath boolean() function on the result of the given
13190
 * compiled expression.
13191
 *
13192
 * Returns 1 if the expression evaluated to true, 0 if to false and
13193
 *         -1 in API and internal errors.
13194
 */
13195
int
13196
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13197
            xmlXPathContextPtr ctxt)
13198
0
{
13199
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13200
0
}
13201
13202
/**
13203
 * xmlXPathEvalExpr:
13204
 * @ctxt:  the XPath Parser context
13205
 *
13206
 * Parse and evaluate an XPath expression in the given context,
13207
 * then push the result on the context stack
13208
 */
13209
void
13210
0
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13211
#ifdef XPATH_STREAMING
13212
    xmlXPathCompExprPtr comp;
13213
#endif
13214
0
    int oldDepth = 0;
13215
13216
0
    if (ctxt == NULL)
13217
0
        return;
13218
0
    if (ctxt->context->lastError.code != 0)
13219
0
        return;
13220
13221
#ifdef XPATH_STREAMING
13222
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13223
    if ((comp == NULL) &&
13224
        (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
13225
        xmlXPathPErrMemory(ctxt);
13226
        return;
13227
    }
13228
    if (comp != NULL) {
13229
        if (ctxt->comp != NULL)
13230
      xmlXPathFreeCompExpr(ctxt->comp);
13231
        ctxt->comp = comp;
13232
    } else
13233
#endif
13234
0
    {
13235
0
        if (ctxt->context != NULL)
13236
0
            oldDepth = ctxt->context->depth;
13237
0
  xmlXPathCompileExpr(ctxt, 1);
13238
0
        if (ctxt->context != NULL)
13239
0
            ctxt->context->depth = oldDepth;
13240
0
        CHECK_ERROR;
13241
13242
        /* Check for trailing characters. */
13243
0
        if (*ctxt->cur != 0)
13244
0
            XP_ERROR(XPATH_EXPR_ERROR);
13245
13246
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13247
0
            if (ctxt->context != NULL)
13248
0
                oldDepth = ctxt->context->depth;
13249
0
      xmlXPathOptimizeExpression(ctxt,
13250
0
    &ctxt->comp->steps[ctxt->comp->last]);
13251
0
            if (ctxt->context != NULL)
13252
0
                ctxt->context->depth = oldDepth;
13253
0
        }
13254
0
    }
13255
13256
0
    xmlXPathRunEval(ctxt, 0);
13257
0
}
13258
13259
/**
13260
 * xmlXPathEval:
13261
 * @str:  the XPath expression
13262
 * @ctx:  the XPath context
13263
 *
13264
 * Evaluate the XPath Location Path in the given context.
13265
 *
13266
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13267
 *         the caller has to free the object.
13268
 */
13269
xmlXPathObjectPtr
13270
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13271
0
    xmlXPathParserContextPtr ctxt;
13272
0
    xmlXPathObjectPtr res;
13273
13274
0
    if (ctx == NULL)
13275
0
        return(NULL);
13276
13277
0
    xmlInitParser();
13278
13279
0
    xmlResetError(&ctx->lastError);
13280
13281
0
    ctxt = xmlXPathNewParserContext(str, ctx);
13282
0
    if (ctxt == NULL)
13283
0
        return NULL;
13284
0
    xmlXPathEvalExpr(ctxt);
13285
13286
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
13287
0
  res = NULL;
13288
0
    } else if (ctxt->valueNr != 1) {
13289
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
13290
0
  res = NULL;
13291
0
    } else {
13292
0
  res = valuePop(ctxt);
13293
0
    }
13294
13295
0
    xmlXPathFreeParserContext(ctxt);
13296
0
    return(res);
13297
0
}
13298
13299
/**
13300
 * xmlXPathSetContextNode:
13301
 * @node: the node to to use as the context node
13302
 * @ctx:  the XPath context
13303
 *
13304
 * Sets 'node' as the context node. The node must be in the same
13305
 * document as that associated with the context.
13306
 *
13307
 * Returns -1 in case of error or 0 if successful
13308
 */
13309
int
13310
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13311
0
    if ((node == NULL) || (ctx == NULL))
13312
0
        return(-1);
13313
13314
0
    if (node->doc == ctx->doc) {
13315
0
        ctx->node = node;
13316
0
  return(0);
13317
0
    }
13318
0
    return(-1);
13319
0
}
13320
13321
/**
13322
 * xmlXPathNodeEval:
13323
 * @node: the node to to use as the context node
13324
 * @str:  the XPath expression
13325
 * @ctx:  the XPath context
13326
 *
13327
 * Evaluate the XPath Location Path in the given context. The node 'node'
13328
 * is set as the context node. The context node is not restored.
13329
 *
13330
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13331
 *         the caller has to free the object.
13332
 */
13333
xmlXPathObjectPtr
13334
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13335
0
    if (str == NULL)
13336
0
        return(NULL);
13337
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
13338
0
        return(NULL);
13339
0
    return(xmlXPathEval(str, ctx));
13340
0
}
13341
13342
/**
13343
 * xmlXPathEvalExpression:
13344
 * @str:  the XPath expression
13345
 * @ctxt:  the XPath context
13346
 *
13347
 * Alias for xmlXPathEval().
13348
 *
13349
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13350
 *         the caller has to free the object.
13351
 */
13352
xmlXPathObjectPtr
13353
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13354
0
    return(xmlXPathEval(str, ctxt));
13355
0
}
13356
13357
/************************************************************************
13358
 *                  *
13359
 *  Extra functions not pertaining to the XPath spec    *
13360
 *                  *
13361
 ************************************************************************/
13362
/**
13363
 * xmlXPathEscapeUriFunction:
13364
 * @ctxt:  the XPath Parser context
13365
 * @nargs:  the number of arguments
13366
 *
13367
 * Implement the escape-uri() XPath function
13368
 *    string escape-uri(string $str, bool $escape-reserved)
13369
 *
13370
 * This function applies the URI escaping rules defined in section 2 of [RFC
13371
 * 2396] to the string supplied as $uri-part, which typically represents all
13372
 * or part of a URI. The effect of the function is to replace any special
13373
 * character in the string by an escape sequence of the form %xx%yy...,
13374
 * where xxyy... is the hexadecimal representation of the octets used to
13375
 * represent the character in UTF-8.
13376
 *
13377
 * The set of characters that are escaped depends on the setting of the
13378
 * boolean argument $escape-reserved.
13379
 *
13380
 * If $escape-reserved is true, all characters are escaped other than lower
13381
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13382
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13383
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13384
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13385
 * A-F).
13386
 *
13387
 * If $escape-reserved is false, the behavior differs in that characters
13388
 * referred to in [RFC 2396] as reserved characters are not escaped. These
13389
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13390
 *
13391
 * [RFC 2396] does not define whether escaped URIs should use lower case or
13392
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
13393
 * compared using string comparison functions, this function must always use
13394
 * the upper-case letters A-F.
13395
 *
13396
 * Generally, $escape-reserved should be set to true when escaping a string
13397
 * that is to form a single part of a URI, and to false when escaping an
13398
 * entire URI or URI reference.
13399
 *
13400
 * In the case of non-ascii characters, the string is encoded according to
13401
 * utf-8 and then converted according to RFC 2396.
13402
 *
13403
 * Examples
13404
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13405
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13406
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13407
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13408
 *
13409
 */
13410
static void
13411
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13412
0
    xmlXPathObjectPtr str;
13413
0
    int escape_reserved;
13414
0
    xmlBufPtr target;
13415
0
    xmlChar *cptr;
13416
0
    xmlChar escape[4];
13417
13418
0
    CHECK_ARITY(2);
13419
13420
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
13421
13422
0
    CAST_TO_STRING;
13423
0
    str = valuePop(ctxt);
13424
13425
0
    target = xmlBufCreateSize(64);
13426
13427
0
    escape[0] = '%';
13428
0
    escape[3] = 0;
13429
13430
0
    if (target) {
13431
0
  for (cptr = str->stringval; *cptr; cptr++) {
13432
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
13433
0
    (*cptr >= 'a' && *cptr <= 'z') ||
13434
0
    (*cptr >= '0' && *cptr <= '9') ||
13435
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
13436
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
13437
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13438
0
    (*cptr == '%' &&
13439
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13440
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
13441
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
13442
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13443
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
13444
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
13445
0
    (!escape_reserved &&
13446
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13447
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
13448
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
13449
0
      *cptr == ','))) {
13450
0
    xmlBufAdd(target, cptr, 1);
13451
0
      } else {
13452
0
    if ((*cptr >> 4) < 10)
13453
0
        escape[1] = '0' + (*cptr >> 4);
13454
0
    else
13455
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
13456
0
    if ((*cptr & 0xF) < 10)
13457
0
        escape[2] = '0' + (*cptr & 0xF);
13458
0
    else
13459
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
13460
13461
0
    xmlBufAdd(target, &escape[0], 3);
13462
0
      }
13463
0
  }
13464
0
    }
13465
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
13466
0
    xmlBufFree(target);
13467
0
    xmlXPathReleaseObject(ctxt->context, str);
13468
0
}
13469
13470
/**
13471
 * xmlXPathRegisterAllFunctions:
13472
 * @ctxt:  the XPath context
13473
 *
13474
 * Registers all default XPath functions in this context
13475
 */
13476
void
13477
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13478
0
{
13479
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13480
0
                         xmlXPathBooleanFunction);
13481
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13482
0
                         xmlXPathCeilingFunction);
13483
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13484
0
                         xmlXPathCountFunction);
13485
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13486
0
                         xmlXPathConcatFunction);
13487
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13488
0
                         xmlXPathContainsFunction);
13489
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13490
0
                         xmlXPathIdFunction);
13491
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13492
0
                         xmlXPathFalseFunction);
13493
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13494
0
                         xmlXPathFloorFunction);
13495
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13496
0
                         xmlXPathLastFunction);
13497
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13498
0
                         xmlXPathLangFunction);
13499
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13500
0
                         xmlXPathLocalNameFunction);
13501
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13502
0
                         xmlXPathNotFunction);
13503
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13504
0
                         xmlXPathNameFunction);
13505
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13506
0
                         xmlXPathNamespaceURIFunction);
13507
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13508
0
                         xmlXPathNormalizeFunction);
13509
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13510
0
                         xmlXPathNumberFunction);
13511
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13512
0
                         xmlXPathPositionFunction);
13513
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13514
0
                         xmlXPathRoundFunction);
13515
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13516
0
                         xmlXPathStringFunction);
13517
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13518
0
                         xmlXPathStringLengthFunction);
13519
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13520
0
                         xmlXPathStartsWithFunction);
13521
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13522
0
                         xmlXPathSubstringFunction);
13523
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13524
0
                         xmlXPathSubstringBeforeFunction);
13525
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13526
0
                         xmlXPathSubstringAfterFunction);
13527
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13528
0
                         xmlXPathSumFunction);
13529
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13530
0
                         xmlXPathTrueFunction);
13531
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13532
0
                         xmlXPathTranslateFunction);
13533
13534
0
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13535
0
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13536
0
                         xmlXPathEscapeUriFunction);
13537
0
}
13538
13539
#endif /* LIBXML_XPATH_ENABLED */