Coverage Report

Created: 2024-09-06 07:53

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/xpath.h>
35
#include <libxml/xpathInternals.h>
36
#include <libxml/parserInternals.h>
37
#include <libxml/hash.h>
38
#ifdef LIBXML_DEBUG_ENABLED
39
#include <libxml/debugXML.h>
40
#endif
41
#include <libxml/xmlerror.h>
42
#include <libxml/threads.h>
43
#ifdef LIBXML_PATTERN_ENABLED
44
#include <libxml/pattern.h>
45
#endif
46
47
#include "private/buf.h"
48
#include "private/error.h"
49
#include "private/xpath.h"
50
51
/* Disabled for now */
52
#if 0
53
#ifdef LIBXML_PATTERN_ENABLED
54
#define XPATH_STREAMING
55
#endif
56
#endif
57
58
/**
59
 * WITH_TIM_SORT:
60
 *
61
 * Use the Timsort algorithm provided in timsort.h to sort
62
 * nodeset as this is a great improvement over the old Shell sort
63
 * used in xmlXPathNodeSetSort()
64
 */
65
#define WITH_TIM_SORT
66
67
/*
68
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
69
* If defined, this will use xmlXPathCmpNodesExt() instead of
70
* xmlXPathCmpNodes(). The new function is optimized comparison of
71
* non-element nodes; actually it will speed up comparison only if
72
* xmlXPathOrderDocElems() was called in order to index the elements of
73
* a tree in document order; Libxslt does such an indexing, thus it will
74
* benefit from this optimization.
75
*/
76
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
77
78
/*
79
* XP_OPTIMIZED_FILTER_FIRST:
80
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81
* in a way, that it stop evaluation at the first node.
82
*/
83
#define XP_OPTIMIZED_FILTER_FIRST
84
85
/*
86
 * XPATH_MAX_STEPS:
87
 * when compiling an XPath expression we arbitrary limit the maximum
88
 * number of step operation in the compiled expression. 1000000 is
89
 * an insanely large value which should never be reached under normal
90
 * circumstances
91
 */
92
0
#define XPATH_MAX_STEPS 1000000
93
94
/*
95
 * XPATH_MAX_STACK_DEPTH:
96
 * when evaluating an XPath expression we arbitrary limit the maximum
97
 * number of object allowed to be pushed on the stack. 1000000 is
98
 * an insanely large value which should never be reached under normal
99
 * circumstances
100
 */
101
0
#define XPATH_MAX_STACK_DEPTH 1000000
102
103
/*
104
 * XPATH_MAX_NODESET_LENGTH:
105
 * when evaluating an XPath expression nodesets are created and we
106
 * arbitrary limit the maximum length of those node set. 10000000 is
107
 * an insanely large value which should never be reached under normal
108
 * circumstances, one would first need to construct an in memory tree
109
 * with more than 10 millions nodes.
110
 */
111
0
#define XPATH_MAX_NODESET_LENGTH 10000000
112
113
/*
114
 * XPATH_MAX_RECRUSION_DEPTH:
115
 * Maximum amount of nested functions calls when parsing or evaluating
116
 * expressions
117
 */
118
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
119
0
#define XPATH_MAX_RECURSION_DEPTH 500
120
#elif defined(_WIN32)
121
/* Windows typically limits stack size to 1MB. */
122
#define XPATH_MAX_RECURSION_DEPTH 1000
123
#else
124
#define XPATH_MAX_RECURSION_DEPTH 5000
125
#endif
126
127
/*
128
 * TODO:
129
 * There are a few spots where some tests are done which depend upon ascii
130
 * data.  These should be enhanced for full UTF8 support (see particularly
131
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
132
 */
133
134
#if defined(LIBXML_XPATH_ENABLED)
135
136
/************************************************************************
137
 *                  *
138
 *      Floating point stuff        *
139
 *                  *
140
 ************************************************************************/
141
142
double xmlXPathNAN = 0.0;
143
double xmlXPathPINF = 0.0;
144
double xmlXPathNINF = 0.0;
145
146
/**
147
 * xmlXPathInit:
148
 *
149
 * DEPRECATED: Alias for xmlInitParser.
150
 */
151
void
152
0
xmlXPathInit(void) {
153
0
    xmlInitParser();
154
0
}
155
156
/**
157
 * xmlInitXPathInternal:
158
 *
159
 * Initialize the XPath environment
160
 */
161
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
162
void
163
9.89k
xmlInitXPathInternal(void) {
164
9.89k
#if defined(NAN) && defined(INFINITY)
165
9.89k
    xmlXPathNAN = NAN;
166
9.89k
    xmlXPathPINF = INFINITY;
167
9.89k
    xmlXPathNINF = -INFINITY;
168
#else
169
    /* MSVC doesn't allow division by zero in constant expressions. */
170
    double zero = 0.0;
171
    xmlXPathNAN = 0.0 / zero;
172
    xmlXPathPINF = 1.0 / zero;
173
    xmlXPathNINF = -xmlXPathPINF;
174
#endif
175
9.89k
}
176
177
/**
178
 * xmlXPathIsNaN:
179
 * @val:  a double value
180
 *
181
 * Checks whether a double is a NaN.
182
 *
183
 * Returns 1 if the value is a NaN, 0 otherwise
184
 */
185
int
186
0
xmlXPathIsNaN(double val) {
187
0
#ifdef isnan
188
0
    return isnan(val);
189
#else
190
    return !(val == val);
191
#endif
192
0
}
193
194
/**
195
 * xmlXPathIsInf:
196
 * @val:  a double value
197
 *
198
 * Checks whether a double is an infinity.
199
 *
200
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
201
 */
202
int
203
0
xmlXPathIsInf(double val) {
204
0
#ifdef isinf
205
0
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
206
#else
207
    if (val >= xmlXPathPINF)
208
        return 1;
209
    if (val <= -xmlXPathPINF)
210
        return -1;
211
    return 0;
212
#endif
213
0
}
214
215
/*
216
 * TODO: when compatibility allows remove all "fake node libxslt" strings
217
 *       the test should just be name[0] = ' '
218
 */
219
220
static const xmlNs xmlXPathXMLNamespaceStruct = {
221
    NULL,
222
    XML_NAMESPACE_DECL,
223
    XML_XML_NAMESPACE,
224
    BAD_CAST "xml",
225
    NULL,
226
    NULL
227
};
228
static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
229
230
static void
231
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
232
233
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
234
/**
235
 * xmlXPathCmpNodesExt:
236
 * @node1:  the first node
237
 * @node2:  the second node
238
 *
239
 * Compare two nodes w.r.t document order.
240
 * This one is optimized for handling of non-element nodes.
241
 *
242
 * Returns -2 in case of error 1 if first point < second point, 0 if
243
 *         it's the same node, -1 otherwise
244
 */
245
static int
246
0
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
247
0
    int depth1, depth2;
248
0
    int misc = 0, precedence1 = 0, precedence2 = 0;
249
0
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
250
0
    xmlNodePtr cur, root;
251
0
    ptrdiff_t l1, l2;
252
253
0
    if ((node1 == NULL) || (node2 == NULL))
254
0
  return(-2);
255
256
0
    if (node1 == node2)
257
0
  return(0);
258
259
    /*
260
     * a couple of optimizations which will avoid computations in most cases
261
     */
262
0
    switch (node1->type) {
263
0
  case XML_ELEMENT_NODE:
264
0
      if (node2->type == XML_ELEMENT_NODE) {
265
0
    if ((0 > (ptrdiff_t) node1->content) &&
266
0
        (0 > (ptrdiff_t) node2->content) &&
267
0
        (node1->doc == node2->doc))
268
0
    {
269
0
        l1 = -((ptrdiff_t) node1->content);
270
0
        l2 = -((ptrdiff_t) node2->content);
271
0
        if (l1 < l2)
272
0
      return(1);
273
0
        if (l1 > l2)
274
0
      return(-1);
275
0
    } else
276
0
        goto turtle_comparison;
277
0
      }
278
0
      break;
279
0
  case XML_ATTRIBUTE_NODE:
280
0
      precedence1 = 1; /* element is owner */
281
0
      miscNode1 = node1;
282
0
      node1 = node1->parent;
283
0
      misc = 1;
284
0
      break;
285
0
  case XML_TEXT_NODE:
286
0
  case XML_CDATA_SECTION_NODE:
287
0
  case XML_COMMENT_NODE:
288
0
  case XML_PI_NODE: {
289
0
      miscNode1 = node1;
290
      /*
291
      * Find nearest element node.
292
      */
293
0
      if (node1->prev != NULL) {
294
0
    do {
295
0
        node1 = node1->prev;
296
0
        if (node1->type == XML_ELEMENT_NODE) {
297
0
      precedence1 = 3; /* element in prev-sibl axis */
298
0
      break;
299
0
        }
300
0
        if (node1->prev == NULL) {
301
0
      precedence1 = 2; /* element is parent */
302
      /*
303
      * URGENT TODO: Are there any cases, where the
304
      * parent of such a node is not an element node?
305
      */
306
0
      node1 = node1->parent;
307
0
      break;
308
0
        }
309
0
    } while (1);
310
0
      } else {
311
0
    precedence1 = 2; /* element is parent */
312
0
    node1 = node1->parent;
313
0
      }
314
0
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
315
0
    (0 <= (ptrdiff_t) node1->content)) {
316
    /*
317
    * Fallback for whatever case.
318
    */
319
0
    node1 = miscNode1;
320
0
    precedence1 = 0;
321
0
      } else
322
0
    misc = 1;
323
0
  }
324
0
      break;
325
0
  case XML_NAMESPACE_DECL:
326
      /*
327
      * TODO: why do we return 1 for namespace nodes?
328
      */
329
0
      return(1);
330
0
  default:
331
0
      break;
332
0
    }
333
0
    switch (node2->type) {
334
0
  case XML_ELEMENT_NODE:
335
0
      break;
336
0
  case XML_ATTRIBUTE_NODE:
337
0
      precedence2 = 1; /* element is owner */
338
0
      miscNode2 = node2;
339
0
      node2 = node2->parent;
340
0
      misc = 1;
341
0
      break;
342
0
  case XML_TEXT_NODE:
343
0
  case XML_CDATA_SECTION_NODE:
344
0
  case XML_COMMENT_NODE:
345
0
  case XML_PI_NODE: {
346
0
      miscNode2 = node2;
347
0
      if (node2->prev != NULL) {
348
0
    do {
349
0
        node2 = node2->prev;
350
0
        if (node2->type == XML_ELEMENT_NODE) {
351
0
      precedence2 = 3; /* element in prev-sibl axis */
352
0
      break;
353
0
        }
354
0
        if (node2->prev == NULL) {
355
0
      precedence2 = 2; /* element is parent */
356
0
      node2 = node2->parent;
357
0
      break;
358
0
        }
359
0
    } while (1);
360
0
      } else {
361
0
    precedence2 = 2; /* element is parent */
362
0
    node2 = node2->parent;
363
0
      }
364
0
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
365
0
    (0 <= (ptrdiff_t) node2->content))
366
0
      {
367
0
    node2 = miscNode2;
368
0
    precedence2 = 0;
369
0
      } else
370
0
    misc = 1;
371
0
  }
372
0
      break;
373
0
  case XML_NAMESPACE_DECL:
374
0
      return(1);
375
0
  default:
376
0
      break;
377
0
    }
378
0
    if (misc) {
379
0
  if (node1 == node2) {
380
0
      if (precedence1 == precedence2) {
381
    /*
382
    * The ugly case; but normally there aren't many
383
    * adjacent non-element nodes around.
384
    */
385
0
    cur = miscNode2->prev;
386
0
    while (cur != NULL) {
387
0
        if (cur == miscNode1)
388
0
      return(1);
389
0
        if (cur->type == XML_ELEMENT_NODE)
390
0
      return(-1);
391
0
        cur = cur->prev;
392
0
    }
393
0
    return (-1);
394
0
      } else {
395
    /*
396
    * Evaluate based on higher precedence wrt to the element.
397
    * TODO: This assumes attributes are sorted before content.
398
    *   Is this 100% correct?
399
    */
400
0
    if (precedence1 < precedence2)
401
0
        return(1);
402
0
    else
403
0
        return(-1);
404
0
      }
405
0
  }
406
  /*
407
  * Special case: One of the helper-elements is contained by the other.
408
  * <foo>
409
  *   <node2>
410
  *     <node1>Text-1(precedence1 == 2)</node1>
411
  *   </node2>
412
  *   Text-6(precedence2 == 3)
413
  * </foo>
414
  */
415
0
  if ((precedence2 == 3) && (precedence1 > 1)) {
416
0
      cur = node1->parent;
417
0
      while (cur) {
418
0
    if (cur == node2)
419
0
        return(1);
420
0
    cur = cur->parent;
421
0
      }
422
0
  }
423
0
  if ((precedence1 == 3) && (precedence2 > 1)) {
424
0
      cur = node2->parent;
425
0
      while (cur) {
426
0
    if (cur == node1)
427
0
        return(-1);
428
0
    cur = cur->parent;
429
0
      }
430
0
  }
431
0
    }
432
433
    /*
434
     * Speedup using document order if available.
435
     */
436
0
    if ((node1->type == XML_ELEMENT_NODE) &&
437
0
  (node2->type == XML_ELEMENT_NODE) &&
438
0
  (0 > (ptrdiff_t) node1->content) &&
439
0
  (0 > (ptrdiff_t) node2->content) &&
440
0
  (node1->doc == node2->doc)) {
441
442
0
  l1 = -((ptrdiff_t) node1->content);
443
0
  l2 = -((ptrdiff_t) node2->content);
444
0
  if (l1 < l2)
445
0
      return(1);
446
0
  if (l1 > l2)
447
0
      return(-1);
448
0
    }
449
450
0
turtle_comparison:
451
452
0
    if (node1 == node2->prev)
453
0
  return(1);
454
0
    if (node1 == node2->next)
455
0
  return(-1);
456
    /*
457
     * compute depth to root
458
     */
459
0
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
460
0
  if (cur->parent == node1)
461
0
      return(1);
462
0
  depth2++;
463
0
    }
464
0
    root = cur;
465
0
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
466
0
  if (cur->parent == node2)
467
0
      return(-1);
468
0
  depth1++;
469
0
    }
470
    /*
471
     * Distinct document (or distinct entities :-( ) case.
472
     */
473
0
    if (root != cur) {
474
0
  return(-2);
475
0
    }
476
    /*
477
     * get the nearest common ancestor.
478
     */
479
0
    while (depth1 > depth2) {
480
0
  depth1--;
481
0
  node1 = node1->parent;
482
0
    }
483
0
    while (depth2 > depth1) {
484
0
  depth2--;
485
0
  node2 = node2->parent;
486
0
    }
487
0
    while (node1->parent != node2->parent) {
488
0
  node1 = node1->parent;
489
0
  node2 = node2->parent;
490
  /* should not happen but just in case ... */
491
0
  if ((node1 == NULL) || (node2 == NULL))
492
0
      return(-2);
493
0
    }
494
    /*
495
     * Find who's first.
496
     */
497
0
    if (node1 == node2->prev)
498
0
  return(1);
499
0
    if (node1 == node2->next)
500
0
  return(-1);
501
    /*
502
     * Speedup using document order if available.
503
     */
504
0
    if ((node1->type == XML_ELEMENT_NODE) &&
505
0
  (node2->type == XML_ELEMENT_NODE) &&
506
0
  (0 > (ptrdiff_t) node1->content) &&
507
0
  (0 > (ptrdiff_t) node2->content) &&
508
0
  (node1->doc == node2->doc)) {
509
510
0
  l1 = -((ptrdiff_t) node1->content);
511
0
  l2 = -((ptrdiff_t) node2->content);
512
0
  if (l1 < l2)
513
0
      return(1);
514
0
  if (l1 > l2)
515
0
      return(-1);
516
0
    }
517
518
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
519
0
  if (cur == node2)
520
0
      return(1);
521
0
    return(-1); /* assume there is no sibling list corruption */
522
0
}
523
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
524
525
/*
526
 * Wrapper for the Timsort algorithm from timsort.h
527
 */
528
#ifdef WITH_TIM_SORT
529
#define SORT_NAME libxml_domnode
530
0
#define SORT_TYPE xmlNodePtr
531
/**
532
 * wrap_cmp:
533
 * @x: a node
534
 * @y: another node
535
 *
536
 * Comparison function for the Timsort implementation
537
 *
538
 * Returns -2 in case of error -1 if first point < second point, 0 if
539
 *         it's the same node, +1 otherwise
540
 */
541
static
542
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
543
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
544
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
545
0
    {
546
0
        int res = xmlXPathCmpNodesExt(x, y);
547
0
        return res == -2 ? res : -res;
548
0
    }
549
#else
550
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
551
    {
552
        int res = xmlXPathCmpNodes(x, y);
553
        return res == -2 ? res : -res;
554
    }
555
#endif
556
0
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
557
#include "timsort.h"
558
#endif /* WITH_TIM_SORT */
559
560
/************************************************************************
561
 *                  *
562
 *      Error handling routines       *
563
 *                  *
564
 ************************************************************************/
565
566
/**
567
 * XP_ERRORNULL:
568
 * @X:  the error code
569
 *
570
 * Macro to raise an XPath error and return NULL.
571
 */
572
#define XP_ERRORNULL(X)             \
573
0
    { xmlXPathErr(ctxt, X); return(NULL); }
574
575
/*
576
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
577
 */
578
static const char* const xmlXPathErrorMessages[] = {
579
    "Ok\n",
580
    "Number encoding\n",
581
    "Unfinished literal\n",
582
    "Start of literal\n",
583
    "Expected $ for variable reference\n",
584
    "Undefined variable\n",
585
    "Invalid predicate\n",
586
    "Invalid expression\n",
587
    "Missing closing curly brace\n",
588
    "Unregistered function\n",
589
    "Invalid operand\n",
590
    "Invalid type\n",
591
    "Invalid number of arguments\n",
592
    "Invalid context size\n",
593
    "Invalid context position\n",
594
    "Memory allocation error\n",
595
    "Syntax error\n",
596
    "Resource error\n",
597
    "Sub resource error\n",
598
    "Undefined namespace prefix\n",
599
    "Encoding error\n",
600
    "Char out of XML range\n",
601
    "Invalid or incomplete context\n",
602
    "Stack usage error\n",
603
    "Forbidden variable\n",
604
    "Operation limit exceeded\n",
605
    "Recursion limit exceeded\n",
606
    "?? Unknown error ??\n" /* Must be last in the list! */
607
};
608
0
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
609
0
       sizeof(xmlXPathErrorMessages[0])) - 1)
610
/**
611
 * xmlXPathErrMemory:
612
 * @ctxt:  an XPath context
613
 *
614
 * Handle a memory allocation failure.
615
 */
616
void
617
xmlXPathErrMemory(xmlXPathContextPtr ctxt)
618
0
{
619
0
    if (ctxt == NULL)
620
0
        return;
621
0
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
622
0
                        &ctxt->lastError);
623
0
}
624
625
/**
626
 * xmlXPathPErrMemory:
627
 * @ctxt:  an XPath parser context
628
 *
629
 * Handle a memory allocation failure.
630
 */
631
void
632
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt)
633
0
{
634
0
    if (ctxt == NULL)
635
0
        return;
636
0
    ctxt->error = XPATH_MEMORY_ERROR;
637
0
    xmlXPathErrMemory(ctxt->context);
638
0
}
639
640
/**
641
 * xmlXPathErr:
642
 * @ctxt:  a XPath parser context
643
 * @code:  the error code
644
 *
645
 * Handle an XPath error
646
 */
647
void
648
xmlXPathErr(xmlXPathParserContextPtr ctxt, int code)
649
0
{
650
0
    xmlStructuredErrorFunc schannel = NULL;
651
0
    xmlGenericErrorFunc channel = NULL;
652
0
    void *data = NULL;
653
0
    xmlNodePtr node = NULL;
654
0
    int res;
655
656
0
    if (ctxt == NULL)
657
0
        return;
658
0
    if ((code < 0) || (code > MAXERRNO))
659
0
  code = MAXERRNO;
660
    /* Only report the first error */
661
0
    if (ctxt->error != 0)
662
0
        return;
663
664
0
    ctxt->error = code;
665
666
0
    if (ctxt->context != NULL) {
667
0
        xmlErrorPtr err = &ctxt->context->lastError;
668
669
        /* Don't overwrite memory error. */
670
0
        if (err->code == XML_ERR_NO_MEMORY)
671
0
            return;
672
673
        /* cleanup current last error */
674
0
        xmlResetError(err);
675
676
0
        err->domain = XML_FROM_XPATH;
677
0
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
678
0
        err->level = XML_ERR_ERROR;
679
0
        if (ctxt->base != NULL) {
680
0
            err->str1 = (char *) xmlStrdup(ctxt->base);
681
0
            if (err->str1 == NULL) {
682
0
                xmlXPathPErrMemory(ctxt);
683
0
                return;
684
0
            }
685
0
        }
686
0
        err->int1 = ctxt->cur - ctxt->base;
687
0
        err->node = ctxt->context->debugNode;
688
689
0
        schannel = ctxt->context->error;
690
0
        data = ctxt->context->userData;
691
0
        node = ctxt->context->debugNode;
692
0
    }
693
694
0
    if (schannel == NULL) {
695
0
        channel = xmlGenericError;
696
0
        data = xmlGenericErrorContext;
697
0
    }
698
699
0
    res = xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
700
0
                        code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
701
0
                        XML_ERR_ERROR, NULL, 0,
702
0
                        (const char *) ctxt->base, NULL, NULL,
703
0
                        ctxt->cur - ctxt->base, 0,
704
0
                        "%s", xmlXPathErrorMessages[code]);
705
0
    if (res < 0)
706
0
        xmlXPathPErrMemory(ctxt);
707
0
}
708
709
/**
710
 * xmlXPatherror:
711
 * @ctxt:  the XPath Parser context
712
 * @file:  the file name
713
 * @line:  the line number
714
 * @no:  the error number
715
 *
716
 * Formats an error message.
717
 */
718
void
719
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
720
0
              int line ATTRIBUTE_UNUSED, int no) {
721
0
    xmlXPathErr(ctxt, no);
722
0
}
723
724
/**
725
 * xmlXPathCheckOpLimit:
726
 * @ctxt:  the XPath Parser context
727
 * @opCount:  the number of operations to be added
728
 *
729
 * Adds opCount to the running total of operations and returns -1 if the
730
 * operation limit is exceeded. Returns 0 otherwise.
731
 */
732
static int
733
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
734
0
    xmlXPathContextPtr xpctxt = ctxt->context;
735
736
0
    if ((opCount > xpctxt->opLimit) ||
737
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
738
0
        xpctxt->opCount = xpctxt->opLimit;
739
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
740
0
        return(-1);
741
0
    }
742
743
0
    xpctxt->opCount += opCount;
744
0
    return(0);
745
0
}
746
747
#define OP_LIMIT_EXCEEDED(ctxt, n) \
748
0
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
749
750
/************************************************************************
751
 *                  *
752
 *      Parser Types          *
753
 *                  *
754
 ************************************************************************/
755
756
/*
757
 * Types are private:
758
 */
759
760
typedef enum {
761
    XPATH_OP_END=0,
762
    XPATH_OP_AND,
763
    XPATH_OP_OR,
764
    XPATH_OP_EQUAL,
765
    XPATH_OP_CMP,
766
    XPATH_OP_PLUS,
767
    XPATH_OP_MULT,
768
    XPATH_OP_UNION,
769
    XPATH_OP_ROOT,
770
    XPATH_OP_NODE,
771
    XPATH_OP_COLLECT,
772
    XPATH_OP_VALUE, /* 11 */
773
    XPATH_OP_VARIABLE,
774
    XPATH_OP_FUNCTION,
775
    XPATH_OP_ARG,
776
    XPATH_OP_PREDICATE,
777
    XPATH_OP_FILTER, /* 16 */
778
    XPATH_OP_SORT /* 17 */
779
} xmlXPathOp;
780
781
typedef enum {
782
    AXIS_ANCESTOR = 1,
783
    AXIS_ANCESTOR_OR_SELF,
784
    AXIS_ATTRIBUTE,
785
    AXIS_CHILD,
786
    AXIS_DESCENDANT,
787
    AXIS_DESCENDANT_OR_SELF,
788
    AXIS_FOLLOWING,
789
    AXIS_FOLLOWING_SIBLING,
790
    AXIS_NAMESPACE,
791
    AXIS_PARENT,
792
    AXIS_PRECEDING,
793
    AXIS_PRECEDING_SIBLING,
794
    AXIS_SELF
795
} xmlXPathAxisVal;
796
797
typedef enum {
798
    NODE_TEST_NONE = 0,
799
    NODE_TEST_TYPE = 1,
800
    NODE_TEST_PI = 2,
801
    NODE_TEST_ALL = 3,
802
    NODE_TEST_NS = 4,
803
    NODE_TEST_NAME = 5
804
} xmlXPathTestVal;
805
806
typedef enum {
807
    NODE_TYPE_NODE = 0,
808
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
809
    NODE_TYPE_TEXT = XML_TEXT_NODE,
810
    NODE_TYPE_PI = XML_PI_NODE
811
} xmlXPathTypeVal;
812
813
typedef struct _xmlXPathStepOp xmlXPathStepOp;
814
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
815
struct _xmlXPathStepOp {
816
    xmlXPathOp op;    /* The identifier of the operation */
817
    int ch1;      /* First child */
818
    int ch2;      /* Second child */
819
    int value;
820
    int value2;
821
    int value3;
822
    void *value4;
823
    void *value5;
824
    xmlXPathFunction cache;
825
    void *cacheURI;
826
};
827
828
struct _xmlXPathCompExpr {
829
    int nbStep;     /* Number of steps in this expression */
830
    int maxStep;    /* Maximum number of steps allocated */
831
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
832
    int last;     /* index of last step in expression */
833
    xmlChar *expr;    /* the expression being computed */
834
    xmlDictPtr dict;    /* the dictionary to use if any */
835
#ifdef XPATH_STREAMING
836
    xmlPatternPtr stream;
837
#endif
838
};
839
840
/************************************************************************
841
 *                  *
842
 *      Forward declarations        *
843
 *                  *
844
 ************************************************************************/
845
846
static void
847
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
848
static int
849
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
850
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
851
static int
852
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
853
          xmlXPathStepOpPtr op,
854
          int isPredicate);
855
static void
856
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
857
858
/************************************************************************
859
 *                  *
860
 *      Parser Type functions       *
861
 *                  *
862
 ************************************************************************/
863
864
/**
865
 * xmlXPathNewCompExpr:
866
 *
867
 * Create a new Xpath component
868
 *
869
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
870
 */
871
static xmlXPathCompExprPtr
872
0
xmlXPathNewCompExpr(void) {
873
0
    xmlXPathCompExprPtr cur;
874
875
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
876
0
    if (cur == NULL)
877
0
  return(NULL);
878
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
879
0
    cur->maxStep = 10;
880
0
    cur->nbStep = 0;
881
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
882
0
                                     sizeof(xmlXPathStepOp));
883
0
    if (cur->steps == NULL) {
884
0
  xmlFree(cur);
885
0
  return(NULL);
886
0
    }
887
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
888
0
    cur->last = -1;
889
0
    return(cur);
890
0
}
891
892
/**
893
 * xmlXPathFreeCompExpr:
894
 * @comp:  an XPATH comp
895
 *
896
 * Free up the memory allocated by @comp
897
 */
898
void
899
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
900
0
{
901
0
    xmlXPathStepOpPtr op;
902
0
    int i;
903
904
0
    if (comp == NULL)
905
0
        return;
906
0
    if (comp->dict == NULL) {
907
0
  for (i = 0; i < comp->nbStep; i++) {
908
0
      op = &comp->steps[i];
909
0
      if (op->value4 != NULL) {
910
0
    if (op->op == XPATH_OP_VALUE)
911
0
        xmlXPathFreeObject(op->value4);
912
0
    else
913
0
        xmlFree(op->value4);
914
0
      }
915
0
      if (op->value5 != NULL)
916
0
    xmlFree(op->value5);
917
0
  }
918
0
    } else {
919
0
  for (i = 0; i < comp->nbStep; i++) {
920
0
      op = &comp->steps[i];
921
0
      if (op->value4 != NULL) {
922
0
    if (op->op == XPATH_OP_VALUE)
923
0
        xmlXPathFreeObject(op->value4);
924
0
      }
925
0
  }
926
0
        xmlDictFree(comp->dict);
927
0
    }
928
0
    if (comp->steps != NULL) {
929
0
        xmlFree(comp->steps);
930
0
    }
931
#ifdef XPATH_STREAMING
932
    if (comp->stream != NULL) {
933
        xmlFreePatternList(comp->stream);
934
    }
935
#endif
936
0
    if (comp->expr != NULL) {
937
0
        xmlFree(comp->expr);
938
0
    }
939
940
0
    xmlFree(comp);
941
0
}
942
943
/**
944
 * xmlXPathCompExprAdd:
945
 * @comp:  the compiled expression
946
 * @ch1: first child index
947
 * @ch2: second child index
948
 * @op:  an op
949
 * @value:  the first int value
950
 * @value2:  the second int value
951
 * @value3:  the third int value
952
 * @value4:  the first string value
953
 * @value5:  the second string value
954
 *
955
 * Add a step to an XPath Compiled Expression
956
 *
957
 * Returns -1 in case of failure, the index otherwise
958
 */
959
static int
960
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
961
   xmlXPathOp op, int value,
962
0
   int value2, int value3, void *value4, void *value5) {
963
0
    xmlXPathCompExprPtr comp = ctxt->comp;
964
0
    if (comp->nbStep >= comp->maxStep) {
965
0
  xmlXPathStepOp *real;
966
967
0
        if (comp->maxStep >= XPATH_MAX_STEPS) {
968
0
      xmlXPathPErrMemory(ctxt);
969
0
      return(-1);
970
0
        }
971
0
  comp->maxStep *= 2;
972
0
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
973
0
                          comp->maxStep * sizeof(xmlXPathStepOp));
974
0
  if (real == NULL) {
975
0
      comp->maxStep /= 2;
976
0
      xmlXPathPErrMemory(ctxt);
977
0
      return(-1);
978
0
  }
979
0
  comp->steps = real;
980
0
    }
981
0
    comp->last = comp->nbStep;
982
0
    comp->steps[comp->nbStep].ch1 = ch1;
983
0
    comp->steps[comp->nbStep].ch2 = ch2;
984
0
    comp->steps[comp->nbStep].op = op;
985
0
    comp->steps[comp->nbStep].value = value;
986
0
    comp->steps[comp->nbStep].value2 = value2;
987
0
    comp->steps[comp->nbStep].value3 = value3;
988
0
    if ((comp->dict != NULL) &&
989
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
990
0
   (op == XPATH_OP_COLLECT))) {
991
0
        if (value4 != NULL) {
992
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
993
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
994
0
      xmlFree(value4);
995
0
  } else
996
0
      comp->steps[comp->nbStep].value4 = NULL;
997
0
        if (value5 != NULL) {
998
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
999
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1000
0
      xmlFree(value5);
1001
0
  } else
1002
0
      comp->steps[comp->nbStep].value5 = NULL;
1003
0
    } else {
1004
0
  comp->steps[comp->nbStep].value4 = value4;
1005
0
  comp->steps[comp->nbStep].value5 = value5;
1006
0
    }
1007
0
    comp->steps[comp->nbStep].cache = NULL;
1008
0
    return(comp->nbStep++);
1009
0
}
1010
1011
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1012
0
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1013
0
                  (op), (val), (val2), (val3), (val4), (val5))
1014
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1015
0
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1016
0
                  (op), (val), (val2), (val3), (val4), (val5))
1017
1018
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1019
0
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1020
1021
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1022
0
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1023
1024
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1025
0
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1026
0
      (val), (val2), 0 ,NULL ,NULL)
1027
1028
/************************************************************************
1029
 *                  *
1030
 *    XPath object cache structures       *
1031
 *                  *
1032
 ************************************************************************/
1033
1034
/* #define XP_DEFAULT_CACHE_ON */
1035
1036
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1037
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1038
struct _xmlXPathContextCache {
1039
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1040
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1041
    int numNodeset;
1042
    int maxNodeset;
1043
    int numMisc;
1044
    int maxMisc;
1045
};
1046
1047
/************************************************************************
1048
 *                  *
1049
 *    Debugging related functions       *
1050
 *                  *
1051
 ************************************************************************/
1052
1053
#ifdef LIBXML_DEBUG_ENABLED
1054
static void
1055
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1056
    int i;
1057
    char shift[100];
1058
1059
    for (i = 0;((i < depth) && (i < 25));i++)
1060
        shift[2 * i] = shift[2 * i + 1] = ' ';
1061
    shift[2 * i] = shift[2 * i + 1] = 0;
1062
    if (cur == NULL) {
1063
  fprintf(output, "%s", shift);
1064
  fprintf(output, "Node is NULL !\n");
1065
  return;
1066
1067
    }
1068
1069
    if ((cur->type == XML_DOCUMENT_NODE) ||
1070
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1071
  fprintf(output, "%s", shift);
1072
  fprintf(output, " /\n");
1073
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1074
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1075
    else
1076
  xmlDebugDumpOneNode(output, cur, depth);
1077
}
1078
static void
1079
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1080
    xmlNodePtr tmp;
1081
    int i;
1082
    char shift[100];
1083
1084
    for (i = 0;((i < depth) && (i < 25));i++)
1085
        shift[2 * i] = shift[2 * i + 1] = ' ';
1086
    shift[2 * i] = shift[2 * i + 1] = 0;
1087
    if (cur == NULL) {
1088
  fprintf(output, "%s", shift);
1089
  fprintf(output, "Node is NULL !\n");
1090
  return;
1091
1092
    }
1093
1094
    while (cur != NULL) {
1095
  tmp = cur;
1096
  cur = cur->next;
1097
  xmlDebugDumpOneNode(output, tmp, depth);
1098
    }
1099
}
1100
1101
static void
1102
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1103
    int i;
1104
    char shift[100];
1105
1106
    for (i = 0;((i < depth) && (i < 25));i++)
1107
        shift[2 * i] = shift[2 * i + 1] = ' ';
1108
    shift[2 * i] = shift[2 * i + 1] = 0;
1109
1110
    if (cur == NULL) {
1111
  fprintf(output, "%s", shift);
1112
  fprintf(output, "NodeSet is NULL !\n");
1113
  return;
1114
1115
    }
1116
1117
    if (cur != NULL) {
1118
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1119
  for (i = 0;i < cur->nodeNr;i++) {
1120
      fprintf(output, "%s", shift);
1121
      fprintf(output, "%d", i + 1);
1122
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1123
  }
1124
    }
1125
}
1126
1127
static void
1128
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1129
    int i;
1130
    char shift[100];
1131
1132
    for (i = 0;((i < depth) && (i < 25));i++)
1133
        shift[2 * i] = shift[2 * i + 1] = ' ';
1134
    shift[2 * i] = shift[2 * i + 1] = 0;
1135
1136
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1137
  fprintf(output, "%s", shift);
1138
  fprintf(output, "Value Tree is NULL !\n");
1139
  return;
1140
1141
    }
1142
1143
    fprintf(output, "%s", shift);
1144
    fprintf(output, "%d", i + 1);
1145
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1146
}
1147
1148
/**
1149
 * xmlXPathDebugDumpObject:
1150
 * @output:  the FILE * to dump the output
1151
 * @cur:  the object to inspect
1152
 * @depth:  indentation level
1153
 *
1154
 * Dump the content of the object for debugging purposes
1155
 */
1156
void
1157
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1158
    int i;
1159
    char shift[100];
1160
1161
    if (output == NULL) return;
1162
1163
    for (i = 0;((i < depth) && (i < 25));i++)
1164
        shift[2 * i] = shift[2 * i + 1] = ' ';
1165
    shift[2 * i] = shift[2 * i + 1] = 0;
1166
1167
1168
    fprintf(output, "%s", shift);
1169
1170
    if (cur == NULL) {
1171
        fprintf(output, "Object is empty (NULL)\n");
1172
  return;
1173
    }
1174
    switch(cur->type) {
1175
        case XPATH_UNDEFINED:
1176
      fprintf(output, "Object is uninitialized\n");
1177
      break;
1178
        case XPATH_NODESET:
1179
      fprintf(output, "Object is a Node Set :\n");
1180
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1181
      break;
1182
  case XPATH_XSLT_TREE:
1183
      fprintf(output, "Object is an XSLT value tree :\n");
1184
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1185
      break;
1186
        case XPATH_BOOLEAN:
1187
      fprintf(output, "Object is a Boolean : ");
1188
      if (cur->boolval) fprintf(output, "true\n");
1189
      else fprintf(output, "false\n");
1190
      break;
1191
        case XPATH_NUMBER:
1192
      switch (xmlXPathIsInf(cur->floatval)) {
1193
      case 1:
1194
    fprintf(output, "Object is a number : Infinity\n");
1195
    break;
1196
      case -1:
1197
    fprintf(output, "Object is a number : -Infinity\n");
1198
    break;
1199
      default:
1200
    if (xmlXPathIsNaN(cur->floatval)) {
1201
        fprintf(output, "Object is a number : NaN\n");
1202
    } else if (cur->floatval == 0) {
1203
                    /* Omit sign for negative zero. */
1204
        fprintf(output, "Object is a number : 0\n");
1205
    } else {
1206
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1207
    }
1208
      }
1209
      break;
1210
        case XPATH_STRING:
1211
      fprintf(output, "Object is a string : ");
1212
      xmlDebugDumpString(output, cur->stringval);
1213
      fprintf(output, "\n");
1214
      break;
1215
  case XPATH_USERS:
1216
      fprintf(output, "Object is user defined\n");
1217
      break;
1218
    }
1219
}
1220
1221
static void
1222
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1223
                       xmlXPathStepOpPtr op, int depth) {
1224
    int i;
1225
    char shift[100];
1226
1227
    for (i = 0;((i < depth) && (i < 25));i++)
1228
        shift[2 * i] = shift[2 * i + 1] = ' ';
1229
    shift[2 * i] = shift[2 * i + 1] = 0;
1230
1231
    fprintf(output, "%s", shift);
1232
    if (op == NULL) {
1233
  fprintf(output, "Step is NULL\n");
1234
  return;
1235
    }
1236
    switch (op->op) {
1237
        case XPATH_OP_END:
1238
      fprintf(output, "END"); break;
1239
        case XPATH_OP_AND:
1240
      fprintf(output, "AND"); break;
1241
        case XPATH_OP_OR:
1242
      fprintf(output, "OR"); break;
1243
        case XPATH_OP_EQUAL:
1244
       if (op->value)
1245
     fprintf(output, "EQUAL =");
1246
       else
1247
     fprintf(output, "EQUAL !=");
1248
       break;
1249
        case XPATH_OP_CMP:
1250
       if (op->value)
1251
     fprintf(output, "CMP <");
1252
       else
1253
     fprintf(output, "CMP >");
1254
       if (!op->value2)
1255
     fprintf(output, "=");
1256
       break;
1257
        case XPATH_OP_PLUS:
1258
       if (op->value == 0)
1259
     fprintf(output, "PLUS -");
1260
       else if (op->value == 1)
1261
     fprintf(output, "PLUS +");
1262
       else if (op->value == 2)
1263
     fprintf(output, "PLUS unary -");
1264
       else if (op->value == 3)
1265
     fprintf(output, "PLUS unary - -");
1266
       break;
1267
        case XPATH_OP_MULT:
1268
       if (op->value == 0)
1269
     fprintf(output, "MULT *");
1270
       else if (op->value == 1)
1271
     fprintf(output, "MULT div");
1272
       else
1273
     fprintf(output, "MULT mod");
1274
       break;
1275
        case XPATH_OP_UNION:
1276
       fprintf(output, "UNION"); break;
1277
        case XPATH_OP_ROOT:
1278
       fprintf(output, "ROOT"); break;
1279
        case XPATH_OP_NODE:
1280
       fprintf(output, "NODE"); break;
1281
        case XPATH_OP_SORT:
1282
       fprintf(output, "SORT"); break;
1283
        case XPATH_OP_COLLECT: {
1284
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1285
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1286
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1287
      const xmlChar *prefix = op->value4;
1288
      const xmlChar *name = op->value5;
1289
1290
      fprintf(output, "COLLECT ");
1291
      switch (axis) {
1292
    case AXIS_ANCESTOR:
1293
        fprintf(output, " 'ancestors' "); break;
1294
    case AXIS_ANCESTOR_OR_SELF:
1295
        fprintf(output, " 'ancestors-or-self' "); break;
1296
    case AXIS_ATTRIBUTE:
1297
        fprintf(output, " 'attributes' "); break;
1298
    case AXIS_CHILD:
1299
        fprintf(output, " 'child' "); break;
1300
    case AXIS_DESCENDANT:
1301
        fprintf(output, " 'descendant' "); break;
1302
    case AXIS_DESCENDANT_OR_SELF:
1303
        fprintf(output, " 'descendant-or-self' "); break;
1304
    case AXIS_FOLLOWING:
1305
        fprintf(output, " 'following' "); break;
1306
    case AXIS_FOLLOWING_SIBLING:
1307
        fprintf(output, " 'following-siblings' "); break;
1308
    case AXIS_NAMESPACE:
1309
        fprintf(output, " 'namespace' "); break;
1310
    case AXIS_PARENT:
1311
        fprintf(output, " 'parent' "); break;
1312
    case AXIS_PRECEDING:
1313
        fprintf(output, " 'preceding' "); break;
1314
    case AXIS_PRECEDING_SIBLING:
1315
        fprintf(output, " 'preceding-sibling' "); break;
1316
    case AXIS_SELF:
1317
        fprintf(output, " 'self' "); break;
1318
      }
1319
      switch (test) {
1320
                case NODE_TEST_NONE:
1321
        fprintf(output, "'none' "); break;
1322
                case NODE_TEST_TYPE:
1323
        fprintf(output, "'type' "); break;
1324
                case NODE_TEST_PI:
1325
        fprintf(output, "'PI' "); break;
1326
                case NODE_TEST_ALL:
1327
        fprintf(output, "'all' "); break;
1328
                case NODE_TEST_NS:
1329
        fprintf(output, "'namespace' "); break;
1330
                case NODE_TEST_NAME:
1331
        fprintf(output, "'name' "); break;
1332
      }
1333
      switch (type) {
1334
                case NODE_TYPE_NODE:
1335
        fprintf(output, "'node' "); break;
1336
                case NODE_TYPE_COMMENT:
1337
        fprintf(output, "'comment' "); break;
1338
                case NODE_TYPE_TEXT:
1339
        fprintf(output, "'text' "); break;
1340
                case NODE_TYPE_PI:
1341
        fprintf(output, "'PI' "); break;
1342
      }
1343
      if (prefix != NULL)
1344
    fprintf(output, "%s:", prefix);
1345
      if (name != NULL)
1346
    fprintf(output, "%s", (const char *) name);
1347
      break;
1348
1349
        }
1350
  case XPATH_OP_VALUE: {
1351
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1352
1353
      fprintf(output, "ELEM ");
1354
      xmlXPathDebugDumpObject(output, object, 0);
1355
      goto finish;
1356
  }
1357
  case XPATH_OP_VARIABLE: {
1358
      const xmlChar *prefix = op->value5;
1359
      const xmlChar *name = op->value4;
1360
1361
      if (prefix != NULL)
1362
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1363
      else
1364
    fprintf(output, "VARIABLE %s", name);
1365
      break;
1366
  }
1367
  case XPATH_OP_FUNCTION: {
1368
      int nbargs = op->value;
1369
      const xmlChar *prefix = op->value5;
1370
      const xmlChar *name = op->value4;
1371
1372
      if (prefix != NULL)
1373
    fprintf(output, "FUNCTION %s:%s(%d args)",
1374
      prefix, name, nbargs);
1375
      else
1376
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1377
      break;
1378
  }
1379
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1380
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1381
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1382
  default:
1383
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1384
    }
1385
    fprintf(output, "\n");
1386
finish:
1387
    if (op->ch1 >= 0)
1388
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1389
    if (op->ch2 >= 0)
1390
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1391
}
1392
1393
/**
1394
 * xmlXPathDebugDumpCompExpr:
1395
 * @output:  the FILE * for the output
1396
 * @comp:  the precompiled XPath expression
1397
 * @depth:  the indentation level.
1398
 *
1399
 * Dumps the tree of the compiled XPath expression.
1400
 */
1401
void
1402
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1403
                    int depth) {
1404
    int i;
1405
    char shift[100];
1406
1407
    if ((output == NULL) || (comp == NULL)) return;
1408
1409
    for (i = 0;((i < depth) && (i < 25));i++)
1410
        shift[2 * i] = shift[2 * i + 1] = ' ';
1411
    shift[2 * i] = shift[2 * i + 1] = 0;
1412
1413
    fprintf(output, "%s", shift);
1414
1415
#ifdef XPATH_STREAMING
1416
    if (comp->stream) {
1417
        fprintf(output, "Streaming Expression\n");
1418
    } else
1419
#endif
1420
    {
1421
        fprintf(output, "Compiled Expression : %d elements\n",
1422
                comp->nbStep);
1423
        i = comp->last;
1424
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1425
    }
1426
}
1427
1428
#endif /* LIBXML_DEBUG_ENABLED */
1429
1430
/************************************************************************
1431
 *                  *
1432
 *      XPath object caching        *
1433
 *                  *
1434
 ************************************************************************/
1435
1436
/**
1437
 * xmlXPathNewCache:
1438
 *
1439
 * Create a new object cache
1440
 *
1441
 * Returns the xmlXPathCache just allocated.
1442
 */
1443
static xmlXPathContextCachePtr
1444
xmlXPathNewCache(void)
1445
0
{
1446
0
    xmlXPathContextCachePtr ret;
1447
1448
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1449
0
    if (ret == NULL)
1450
0
  return(NULL);
1451
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1452
0
    ret->maxNodeset = 100;
1453
0
    ret->maxMisc = 100;
1454
0
    return(ret);
1455
0
}
1456
1457
static void
1458
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1459
0
{
1460
0
    while (list != NULL) {
1461
0
        xmlXPathObjectPtr next;
1462
1463
0
        next = (void *) list->stringval;
1464
1465
0
  if (list->nodesetval != NULL) {
1466
0
      if (list->nodesetval->nodeTab != NULL)
1467
0
    xmlFree(list->nodesetval->nodeTab);
1468
0
      xmlFree(list->nodesetval);
1469
0
  }
1470
0
  xmlFree(list);
1471
1472
0
        list = next;
1473
0
    }
1474
0
}
1475
1476
static void
1477
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1478
0
{
1479
0
    if (cache == NULL)
1480
0
  return;
1481
0
    if (cache->nodesetObjs)
1482
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1483
0
    if (cache->miscObjs)
1484
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1485
0
    xmlFree(cache);
1486
0
}
1487
1488
/**
1489
 * xmlXPathContextSetCache:
1490
 *
1491
 * @ctxt:  the XPath context
1492
 * @active: enables/disables (creates/frees) the cache
1493
 * @value: a value with semantics dependent on @options
1494
 * @options: options (currently only the value 0 is used)
1495
 *
1496
 * Creates/frees an object cache on the XPath context.
1497
 * If activates XPath objects (xmlXPathObject) will be cached internally
1498
 * to be reused.
1499
 * @options:
1500
 *   0: This will set the XPath object caching:
1501
 *      @value:
1502
 *        This will set the maximum number of XPath objects
1503
 *        to be cached per slot
1504
 *        There are two slots for node-set and misc objects.
1505
 *        Use <0 for the default number (100).
1506
 *   Other values for @options have currently no effect.
1507
 *
1508
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1509
 */
1510
int
1511
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1512
      int active,
1513
      int value,
1514
      int options)
1515
0
{
1516
0
    if (ctxt == NULL)
1517
0
  return(-1);
1518
0
    if (active) {
1519
0
  xmlXPathContextCachePtr cache;
1520
1521
0
  if (ctxt->cache == NULL) {
1522
0
      ctxt->cache = xmlXPathNewCache();
1523
0
      if (ctxt->cache == NULL) {
1524
0
                xmlXPathErrMemory(ctxt);
1525
0
    return(-1);
1526
0
            }
1527
0
  }
1528
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1529
0
  if (options == 0) {
1530
0
      if (value < 0)
1531
0
    value = 100;
1532
0
      cache->maxNodeset = value;
1533
0
      cache->maxMisc = value;
1534
0
  }
1535
0
    } else if (ctxt->cache != NULL) {
1536
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1537
0
  ctxt->cache = NULL;
1538
0
    }
1539
0
    return(0);
1540
0
}
1541
1542
/**
1543
 * xmlXPathCacheWrapNodeSet:
1544
 * @pctxt: the XPath context
1545
 * @val:  the NodePtr value
1546
 *
1547
 * This is the cached version of xmlXPathWrapNodeSet().
1548
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1549
 *
1550
 * Returns the created or reused object.
1551
 *
1552
 * In case of error the node set is destroyed and NULL is returned.
1553
 */
1554
static xmlXPathObjectPtr
1555
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1556
0
{
1557
0
    xmlXPathObjectPtr ret;
1558
0
    xmlXPathContextPtr ctxt = pctxt->context;
1559
1560
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1561
0
  xmlXPathContextCachePtr cache =
1562
0
      (xmlXPathContextCachePtr) ctxt->cache;
1563
1564
0
  if (cache->miscObjs != NULL) {
1565
0
      ret = cache->miscObjs;
1566
0
            cache->miscObjs = (void *) ret->stringval;
1567
0
            cache->numMisc -= 1;
1568
0
            ret->stringval = NULL;
1569
0
      ret->type = XPATH_NODESET;
1570
0
      ret->nodesetval = val;
1571
0
      return(ret);
1572
0
  }
1573
0
    }
1574
1575
0
    ret = xmlXPathWrapNodeSet(val);
1576
0
    if (ret == NULL)
1577
0
        xmlXPathPErrMemory(pctxt);
1578
0
    return(ret);
1579
0
}
1580
1581
/**
1582
 * xmlXPathCacheWrapString:
1583
 * @pctxt the XPath context
1584
 * @val:  the xmlChar * value
1585
 *
1586
 * This is the cached version of xmlXPathWrapString().
1587
 * Wraps the @val string into an XPath object.
1588
 *
1589
 * Returns the created or reused object.
1590
 */
1591
static xmlXPathObjectPtr
1592
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1593
0
{
1594
0
    xmlXPathObjectPtr ret;
1595
0
    xmlXPathContextPtr ctxt = pctxt->context;
1596
1597
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1598
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1599
1600
0
  if (cache->miscObjs != NULL) {
1601
0
      ret = cache->miscObjs;
1602
0
            cache->miscObjs = (void *) ret->stringval;
1603
0
            cache->numMisc -= 1;
1604
0
      ret->type = XPATH_STRING;
1605
0
      ret->stringval = val;
1606
0
      return(ret);
1607
0
  }
1608
0
    }
1609
1610
0
    ret = xmlXPathWrapString(val);
1611
0
    if (ret == NULL)
1612
0
        xmlXPathPErrMemory(pctxt);
1613
0
    return(ret);
1614
0
}
1615
1616
/**
1617
 * xmlXPathCacheNewNodeSet:
1618
 * @pctxt the XPath context
1619
 * @val:  the NodePtr value
1620
 *
1621
 * This is the cached version of xmlXPathNewNodeSet().
1622
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1623
 * it with the single Node @val
1624
 *
1625
 * Returns the created or reused object.
1626
 */
1627
static xmlXPathObjectPtr
1628
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1629
0
{
1630
0
    xmlXPathObjectPtr ret;
1631
0
    xmlXPathContextPtr ctxt = pctxt->context;
1632
1633
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1634
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1635
1636
0
  if (cache->nodesetObjs != NULL) {
1637
      /*
1638
      * Use the nodeset-cache.
1639
      */
1640
0
      ret = cache->nodesetObjs;
1641
0
            cache->nodesetObjs = (void *) ret->stringval;
1642
0
            cache->numNodeset -= 1;
1643
0
            ret->stringval = NULL;
1644
0
      ret->type = XPATH_NODESET;
1645
0
      ret->boolval = 0;
1646
0
      if (val) {
1647
0
    if ((ret->nodesetval->nodeMax == 0) ||
1648
0
        (val->type == XML_NAMESPACE_DECL))
1649
0
    {
1650
0
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1651
0
                        xmlXPathPErrMemory(pctxt);
1652
0
    } else {
1653
0
        ret->nodesetval->nodeTab[0] = val;
1654
0
        ret->nodesetval->nodeNr = 1;
1655
0
    }
1656
0
      }
1657
0
      return(ret);
1658
0
  } else if (cache->miscObjs != NULL) {
1659
0
            xmlNodeSetPtr set;
1660
      /*
1661
      * Fallback to misc-cache.
1662
      */
1663
1664
0
      set = xmlXPathNodeSetCreate(val);
1665
0
      if (set == NULL) {
1666
0
                xmlXPathPErrMemory(pctxt);
1667
0
    return(NULL);
1668
0
      }
1669
1670
0
      ret = cache->miscObjs;
1671
0
            cache->miscObjs = (void *) ret->stringval;
1672
0
            cache->numMisc -= 1;
1673
0
            ret->stringval = NULL;
1674
0
      ret->type = XPATH_NODESET;
1675
0
      ret->boolval = 0;
1676
0
      ret->nodesetval = set;
1677
0
      return(ret);
1678
0
  }
1679
0
    }
1680
0
    ret = xmlXPathNewNodeSet(val);
1681
0
    if (ret == NULL)
1682
0
        xmlXPathPErrMemory(pctxt);
1683
0
    return(ret);
1684
0
}
1685
1686
/**
1687
 * xmlXPathCacheNewString:
1688
 * @pctxt the XPath context
1689
 * @val:  the xmlChar * value
1690
 *
1691
 * This is the cached version of xmlXPathNewString().
1692
 * Acquire an xmlXPathObjectPtr of type string and of value @val
1693
 *
1694
 * Returns the created or reused object.
1695
 */
1696
static xmlXPathObjectPtr
1697
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1698
0
{
1699
0
    xmlXPathObjectPtr ret;
1700
0
    xmlXPathContextPtr ctxt = pctxt->context;
1701
1702
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1703
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1704
1705
0
  if (cache->miscObjs != NULL) {
1706
0
            xmlChar *copy;
1707
1708
0
            if (val == NULL)
1709
0
                val = BAD_CAST "";
1710
0
            copy = xmlStrdup(val);
1711
0
            if (copy == NULL) {
1712
0
                xmlXPathPErrMemory(pctxt);
1713
0
                return(NULL);
1714
0
            }
1715
1716
0
      ret = cache->miscObjs;
1717
0
            cache->miscObjs = (void *) ret->stringval;
1718
0
            cache->numMisc -= 1;
1719
0
      ret->type = XPATH_STRING;
1720
0
            ret->stringval = copy;
1721
0
      return(ret);
1722
0
  }
1723
0
    }
1724
1725
0
    ret = xmlXPathNewString(val);
1726
0
    if (ret == NULL)
1727
0
        xmlXPathPErrMemory(pctxt);
1728
0
    return(ret);
1729
0
}
1730
1731
/**
1732
 * xmlXPathCacheNewCString:
1733
 * @pctxt the XPath context
1734
 * @val:  the char * value
1735
 *
1736
 * This is the cached version of xmlXPathNewCString().
1737
 * Acquire an xmlXPathObjectPtr of type string and of value @val
1738
 *
1739
 * Returns the created or reused object.
1740
 */
1741
static xmlXPathObjectPtr
1742
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1743
0
{
1744
0
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1745
0
}
1746
1747
/**
1748
 * xmlXPathCacheNewBoolean:
1749
 * @pctxt the XPath context
1750
 * @val:  the boolean value
1751
 *
1752
 * This is the cached version of xmlXPathNewBoolean().
1753
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
1754
 *
1755
 * Returns the created or reused object.
1756
 */
1757
static xmlXPathObjectPtr
1758
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1759
0
{
1760
0
    xmlXPathObjectPtr ret;
1761
0
    xmlXPathContextPtr ctxt = pctxt->context;
1762
1763
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1764
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1765
1766
0
  if (cache->miscObjs != NULL) {
1767
0
      ret = cache->miscObjs;
1768
0
            cache->miscObjs = (void *) ret->stringval;
1769
0
            cache->numMisc -= 1;
1770
0
            ret->stringval = NULL;
1771
0
      ret->type = XPATH_BOOLEAN;
1772
0
      ret->boolval = (val != 0);
1773
0
      return(ret);
1774
0
  }
1775
0
    }
1776
1777
0
    ret = xmlXPathNewBoolean(val);
1778
0
    if (ret == NULL)
1779
0
        xmlXPathPErrMemory(pctxt);
1780
0
    return(ret);
1781
0
}
1782
1783
/**
1784
 * xmlXPathCacheNewFloat:
1785
 * @pctxt the XPath context
1786
 * @val:  the double value
1787
 *
1788
 * This is the cached version of xmlXPathNewFloat().
1789
 * Acquires an xmlXPathObjectPtr of type double and of value @val
1790
 *
1791
 * Returns the created or reused object.
1792
 */
1793
static xmlXPathObjectPtr
1794
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1795
0
{
1796
0
    xmlXPathObjectPtr ret;
1797
0
    xmlXPathContextPtr ctxt = pctxt->context;
1798
1799
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1800
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1801
1802
0
  if (cache->miscObjs != NULL) {
1803
0
      ret = cache->miscObjs;
1804
0
            cache->miscObjs = (void *) ret->stringval;
1805
0
            cache->numMisc -= 1;
1806
0
            ret->stringval = NULL;
1807
0
      ret->type = XPATH_NUMBER;
1808
0
      ret->floatval = val;
1809
0
      return(ret);
1810
0
  }
1811
0
    }
1812
1813
0
    ret = xmlXPathNewFloat(val);
1814
0
    if (ret == NULL)
1815
0
        xmlXPathPErrMemory(pctxt);
1816
0
    return(ret);
1817
0
}
1818
1819
/**
1820
 * xmlXPathCacheObjectCopy:
1821
 * @pctxt the XPath context
1822
 * @val:  the original object
1823
 *
1824
 * This is the cached version of xmlXPathObjectCopy().
1825
 * Acquire a copy of a given object
1826
 *
1827
 * Returns a created or reused created object.
1828
 */
1829
static xmlXPathObjectPtr
1830
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1831
0
{
1832
0
    xmlXPathObjectPtr ret;
1833
0
    xmlXPathContextPtr ctxt = pctxt->context;
1834
1835
0
    if (val == NULL)
1836
0
  return(NULL);
1837
1838
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1839
0
  switch (val->type) {
1840
0
            case XPATH_NODESET: {
1841
0
                xmlNodeSetPtr set;
1842
1843
0
                set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1844
0
                if (set == NULL) {
1845
0
                    xmlXPathPErrMemory(pctxt);
1846
0
                    return(NULL);
1847
0
                }
1848
0
                return(xmlXPathCacheWrapNodeSet(pctxt, set));
1849
0
            }
1850
0
      case XPATH_STRING:
1851
0
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1852
0
      case XPATH_BOOLEAN:
1853
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1854
0
      case XPATH_NUMBER:
1855
0
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1856
0
      default:
1857
0
    break;
1858
0
  }
1859
0
    }
1860
0
    ret = xmlXPathObjectCopy(val);
1861
0
    if (ret == NULL)
1862
0
        xmlXPathPErrMemory(pctxt);
1863
0
    return(ret);
1864
0
}
1865
1866
/************************************************************************
1867
 *                  *
1868
 *    Parser stacks related functions and macros    *
1869
 *                  *
1870
 ************************************************************************/
1871
1872
/**
1873
 * xmlXPathCastToNumberInternal:
1874
 * @ctxt:  parser context
1875
 * @val:  an XPath object
1876
 *
1877
 * Converts an XPath object to its number value
1878
 *
1879
 * Returns the number value
1880
 */
1881
static double
1882
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1883
0
                             xmlXPathObjectPtr val) {
1884
0
    double ret = 0.0;
1885
1886
0
    if (val == NULL)
1887
0
  return(xmlXPathNAN);
1888
0
    switch (val->type) {
1889
0
    case XPATH_UNDEFINED:
1890
0
  ret = xmlXPathNAN;
1891
0
  break;
1892
0
    case XPATH_NODESET:
1893
0
    case XPATH_XSLT_TREE: {
1894
0
        xmlChar *str;
1895
1896
0
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1897
0
        if (str == NULL) {
1898
0
            xmlXPathPErrMemory(ctxt);
1899
0
            ret = xmlXPathNAN;
1900
0
        } else {
1901
0
      ret = xmlXPathCastStringToNumber(str);
1902
0
            xmlFree(str);
1903
0
        }
1904
0
  break;
1905
0
    }
1906
0
    case XPATH_STRING:
1907
0
  ret = xmlXPathCastStringToNumber(val->stringval);
1908
0
  break;
1909
0
    case XPATH_NUMBER:
1910
0
  ret = val->floatval;
1911
0
  break;
1912
0
    case XPATH_BOOLEAN:
1913
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1914
0
  break;
1915
0
    case XPATH_USERS:
1916
  /* TODO */
1917
0
  ret = xmlXPathNAN;
1918
0
  break;
1919
0
    }
1920
0
    return(ret);
1921
0
}
1922
1923
/**
1924
 * valuePop:
1925
 * @ctxt: an XPath evaluation context
1926
 *
1927
 * Pops the top XPath object from the value stack
1928
 *
1929
 * Returns the XPath object just removed
1930
 */
1931
xmlXPathObjectPtr
1932
valuePop(xmlXPathParserContextPtr ctxt)
1933
0
{
1934
0
    xmlXPathObjectPtr ret;
1935
1936
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1937
0
        return (NULL);
1938
1939
0
    ctxt->valueNr--;
1940
0
    if (ctxt->valueNr > 0)
1941
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1942
0
    else
1943
0
        ctxt->value = NULL;
1944
0
    ret = ctxt->valueTab[ctxt->valueNr];
1945
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
1946
0
    return (ret);
1947
0
}
1948
/**
1949
 * valuePush:
1950
 * @ctxt:  an XPath evaluation context
1951
 * @value:  the XPath object
1952
 *
1953
 * Pushes a new XPath object on top of the value stack. If value is NULL,
1954
 * a memory error is recorded in the parser context.
1955
 *
1956
 * Returns the number of items on the value stack, or -1 in case of error.
1957
 *
1958
 * The object is destroyed in case of error.
1959
 */
1960
int
1961
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
1962
0
{
1963
0
    if (ctxt == NULL) return(-1);
1964
0
    if (value == NULL) {
1965
        /*
1966
         * A NULL value typically indicates that a memory allocation failed.
1967
         */
1968
0
        xmlXPathPErrMemory(ctxt);
1969
0
        return(-1);
1970
0
    }
1971
0
    if (ctxt->valueNr >= ctxt->valueMax) {
1972
0
        xmlXPathObjectPtr *tmp;
1973
1974
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
1975
0
            xmlXPathPErrMemory(ctxt);
1976
0
            xmlXPathFreeObject(value);
1977
0
            return (-1);
1978
0
        }
1979
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
1980
0
                                             2 * ctxt->valueMax *
1981
0
                                             sizeof(ctxt->valueTab[0]));
1982
0
        if (tmp == NULL) {
1983
0
            xmlXPathPErrMemory(ctxt);
1984
0
            xmlXPathFreeObject(value);
1985
0
            return (-1);
1986
0
        }
1987
0
        ctxt->valueMax *= 2;
1988
0
  ctxt->valueTab = tmp;
1989
0
    }
1990
0
    ctxt->valueTab[ctxt->valueNr] = value;
1991
0
    ctxt->value = value;
1992
0
    return (ctxt->valueNr++);
1993
0
}
1994
1995
/**
1996
 * xmlXPathPopBoolean:
1997
 * @ctxt:  an XPath parser context
1998
 *
1999
 * Pops a boolean from the stack, handling conversion if needed.
2000
 * Check error with #xmlXPathCheckError.
2001
 *
2002
 * Returns the boolean
2003
 */
2004
int
2005
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2006
0
    xmlXPathObjectPtr obj;
2007
0
    int ret;
2008
2009
0
    obj = valuePop(ctxt);
2010
0
    if (obj == NULL) {
2011
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2012
0
  return(0);
2013
0
    }
2014
0
    if (obj->type != XPATH_BOOLEAN)
2015
0
  ret = xmlXPathCastToBoolean(obj);
2016
0
    else
2017
0
        ret = obj->boolval;
2018
0
    xmlXPathReleaseObject(ctxt->context, obj);
2019
0
    return(ret);
2020
0
}
2021
2022
/**
2023
 * xmlXPathPopNumber:
2024
 * @ctxt:  an XPath parser context
2025
 *
2026
 * Pops a number from the stack, handling conversion if needed.
2027
 * Check error with #xmlXPathCheckError.
2028
 *
2029
 * Returns the number
2030
 */
2031
double
2032
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2033
0
    xmlXPathObjectPtr obj;
2034
0
    double ret;
2035
2036
0
    obj = valuePop(ctxt);
2037
0
    if (obj == NULL) {
2038
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2039
0
  return(0);
2040
0
    }
2041
0
    if (obj->type != XPATH_NUMBER)
2042
0
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2043
0
    else
2044
0
        ret = obj->floatval;
2045
0
    xmlXPathReleaseObject(ctxt->context, obj);
2046
0
    return(ret);
2047
0
}
2048
2049
/**
2050
 * xmlXPathPopString:
2051
 * @ctxt:  an XPath parser context
2052
 *
2053
 * Pops a string from the stack, handling conversion if needed.
2054
 * Check error with #xmlXPathCheckError.
2055
 *
2056
 * Returns the string
2057
 */
2058
xmlChar *
2059
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2060
0
    xmlXPathObjectPtr obj;
2061
0
    xmlChar * ret;
2062
2063
0
    obj = valuePop(ctxt);
2064
0
    if (obj == NULL) {
2065
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2066
0
  return(NULL);
2067
0
    }
2068
0
    ret = xmlXPathCastToString(obj);
2069
0
    if (ret == NULL)
2070
0
        xmlXPathPErrMemory(ctxt);
2071
0
    xmlXPathReleaseObject(ctxt->context, obj);
2072
0
    return(ret);
2073
0
}
2074
2075
/**
2076
 * xmlXPathPopNodeSet:
2077
 * @ctxt:  an XPath parser context
2078
 *
2079
 * Pops a node-set from the stack, handling conversion if needed.
2080
 * Check error with #xmlXPathCheckError.
2081
 *
2082
 * Returns the node-set
2083
 */
2084
xmlNodeSetPtr
2085
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2086
0
    xmlXPathObjectPtr obj;
2087
0
    xmlNodeSetPtr ret;
2088
2089
0
    if (ctxt == NULL) return(NULL);
2090
0
    if (ctxt->value == NULL) {
2091
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2092
0
  return(NULL);
2093
0
    }
2094
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2095
0
  xmlXPathSetTypeError(ctxt);
2096
0
  return(NULL);
2097
0
    }
2098
0
    obj = valuePop(ctxt);
2099
0
    ret = obj->nodesetval;
2100
0
    obj->nodesetval = NULL;
2101
0
    xmlXPathReleaseObject(ctxt->context, obj);
2102
0
    return(ret);
2103
0
}
2104
2105
/**
2106
 * xmlXPathPopExternal:
2107
 * @ctxt:  an XPath parser context
2108
 *
2109
 * Pops an external object from the stack, handling conversion if needed.
2110
 * Check error with #xmlXPathCheckError.
2111
 *
2112
 * Returns the object
2113
 */
2114
void *
2115
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2116
0
    xmlXPathObjectPtr obj;
2117
0
    void * ret;
2118
2119
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2120
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2121
0
  return(NULL);
2122
0
    }
2123
0
    if (ctxt->value->type != XPATH_USERS) {
2124
0
  xmlXPathSetTypeError(ctxt);
2125
0
  return(NULL);
2126
0
    }
2127
0
    obj = valuePop(ctxt);
2128
0
    ret = obj->user;
2129
0
    obj->user = NULL;
2130
0
    xmlXPathReleaseObject(ctxt->context, obj);
2131
0
    return(ret);
2132
0
}
2133
2134
/*
2135
 * Macros for accessing the content. Those should be used only by the parser,
2136
 * and not exported.
2137
 *
2138
 * Dirty macros, i.e. one need to make assumption on the context to use them
2139
 *
2140
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2141
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2142
 *           in ISO-Latin or UTF-8.
2143
 *           This should be used internally by the parser
2144
 *           only to compare to ASCII values otherwise it would break when
2145
 *           running with UTF-8 encoding.
2146
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2147
 *           to compare on ASCII based substring.
2148
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2149
 *           strings within the parser.
2150
 *   CURRENT Returns the current char value, with the full decoding of
2151
 *           UTF-8 if we are using this mode. It returns an int.
2152
 *   NEXT    Skip to the next character, this does the proper decoding
2153
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2154
 *           It returns the pointer to the current xmlChar.
2155
 */
2156
2157
0
#define CUR (*ctxt->cur)
2158
0
#define SKIP(val) ctxt->cur += (val)
2159
0
#define NXT(val) ctxt->cur[(val)]
2160
0
#define CUR_PTR ctxt->cur
2161
0
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2162
2163
#define COPY_BUF(b, i, v)           \
2164
0
    if (v < 0x80) b[i++] = v;           \
2165
0
    else i += xmlCopyCharMultiByte(&b[i],v)
2166
2167
0
#define NEXTL(l)  ctxt->cur += l
2168
2169
#define SKIP_BLANKS             \
2170
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2171
2172
#define CURRENT (*ctxt->cur)
2173
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2174
2175
2176
#ifndef DBL_DIG
2177
#define DBL_DIG 16
2178
#endif
2179
#ifndef DBL_EPSILON
2180
#define DBL_EPSILON 1E-9
2181
#endif
2182
2183
0
#define UPPER_DOUBLE 1E9
2184
0
#define LOWER_DOUBLE 1E-5
2185
#define LOWER_DOUBLE_EXP 5
2186
2187
#define INTEGER_DIGITS DBL_DIG
2188
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2189
0
#define EXPONENT_DIGITS (3 + 2)
2190
2191
/**
2192
 * xmlXPathFormatNumber:
2193
 * @number:     number to format
2194
 * @buffer:     output buffer
2195
 * @buffersize: size of output buffer
2196
 *
2197
 * Convert the number into a string representation.
2198
 */
2199
static void
2200
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2201
0
{
2202
0
    switch (xmlXPathIsInf(number)) {
2203
0
    case 1:
2204
0
  if (buffersize > (int)sizeof("Infinity"))
2205
0
      snprintf(buffer, buffersize, "Infinity");
2206
0
  break;
2207
0
    case -1:
2208
0
  if (buffersize > (int)sizeof("-Infinity"))
2209
0
      snprintf(buffer, buffersize, "-Infinity");
2210
0
  break;
2211
0
    default:
2212
0
  if (xmlXPathIsNaN(number)) {
2213
0
      if (buffersize > (int)sizeof("NaN"))
2214
0
    snprintf(buffer, buffersize, "NaN");
2215
0
  } else if (number == 0) {
2216
            /* Omit sign for negative zero. */
2217
0
      snprintf(buffer, buffersize, "0");
2218
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2219
0
                   (number == (int) number)) {
2220
0
      char work[30];
2221
0
      char *ptr, *cur;
2222
0
      int value = (int) number;
2223
2224
0
            ptr = &buffer[0];
2225
0
      if (value == 0) {
2226
0
    *ptr++ = '0';
2227
0
      } else {
2228
0
    snprintf(work, 29, "%d", value);
2229
0
    cur = &work[0];
2230
0
    while ((*cur) && (ptr - buffer < buffersize)) {
2231
0
        *ptr++ = *cur++;
2232
0
    }
2233
0
      }
2234
0
      if (ptr - buffer < buffersize) {
2235
0
    *ptr = 0;
2236
0
      } else if (buffersize > 0) {
2237
0
    ptr--;
2238
0
    *ptr = 0;
2239
0
      }
2240
0
  } else {
2241
      /*
2242
        For the dimension of work,
2243
            DBL_DIG is number of significant digits
2244
      EXPONENT is only needed for "scientific notation"
2245
            3 is sign, decimal point, and terminating zero
2246
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2247
        Note that this dimension is slightly (a few characters)
2248
        larger than actually necessary.
2249
      */
2250
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2251
0
      int integer_place, fraction_place;
2252
0
      char *ptr;
2253
0
      char *after_fraction;
2254
0
      double absolute_value;
2255
0
      int size;
2256
2257
0
      absolute_value = fabs(number);
2258
2259
      /*
2260
       * First choose format - scientific or regular floating point.
2261
       * In either case, result is in work, and after_fraction points
2262
       * just past the fractional part.
2263
      */
2264
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
2265
0
      (absolute_value < LOWER_DOUBLE)) &&
2266
0
     (absolute_value != 0.0) ) {
2267
    /* Use scientific notation */
2268
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2269
0
    fraction_place = DBL_DIG - 1;
2270
0
    size = snprintf(work, sizeof(work),"%*.*e",
2271
0
       integer_place, fraction_place, number);
2272
0
    while ((size > 0) && (work[size] != 'e')) size--;
2273
2274
0
      }
2275
0
      else {
2276
    /* Use regular notation */
2277
0
    if (absolute_value > 0.0) {
2278
0
        integer_place = (int)log10(absolute_value);
2279
0
        if (integer_place > 0)
2280
0
            fraction_place = DBL_DIG - integer_place - 1;
2281
0
        else
2282
0
            fraction_place = DBL_DIG - integer_place;
2283
0
    } else {
2284
0
        fraction_place = 1;
2285
0
    }
2286
0
    size = snprintf(work, sizeof(work), "%0.*f",
2287
0
        fraction_place, number);
2288
0
      }
2289
2290
      /* Remove leading spaces sometimes inserted by snprintf */
2291
0
      while (work[0] == ' ') {
2292
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2293
0
    size--;
2294
0
      }
2295
2296
      /* Remove fractional trailing zeroes */
2297
0
      after_fraction = work + size;
2298
0
      ptr = after_fraction;
2299
0
      while (*(--ptr) == '0')
2300
0
    ;
2301
0
      if (*ptr != '.')
2302
0
          ptr++;
2303
0
      while ((*ptr++ = *after_fraction++) != 0);
2304
2305
      /* Finally copy result back to caller */
2306
0
      size = strlen(work) + 1;
2307
0
      if (size > buffersize) {
2308
0
    work[buffersize - 1] = 0;
2309
0
    size = buffersize;
2310
0
      }
2311
0
      memmove(buffer, work, size);
2312
0
  }
2313
0
  break;
2314
0
    }
2315
0
}
2316
2317
2318
/************************************************************************
2319
 *                  *
2320
 *      Routines to handle NodeSets     *
2321
 *                  *
2322
 ************************************************************************/
2323
2324
/**
2325
 * xmlXPathOrderDocElems:
2326
 * @doc:  an input document
2327
 *
2328
 * Call this routine to speed up XPath computation on static documents.
2329
 * This stamps all the element nodes with the document order
2330
 * Like for line information, the order is kept in the element->content
2331
 * field, the value stored is actually - the node number (starting at -1)
2332
 * to be able to differentiate from line numbers.
2333
 *
2334
 * Returns the number of elements found in the document or -1 in case
2335
 *    of error.
2336
 */
2337
long
2338
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
2339
0
    ptrdiff_t count = 0;
2340
0
    xmlNodePtr cur;
2341
2342
0
    if (doc == NULL)
2343
0
  return(-1);
2344
0
    cur = doc->children;
2345
0
    while (cur != NULL) {
2346
0
  if (cur->type == XML_ELEMENT_NODE) {
2347
0
      cur->content = (void *) (-(++count));
2348
0
      if (cur->children != NULL) {
2349
0
    cur = cur->children;
2350
0
    continue;
2351
0
      }
2352
0
  }
2353
0
  if (cur->next != NULL) {
2354
0
      cur = cur->next;
2355
0
      continue;
2356
0
  }
2357
0
  do {
2358
0
      cur = cur->parent;
2359
0
      if (cur == NULL)
2360
0
    break;
2361
0
      if (cur == (xmlNodePtr) doc) {
2362
0
    cur = NULL;
2363
0
    break;
2364
0
      }
2365
0
      if (cur->next != NULL) {
2366
0
    cur = cur->next;
2367
0
    break;
2368
0
      }
2369
0
  } while (cur != NULL);
2370
0
    }
2371
0
    return(count);
2372
0
}
2373
2374
/**
2375
 * xmlXPathCmpNodes:
2376
 * @node1:  the first node
2377
 * @node2:  the second node
2378
 *
2379
 * Compare two nodes w.r.t document order
2380
 *
2381
 * Returns -2 in case of error 1 if first point < second point, 0 if
2382
 *         it's the same node, -1 otherwise
2383
 */
2384
int
2385
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2386
0
    int depth1, depth2;
2387
0
    int attr1 = 0, attr2 = 0;
2388
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2389
0
    xmlNodePtr cur, root;
2390
2391
0
    if ((node1 == NULL) || (node2 == NULL))
2392
0
  return(-2);
2393
    /*
2394
     * a couple of optimizations which will avoid computations in most cases
2395
     */
2396
0
    if (node1 == node2)   /* trivial case */
2397
0
  return(0);
2398
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2399
0
  attr1 = 1;
2400
0
  attrNode1 = node1;
2401
0
  node1 = node1->parent;
2402
0
    }
2403
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2404
0
  attr2 = 1;
2405
0
  attrNode2 = node2;
2406
0
  node2 = node2->parent;
2407
0
    }
2408
0
    if (node1 == node2) {
2409
0
  if (attr1 == attr2) {
2410
      /* not required, but we keep attributes in order */
2411
0
      if (attr1 != 0) {
2412
0
          cur = attrNode2->prev;
2413
0
    while (cur != NULL) {
2414
0
        if (cur == attrNode1)
2415
0
            return (1);
2416
0
        cur = cur->prev;
2417
0
    }
2418
0
    return (-1);
2419
0
      }
2420
0
      return(0);
2421
0
  }
2422
0
  if (attr2 == 1)
2423
0
      return(1);
2424
0
  return(-1);
2425
0
    }
2426
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2427
0
        (node2->type == XML_NAMESPACE_DECL))
2428
0
  return(1);
2429
0
    if (node1 == node2->prev)
2430
0
  return(1);
2431
0
    if (node1 == node2->next)
2432
0
  return(-1);
2433
2434
    /*
2435
     * Speedup using document order if available.
2436
     */
2437
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2438
0
  (node2->type == XML_ELEMENT_NODE) &&
2439
0
  (0 > (ptrdiff_t) node1->content) &&
2440
0
  (0 > (ptrdiff_t) node2->content) &&
2441
0
  (node1->doc == node2->doc)) {
2442
0
  ptrdiff_t l1, l2;
2443
2444
0
  l1 = -((ptrdiff_t) node1->content);
2445
0
  l2 = -((ptrdiff_t) node2->content);
2446
0
  if (l1 < l2)
2447
0
      return(1);
2448
0
  if (l1 > l2)
2449
0
      return(-1);
2450
0
    }
2451
2452
    /*
2453
     * compute depth to root
2454
     */
2455
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2456
0
  if (cur->parent == node1)
2457
0
      return(1);
2458
0
  depth2++;
2459
0
    }
2460
0
    root = cur;
2461
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2462
0
  if (cur->parent == node2)
2463
0
      return(-1);
2464
0
  depth1++;
2465
0
    }
2466
    /*
2467
     * Distinct document (or distinct entities :-( ) case.
2468
     */
2469
0
    if (root != cur) {
2470
0
  return(-2);
2471
0
    }
2472
    /*
2473
     * get the nearest common ancestor.
2474
     */
2475
0
    while (depth1 > depth2) {
2476
0
  depth1--;
2477
0
  node1 = node1->parent;
2478
0
    }
2479
0
    while (depth2 > depth1) {
2480
0
  depth2--;
2481
0
  node2 = node2->parent;
2482
0
    }
2483
0
    while (node1->parent != node2->parent) {
2484
0
  node1 = node1->parent;
2485
0
  node2 = node2->parent;
2486
  /* should not happen but just in case ... */
2487
0
  if ((node1 == NULL) || (node2 == NULL))
2488
0
      return(-2);
2489
0
    }
2490
    /*
2491
     * Find who's first.
2492
     */
2493
0
    if (node1 == node2->prev)
2494
0
  return(1);
2495
0
    if (node1 == node2->next)
2496
0
  return(-1);
2497
    /*
2498
     * Speedup using document order if available.
2499
     */
2500
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2501
0
  (node2->type == XML_ELEMENT_NODE) &&
2502
0
  (0 > (ptrdiff_t) node1->content) &&
2503
0
  (0 > (ptrdiff_t) node2->content) &&
2504
0
  (node1->doc == node2->doc)) {
2505
0
  ptrdiff_t l1, l2;
2506
2507
0
  l1 = -((ptrdiff_t) node1->content);
2508
0
  l2 = -((ptrdiff_t) node2->content);
2509
0
  if (l1 < l2)
2510
0
      return(1);
2511
0
  if (l1 > l2)
2512
0
      return(-1);
2513
0
    }
2514
2515
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2516
0
  if (cur == node2)
2517
0
      return(1);
2518
0
    return(-1); /* assume there is no sibling list corruption */
2519
0
}
2520
2521
/**
2522
 * xmlXPathNodeSetSort:
2523
 * @set:  the node set
2524
 *
2525
 * Sort the node set in document order
2526
 */
2527
void
2528
0
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2529
#ifndef WITH_TIM_SORT
2530
    int i, j, incr, len;
2531
    xmlNodePtr tmp;
2532
#endif
2533
2534
0
    if (set == NULL)
2535
0
  return;
2536
2537
#ifndef WITH_TIM_SORT
2538
    /*
2539
     * Use the old Shell's sort implementation to sort the node-set
2540
     * Timsort ought to be quite faster
2541
     */
2542
    len = set->nodeNr;
2543
    for (incr = len / 2; incr > 0; incr /= 2) {
2544
  for (i = incr; i < len; i++) {
2545
      j = i - incr;
2546
      while (j >= 0) {
2547
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2548
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
2549
      set->nodeTab[j + incr]) == -1)
2550
#else
2551
    if (xmlXPathCmpNodes(set->nodeTab[j],
2552
      set->nodeTab[j + incr]) == -1)
2553
#endif
2554
    {
2555
        tmp = set->nodeTab[j];
2556
        set->nodeTab[j] = set->nodeTab[j + incr];
2557
        set->nodeTab[j + incr] = tmp;
2558
        j -= incr;
2559
    } else
2560
        break;
2561
      }
2562
  }
2563
    }
2564
#else /* WITH_TIM_SORT */
2565
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2566
0
#endif /* WITH_TIM_SORT */
2567
0
}
2568
2569
0
#define XML_NODESET_DEFAULT 10
2570
/**
2571
 * xmlXPathNodeSetDupNs:
2572
 * @node:  the parent node of the namespace XPath node
2573
 * @ns:  the libxml namespace declaration node.
2574
 *
2575
 * Namespace node in libxml don't match the XPath semantic. In a node set
2576
 * the namespace nodes are duplicated and the next pointer is set to the
2577
 * parent node in the XPath semantic.
2578
 *
2579
 * Returns the newly created object.
2580
 */
2581
static xmlNodePtr
2582
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2583
0
    xmlNsPtr cur;
2584
2585
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2586
0
  return(NULL);
2587
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2588
0
  return((xmlNodePtr) ns);
2589
2590
    /*
2591
     * Allocate a new Namespace and fill the fields.
2592
     */
2593
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2594
0
    if (cur == NULL)
2595
0
  return(NULL);
2596
0
    memset(cur, 0, sizeof(xmlNs));
2597
0
    cur->type = XML_NAMESPACE_DECL;
2598
0
    if (ns->href != NULL) {
2599
0
  cur->href = xmlStrdup(ns->href);
2600
0
        if (cur->href == NULL) {
2601
0
            xmlFree(cur);
2602
0
            return(NULL);
2603
0
        }
2604
0
    }
2605
0
    if (ns->prefix != NULL) {
2606
0
  cur->prefix = xmlStrdup(ns->prefix);
2607
0
        if (cur->prefix == NULL) {
2608
0
            xmlFree((xmlChar *) cur->href);
2609
0
            xmlFree(cur);
2610
0
            return(NULL);
2611
0
        }
2612
0
    }
2613
0
    cur->next = (xmlNsPtr) node;
2614
0
    return((xmlNodePtr) cur);
2615
0
}
2616
2617
/**
2618
 * xmlXPathNodeSetFreeNs:
2619
 * @ns:  the XPath namespace node found in a nodeset.
2620
 *
2621
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2622
 * the namespace nodes are duplicated and the next pointer is set to the
2623
 * parent node in the XPath semantic. Check if such a node needs to be freed
2624
 */
2625
void
2626
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2627
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2628
0
  return;
2629
2630
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2631
0
  if (ns->href != NULL)
2632
0
      xmlFree((xmlChar *)ns->href);
2633
0
  if (ns->prefix != NULL)
2634
0
      xmlFree((xmlChar *)ns->prefix);
2635
0
  xmlFree(ns);
2636
0
    }
2637
0
}
2638
2639
/**
2640
 * xmlXPathNodeSetCreate:
2641
 * @val:  an initial xmlNodePtr, or NULL
2642
 *
2643
 * Create a new xmlNodeSetPtr of type double and of value @val
2644
 *
2645
 * Returns the newly created object.
2646
 */
2647
xmlNodeSetPtr
2648
0
xmlXPathNodeSetCreate(xmlNodePtr val) {
2649
0
    xmlNodeSetPtr ret;
2650
2651
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2652
0
    if (ret == NULL)
2653
0
  return(NULL);
2654
0
    memset(ret, 0 , sizeof(xmlNodeSet));
2655
0
    if (val != NULL) {
2656
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2657
0
               sizeof(xmlNodePtr));
2658
0
  if (ret->nodeTab == NULL) {
2659
0
      xmlFree(ret);
2660
0
      return(NULL);
2661
0
  }
2662
0
  memset(ret->nodeTab, 0 ,
2663
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2664
0
        ret->nodeMax = XML_NODESET_DEFAULT;
2665
0
  if (val->type == XML_NAMESPACE_DECL) {
2666
0
      xmlNsPtr ns = (xmlNsPtr) val;
2667
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2668
2669
0
            if (nsNode == NULL) {
2670
0
                xmlXPathFreeNodeSet(ret);
2671
0
                return(NULL);
2672
0
            }
2673
0
      ret->nodeTab[ret->nodeNr++] = nsNode;
2674
0
  } else
2675
0
      ret->nodeTab[ret->nodeNr++] = val;
2676
0
    }
2677
0
    return(ret);
2678
0
}
2679
2680
/**
2681
 * xmlXPathNodeSetContains:
2682
 * @cur:  the node-set
2683
 * @val:  the node
2684
 *
2685
 * checks whether @cur contains @val
2686
 *
2687
 * Returns true (1) if @cur contains @val, false (0) otherwise
2688
 */
2689
int
2690
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
2691
0
    int i;
2692
2693
0
    if ((cur == NULL) || (val == NULL)) return(0);
2694
0
    if (val->type == XML_NAMESPACE_DECL) {
2695
0
  for (i = 0; i < cur->nodeNr; i++) {
2696
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2697
0
    xmlNsPtr ns1, ns2;
2698
2699
0
    ns1 = (xmlNsPtr) val;
2700
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2701
0
    if (ns1 == ns2)
2702
0
        return(1);
2703
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2704
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2705
0
        return(1);
2706
0
      }
2707
0
  }
2708
0
    } else {
2709
0
  for (i = 0; i < cur->nodeNr; i++) {
2710
0
      if (cur->nodeTab[i] == val)
2711
0
    return(1);
2712
0
  }
2713
0
    }
2714
0
    return(0);
2715
0
}
2716
2717
/**
2718
 * xmlXPathNodeSetAddNs:
2719
 * @cur:  the initial node set
2720
 * @node:  the hosting node
2721
 * @ns:  a the namespace node
2722
 *
2723
 * add a new namespace node to an existing NodeSet
2724
 *
2725
 * Returns 0 in case of success and -1 in case of error
2726
 */
2727
int
2728
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
2729
0
    int i;
2730
0
    xmlNodePtr nsNode;
2731
2732
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2733
0
        (ns->type != XML_NAMESPACE_DECL) ||
2734
0
  (node->type != XML_ELEMENT_NODE))
2735
0
  return(-1);
2736
2737
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2738
    /*
2739
     * prevent duplicates
2740
     */
2741
0
    for (i = 0;i < cur->nodeNr;i++) {
2742
0
        if ((cur->nodeTab[i] != NULL) &&
2743
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2744
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2745
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2746
0
      return(0);
2747
0
    }
2748
2749
    /*
2750
     * grow the nodeTab if needed
2751
     */
2752
0
    if (cur->nodeMax == 0) {
2753
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2754
0
               sizeof(xmlNodePtr));
2755
0
  if (cur->nodeTab == NULL)
2756
0
      return(-1);
2757
0
  memset(cur->nodeTab, 0 ,
2758
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2759
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2760
0
    } else if (cur->nodeNr == cur->nodeMax) {
2761
0
        xmlNodePtr *temp;
2762
2763
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2764
0
            return(-1);
2765
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2766
0
              sizeof(xmlNodePtr));
2767
0
  if (temp == NULL)
2768
0
      return(-1);
2769
0
        cur->nodeMax *= 2;
2770
0
  cur->nodeTab = temp;
2771
0
    }
2772
0
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2773
0
    if(nsNode == NULL)
2774
0
        return(-1);
2775
0
    cur->nodeTab[cur->nodeNr++] = nsNode;
2776
0
    return(0);
2777
0
}
2778
2779
/**
2780
 * xmlXPathNodeSetAdd:
2781
 * @cur:  the initial node set
2782
 * @val:  a new xmlNodePtr
2783
 *
2784
 * add a new xmlNodePtr to an existing NodeSet
2785
 *
2786
 * Returns 0 in case of success, and -1 in case of error
2787
 */
2788
int
2789
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
2790
0
    int i;
2791
2792
0
    if ((cur == NULL) || (val == NULL)) return(-1);
2793
2794
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2795
    /*
2796
     * prevent duplicates
2797
     */
2798
0
    for (i = 0;i < cur->nodeNr;i++)
2799
0
        if (cur->nodeTab[i] == val) return(0);
2800
2801
    /*
2802
     * grow the nodeTab if needed
2803
     */
2804
0
    if (cur->nodeMax == 0) {
2805
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2806
0
               sizeof(xmlNodePtr));
2807
0
  if (cur->nodeTab == NULL)
2808
0
      return(-1);
2809
0
  memset(cur->nodeTab, 0 ,
2810
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2811
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2812
0
    } else if (cur->nodeNr == cur->nodeMax) {
2813
0
        xmlNodePtr *temp;
2814
2815
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2816
0
            return(-1);
2817
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2818
0
              sizeof(xmlNodePtr));
2819
0
  if (temp == NULL)
2820
0
      return(-1);
2821
0
        cur->nodeMax *= 2;
2822
0
  cur->nodeTab = temp;
2823
0
    }
2824
0
    if (val->type == XML_NAMESPACE_DECL) {
2825
0
  xmlNsPtr ns = (xmlNsPtr) val;
2826
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2827
2828
0
        if (nsNode == NULL)
2829
0
            return(-1);
2830
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2831
0
    } else
2832
0
  cur->nodeTab[cur->nodeNr++] = val;
2833
0
    return(0);
2834
0
}
2835
2836
/**
2837
 * xmlXPathNodeSetAddUnique:
2838
 * @cur:  the initial node set
2839
 * @val:  a new xmlNodePtr
2840
 *
2841
 * add a new xmlNodePtr to an existing NodeSet, optimized version
2842
 * when we are sure the node is not already in the set.
2843
 *
2844
 * Returns 0 in case of success and -1 in case of failure
2845
 */
2846
int
2847
0
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
2848
0
    if ((cur == NULL) || (val == NULL)) return(-1);
2849
2850
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2851
    /*
2852
     * grow the nodeTab if needed
2853
     */
2854
0
    if (cur->nodeMax == 0) {
2855
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2856
0
               sizeof(xmlNodePtr));
2857
0
  if (cur->nodeTab == NULL)
2858
0
      return(-1);
2859
0
  memset(cur->nodeTab, 0 ,
2860
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2861
0
        cur->nodeMax = XML_NODESET_DEFAULT;
2862
0
    } else if (cur->nodeNr == cur->nodeMax) {
2863
0
        xmlNodePtr *temp;
2864
2865
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2866
0
            return(-1);
2867
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
2868
0
              sizeof(xmlNodePtr));
2869
0
  if (temp == NULL)
2870
0
      return(-1);
2871
0
  cur->nodeTab = temp;
2872
0
        cur->nodeMax *= 2;
2873
0
    }
2874
0
    if (val->type == XML_NAMESPACE_DECL) {
2875
0
  xmlNsPtr ns = (xmlNsPtr) val;
2876
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2877
2878
0
        if (nsNode == NULL)
2879
0
            return(-1);
2880
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2881
0
    } else
2882
0
  cur->nodeTab[cur->nodeNr++] = val;
2883
0
    return(0);
2884
0
}
2885
2886
/**
2887
 * xmlXPathNodeSetMerge:
2888
 * @val1:  the first NodeSet or NULL
2889
 * @val2:  the second NodeSet
2890
 *
2891
 * Merges two nodesets, all nodes from @val2 are added to @val1
2892
 * if @val1 is NULL, a new set is created and copied from @val2
2893
 *
2894
 * Returns @val1 once extended or NULL in case of error.
2895
 *
2896
 * Frees @val1 in case of error.
2897
 */
2898
xmlNodeSetPtr
2899
0
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
2900
0
    int i, j, initNr, skip;
2901
0
    xmlNodePtr n1, n2;
2902
2903
0
    if (val1 == NULL) {
2904
0
  val1 = xmlXPathNodeSetCreate(NULL);
2905
0
        if (val1 == NULL)
2906
0
            return (NULL);
2907
0
    }
2908
0
    if (val2 == NULL)
2909
0
        return(val1);
2910
2911
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2912
0
    initNr = val1->nodeNr;
2913
2914
0
    for (i = 0;i < val2->nodeNr;i++) {
2915
0
  n2 = val2->nodeTab[i];
2916
  /*
2917
   * check against duplicates
2918
   */
2919
0
  skip = 0;
2920
0
  for (j = 0; j < initNr; j++) {
2921
0
      n1 = val1->nodeTab[j];
2922
0
      if (n1 == n2) {
2923
0
    skip = 1;
2924
0
    break;
2925
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2926
0
           (n2->type == XML_NAMESPACE_DECL)) {
2927
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2928
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2929
0
      ((xmlNsPtr) n2)->prefix)))
2930
0
    {
2931
0
        skip = 1;
2932
0
        break;
2933
0
    }
2934
0
      }
2935
0
  }
2936
0
  if (skip)
2937
0
      continue;
2938
2939
  /*
2940
   * grow the nodeTab if needed
2941
   */
2942
0
  if (val1->nodeMax == 0) {
2943
0
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2944
0
                sizeof(xmlNodePtr));
2945
0
      if (val1->nodeTab == NULL)
2946
0
    goto error;
2947
0
      memset(val1->nodeTab, 0 ,
2948
0
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2949
0
      val1->nodeMax = XML_NODESET_DEFAULT;
2950
0
  } else if (val1->nodeNr == val1->nodeMax) {
2951
0
      xmlNodePtr *temp;
2952
2953
0
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
2954
0
                goto error;
2955
0
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
2956
0
               sizeof(xmlNodePtr));
2957
0
      if (temp == NULL)
2958
0
    goto error;
2959
0
      val1->nodeTab = temp;
2960
0
      val1->nodeMax *= 2;
2961
0
  }
2962
0
  if (n2->type == XML_NAMESPACE_DECL) {
2963
0
      xmlNsPtr ns = (xmlNsPtr) n2;
2964
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2965
2966
0
            if (nsNode == NULL)
2967
0
                goto error;
2968
0
      val1->nodeTab[val1->nodeNr++] = nsNode;
2969
0
  } else
2970
0
      val1->nodeTab[val1->nodeNr++] = n2;
2971
0
    }
2972
2973
0
    return(val1);
2974
2975
0
error:
2976
0
    xmlXPathFreeNodeSet(val1);
2977
0
    return(NULL);
2978
0
}
2979
2980
2981
/**
2982
 * xmlXPathNodeSetMergeAndClear:
2983
 * @set1:  the first NodeSet or NULL
2984
 * @set2:  the second NodeSet
2985
 *
2986
 * Merges two nodesets, all nodes from @set2 are added to @set1.
2987
 * Checks for duplicate nodes. Clears set2.
2988
 *
2989
 * Returns @set1 once extended or NULL in case of error.
2990
 *
2991
 * Frees @set1 in case of error.
2992
 */
2993
static xmlNodeSetPtr
2994
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2995
0
{
2996
0
    {
2997
0
  int i, j, initNbSet1;
2998
0
  xmlNodePtr n1, n2;
2999
3000
0
  initNbSet1 = set1->nodeNr;
3001
0
  for (i = 0;i < set2->nodeNr;i++) {
3002
0
      n2 = set2->nodeTab[i];
3003
      /*
3004
      * Skip duplicates.
3005
      */
3006
0
      for (j = 0; j < initNbSet1; j++) {
3007
0
    n1 = set1->nodeTab[j];
3008
0
    if (n1 == n2) {
3009
0
        goto skip_node;
3010
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3011
0
        (n2->type == XML_NAMESPACE_DECL))
3012
0
    {
3013
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3014
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3015
0
      ((xmlNsPtr) n2)->prefix)))
3016
0
        {
3017
      /*
3018
      * Free the namespace node.
3019
      */
3020
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3021
0
      goto skip_node;
3022
0
        }
3023
0
    }
3024
0
      }
3025
      /*
3026
      * grow the nodeTab if needed
3027
      */
3028
0
      if (set1->nodeMax == 0) {
3029
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3030
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3031
0
    if (set1->nodeTab == NULL)
3032
0
        goto error;
3033
0
    memset(set1->nodeTab, 0,
3034
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3035
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3036
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3037
0
    xmlNodePtr *temp;
3038
3039
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3040
0
                    goto error;
3041
0
    temp = (xmlNodePtr *) xmlRealloc(
3042
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3043
0
    if (temp == NULL)
3044
0
        goto error;
3045
0
    set1->nodeTab = temp;
3046
0
    set1->nodeMax *= 2;
3047
0
      }
3048
0
      set1->nodeTab[set1->nodeNr++] = n2;
3049
0
skip_node:
3050
0
            set2->nodeTab[i] = NULL;
3051
0
  }
3052
0
    }
3053
0
    set2->nodeNr = 0;
3054
0
    return(set1);
3055
3056
0
error:
3057
0
    xmlXPathFreeNodeSet(set1);
3058
0
    xmlXPathNodeSetClear(set2, 1);
3059
0
    return(NULL);
3060
0
}
3061
3062
/**
3063
 * xmlXPathNodeSetMergeAndClearNoDupls:
3064
 * @set1:  the first NodeSet or NULL
3065
 * @set2:  the second NodeSet
3066
 *
3067
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3068
 * Doesn't check for duplicate nodes. Clears set2.
3069
 *
3070
 * Returns @set1 once extended or NULL in case of error.
3071
 *
3072
 * Frees @set1 in case of error.
3073
 */
3074
static xmlNodeSetPtr
3075
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3076
0
{
3077
0
    {
3078
0
  int i;
3079
0
  xmlNodePtr n2;
3080
3081
0
  for (i = 0;i < set2->nodeNr;i++) {
3082
0
      n2 = set2->nodeTab[i];
3083
0
      if (set1->nodeMax == 0) {
3084
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3085
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3086
0
    if (set1->nodeTab == NULL)
3087
0
        goto error;
3088
0
    memset(set1->nodeTab, 0,
3089
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3090
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3091
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3092
0
    xmlNodePtr *temp;
3093
3094
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH)
3095
0
                    goto error;
3096
0
    temp = (xmlNodePtr *) xmlRealloc(
3097
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3098
0
    if (temp == NULL)
3099
0
        goto error;
3100
0
    set1->nodeTab = temp;
3101
0
    set1->nodeMax *= 2;
3102
0
      }
3103
0
      set1->nodeTab[set1->nodeNr++] = n2;
3104
0
            set2->nodeTab[i] = NULL;
3105
0
  }
3106
0
    }
3107
0
    set2->nodeNr = 0;
3108
0
    return(set1);
3109
3110
0
error:
3111
0
    xmlXPathFreeNodeSet(set1);
3112
0
    xmlXPathNodeSetClear(set2, 1);
3113
0
    return(NULL);
3114
0
}
3115
3116
/**
3117
 * xmlXPathNodeSetDel:
3118
 * @cur:  the initial node set
3119
 * @val:  an xmlNodePtr
3120
 *
3121
 * Removes an xmlNodePtr from an existing NodeSet
3122
 */
3123
void
3124
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3125
0
    int i;
3126
3127
0
    if (cur == NULL) return;
3128
0
    if (val == NULL) return;
3129
3130
    /*
3131
     * find node in nodeTab
3132
     */
3133
0
    for (i = 0;i < cur->nodeNr;i++)
3134
0
        if (cur->nodeTab[i] == val) break;
3135
3136
0
    if (i >= cur->nodeNr) { /* not found */
3137
0
        return;
3138
0
    }
3139
0
    if ((cur->nodeTab[i] != NULL) &&
3140
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3141
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3142
0
    cur->nodeNr--;
3143
0
    for (;i < cur->nodeNr;i++)
3144
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
3145
0
    cur->nodeTab[cur->nodeNr] = NULL;
3146
0
}
3147
3148
/**
3149
 * xmlXPathNodeSetRemove:
3150
 * @cur:  the initial node set
3151
 * @val:  the index to remove
3152
 *
3153
 * Removes an entry from an existing NodeSet list.
3154
 */
3155
void
3156
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3157
0
    if (cur == NULL) return;
3158
0
    if (val >= cur->nodeNr) return;
3159
0
    if ((cur->nodeTab[val] != NULL) &&
3160
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3161
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3162
0
    cur->nodeNr--;
3163
0
    for (;val < cur->nodeNr;val++)
3164
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
3165
0
    cur->nodeTab[cur->nodeNr] = NULL;
3166
0
}
3167
3168
/**
3169
 * xmlXPathFreeNodeSet:
3170
 * @obj:  the xmlNodeSetPtr to free
3171
 *
3172
 * Free the NodeSet compound (not the actual nodes !).
3173
 */
3174
void
3175
0
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3176
0
    if (obj == NULL) return;
3177
0
    if (obj->nodeTab != NULL) {
3178
0
  int i;
3179
3180
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3181
0
  for (i = 0;i < obj->nodeNr;i++)
3182
0
      if ((obj->nodeTab[i] != NULL) &&
3183
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3184
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3185
0
  xmlFree(obj->nodeTab);
3186
0
    }
3187
0
    xmlFree(obj);
3188
0
}
3189
3190
/**
3191
 * xmlXPathNodeSetClearFromPos:
3192
 * @set: the node set to be cleared
3193
 * @pos: the start position to clear from
3194
 *
3195
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3196
 * are feed) starting with the entry at @pos, but does *not* free the list
3197
 * itself. Sets the length of the list to @pos.
3198
 */
3199
static void
3200
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3201
0
{
3202
0
    if ((set == NULL) || (pos >= set->nodeNr))
3203
0
  return;
3204
0
    else if ((hasNsNodes)) {
3205
0
  int i;
3206
0
  xmlNodePtr node;
3207
3208
0
  for (i = pos; i < set->nodeNr; i++) {
3209
0
      node = set->nodeTab[i];
3210
0
      if ((node != NULL) &&
3211
0
    (node->type == XML_NAMESPACE_DECL))
3212
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3213
0
  }
3214
0
    }
3215
0
    set->nodeNr = pos;
3216
0
}
3217
3218
/**
3219
 * xmlXPathNodeSetClear:
3220
 * @set:  the node set to clear
3221
 *
3222
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3223
 * are feed), but does *not* free the list itself. Sets the length of the
3224
 * list to 0.
3225
 */
3226
static void
3227
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3228
0
{
3229
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3230
0
}
3231
3232
/**
3233
 * xmlXPathNodeSetKeepLast:
3234
 * @set: the node set to be cleared
3235
 *
3236
 * Move the last node to the first position and clear temporary XPath objects
3237
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3238
 * to 1.
3239
 */
3240
static void
3241
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3242
0
{
3243
0
    int i;
3244
0
    xmlNodePtr node;
3245
3246
0
    if ((set == NULL) || (set->nodeNr <= 1))
3247
0
  return;
3248
0
    for (i = 0; i < set->nodeNr - 1; i++) {
3249
0
        node = set->nodeTab[i];
3250
0
        if ((node != NULL) &&
3251
0
            (node->type == XML_NAMESPACE_DECL))
3252
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3253
0
    }
3254
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3255
0
    set->nodeNr = 1;
3256
0
}
3257
3258
/**
3259
 * xmlXPathNewNodeSet:
3260
 * @val:  the NodePtr value
3261
 *
3262
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3263
 * it with the single Node @val
3264
 *
3265
 * Returns the newly created object.
3266
 */
3267
xmlXPathObjectPtr
3268
0
xmlXPathNewNodeSet(xmlNodePtr val) {
3269
0
    xmlXPathObjectPtr ret;
3270
3271
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3272
0
    if (ret == NULL)
3273
0
  return(NULL);
3274
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3275
0
    ret->type = XPATH_NODESET;
3276
0
    ret->boolval = 0;
3277
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3278
0
    if (ret->nodesetval == NULL) {
3279
0
        xmlFree(ret);
3280
0
        return(NULL);
3281
0
    }
3282
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3283
0
    return(ret);
3284
0
}
3285
3286
/**
3287
 * xmlXPathNewValueTree:
3288
 * @val:  the NodePtr value
3289
 *
3290
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3291
 * it with the tree root @val
3292
 *
3293
 * Returns the newly created object.
3294
 */
3295
xmlXPathObjectPtr
3296
0
xmlXPathNewValueTree(xmlNodePtr val) {
3297
0
    xmlXPathObjectPtr ret;
3298
3299
0
    ret = xmlXPathNewNodeSet(val);
3300
0
    if (ret == NULL)
3301
0
  return(NULL);
3302
0
    ret->type = XPATH_XSLT_TREE;
3303
3304
0
    return(ret);
3305
0
}
3306
3307
/**
3308
 * xmlXPathNewNodeSetList:
3309
 * @val:  an existing NodeSet
3310
 *
3311
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3312
 * it with the Nodeset @val
3313
 *
3314
 * Returns the newly created object.
3315
 */
3316
xmlXPathObjectPtr
3317
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3318
0
{
3319
0
    xmlXPathObjectPtr ret;
3320
3321
0
    if (val == NULL)
3322
0
        ret = NULL;
3323
0
    else if (val->nodeTab == NULL)
3324
0
        ret = xmlXPathNewNodeSet(NULL);
3325
0
    else {
3326
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3327
0
        if (ret) {
3328
0
            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3329
0
            if (ret->nodesetval == NULL) {
3330
0
                xmlFree(ret);
3331
0
                return(NULL);
3332
0
            }
3333
0
        }
3334
0
    }
3335
3336
0
    return (ret);
3337
0
}
3338
3339
/**
3340
 * xmlXPathWrapNodeSet:
3341
 * @val:  the NodePtr value
3342
 *
3343
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3344
 *
3345
 * Returns the newly created object.
3346
 *
3347
 * In case of error the node set is destroyed and NULL is returned.
3348
 */
3349
xmlXPathObjectPtr
3350
0
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3351
0
    xmlXPathObjectPtr ret;
3352
3353
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3354
0
    if (ret == NULL) {
3355
0
        xmlXPathFreeNodeSet(val);
3356
0
  return(NULL);
3357
0
    }
3358
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3359
0
    ret->type = XPATH_NODESET;
3360
0
    ret->nodesetval = val;
3361
0
    return(ret);
3362
0
}
3363
3364
/**
3365
 * xmlXPathFreeNodeSetList:
3366
 * @obj:  an existing NodeSetList object
3367
 *
3368
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3369
 * the list contrary to xmlXPathFreeObject().
3370
 */
3371
void
3372
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3373
0
    if (obj == NULL) return;
3374
0
    xmlFree(obj);
3375
0
}
3376
3377
/**
3378
 * xmlXPathDifference:
3379
 * @nodes1:  a node-set
3380
 * @nodes2:  a node-set
3381
 *
3382
 * Implements the EXSLT - Sets difference() function:
3383
 *    node-set set:difference (node-set, node-set)
3384
 *
3385
 * Returns the difference between the two node sets, or nodes1 if
3386
 *         nodes2 is empty
3387
 */
3388
xmlNodeSetPtr
3389
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3390
0
    xmlNodeSetPtr ret;
3391
0
    int i, l1;
3392
0
    xmlNodePtr cur;
3393
3394
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3395
0
  return(nodes1);
3396
3397
0
    ret = xmlXPathNodeSetCreate(NULL);
3398
0
    if (ret == NULL)
3399
0
        return(NULL);
3400
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3401
0
  return(ret);
3402
3403
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3404
3405
0
    for (i = 0; i < l1; i++) {
3406
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3407
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3408
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3409
0
                xmlXPathFreeNodeSet(ret);
3410
0
          return(NULL);
3411
0
            }
3412
0
  }
3413
0
    }
3414
0
    return(ret);
3415
0
}
3416
3417
/**
3418
 * xmlXPathIntersection:
3419
 * @nodes1:  a node-set
3420
 * @nodes2:  a node-set
3421
 *
3422
 * Implements the EXSLT - Sets intersection() function:
3423
 *    node-set set:intersection (node-set, node-set)
3424
 *
3425
 * Returns a node set comprising the nodes that are within both the
3426
 *         node sets passed as arguments
3427
 */
3428
xmlNodeSetPtr
3429
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3430
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3431
0
    int i, l1;
3432
0
    xmlNodePtr cur;
3433
3434
0
    if (ret == NULL)
3435
0
        return(ret);
3436
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3437
0
  return(ret);
3438
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3439
0
  return(ret);
3440
3441
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3442
3443
0
    for (i = 0; i < l1; i++) {
3444
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3445
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3446
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3447
0
                xmlXPathFreeNodeSet(ret);
3448
0
          return(NULL);
3449
0
            }
3450
0
  }
3451
0
    }
3452
0
    return(ret);
3453
0
}
3454
3455
/**
3456
 * xmlXPathDistinctSorted:
3457
 * @nodes:  a node-set, sorted by document order
3458
 *
3459
 * Implements the EXSLT - Sets distinct() function:
3460
 *    node-set set:distinct (node-set)
3461
 *
3462
 * Returns a subset of the nodes contained in @nodes, or @nodes if
3463
 *         it is empty
3464
 */
3465
xmlNodeSetPtr
3466
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3467
0
    xmlNodeSetPtr ret;
3468
0
    xmlHashTablePtr hash;
3469
0
    int i, l;
3470
0
    xmlChar * strval;
3471
0
    xmlNodePtr cur;
3472
3473
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3474
0
  return(nodes);
3475
3476
0
    ret = xmlXPathNodeSetCreate(NULL);
3477
0
    if (ret == NULL)
3478
0
        return(ret);
3479
0
    l = xmlXPathNodeSetGetLength(nodes);
3480
0
    hash = xmlHashCreate (l);
3481
0
    for (i = 0; i < l; i++) {
3482
0
  cur = xmlXPathNodeSetItem(nodes, i);
3483
0
  strval = xmlXPathCastNodeToString(cur);
3484
0
  if (xmlHashLookup(hash, strval) == NULL) {
3485
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3486
0
                xmlFree(strval);
3487
0
                goto error;
3488
0
            }
3489
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3490
0
          goto error;
3491
0
  } else {
3492
0
      xmlFree(strval);
3493
0
  }
3494
0
    }
3495
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3496
0
    return(ret);
3497
3498
0
error:
3499
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3500
0
    xmlXPathFreeNodeSet(ret);
3501
0
    return(NULL);
3502
0
}
3503
3504
/**
3505
 * xmlXPathDistinct:
3506
 * @nodes:  a node-set
3507
 *
3508
 * Implements the EXSLT - Sets distinct() function:
3509
 *    node-set set:distinct (node-set)
3510
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3511
 * is called with the sorted node-set
3512
 *
3513
 * Returns a subset of the nodes contained in @nodes, or @nodes if
3514
 *         it is empty
3515
 */
3516
xmlNodeSetPtr
3517
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
3518
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3519
0
  return(nodes);
3520
3521
0
    xmlXPathNodeSetSort(nodes);
3522
0
    return(xmlXPathDistinctSorted(nodes));
3523
0
}
3524
3525
/**
3526
 * xmlXPathHasSameNodes:
3527
 * @nodes1:  a node-set
3528
 * @nodes2:  a node-set
3529
 *
3530
 * Implements the EXSLT - Sets has-same-nodes function:
3531
 *    boolean set:has-same-node(node-set, node-set)
3532
 *
3533
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3534
 *         otherwise
3535
 */
3536
int
3537
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3538
0
    int i, l;
3539
0
    xmlNodePtr cur;
3540
3541
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3542
0
  xmlXPathNodeSetIsEmpty(nodes2))
3543
0
  return(0);
3544
3545
0
    l = xmlXPathNodeSetGetLength(nodes1);
3546
0
    for (i = 0; i < l; i++) {
3547
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3548
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3549
0
      return(1);
3550
0
    }
3551
0
    return(0);
3552
0
}
3553
3554
/**
3555
 * xmlXPathNodeLeadingSorted:
3556
 * @nodes: a node-set, sorted by document order
3557
 * @node: a node
3558
 *
3559
 * Implements the EXSLT - Sets leading() function:
3560
 *    node-set set:leading (node-set, node-set)
3561
 *
3562
 * Returns the nodes in @nodes that precede @node in document order,
3563
 *         @nodes if @node is NULL or an empty node-set if @nodes
3564
 *         doesn't contain @node
3565
 */
3566
xmlNodeSetPtr
3567
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3568
0
    int i, l;
3569
0
    xmlNodePtr cur;
3570
0
    xmlNodeSetPtr ret;
3571
3572
0
    if (node == NULL)
3573
0
  return(nodes);
3574
3575
0
    ret = xmlXPathNodeSetCreate(NULL);
3576
0
    if (ret == NULL)
3577
0
        return(ret);
3578
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3579
0
  (!xmlXPathNodeSetContains(nodes, node)))
3580
0
  return(ret);
3581
3582
0
    l = xmlXPathNodeSetGetLength(nodes);
3583
0
    for (i = 0; i < l; i++) {
3584
0
  cur = xmlXPathNodeSetItem(nodes, i);
3585
0
  if (cur == node)
3586
0
      break;
3587
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3588
0
            xmlXPathFreeNodeSet(ret);
3589
0
      return(NULL);
3590
0
        }
3591
0
    }
3592
0
    return(ret);
3593
0
}
3594
3595
/**
3596
 * xmlXPathNodeLeading:
3597
 * @nodes:  a node-set
3598
 * @node:  a node
3599
 *
3600
 * Implements the EXSLT - Sets leading() function:
3601
 *    node-set set:leading (node-set, node-set)
3602
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
3603
 * is called.
3604
 *
3605
 * Returns the nodes in @nodes that precede @node in document order,
3606
 *         @nodes if @node is NULL or an empty node-set if @nodes
3607
 *         doesn't contain @node
3608
 */
3609
xmlNodeSetPtr
3610
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
3611
0
    xmlXPathNodeSetSort(nodes);
3612
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3613
0
}
3614
3615
/**
3616
 * xmlXPathLeadingSorted:
3617
 * @nodes1:  a node-set, sorted by document order
3618
 * @nodes2:  a node-set, sorted by document order
3619
 *
3620
 * Implements the EXSLT - Sets leading() function:
3621
 *    node-set set:leading (node-set, node-set)
3622
 *
3623
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3624
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3625
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3626
 */
3627
xmlNodeSetPtr
3628
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3629
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3630
0
  return(nodes1);
3631
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3632
0
             xmlXPathNodeSetItem(nodes2, 1)));
3633
0
}
3634
3635
/**
3636
 * xmlXPathLeading:
3637
 * @nodes1:  a node-set
3638
 * @nodes2:  a node-set
3639
 *
3640
 * Implements the EXSLT - Sets leading() function:
3641
 *    node-set set:leading (node-set, node-set)
3642
 * @nodes1 and @nodes2 are sorted by document order, then
3643
 * #exslSetsLeadingSorted is called.
3644
 *
3645
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
3646
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3647
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3648
 */
3649
xmlNodeSetPtr
3650
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3651
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3652
0
  return(nodes1);
3653
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3654
0
  return(xmlXPathNodeSetCreate(NULL));
3655
0
    xmlXPathNodeSetSort(nodes1);
3656
0
    xmlXPathNodeSetSort(nodes2);
3657
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3658
0
             xmlXPathNodeSetItem(nodes2, 1)));
3659
0
}
3660
3661
/**
3662
 * xmlXPathNodeTrailingSorted:
3663
 * @nodes: a node-set, sorted by document order
3664
 * @node: a node
3665
 *
3666
 * Implements the EXSLT - Sets trailing() function:
3667
 *    node-set set:trailing (node-set, node-set)
3668
 *
3669
 * Returns the nodes in @nodes that follow @node in document order,
3670
 *         @nodes if @node is NULL or an empty node-set if @nodes
3671
 *         doesn't contain @node
3672
 */
3673
xmlNodeSetPtr
3674
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3675
0
    int i, l;
3676
0
    xmlNodePtr cur;
3677
0
    xmlNodeSetPtr ret;
3678
3679
0
    if (node == NULL)
3680
0
  return(nodes);
3681
3682
0
    ret = xmlXPathNodeSetCreate(NULL);
3683
0
    if (ret == NULL)
3684
0
        return(ret);
3685
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3686
0
  (!xmlXPathNodeSetContains(nodes, node)))
3687
0
  return(ret);
3688
3689
0
    l = xmlXPathNodeSetGetLength(nodes);
3690
0
    for (i = l - 1; i >= 0; i--) {
3691
0
  cur = xmlXPathNodeSetItem(nodes, i);
3692
0
  if (cur == node)
3693
0
      break;
3694
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3695
0
            xmlXPathFreeNodeSet(ret);
3696
0
      return(NULL);
3697
0
        }
3698
0
    }
3699
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3700
0
    return(ret);
3701
0
}
3702
3703
/**
3704
 * xmlXPathNodeTrailing:
3705
 * @nodes:  a node-set
3706
 * @node:  a node
3707
 *
3708
 * Implements the EXSLT - Sets trailing() function:
3709
 *    node-set set:trailing (node-set, node-set)
3710
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
3711
 * is called.
3712
 *
3713
 * Returns the nodes in @nodes that follow @node in document order,
3714
 *         @nodes if @node is NULL or an empty node-set if @nodes
3715
 *         doesn't contain @node
3716
 */
3717
xmlNodeSetPtr
3718
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
3719
0
    xmlXPathNodeSetSort(nodes);
3720
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3721
0
}
3722
3723
/**
3724
 * xmlXPathTrailingSorted:
3725
 * @nodes1:  a node-set, sorted by document order
3726
 * @nodes2:  a node-set, sorted by document order
3727
 *
3728
 * Implements the EXSLT - Sets trailing() function:
3729
 *    node-set set:trailing (node-set, node-set)
3730
 *
3731
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3732
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3733
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3734
 */
3735
xmlNodeSetPtr
3736
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3737
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3738
0
  return(nodes1);
3739
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3740
0
              xmlXPathNodeSetItem(nodes2, 0)));
3741
0
}
3742
3743
/**
3744
 * xmlXPathTrailing:
3745
 * @nodes1:  a node-set
3746
 * @nodes2:  a node-set
3747
 *
3748
 * Implements the EXSLT - Sets trailing() function:
3749
 *    node-set set:trailing (node-set, node-set)
3750
 * @nodes1 and @nodes2 are sorted by document order, then
3751
 * #xmlXPathTrailingSorted is called.
3752
 *
3753
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
3754
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
3755
 *         an empty node-set if @nodes1 doesn't contain @nodes2
3756
 */
3757
xmlNodeSetPtr
3758
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3759
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3760
0
  return(nodes1);
3761
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3762
0
  return(xmlXPathNodeSetCreate(NULL));
3763
0
    xmlXPathNodeSetSort(nodes1);
3764
0
    xmlXPathNodeSetSort(nodes2);
3765
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3766
0
              xmlXPathNodeSetItem(nodes2, 0)));
3767
0
}
3768
3769
/************************************************************************
3770
 *                  *
3771
 *    Routines to handle extra functions      *
3772
 *                  *
3773
 ************************************************************************/
3774
3775
/**
3776
 * xmlXPathRegisterFunc:
3777
 * @ctxt:  the XPath context
3778
 * @name:  the function name
3779
 * @f:  the function implementation or NULL
3780
 *
3781
 * Register a new function. If @f is NULL it unregisters the function
3782
 *
3783
 * Returns 0 in case of success, -1 in case of error
3784
 */
3785
int
3786
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
3787
0
         xmlXPathFunction f) {
3788
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3789
0
}
3790
3791
/**
3792
 * xmlXPathRegisterFuncNS:
3793
 * @ctxt:  the XPath context
3794
 * @name:  the function name
3795
 * @ns_uri:  the function namespace URI
3796
 * @f:  the function implementation or NULL
3797
 *
3798
 * Register a new function. If @f is NULL it unregisters the function
3799
 *
3800
 * Returns 0 in case of success, -1 in case of error
3801
 */
3802
int
3803
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3804
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
3805
0
    int ret;
3806
3807
0
    if (ctxt == NULL)
3808
0
  return(-1);
3809
0
    if (name == NULL)
3810
0
  return(-1);
3811
3812
0
    if (ctxt->funcHash == NULL)
3813
0
  ctxt->funcHash = xmlHashCreate(0);
3814
0
    if (ctxt->funcHash == NULL) {
3815
0
        xmlXPathErrMemory(ctxt);
3816
0
  return(-1);
3817
0
    }
3818
0
    if (f == NULL)
3819
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3820
0
XML_IGNORE_FPTR_CAST_WARNINGS
3821
0
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f);
3822
0
XML_POP_WARNINGS
3823
0
    if (ret < 0) {
3824
0
        xmlXPathErrMemory(ctxt);
3825
0
        return(-1);
3826
0
    }
3827
3828
0
    return(0);
3829
0
}
3830
3831
/**
3832
 * xmlXPathRegisterFuncLookup:
3833
 * @ctxt:  the XPath context
3834
 * @f:  the lookup function
3835
 * @funcCtxt:  the lookup data
3836
 *
3837
 * Registers an external mechanism to do function lookup.
3838
 */
3839
void
3840
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
3841
          xmlXPathFuncLookupFunc f,
3842
0
          void *funcCtxt) {
3843
0
    if (ctxt == NULL)
3844
0
  return;
3845
0
    ctxt->funcLookupFunc = f;
3846
0
    ctxt->funcLookupData = funcCtxt;
3847
0
}
3848
3849
/**
3850
 * xmlXPathFunctionLookup:
3851
 * @ctxt:  the XPath context
3852
 * @name:  the function name
3853
 *
3854
 * Search in the Function array of the context for the given
3855
 * function.
3856
 *
3857
 * Returns the xmlXPathFunction or NULL if not found
3858
 */
3859
xmlXPathFunction
3860
0
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
3861
0
    if (ctxt == NULL)
3862
0
  return (NULL);
3863
3864
0
    if (ctxt->funcLookupFunc != NULL) {
3865
0
  xmlXPathFunction ret;
3866
0
  xmlXPathFuncLookupFunc f;
3867
3868
0
  f = ctxt->funcLookupFunc;
3869
0
  ret = f(ctxt->funcLookupData, name, NULL);
3870
0
  if (ret != NULL)
3871
0
      return(ret);
3872
0
    }
3873
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3874
0
}
3875
3876
/**
3877
 * xmlXPathFunctionLookupNS:
3878
 * @ctxt:  the XPath context
3879
 * @name:  the function name
3880
 * @ns_uri:  the function namespace URI
3881
 *
3882
 * Search in the Function array of the context for the given
3883
 * function.
3884
 *
3885
 * Returns the xmlXPathFunction or NULL if not found
3886
 */
3887
xmlXPathFunction
3888
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3889
0
       const xmlChar *ns_uri) {
3890
0
    xmlXPathFunction ret;
3891
3892
0
    if (ctxt == NULL)
3893
0
  return(NULL);
3894
0
    if (name == NULL)
3895
0
  return(NULL);
3896
3897
0
    if (ctxt->funcLookupFunc != NULL) {
3898
0
  xmlXPathFuncLookupFunc f;
3899
3900
0
  f = ctxt->funcLookupFunc;
3901
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
3902
0
  if (ret != NULL)
3903
0
      return(ret);
3904
0
    }
3905
3906
0
    if (ctxt->funcHash == NULL)
3907
0
  return(NULL);
3908
3909
0
XML_IGNORE_FPTR_CAST_WARNINGS
3910
0
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3911
0
XML_POP_WARNINGS
3912
0
    return(ret);
3913
0
}
3914
3915
/**
3916
 * xmlXPathRegisteredFuncsCleanup:
3917
 * @ctxt:  the XPath context
3918
 *
3919
 * Cleanup the XPath context data associated to registered functions
3920
 */
3921
void
3922
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
3923
0
    if (ctxt == NULL)
3924
0
  return;
3925
3926
0
    xmlHashFree(ctxt->funcHash, NULL);
3927
0
    ctxt->funcHash = NULL;
3928
0
}
3929
3930
/************************************************************************
3931
 *                  *
3932
 *      Routines to handle Variables      *
3933
 *                  *
3934
 ************************************************************************/
3935
3936
/**
3937
 * xmlXPathRegisterVariable:
3938
 * @ctxt:  the XPath context
3939
 * @name:  the variable name
3940
 * @value:  the variable value or NULL
3941
 *
3942
 * Register a new variable value. If @value is NULL it unregisters
3943
 * the variable
3944
 *
3945
 * Returns 0 in case of success, -1 in case of error
3946
 */
3947
int
3948
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
3949
0
       xmlXPathObjectPtr value) {
3950
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3951
0
}
3952
3953
/**
3954
 * xmlXPathRegisterVariableNS:
3955
 * @ctxt:  the XPath context
3956
 * @name:  the variable name
3957
 * @ns_uri:  the variable namespace URI
3958
 * @value:  the variable value or NULL
3959
 *
3960
 * Register a new variable value. If @value is NULL it unregisters
3961
 * the variable
3962
 *
3963
 * Returns 0 in case of success, -1 in case of error
3964
 */
3965
int
3966
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
3967
         const xmlChar *ns_uri,
3968
0
         xmlXPathObjectPtr value) {
3969
0
    if (ctxt == NULL)
3970
0
  return(-1);
3971
0
    if (name == NULL)
3972
0
  return(-1);
3973
3974
0
    if (ctxt->varHash == NULL)
3975
0
  ctxt->varHash = xmlHashCreate(0);
3976
0
    if (ctxt->varHash == NULL)
3977
0
  return(-1);
3978
0
    if (value == NULL)
3979
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3980
0
                             xmlXPathFreeObjectEntry));
3981
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3982
0
             (void *) value, xmlXPathFreeObjectEntry));
3983
0
}
3984
3985
/**
3986
 * xmlXPathRegisterVariableLookup:
3987
 * @ctxt:  the XPath context
3988
 * @f:  the lookup function
3989
 * @data:  the lookup data
3990
 *
3991
 * register an external mechanism to do variable lookup
3992
 */
3993
void
3994
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
3995
0
   xmlXPathVariableLookupFunc f, void *data) {
3996
0
    if (ctxt == NULL)
3997
0
  return;
3998
0
    ctxt->varLookupFunc = f;
3999
0
    ctxt->varLookupData = data;
4000
0
}
4001
4002
/**
4003
 * xmlXPathVariableLookup:
4004
 * @ctxt:  the XPath context
4005
 * @name:  the variable name
4006
 *
4007
 * Search in the Variable array of the context for the given
4008
 * variable value.
4009
 *
4010
 * Returns a copy of the value or NULL if not found
4011
 */
4012
xmlXPathObjectPtr
4013
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4014
0
    if (ctxt == NULL)
4015
0
  return(NULL);
4016
4017
0
    if (ctxt->varLookupFunc != NULL) {
4018
0
  xmlXPathObjectPtr ret;
4019
4020
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4021
0
          (ctxt->varLookupData, name, NULL);
4022
0
  return(ret);
4023
0
    }
4024
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4025
0
}
4026
4027
/**
4028
 * xmlXPathVariableLookupNS:
4029
 * @ctxt:  the XPath context
4030
 * @name:  the variable name
4031
 * @ns_uri:  the variable namespace URI
4032
 *
4033
 * Search in the Variable array of the context for the given
4034
 * variable value.
4035
 *
4036
 * Returns the a copy of the value or NULL if not found
4037
 */
4038
xmlXPathObjectPtr
4039
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4040
0
       const xmlChar *ns_uri) {
4041
0
    if (ctxt == NULL)
4042
0
  return(NULL);
4043
4044
0
    if (ctxt->varLookupFunc != NULL) {
4045
0
  xmlXPathObjectPtr ret;
4046
4047
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4048
0
          (ctxt->varLookupData, name, ns_uri);
4049
0
  if (ret != NULL) return(ret);
4050
0
    }
4051
4052
0
    if (ctxt->varHash == NULL)
4053
0
  return(NULL);
4054
0
    if (name == NULL)
4055
0
  return(NULL);
4056
4057
0
    return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4058
0
}
4059
4060
/**
4061
 * xmlXPathRegisteredVariablesCleanup:
4062
 * @ctxt:  the XPath context
4063
 *
4064
 * Cleanup the XPath context data associated to registered variables
4065
 */
4066
void
4067
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4068
0
    if (ctxt == NULL)
4069
0
  return;
4070
4071
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4072
0
    ctxt->varHash = NULL;
4073
0
}
4074
4075
/**
4076
 * xmlXPathRegisterNs:
4077
 * @ctxt:  the XPath context
4078
 * @prefix:  the namespace prefix cannot be NULL or empty string
4079
 * @ns_uri:  the namespace name
4080
 *
4081
 * Register a new namespace. If @ns_uri is NULL it unregisters
4082
 * the namespace
4083
 *
4084
 * Returns 0 in case of success, -1 in case of error
4085
 */
4086
int
4087
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4088
0
         const xmlChar *ns_uri) {
4089
0
    xmlChar *copy;
4090
4091
0
    if (ctxt == NULL)
4092
0
  return(-1);
4093
0
    if (prefix == NULL)
4094
0
  return(-1);
4095
0
    if (prefix[0] == 0)
4096
0
  return(-1);
4097
4098
0
    if (ctxt->nsHash == NULL)
4099
0
  ctxt->nsHash = xmlHashCreate(10);
4100
0
    if (ctxt->nsHash == NULL) {
4101
0
        xmlXPathErrMemory(ctxt);
4102
0
  return(-1);
4103
0
    }
4104
0
    if (ns_uri == NULL)
4105
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4106
0
                            xmlHashDefaultDeallocator));
4107
4108
0
    copy = xmlStrdup(ns_uri);
4109
0
    if (copy == NULL) {
4110
0
        xmlXPathErrMemory(ctxt);
4111
0
        return(-1);
4112
0
    }
4113
0
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4114
0
                           xmlHashDefaultDeallocator) < 0) {
4115
0
        xmlXPathErrMemory(ctxt);
4116
0
        xmlFree(copy);
4117
0
        return(-1);
4118
0
    }
4119
4120
0
    return(0);
4121
0
}
4122
4123
/**
4124
 * xmlXPathNsLookup:
4125
 * @ctxt:  the XPath context
4126
 * @prefix:  the namespace prefix value
4127
 *
4128
 * Search in the namespace declaration array of the context for the given
4129
 * namespace name associated to the given prefix
4130
 *
4131
 * Returns the value or NULL if not found
4132
 */
4133
const xmlChar *
4134
0
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4135
0
    if (ctxt == NULL)
4136
0
  return(NULL);
4137
0
    if (prefix == NULL)
4138
0
  return(NULL);
4139
4140
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4141
0
  return(XML_XML_NAMESPACE);
4142
4143
0
    if (ctxt->namespaces != NULL) {
4144
0
  int i;
4145
4146
0
  for (i = 0;i < ctxt->nsNr;i++) {
4147
0
      if ((ctxt->namespaces[i] != NULL) &&
4148
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4149
0
    return(ctxt->namespaces[i]->href);
4150
0
  }
4151
0
    }
4152
4153
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4154
0
}
4155
4156
/**
4157
 * xmlXPathRegisteredNsCleanup:
4158
 * @ctxt:  the XPath context
4159
 *
4160
 * Cleanup the XPath context data associated to registered variables
4161
 */
4162
void
4163
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4164
0
    if (ctxt == NULL)
4165
0
  return;
4166
4167
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4168
0
    ctxt->nsHash = NULL;
4169
0
}
4170
4171
/************************************************************************
4172
 *                  *
4173
 *      Routines to handle Values     *
4174
 *                  *
4175
 ************************************************************************/
4176
4177
/* Allocations are terrible, one needs to optimize all this !!! */
4178
4179
/**
4180
 * xmlXPathNewFloat:
4181
 * @val:  the double value
4182
 *
4183
 * Create a new xmlXPathObjectPtr of type double and of value @val
4184
 *
4185
 * Returns the newly created object.
4186
 */
4187
xmlXPathObjectPtr
4188
0
xmlXPathNewFloat(double val) {
4189
0
    xmlXPathObjectPtr ret;
4190
4191
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4192
0
    if (ret == NULL)
4193
0
  return(NULL);
4194
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4195
0
    ret->type = XPATH_NUMBER;
4196
0
    ret->floatval = val;
4197
0
    return(ret);
4198
0
}
4199
4200
/**
4201
 * xmlXPathNewBoolean:
4202
 * @val:  the boolean value
4203
 *
4204
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4205
 *
4206
 * Returns the newly created object.
4207
 */
4208
xmlXPathObjectPtr
4209
0
xmlXPathNewBoolean(int val) {
4210
0
    xmlXPathObjectPtr ret;
4211
4212
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4213
0
    if (ret == NULL)
4214
0
  return(NULL);
4215
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4216
0
    ret->type = XPATH_BOOLEAN;
4217
0
    ret->boolval = (val != 0);
4218
0
    return(ret);
4219
0
}
4220
4221
/**
4222
 * xmlXPathNewString:
4223
 * @val:  the xmlChar * value
4224
 *
4225
 * Create a new xmlXPathObjectPtr of type string and of value @val
4226
 *
4227
 * Returns the newly created object.
4228
 */
4229
xmlXPathObjectPtr
4230
0
xmlXPathNewString(const xmlChar *val) {
4231
0
    xmlXPathObjectPtr ret;
4232
4233
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4234
0
    if (ret == NULL)
4235
0
  return(NULL);
4236
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4237
0
    ret->type = XPATH_STRING;
4238
0
    if (val == NULL)
4239
0
        val = BAD_CAST "";
4240
0
    ret->stringval = xmlStrdup(val);
4241
0
    if (ret->stringval == NULL) {
4242
0
        xmlFree(ret);
4243
0
        return(NULL);
4244
0
    }
4245
0
    return(ret);
4246
0
}
4247
4248
/**
4249
 * xmlXPathWrapString:
4250
 * @val:  the xmlChar * value
4251
 *
4252
 * Wraps the @val string into an XPath object.
4253
 *
4254
 * Returns the newly created object.
4255
 *
4256
 * Frees @val in case of error.
4257
 */
4258
xmlXPathObjectPtr
4259
0
xmlXPathWrapString (xmlChar *val) {
4260
0
    xmlXPathObjectPtr ret;
4261
4262
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4263
0
    if (ret == NULL) {
4264
0
        xmlFree(val);
4265
0
  return(NULL);
4266
0
    }
4267
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4268
0
    ret->type = XPATH_STRING;
4269
0
    ret->stringval = val;
4270
0
    return(ret);
4271
0
}
4272
4273
/**
4274
 * xmlXPathNewCString:
4275
 * @val:  the char * value
4276
 *
4277
 * Create a new xmlXPathObjectPtr of type string and of value @val
4278
 *
4279
 * Returns the newly created object.
4280
 */
4281
xmlXPathObjectPtr
4282
0
xmlXPathNewCString(const char *val) {
4283
0
    return(xmlXPathNewString(BAD_CAST val));
4284
0
}
4285
4286
/**
4287
 * xmlXPathWrapCString:
4288
 * @val:  the char * value
4289
 *
4290
 * Wraps a string into an XPath object.
4291
 *
4292
 * Returns the newly created object.
4293
 */
4294
xmlXPathObjectPtr
4295
0
xmlXPathWrapCString (char * val) {
4296
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4297
0
}
4298
4299
/**
4300
 * xmlXPathWrapExternal:
4301
 * @val:  the user data
4302
 *
4303
 * Wraps the @val data into an XPath object.
4304
 *
4305
 * Returns the newly created object.
4306
 */
4307
xmlXPathObjectPtr
4308
0
xmlXPathWrapExternal (void *val) {
4309
0
    xmlXPathObjectPtr ret;
4310
4311
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4312
0
    if (ret == NULL)
4313
0
  return(NULL);
4314
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4315
0
    ret->type = XPATH_USERS;
4316
0
    ret->user = val;
4317
0
    return(ret);
4318
0
}
4319
4320
/**
4321
 * xmlXPathObjectCopy:
4322
 * @val:  the original object
4323
 *
4324
 * allocate a new copy of a given object
4325
 *
4326
 * Returns the newly created object.
4327
 */
4328
xmlXPathObjectPtr
4329
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4330
0
    xmlXPathObjectPtr ret;
4331
4332
0
    if (val == NULL)
4333
0
  return(NULL);
4334
4335
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4336
0
    if (ret == NULL)
4337
0
  return(NULL);
4338
0
    memcpy(ret, val , sizeof(xmlXPathObject));
4339
0
    switch (val->type) {
4340
0
  case XPATH_BOOLEAN:
4341
0
  case XPATH_NUMBER:
4342
0
      break;
4343
0
  case XPATH_STRING:
4344
0
      ret->stringval = xmlStrdup(val->stringval);
4345
0
            if (ret->stringval == NULL) {
4346
0
                xmlFree(ret);
4347
0
                return(NULL);
4348
0
            }
4349
0
      break;
4350
0
  case XPATH_XSLT_TREE:
4351
0
  case XPATH_NODESET:
4352
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4353
0
            if (ret->nodesetval == NULL) {
4354
0
                xmlFree(ret);
4355
0
                return(NULL);
4356
0
            }
4357
      /* Do not deallocate the copied tree value */
4358
0
      ret->boolval = 0;
4359
0
      break;
4360
0
        case XPATH_USERS:
4361
0
      ret->user = val->user;
4362
0
      break;
4363
0
        default:
4364
0
            xmlFree(ret);
4365
0
            ret = NULL;
4366
0
      break;
4367
0
    }
4368
0
    return(ret);
4369
0
}
4370
4371
/**
4372
 * xmlXPathFreeObject:
4373
 * @obj:  the object to free
4374
 *
4375
 * Free up an xmlXPathObjectPtr object.
4376
 */
4377
void
4378
0
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4379
0
    if (obj == NULL) return;
4380
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4381
0
        if (obj->nodesetval != NULL)
4382
0
            xmlXPathFreeNodeSet(obj->nodesetval);
4383
0
    } else if (obj->type == XPATH_STRING) {
4384
0
  if (obj->stringval != NULL)
4385
0
      xmlFree(obj->stringval);
4386
0
    }
4387
0
    xmlFree(obj);
4388
0
}
4389
4390
static void
4391
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4392
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4393
0
}
4394
4395
/**
4396
 * xmlXPathReleaseObject:
4397
 * @obj:  the xmlXPathObjectPtr to free or to cache
4398
 *
4399
 * Depending on the state of the cache this frees the given
4400
 * XPath object or stores it in the cache.
4401
 */
4402
static void
4403
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4404
0
{
4405
0
    if (obj == NULL)
4406
0
  return;
4407
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4408
0
   xmlXPathFreeObject(obj);
4409
0
    } else {
4410
0
  xmlXPathContextCachePtr cache =
4411
0
      (xmlXPathContextCachePtr) ctxt->cache;
4412
4413
0
  switch (obj->type) {
4414
0
      case XPATH_NODESET:
4415
0
      case XPATH_XSLT_TREE:
4416
0
    if (obj->nodesetval != NULL) {
4417
0
        if ((obj->nodesetval->nodeMax <= 40) &&
4418
0
      (cache->numNodeset < cache->maxNodeset)) {
4419
0
                        obj->stringval = (void *) cache->nodesetObjs;
4420
0
                        cache->nodesetObjs = obj;
4421
0
                        cache->numNodeset += 1;
4422
0
      goto obj_cached;
4423
0
        } else {
4424
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4425
0
      obj->nodesetval = NULL;
4426
0
        }
4427
0
    }
4428
0
    break;
4429
0
      case XPATH_STRING:
4430
0
    if (obj->stringval != NULL)
4431
0
        xmlFree(obj->stringval);
4432
0
                obj->stringval = NULL;
4433
0
    break;
4434
0
      case XPATH_BOOLEAN:
4435
0
      case XPATH_NUMBER:
4436
0
    break;
4437
0
      default:
4438
0
    goto free_obj;
4439
0
  }
4440
4441
  /*
4442
  * Fallback to adding to the misc-objects slot.
4443
  */
4444
0
        if (cache->numMisc >= cache->maxMisc)
4445
0
      goto free_obj;
4446
0
        obj->stringval = (void *) cache->miscObjs;
4447
0
        cache->miscObjs = obj;
4448
0
        cache->numMisc += 1;
4449
4450
0
obj_cached:
4451
0
        obj->boolval = 0;
4452
0
  if (obj->nodesetval != NULL) {
4453
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
4454
4455
      /*
4456
      * Due to those nasty ns-nodes, we need to traverse
4457
      * the list and free the ns-nodes.
4458
      */
4459
0
      if (tmpset->nodeNr > 0) {
4460
0
    int i;
4461
0
    xmlNodePtr node;
4462
4463
0
    for (i = 0; i < tmpset->nodeNr; i++) {
4464
0
        node = tmpset->nodeTab[i];
4465
0
        if ((node != NULL) &&
4466
0
      (node->type == XML_NAMESPACE_DECL))
4467
0
        {
4468
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4469
0
        }
4470
0
    }
4471
0
      }
4472
0
      tmpset->nodeNr = 0;
4473
0
        }
4474
4475
0
  return;
4476
4477
0
free_obj:
4478
  /*
4479
  * Cache is full; free the object.
4480
  */
4481
0
  if (obj->nodesetval != NULL)
4482
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4483
0
  xmlFree(obj);
4484
0
    }
4485
0
}
4486
4487
4488
/************************************************************************
4489
 *                  *
4490
 *      Type Casting Routines       *
4491
 *                  *
4492
 ************************************************************************/
4493
4494
/**
4495
 * xmlXPathCastBooleanToString:
4496
 * @val:  a boolean
4497
 *
4498
 * Converts a boolean to its string value.
4499
 *
4500
 * Returns a newly allocated string.
4501
 */
4502
xmlChar *
4503
0
xmlXPathCastBooleanToString (int val) {
4504
0
    xmlChar *ret;
4505
0
    if (val)
4506
0
  ret = xmlStrdup((const xmlChar *) "true");
4507
0
    else
4508
0
  ret = xmlStrdup((const xmlChar *) "false");
4509
0
    return(ret);
4510
0
}
4511
4512
/**
4513
 * xmlXPathCastNumberToString:
4514
 * @val:  a number
4515
 *
4516
 * Converts a number to its string value.
4517
 *
4518
 * Returns a newly allocated string.
4519
 */
4520
xmlChar *
4521
0
xmlXPathCastNumberToString (double val) {
4522
0
    xmlChar *ret;
4523
0
    switch (xmlXPathIsInf(val)) {
4524
0
    case 1:
4525
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
4526
0
  break;
4527
0
    case -1:
4528
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4529
0
  break;
4530
0
    default:
4531
0
  if (xmlXPathIsNaN(val)) {
4532
0
      ret = xmlStrdup((const xmlChar *) "NaN");
4533
0
  } else if (val == 0) {
4534
            /* Omit sign for negative zero. */
4535
0
      ret = xmlStrdup((const xmlChar *) "0");
4536
0
  } else {
4537
      /* could be improved */
4538
0
      char buf[100];
4539
0
      xmlXPathFormatNumber(val, buf, 99);
4540
0
      buf[99] = 0;
4541
0
      ret = xmlStrdup((const xmlChar *) buf);
4542
0
  }
4543
0
    }
4544
0
    return(ret);
4545
0
}
4546
4547
/**
4548
 * xmlXPathCastNodeToString:
4549
 * @node:  a node
4550
 *
4551
 * Converts a node to its string value.
4552
 *
4553
 * Returns a newly allocated string.
4554
 */
4555
xmlChar *
4556
0
xmlXPathCastNodeToString (xmlNodePtr node) {
4557
0
    return(xmlNodeGetContent(node));
4558
0
}
4559
4560
/**
4561
 * xmlXPathCastNodeSetToString:
4562
 * @ns:  a node-set
4563
 *
4564
 * Converts a node-set to its string value.
4565
 *
4566
 * Returns a newly allocated string.
4567
 */
4568
xmlChar *
4569
0
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
4570
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4571
0
  return(xmlStrdup((const xmlChar *) ""));
4572
4573
0
    if (ns->nodeNr > 1)
4574
0
  xmlXPathNodeSetSort(ns);
4575
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4576
0
}
4577
4578
/**
4579
 * xmlXPathCastToString:
4580
 * @val:  an XPath object
4581
 *
4582
 * Converts an existing object to its string() equivalent
4583
 *
4584
 * Returns the allocated string value of the object, NULL in case of error.
4585
 *         It's up to the caller to free the string memory with xmlFree().
4586
 */
4587
xmlChar *
4588
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
4589
0
    xmlChar *ret = NULL;
4590
4591
0
    if (val == NULL)
4592
0
  return(xmlStrdup((const xmlChar *) ""));
4593
0
    switch (val->type) {
4594
0
  case XPATH_UNDEFINED:
4595
0
      ret = xmlStrdup((const xmlChar *) "");
4596
0
      break;
4597
0
        case XPATH_NODESET:
4598
0
        case XPATH_XSLT_TREE:
4599
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4600
0
      break;
4601
0
  case XPATH_STRING:
4602
0
      return(xmlStrdup(val->stringval));
4603
0
        case XPATH_BOOLEAN:
4604
0
      ret = xmlXPathCastBooleanToString(val->boolval);
4605
0
      break;
4606
0
  case XPATH_NUMBER: {
4607
0
      ret = xmlXPathCastNumberToString(val->floatval);
4608
0
      break;
4609
0
  }
4610
0
  case XPATH_USERS:
4611
      /* TODO */
4612
0
      ret = xmlStrdup((const xmlChar *) "");
4613
0
      break;
4614
0
    }
4615
0
    return(ret);
4616
0
}
4617
4618
/**
4619
 * xmlXPathConvertString:
4620
 * @val:  an XPath object
4621
 *
4622
 * Converts an existing object to its string() equivalent
4623
 *
4624
 * Returns the new object, the old one is freed (or the operation
4625
 *         is done directly on @val)
4626
 */
4627
xmlXPathObjectPtr
4628
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
4629
0
    xmlChar *res = NULL;
4630
4631
0
    if (val == NULL)
4632
0
  return(xmlXPathNewCString(""));
4633
4634
0
    switch (val->type) {
4635
0
    case XPATH_UNDEFINED:
4636
0
  break;
4637
0
    case XPATH_NODESET:
4638
0
    case XPATH_XSLT_TREE:
4639
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4640
0
  break;
4641
0
    case XPATH_STRING:
4642
0
  return(val);
4643
0
    case XPATH_BOOLEAN:
4644
0
  res = xmlXPathCastBooleanToString(val->boolval);
4645
0
  break;
4646
0
    case XPATH_NUMBER:
4647
0
  res = xmlXPathCastNumberToString(val->floatval);
4648
0
  break;
4649
0
    case XPATH_USERS:
4650
  /* TODO */
4651
0
  break;
4652
0
    }
4653
0
    xmlXPathFreeObject(val);
4654
0
    if (res == NULL)
4655
0
  return(xmlXPathNewCString(""));
4656
0
    return(xmlXPathWrapString(res));
4657
0
}
4658
4659
/**
4660
 * xmlXPathCastBooleanToNumber:
4661
 * @val:  a boolean
4662
 *
4663
 * Converts a boolean to its number value
4664
 *
4665
 * Returns the number value
4666
 */
4667
double
4668
0
xmlXPathCastBooleanToNumber(int val) {
4669
0
    if (val)
4670
0
  return(1.0);
4671
0
    return(0.0);
4672
0
}
4673
4674
/**
4675
 * xmlXPathCastStringToNumber:
4676
 * @val:  a string
4677
 *
4678
 * Converts a string to its number value
4679
 *
4680
 * Returns the number value
4681
 */
4682
double
4683
0
xmlXPathCastStringToNumber(const xmlChar * val) {
4684
0
    return(xmlXPathStringEvalNumber(val));
4685
0
}
4686
4687
/**
4688
 * xmlXPathNodeToNumberInternal:
4689
 * @node:  a node
4690
 *
4691
 * Converts a node to its number value
4692
 *
4693
 * Returns the number value
4694
 */
4695
static double
4696
0
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4697
0
    xmlChar *strval;
4698
0
    double ret;
4699
4700
0
    if (node == NULL)
4701
0
  return(xmlXPathNAN);
4702
0
    strval = xmlXPathCastNodeToString(node);
4703
0
    if (strval == NULL) {
4704
0
        xmlXPathPErrMemory(ctxt);
4705
0
  return(xmlXPathNAN);
4706
0
    }
4707
0
    ret = xmlXPathCastStringToNumber(strval);
4708
0
    xmlFree(strval);
4709
4710
0
    return(ret);
4711
0
}
4712
4713
/**
4714
 * xmlXPathCastNodeToNumber:
4715
 * @node:  a node
4716
 *
4717
 * Converts a node to its number value
4718
 *
4719
 * Returns the number value
4720
 */
4721
double
4722
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
4723
0
    return(xmlXPathNodeToNumberInternal(NULL, node));
4724
0
}
4725
4726
/**
4727
 * xmlXPathCastNodeSetToNumber:
4728
 * @ns:  a node-set
4729
 *
4730
 * Converts a node-set to its number value
4731
 *
4732
 * Returns the number value
4733
 */
4734
double
4735
0
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
4736
0
    xmlChar *str;
4737
0
    double ret;
4738
4739
0
    if (ns == NULL)
4740
0
  return(xmlXPathNAN);
4741
0
    str = xmlXPathCastNodeSetToString(ns);
4742
0
    ret = xmlXPathCastStringToNumber(str);
4743
0
    xmlFree(str);
4744
0
    return(ret);
4745
0
}
4746
4747
/**
4748
 * xmlXPathCastToNumber:
4749
 * @val:  an XPath object
4750
 *
4751
 * Converts an XPath object to its number value
4752
 *
4753
 * Returns the number value
4754
 */
4755
double
4756
0
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
4757
0
    return(xmlXPathCastToNumberInternal(NULL, val));
4758
0
}
4759
4760
/**
4761
 * xmlXPathConvertNumber:
4762
 * @val:  an XPath object
4763
 *
4764
 * Converts an existing object to its number() equivalent
4765
 *
4766
 * Returns the new object, the old one is freed (or the operation
4767
 *         is done directly on @val)
4768
 */
4769
xmlXPathObjectPtr
4770
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
4771
0
    xmlXPathObjectPtr ret;
4772
4773
0
    if (val == NULL)
4774
0
  return(xmlXPathNewFloat(0.0));
4775
0
    if (val->type == XPATH_NUMBER)
4776
0
  return(val);
4777
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4778
0
    xmlXPathFreeObject(val);
4779
0
    return(ret);
4780
0
}
4781
4782
/**
4783
 * xmlXPathCastNumberToBoolean:
4784
 * @val:  a number
4785
 *
4786
 * Converts a number to its boolean value
4787
 *
4788
 * Returns the boolean value
4789
 */
4790
int
4791
0
xmlXPathCastNumberToBoolean (double val) {
4792
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
4793
0
   return(0);
4794
0
     return(1);
4795
0
}
4796
4797
/**
4798
 * xmlXPathCastStringToBoolean:
4799
 * @val:  a string
4800
 *
4801
 * Converts a string to its boolean value
4802
 *
4803
 * Returns the boolean value
4804
 */
4805
int
4806
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
4807
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
4808
0
  return(0);
4809
0
    return(1);
4810
0
}
4811
4812
/**
4813
 * xmlXPathCastNodeSetToBoolean:
4814
 * @ns:  a node-set
4815
 *
4816
 * Converts a node-set to its boolean value
4817
 *
4818
 * Returns the boolean value
4819
 */
4820
int
4821
0
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
4822
0
    if ((ns == NULL) || (ns->nodeNr == 0))
4823
0
  return(0);
4824
0
    return(1);
4825
0
}
4826
4827
/**
4828
 * xmlXPathCastToBoolean:
4829
 * @val:  an XPath object
4830
 *
4831
 * Converts an XPath object to its boolean value
4832
 *
4833
 * Returns the boolean value
4834
 */
4835
int
4836
0
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
4837
0
    int ret = 0;
4838
4839
0
    if (val == NULL)
4840
0
  return(0);
4841
0
    switch (val->type) {
4842
0
    case XPATH_UNDEFINED:
4843
0
  ret = 0;
4844
0
  break;
4845
0
    case XPATH_NODESET:
4846
0
    case XPATH_XSLT_TREE:
4847
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4848
0
  break;
4849
0
    case XPATH_STRING:
4850
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
4851
0
  break;
4852
0
    case XPATH_NUMBER:
4853
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4854
0
  break;
4855
0
    case XPATH_BOOLEAN:
4856
0
  ret = val->boolval;
4857
0
  break;
4858
0
    case XPATH_USERS:
4859
  /* TODO */
4860
0
  ret = 0;
4861
0
  break;
4862
0
    }
4863
0
    return(ret);
4864
0
}
4865
4866
4867
/**
4868
 * xmlXPathConvertBoolean:
4869
 * @val:  an XPath object
4870
 *
4871
 * Converts an existing object to its boolean() equivalent
4872
 *
4873
 * Returns the new object, the old one is freed (or the operation
4874
 *         is done directly on @val)
4875
 */
4876
xmlXPathObjectPtr
4877
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
4878
0
    xmlXPathObjectPtr ret;
4879
4880
0
    if (val == NULL)
4881
0
  return(xmlXPathNewBoolean(0));
4882
0
    if (val->type == XPATH_BOOLEAN)
4883
0
  return(val);
4884
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4885
0
    xmlXPathFreeObject(val);
4886
0
    return(ret);
4887
0
}
4888
4889
/************************************************************************
4890
 *                  *
4891
 *    Routines to handle XPath contexts     *
4892
 *                  *
4893
 ************************************************************************/
4894
4895
/**
4896
 * xmlXPathNewContext:
4897
 * @doc:  the XML document
4898
 *
4899
 * Create a new xmlXPathContext
4900
 *
4901
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
4902
 */
4903
xmlXPathContextPtr
4904
0
xmlXPathNewContext(xmlDocPtr doc) {
4905
0
    xmlXPathContextPtr ret;
4906
4907
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4908
0
    if (ret == NULL)
4909
0
  return(NULL);
4910
0
    memset(ret, 0 , sizeof(xmlXPathContext));
4911
0
    ret->doc = doc;
4912
0
    ret->node = NULL;
4913
4914
0
    ret->varHash = NULL;
4915
4916
0
    ret->nb_types = 0;
4917
0
    ret->max_types = 0;
4918
0
    ret->types = NULL;
4919
4920
0
    ret->nb_axis = 0;
4921
0
    ret->max_axis = 0;
4922
0
    ret->axis = NULL;
4923
4924
0
    ret->nsHash = NULL;
4925
0
    ret->user = NULL;
4926
4927
0
    ret->contextSize = -1;
4928
0
    ret->proximityPosition = -1;
4929
4930
#ifdef XP_DEFAULT_CACHE_ON
4931
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
4932
  xmlXPathFreeContext(ret);
4933
  return(NULL);
4934
    }
4935
#endif
4936
4937
0
    xmlXPathRegisterAllFunctions(ret);
4938
4939
0
    if (ret->lastError.code != XML_ERR_OK) {
4940
0
  xmlXPathFreeContext(ret);
4941
0
  return(NULL);
4942
0
    }
4943
4944
0
    return(ret);
4945
0
}
4946
4947
/**
4948
 * xmlXPathFreeContext:
4949
 * @ctxt:  the context to free
4950
 *
4951
 * Free up an xmlXPathContext
4952
 */
4953
void
4954
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
4955
0
    if (ctxt == NULL) return;
4956
4957
0
    if (ctxt->cache != NULL)
4958
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4959
0
    xmlXPathRegisteredNsCleanup(ctxt);
4960
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
4961
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
4962
0
    xmlResetError(&ctxt->lastError);
4963
0
    xmlFree(ctxt);
4964
0
}
4965
4966
/**
4967
 * xmlXPathSetErrorHandler:
4968
 * @ctxt:  the XPath context
4969
 * @handler:  error handler
4970
 * @data:  user data which will be passed to the handler
4971
 *
4972
 * Register a callback function that will be called on errors and
4973
 * warnings. If handler is NULL, the error handler will be deactivated.
4974
 *
4975
 * Available since 2.13.0.
4976
 */
4977
void
4978
xmlXPathSetErrorHandler(xmlXPathContextPtr ctxt,
4979
0
                        xmlStructuredErrorFunc handler, void *data) {
4980
0
    if (ctxt == NULL)
4981
0
        return;
4982
4983
0
    ctxt->error = handler;
4984
0
    ctxt->userData = data;
4985
0
}
4986
4987
/************************************************************************
4988
 *                  *
4989
 *    Routines to handle XPath parser contexts    *
4990
 *                  *
4991
 ************************************************************************/
4992
4993
/**
4994
 * xmlXPathNewParserContext:
4995
 * @str:  the XPath expression
4996
 * @ctxt:  the XPath context
4997
 *
4998
 * Create a new xmlXPathParserContext
4999
 *
5000
 * Returns the xmlXPathParserContext just allocated.
5001
 */
5002
xmlXPathParserContextPtr
5003
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5004
0
    xmlXPathParserContextPtr ret;
5005
5006
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5007
0
    if (ret == NULL) {
5008
0
        xmlXPathErrMemory(ctxt);
5009
0
  return(NULL);
5010
0
    }
5011
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
5012
0
    ret->cur = ret->base = str;
5013
0
    ret->context = ctxt;
5014
5015
0
    ret->comp = xmlXPathNewCompExpr();
5016
0
    if (ret->comp == NULL) {
5017
0
        xmlXPathErrMemory(ctxt);
5018
0
  xmlFree(ret->valueTab);
5019
0
  xmlFree(ret);
5020
0
  return(NULL);
5021
0
    }
5022
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5023
0
        ret->comp->dict = ctxt->dict;
5024
0
  xmlDictReference(ret->comp->dict);
5025
0
    }
5026
5027
0
    return(ret);
5028
0
}
5029
5030
/**
5031
 * xmlXPathCompParserContext:
5032
 * @comp:  the XPath compiled expression
5033
 * @ctxt:  the XPath context
5034
 *
5035
 * Create a new xmlXPathParserContext when processing a compiled expression
5036
 *
5037
 * Returns the xmlXPathParserContext just allocated.
5038
 */
5039
static xmlXPathParserContextPtr
5040
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5041
0
    xmlXPathParserContextPtr ret;
5042
5043
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5044
0
    if (ret == NULL) {
5045
0
        xmlXPathErrMemory(ctxt);
5046
0
  return(NULL);
5047
0
    }
5048
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
5049
5050
    /* Allocate the value stack */
5051
0
    ret->valueTab = (xmlXPathObjectPtr *)
5052
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5053
0
    if (ret->valueTab == NULL) {
5054
0
  xmlFree(ret);
5055
0
  xmlXPathErrMemory(ctxt);
5056
0
  return(NULL);
5057
0
    }
5058
0
    ret->valueNr = 0;
5059
0
    ret->valueMax = 10;
5060
0
    ret->value = NULL;
5061
5062
0
    ret->context = ctxt;
5063
0
    ret->comp = comp;
5064
5065
0
    return(ret);
5066
0
}
5067
5068
/**
5069
 * xmlXPathFreeParserContext:
5070
 * @ctxt:  the context to free
5071
 *
5072
 * Free up an xmlXPathParserContext
5073
 */
5074
void
5075
0
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5076
0
    int i;
5077
5078
0
    if (ctxt->valueTab != NULL) {
5079
0
        for (i = 0; i < ctxt->valueNr; i++) {
5080
0
            if (ctxt->context)
5081
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5082
0
            else
5083
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
5084
0
        }
5085
0
        xmlFree(ctxt->valueTab);
5086
0
    }
5087
0
    if (ctxt->comp != NULL) {
5088
#ifdef XPATH_STREAMING
5089
  if (ctxt->comp->stream != NULL) {
5090
      xmlFreePatternList(ctxt->comp->stream);
5091
      ctxt->comp->stream = NULL;
5092
  }
5093
#endif
5094
0
  xmlXPathFreeCompExpr(ctxt->comp);
5095
0
    }
5096
0
    xmlFree(ctxt);
5097
0
}
5098
5099
/************************************************************************
5100
 *                  *
5101
 *    The implicit core function library      *
5102
 *                  *
5103
 ************************************************************************/
5104
5105
/**
5106
 * xmlXPathNodeValHash:
5107
 * @node:  a node pointer
5108
 *
5109
 * Function computing the beginning of the string value of the node,
5110
 * used to speed up comparisons
5111
 *
5112
 * Returns an int usable as a hash
5113
 */
5114
static unsigned int
5115
0
xmlXPathNodeValHash(xmlNodePtr node) {
5116
0
    int len = 2;
5117
0
    const xmlChar * string = NULL;
5118
0
    xmlNodePtr tmp = NULL;
5119
0
    unsigned int ret = 0;
5120
5121
0
    if (node == NULL)
5122
0
  return(0);
5123
5124
0
    if (node->type == XML_DOCUMENT_NODE) {
5125
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
5126
0
  if (tmp == NULL)
5127
0
      node = node->children;
5128
0
  else
5129
0
      node = tmp;
5130
5131
0
  if (node == NULL)
5132
0
      return(0);
5133
0
    }
5134
5135
0
    switch (node->type) {
5136
0
  case XML_COMMENT_NODE:
5137
0
  case XML_PI_NODE:
5138
0
  case XML_CDATA_SECTION_NODE:
5139
0
  case XML_TEXT_NODE:
5140
0
      string = node->content;
5141
0
      if (string == NULL)
5142
0
    return(0);
5143
0
      if (string[0] == 0)
5144
0
    return(0);
5145
0
      return(string[0] + (string[1] << 8));
5146
0
  case XML_NAMESPACE_DECL:
5147
0
      string = ((xmlNsPtr)node)->href;
5148
0
      if (string == NULL)
5149
0
    return(0);
5150
0
      if (string[0] == 0)
5151
0
    return(0);
5152
0
      return(string[0] + (string[1] << 8));
5153
0
  case XML_ATTRIBUTE_NODE:
5154
0
      tmp = ((xmlAttrPtr) node)->children;
5155
0
      break;
5156
0
  case XML_ELEMENT_NODE:
5157
0
      tmp = node->children;
5158
0
      break;
5159
0
  default:
5160
0
      return(0);
5161
0
    }
5162
0
    while (tmp != NULL) {
5163
0
  switch (tmp->type) {
5164
0
      case XML_CDATA_SECTION_NODE:
5165
0
      case XML_TEXT_NODE:
5166
0
    string = tmp->content;
5167
0
    break;
5168
0
      default:
5169
0
                string = NULL;
5170
0
    break;
5171
0
  }
5172
0
  if ((string != NULL) && (string[0] != 0)) {
5173
0
      if (len == 1) {
5174
0
    return(ret + (string[0] << 8));
5175
0
      }
5176
0
      if (string[1] == 0) {
5177
0
    len = 1;
5178
0
    ret = string[0];
5179
0
      } else {
5180
0
    return(string[0] + (string[1] << 8));
5181
0
      }
5182
0
  }
5183
  /*
5184
   * Skip to next node
5185
   */
5186
0
        if ((tmp->children != NULL) &&
5187
0
            (tmp->type != XML_DTD_NODE) &&
5188
0
            (tmp->type != XML_ENTITY_REF_NODE) &&
5189
0
            (tmp->children->type != XML_ENTITY_DECL)) {
5190
0
            tmp = tmp->children;
5191
0
            continue;
5192
0
  }
5193
0
  if (tmp == node)
5194
0
      break;
5195
5196
0
  if (tmp->next != NULL) {
5197
0
      tmp = tmp->next;
5198
0
      continue;
5199
0
  }
5200
5201
0
  do {
5202
0
      tmp = tmp->parent;
5203
0
      if (tmp == NULL)
5204
0
    break;
5205
0
      if (tmp == node) {
5206
0
    tmp = NULL;
5207
0
    break;
5208
0
      }
5209
0
      if (tmp->next != NULL) {
5210
0
    tmp = tmp->next;
5211
0
    break;
5212
0
      }
5213
0
  } while (tmp != NULL);
5214
0
    }
5215
0
    return(ret);
5216
0
}
5217
5218
/**
5219
 * xmlXPathStringHash:
5220
 * @string:  a string
5221
 *
5222
 * Function computing the beginning of the string value of the node,
5223
 * used to speed up comparisons
5224
 *
5225
 * Returns an int usable as a hash
5226
 */
5227
static unsigned int
5228
0
xmlXPathStringHash(const xmlChar * string) {
5229
0
    if (string == NULL)
5230
0
  return(0);
5231
0
    if (string[0] == 0)
5232
0
  return(0);
5233
0
    return(string[0] + (string[1] << 8));
5234
0
}
5235
5236
/**
5237
 * xmlXPathCompareNodeSetFloat:
5238
 * @ctxt:  the XPath Parser context
5239
 * @inf:  less than (1) or greater than (0)
5240
 * @strict:  is the comparison strict
5241
 * @arg:  the node set
5242
 * @f:  the value
5243
 *
5244
 * Implement the compare operation between a nodeset and a number
5245
 *     @ns < @val    (1, 1, ...
5246
 *     @ns <= @val   (1, 0, ...
5247
 *     @ns > @val    (0, 1, ...
5248
 *     @ns >= @val   (0, 0, ...
5249
 *
5250
 * If one object to be compared is a node-set and the other is a number,
5251
 * then the comparison will be true if and only if there is a node in the
5252
 * node-set such that the result of performing the comparison on the number
5253
 * to be compared and on the result of converting the string-value of that
5254
 * node to a number using the number function is true.
5255
 *
5256
 * Returns 0 or 1 depending on the results of the test.
5257
 */
5258
static int
5259
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5260
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5261
0
    int i, ret = 0;
5262
0
    xmlNodeSetPtr ns;
5263
0
    xmlChar *str2;
5264
5265
0
    if ((f == NULL) || (arg == NULL) ||
5266
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5267
0
  xmlXPathReleaseObject(ctxt->context, arg);
5268
0
  xmlXPathReleaseObject(ctxt->context, f);
5269
0
        return(0);
5270
0
    }
5271
0
    ns = arg->nodesetval;
5272
0
    if (ns != NULL) {
5273
0
  for (i = 0;i < ns->nodeNr;i++) {
5274
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5275
0
       if (str2 != NULL) {
5276
0
     valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5277
0
     xmlFree(str2);
5278
0
     xmlXPathNumberFunction(ctxt, 1);
5279
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5280
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5281
0
     if (ret)
5282
0
         break;
5283
0
       } else {
5284
0
                 xmlXPathPErrMemory(ctxt);
5285
0
             }
5286
0
  }
5287
0
    }
5288
0
    xmlXPathReleaseObject(ctxt->context, arg);
5289
0
    xmlXPathReleaseObject(ctxt->context, f);
5290
0
    return(ret);
5291
0
}
5292
5293
/**
5294
 * xmlXPathCompareNodeSetString:
5295
 * @ctxt:  the XPath Parser context
5296
 * @inf:  less than (1) or greater than (0)
5297
 * @strict:  is the comparison strict
5298
 * @arg:  the node set
5299
 * @s:  the value
5300
 *
5301
 * Implement the compare operation between a nodeset and a string
5302
 *     @ns < @val    (1, 1, ...
5303
 *     @ns <= @val   (1, 0, ...
5304
 *     @ns > @val    (0, 1, ...
5305
 *     @ns >= @val   (0, 0, ...
5306
 *
5307
 * If one object to be compared is a node-set and the other is a string,
5308
 * then the comparison will be true if and only if there is a node in
5309
 * the node-set such that the result of performing the comparison on the
5310
 * string-value of the node and the other string is true.
5311
 *
5312
 * Returns 0 or 1 depending on the results of the test.
5313
 */
5314
static int
5315
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5316
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5317
0
    int i, ret = 0;
5318
0
    xmlNodeSetPtr ns;
5319
0
    xmlChar *str2;
5320
5321
0
    if ((s == NULL) || (arg == NULL) ||
5322
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5323
0
  xmlXPathReleaseObject(ctxt->context, arg);
5324
0
  xmlXPathReleaseObject(ctxt->context, s);
5325
0
        return(0);
5326
0
    }
5327
0
    ns = arg->nodesetval;
5328
0
    if (ns != NULL) {
5329
0
  for (i = 0;i < ns->nodeNr;i++) {
5330
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5331
0
       if (str2 != NULL) {
5332
0
     valuePush(ctxt,
5333
0
         xmlXPathCacheNewString(ctxt, str2));
5334
0
     xmlFree(str2);
5335
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5336
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5337
0
     if (ret)
5338
0
         break;
5339
0
       } else {
5340
0
                 xmlXPathPErrMemory(ctxt);
5341
0
             }
5342
0
  }
5343
0
    }
5344
0
    xmlXPathReleaseObject(ctxt->context, arg);
5345
0
    xmlXPathReleaseObject(ctxt->context, s);
5346
0
    return(ret);
5347
0
}
5348
5349
/**
5350
 * xmlXPathCompareNodeSets:
5351
 * @inf:  less than (1) or greater than (0)
5352
 * @strict:  is the comparison strict
5353
 * @arg1:  the first node set object
5354
 * @arg2:  the second node set object
5355
 *
5356
 * Implement the compare operation on nodesets:
5357
 *
5358
 * If both objects to be compared are node-sets, then the comparison
5359
 * will be true if and only if there is a node in the first node-set
5360
 * and a node in the second node-set such that the result of performing
5361
 * the comparison on the string-values of the two nodes is true.
5362
 * ....
5363
 * When neither object to be compared is a node-set and the operator
5364
 * is <=, <, >= or >, then the objects are compared by converting both
5365
 * objects to numbers and comparing the numbers according to IEEE 754.
5366
 * ....
5367
 * The number function converts its argument to a number as follows:
5368
 *  - a string that consists of optional whitespace followed by an
5369
 *    optional minus sign followed by a Number followed by whitespace
5370
 *    is converted to the IEEE 754 number that is nearest (according
5371
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5372
 *    represented by the string; any other string is converted to NaN
5373
 *
5374
 * Conclusion all nodes need to be converted first to their string value
5375
 * and then the comparison must be done when possible
5376
 */
5377
static int
5378
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5379
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5380
0
    int i, j, init = 0;
5381
0
    double val1;
5382
0
    double *values2;
5383
0
    int ret = 0;
5384
0
    xmlNodeSetPtr ns1;
5385
0
    xmlNodeSetPtr ns2;
5386
5387
0
    if ((arg1 == NULL) ||
5388
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5389
0
  xmlXPathFreeObject(arg2);
5390
0
        return(0);
5391
0
    }
5392
0
    if ((arg2 == NULL) ||
5393
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5394
0
  xmlXPathFreeObject(arg1);
5395
0
  xmlXPathFreeObject(arg2);
5396
0
        return(0);
5397
0
    }
5398
5399
0
    ns1 = arg1->nodesetval;
5400
0
    ns2 = arg2->nodesetval;
5401
5402
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5403
0
  xmlXPathFreeObject(arg1);
5404
0
  xmlXPathFreeObject(arg2);
5405
0
  return(0);
5406
0
    }
5407
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5408
0
  xmlXPathFreeObject(arg1);
5409
0
  xmlXPathFreeObject(arg2);
5410
0
  return(0);
5411
0
    }
5412
5413
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5414
0
    if (values2 == NULL) {
5415
0
        xmlXPathPErrMemory(ctxt);
5416
0
  xmlXPathFreeObject(arg1);
5417
0
  xmlXPathFreeObject(arg2);
5418
0
  return(0);
5419
0
    }
5420
0
    for (i = 0;i < ns1->nodeNr;i++) {
5421
0
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5422
0
  if (xmlXPathIsNaN(val1))
5423
0
      continue;
5424
0
  for (j = 0;j < ns2->nodeNr;j++) {
5425
0
      if (init == 0) {
5426
0
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5427
0
                                                          ns2->nodeTab[j]);
5428
0
      }
5429
0
      if (xmlXPathIsNaN(values2[j]))
5430
0
    continue;
5431
0
      if (inf && strict)
5432
0
    ret = (val1 < values2[j]);
5433
0
      else if (inf && !strict)
5434
0
    ret = (val1 <= values2[j]);
5435
0
      else if (!inf && strict)
5436
0
    ret = (val1 > values2[j]);
5437
0
      else if (!inf && !strict)
5438
0
    ret = (val1 >= values2[j]);
5439
0
      if (ret)
5440
0
    break;
5441
0
  }
5442
0
  if (ret)
5443
0
      break;
5444
0
  init = 1;
5445
0
    }
5446
0
    xmlFree(values2);
5447
0
    xmlXPathFreeObject(arg1);
5448
0
    xmlXPathFreeObject(arg2);
5449
0
    return(ret);
5450
0
}
5451
5452
/**
5453
 * xmlXPathCompareNodeSetValue:
5454
 * @ctxt:  the XPath Parser context
5455
 * @inf:  less than (1) or greater than (0)
5456
 * @strict:  is the comparison strict
5457
 * @arg:  the node set
5458
 * @val:  the value
5459
 *
5460
 * Implement the compare operation between a nodeset and a value
5461
 *     @ns < @val    (1, 1, ...
5462
 *     @ns <= @val   (1, 0, ...
5463
 *     @ns > @val    (0, 1, ...
5464
 *     @ns >= @val   (0, 0, ...
5465
 *
5466
 * If one object to be compared is a node-set and the other is a boolean,
5467
 * then the comparison will be true if and only if the result of performing
5468
 * the comparison on the boolean and on the result of converting
5469
 * the node-set to a boolean using the boolean function is true.
5470
 *
5471
 * Returns 0 or 1 depending on the results of the test.
5472
 */
5473
static int
5474
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5475
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5476
0
    if ((val == NULL) || (arg == NULL) ||
5477
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5478
0
        return(0);
5479
5480
0
    switch(val->type) {
5481
0
        case XPATH_NUMBER:
5482
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5483
0
        case XPATH_NODESET:
5484
0
        case XPATH_XSLT_TREE:
5485
0
      return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5486
0
        case XPATH_STRING:
5487
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5488
0
        case XPATH_BOOLEAN:
5489
0
      valuePush(ctxt, arg);
5490
0
      xmlXPathBooleanFunction(ctxt, 1);
5491
0
      valuePush(ctxt, val);
5492
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
5493
0
  default:
5494
0
            xmlXPathReleaseObject(ctxt->context, arg);
5495
0
            xmlXPathReleaseObject(ctxt->context, val);
5496
0
            XP_ERROR0(XPATH_INVALID_TYPE);
5497
0
    }
5498
0
    return(0);
5499
0
}
5500
5501
/**
5502
 * xmlXPathEqualNodeSetString:
5503
 * @arg:  the nodeset object argument
5504
 * @str:  the string to compare to.
5505
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
5506
 *
5507
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5508
 * If one object to be compared is a node-set and the other is a string,
5509
 * then the comparison will be true if and only if there is a node in
5510
 * the node-set such that the result of performing the comparison on the
5511
 * string-value of the node and the other string is true.
5512
 *
5513
 * Returns 0 or 1 depending on the results of the test.
5514
 */
5515
static int
5516
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5517
                           xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5518
0
{
5519
0
    int i;
5520
0
    xmlNodeSetPtr ns;
5521
0
    xmlChar *str2;
5522
0
    unsigned int hash;
5523
5524
0
    if ((str == NULL) || (arg == NULL) ||
5525
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5526
0
        return (0);
5527
0
    ns = arg->nodesetval;
5528
    /*
5529
     * A NULL nodeset compared with a string is always false
5530
     * (since there is no node equal, and no node not equal)
5531
     */
5532
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5533
0
        return (0);
5534
0
    hash = xmlXPathStringHash(str);
5535
0
    for (i = 0; i < ns->nodeNr; i++) {
5536
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5537
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5538
0
            if (str2 == NULL) {
5539
0
                xmlXPathPErrMemory(ctxt);
5540
0
                return(0);
5541
0
            }
5542
0
            if (xmlStrEqual(str, str2)) {
5543
0
                xmlFree(str2);
5544
0
    if (neq)
5545
0
        continue;
5546
0
                return (1);
5547
0
            } else if (neq) {
5548
0
    xmlFree(str2);
5549
0
    return (1);
5550
0
      }
5551
0
            xmlFree(str2);
5552
0
        } else if (neq)
5553
0
      return (1);
5554
0
    }
5555
0
    return (0);
5556
0
}
5557
5558
/**
5559
 * xmlXPathEqualNodeSetFloat:
5560
 * @arg:  the nodeset object argument
5561
 * @f:  the float to compare to
5562
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
5563
 *
5564
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5565
 * If one object to be compared is a node-set and the other is a number,
5566
 * then the comparison will be true if and only if there is a node in
5567
 * the node-set such that the result of performing the comparison on the
5568
 * number to be compared and on the result of converting the string-value
5569
 * of that node to a number using the number function is true.
5570
 *
5571
 * Returns 0 or 1 depending on the results of the test.
5572
 */
5573
static int
5574
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5575
0
    xmlXPathObjectPtr arg, double f, int neq) {
5576
0
  int i, ret=0;
5577
0
  xmlNodeSetPtr ns;
5578
0
  xmlChar *str2;
5579
0
  xmlXPathObjectPtr val;
5580
0
  double v;
5581
5582
0
    if ((arg == NULL) ||
5583
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5584
0
        return(0);
5585
5586
0
    ns = arg->nodesetval;
5587
0
    if (ns != NULL) {
5588
0
  for (i=0;i<ns->nodeNr;i++) {
5589
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5590
0
      if (str2 != NULL) {
5591
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5592
0
    xmlFree(str2);
5593
0
    xmlXPathNumberFunction(ctxt, 1);
5594
0
                CHECK_ERROR0;
5595
0
    val = valuePop(ctxt);
5596
0
    v = val->floatval;
5597
0
    xmlXPathReleaseObject(ctxt->context, val);
5598
0
    if (!xmlXPathIsNaN(v)) {
5599
0
        if ((!neq) && (v==f)) {
5600
0
      ret = 1;
5601
0
      break;
5602
0
        } else if ((neq) && (v!=f)) {
5603
0
      ret = 1;
5604
0
      break;
5605
0
        }
5606
0
    } else { /* NaN is unequal to any value */
5607
0
        if (neq)
5608
0
      ret = 1;
5609
0
    }
5610
0
      } else {
5611
0
                xmlXPathPErrMemory(ctxt);
5612
0
            }
5613
0
  }
5614
0
    }
5615
5616
0
    return(ret);
5617
0
}
5618
5619
5620
/**
5621
 * xmlXPathEqualNodeSets:
5622
 * @arg1:  first nodeset object argument
5623
 * @arg2:  second nodeset object argument
5624
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
5625
 *
5626
 * Implement the equal / not equal operation on XPath nodesets:
5627
 * @arg1 == @arg2  or  @arg1 != @arg2
5628
 * If both objects to be compared are node-sets, then the comparison
5629
 * will be true if and only if there is a node in the first node-set and
5630
 * a node in the second node-set such that the result of performing the
5631
 * comparison on the string-values of the two nodes is true.
5632
 *
5633
 * (needless to say, this is a costly operation)
5634
 *
5635
 * Returns 0 or 1 depending on the results of the test.
5636
 */
5637
static int
5638
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5639
0
                      xmlXPathObjectPtr arg2, int neq) {
5640
0
    int i, j;
5641
0
    unsigned int *hashs1;
5642
0
    unsigned int *hashs2;
5643
0
    xmlChar **values1;
5644
0
    xmlChar **values2;
5645
0
    int ret = 0;
5646
0
    xmlNodeSetPtr ns1;
5647
0
    xmlNodeSetPtr ns2;
5648
5649
0
    if ((arg1 == NULL) ||
5650
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5651
0
        return(0);
5652
0
    if ((arg2 == NULL) ||
5653
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5654
0
        return(0);
5655
5656
0
    ns1 = arg1->nodesetval;
5657
0
    ns2 = arg2->nodesetval;
5658
5659
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5660
0
  return(0);
5661
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5662
0
  return(0);
5663
5664
    /*
5665
     * for equal, check if there is a node pertaining to both sets
5666
     */
5667
0
    if (neq == 0)
5668
0
  for (i = 0;i < ns1->nodeNr;i++)
5669
0
      for (j = 0;j < ns2->nodeNr;j++)
5670
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5671
0
        return(1);
5672
5673
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5674
0
    if (values1 == NULL) {
5675
0
        xmlXPathPErrMemory(ctxt);
5676
0
  return(0);
5677
0
    }
5678
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5679
0
    if (hashs1 == NULL) {
5680
0
        xmlXPathPErrMemory(ctxt);
5681
0
  xmlFree(values1);
5682
0
  return(0);
5683
0
    }
5684
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5685
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5686
0
    if (values2 == NULL) {
5687
0
        xmlXPathPErrMemory(ctxt);
5688
0
  xmlFree(hashs1);
5689
0
  xmlFree(values1);
5690
0
  return(0);
5691
0
    }
5692
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5693
0
    if (hashs2 == NULL) {
5694
0
        xmlXPathPErrMemory(ctxt);
5695
0
  xmlFree(hashs1);
5696
0
  xmlFree(values1);
5697
0
  xmlFree(values2);
5698
0
  return(0);
5699
0
    }
5700
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5701
0
    for (i = 0;i < ns1->nodeNr;i++) {
5702
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5703
0
  for (j = 0;j < ns2->nodeNr;j++) {
5704
0
      if (i == 0)
5705
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5706
0
      if (hashs1[i] != hashs2[j]) {
5707
0
    if (neq) {
5708
0
        ret = 1;
5709
0
        break;
5710
0
    }
5711
0
      }
5712
0
      else {
5713
0
    if (values1[i] == NULL) {
5714
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5715
0
                    if (values1[i] == NULL)
5716
0
                        xmlXPathPErrMemory(ctxt);
5717
0
                }
5718
0
    if (values2[j] == NULL) {
5719
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5720
0
                    if (values2[j] == NULL)
5721
0
                        xmlXPathPErrMemory(ctxt);
5722
0
                }
5723
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5724
0
    if (ret)
5725
0
        break;
5726
0
      }
5727
0
  }
5728
0
  if (ret)
5729
0
      break;
5730
0
    }
5731
0
    for (i = 0;i < ns1->nodeNr;i++)
5732
0
  if (values1[i] != NULL)
5733
0
      xmlFree(values1[i]);
5734
0
    for (j = 0;j < ns2->nodeNr;j++)
5735
0
  if (values2[j] != NULL)
5736
0
      xmlFree(values2[j]);
5737
0
    xmlFree(values1);
5738
0
    xmlFree(values2);
5739
0
    xmlFree(hashs1);
5740
0
    xmlFree(hashs2);
5741
0
    return(ret);
5742
0
}
5743
5744
static int
5745
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5746
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5747
0
    int ret = 0;
5748
    /*
5749
     *At this point we are assured neither arg1 nor arg2
5750
     *is a nodeset, so we can just pick the appropriate routine.
5751
     */
5752
0
    switch (arg1->type) {
5753
0
        case XPATH_UNDEFINED:
5754
0
      break;
5755
0
        case XPATH_BOOLEAN:
5756
0
      switch (arg2->type) {
5757
0
          case XPATH_UNDEFINED:
5758
0
        break;
5759
0
    case XPATH_BOOLEAN:
5760
0
        ret = (arg1->boolval == arg2->boolval);
5761
0
        break;
5762
0
    case XPATH_NUMBER:
5763
0
        ret = (arg1->boolval ==
5764
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
5765
0
        break;
5766
0
    case XPATH_STRING:
5767
0
        if ((arg2->stringval == NULL) ||
5768
0
      (arg2->stringval[0] == 0)) ret = 0;
5769
0
        else
5770
0
      ret = 1;
5771
0
        ret = (arg1->boolval == ret);
5772
0
        break;
5773
0
    case XPATH_USERS:
5774
        /* TODO */
5775
0
        break;
5776
0
    case XPATH_NODESET:
5777
0
    case XPATH_XSLT_TREE:
5778
0
        break;
5779
0
      }
5780
0
      break;
5781
0
        case XPATH_NUMBER:
5782
0
      switch (arg2->type) {
5783
0
          case XPATH_UNDEFINED:
5784
0
        break;
5785
0
    case XPATH_BOOLEAN:
5786
0
        ret = (arg2->boolval==
5787
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
5788
0
        break;
5789
0
    case XPATH_STRING:
5790
0
        valuePush(ctxt, arg2);
5791
0
        xmlXPathNumberFunction(ctxt, 1);
5792
0
        arg2 = valuePop(ctxt);
5793
0
                    if (ctxt->error)
5794
0
                        break;
5795
                    /* Falls through. */
5796
0
    case XPATH_NUMBER:
5797
        /* Hand check NaN and Infinity equalities */
5798
0
        if (xmlXPathIsNaN(arg1->floatval) ||
5799
0
          xmlXPathIsNaN(arg2->floatval)) {
5800
0
            ret = 0;
5801
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5802
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
5803
0
          ret = 1;
5804
0
      else
5805
0
          ret = 0;
5806
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5807
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
5808
0
          ret = 1;
5809
0
      else
5810
0
          ret = 0;
5811
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5812
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
5813
0
          ret = 1;
5814
0
      else
5815
0
          ret = 0;
5816
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5817
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5818
0
          ret = 1;
5819
0
      else
5820
0
          ret = 0;
5821
0
        } else {
5822
0
            ret = (arg1->floatval == arg2->floatval);
5823
0
        }
5824
0
        break;
5825
0
    case XPATH_USERS:
5826
        /* TODO */
5827
0
        break;
5828
0
    case XPATH_NODESET:
5829
0
    case XPATH_XSLT_TREE:
5830
0
        break;
5831
0
      }
5832
0
      break;
5833
0
        case XPATH_STRING:
5834
0
      switch (arg2->type) {
5835
0
          case XPATH_UNDEFINED:
5836
0
        break;
5837
0
    case XPATH_BOOLEAN:
5838
0
        if ((arg1->stringval == NULL) ||
5839
0
      (arg1->stringval[0] == 0)) ret = 0;
5840
0
        else
5841
0
      ret = 1;
5842
0
        ret = (arg2->boolval == ret);
5843
0
        break;
5844
0
    case XPATH_STRING:
5845
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5846
0
        break;
5847
0
    case XPATH_NUMBER:
5848
0
        valuePush(ctxt, arg1);
5849
0
        xmlXPathNumberFunction(ctxt, 1);
5850
0
        arg1 = valuePop(ctxt);
5851
0
                    if (ctxt->error)
5852
0
                        break;
5853
        /* Hand check NaN and Infinity equalities */
5854
0
        if (xmlXPathIsNaN(arg1->floatval) ||
5855
0
          xmlXPathIsNaN(arg2->floatval)) {
5856
0
            ret = 0;
5857
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5858
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
5859
0
          ret = 1;
5860
0
      else
5861
0
          ret = 0;
5862
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5863
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
5864
0
          ret = 1;
5865
0
      else
5866
0
          ret = 0;
5867
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5868
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
5869
0
          ret = 1;
5870
0
      else
5871
0
          ret = 0;
5872
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5873
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5874
0
          ret = 1;
5875
0
      else
5876
0
          ret = 0;
5877
0
        } else {
5878
0
            ret = (arg1->floatval == arg2->floatval);
5879
0
        }
5880
0
        break;
5881
0
    case XPATH_USERS:
5882
        /* TODO */
5883
0
        break;
5884
0
    case XPATH_NODESET:
5885
0
    case XPATH_XSLT_TREE:
5886
0
        break;
5887
0
      }
5888
0
      break;
5889
0
        case XPATH_USERS:
5890
      /* TODO */
5891
0
      break;
5892
0
  case XPATH_NODESET:
5893
0
  case XPATH_XSLT_TREE:
5894
0
      break;
5895
0
    }
5896
0
    xmlXPathReleaseObject(ctxt->context, arg1);
5897
0
    xmlXPathReleaseObject(ctxt->context, arg2);
5898
0
    return(ret);
5899
0
}
5900
5901
/**
5902
 * xmlXPathEqualValues:
5903
 * @ctxt:  the XPath Parser context
5904
 *
5905
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5906
 *
5907
 * Returns 0 or 1 depending on the results of the test.
5908
 */
5909
int
5910
0
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
5911
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
5912
0
    int ret = 0;
5913
5914
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5915
0
    arg2 = valuePop(ctxt);
5916
0
    arg1 = valuePop(ctxt);
5917
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
5918
0
  if (arg1 != NULL)
5919
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5920
0
  else
5921
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5922
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5923
0
    }
5924
5925
0
    if (arg1 == arg2) {
5926
0
  xmlXPathFreeObject(arg1);
5927
0
        return(1);
5928
0
    }
5929
5930
    /*
5931
     *If either argument is a nodeset, it's a 'special case'
5932
     */
5933
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5934
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5935
  /*
5936
   *Hack it to assure arg1 is the nodeset
5937
   */
5938
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5939
0
    argtmp = arg2;
5940
0
    arg2 = arg1;
5941
0
    arg1 = argtmp;
5942
0
  }
5943
0
  switch (arg2->type) {
5944
0
      case XPATH_UNDEFINED:
5945
0
    break;
5946
0
      case XPATH_NODESET:
5947
0
      case XPATH_XSLT_TREE:
5948
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5949
0
    break;
5950
0
      case XPATH_BOOLEAN:
5951
0
    if ((arg1->nodesetval == NULL) ||
5952
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5953
0
    else
5954
0
        ret = 1;
5955
0
    ret = (ret == arg2->boolval);
5956
0
    break;
5957
0
      case XPATH_NUMBER:
5958
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5959
0
    break;
5960
0
      case XPATH_STRING:
5961
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5962
0
                                                 arg2->stringval, 0);
5963
0
    break;
5964
0
      case XPATH_USERS:
5965
    /* TODO */
5966
0
    break;
5967
0
  }
5968
0
  xmlXPathReleaseObject(ctxt->context, arg1);
5969
0
  xmlXPathReleaseObject(ctxt->context, arg2);
5970
0
  return(ret);
5971
0
    }
5972
5973
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5974
0
}
5975
5976
/**
5977
 * xmlXPathNotEqualValues:
5978
 * @ctxt:  the XPath Parser context
5979
 *
5980
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
5981
 *
5982
 * Returns 0 or 1 depending on the results of the test.
5983
 */
5984
int
5985
0
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
5986
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
5987
0
    int ret = 0;
5988
5989
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5990
0
    arg2 = valuePop(ctxt);
5991
0
    arg1 = valuePop(ctxt);
5992
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
5993
0
  if (arg1 != NULL)
5994
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5995
0
  else
5996
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5997
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5998
0
    }
5999
6000
0
    if (arg1 == arg2) {
6001
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6002
0
        return(0);
6003
0
    }
6004
6005
    /*
6006
     *If either argument is a nodeset, it's a 'special case'
6007
     */
6008
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6009
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6010
  /*
6011
   *Hack it to assure arg1 is the nodeset
6012
   */
6013
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6014
0
    argtmp = arg2;
6015
0
    arg2 = arg1;
6016
0
    arg1 = argtmp;
6017
0
  }
6018
0
  switch (arg2->type) {
6019
0
      case XPATH_UNDEFINED:
6020
0
    break;
6021
0
      case XPATH_NODESET:
6022
0
      case XPATH_XSLT_TREE:
6023
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
6024
0
    break;
6025
0
      case XPATH_BOOLEAN:
6026
0
    if ((arg1->nodesetval == NULL) ||
6027
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
6028
0
    else
6029
0
        ret = 1;
6030
0
    ret = (ret != arg2->boolval);
6031
0
    break;
6032
0
      case XPATH_NUMBER:
6033
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6034
0
    break;
6035
0
      case XPATH_STRING:
6036
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
6037
0
                                                 arg2->stringval, 1);
6038
0
    break;
6039
0
      case XPATH_USERS:
6040
    /* TODO */
6041
0
    break;
6042
0
  }
6043
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6044
0
  xmlXPathReleaseObject(ctxt->context, arg2);
6045
0
  return(ret);
6046
0
    }
6047
6048
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6049
0
}
6050
6051
/**
6052
 * xmlXPathCompareValues:
6053
 * @ctxt:  the XPath Parser context
6054
 * @inf:  less than (1) or greater than (0)
6055
 * @strict:  is the comparison strict
6056
 *
6057
 * Implement the compare operation on XPath objects:
6058
 *     @arg1 < @arg2    (1, 1, ...
6059
 *     @arg1 <= @arg2   (1, 0, ...
6060
 *     @arg1 > @arg2    (0, 1, ...
6061
 *     @arg1 >= @arg2   (0, 0, ...
6062
 *
6063
 * When neither object to be compared is a node-set and the operator is
6064
 * <=, <, >=, >, then the objects are compared by converted both objects
6065
 * to numbers and comparing the numbers according to IEEE 754. The <
6066
 * comparison will be true if and only if the first number is less than the
6067
 * second number. The <= comparison will be true if and only if the first
6068
 * number is less than or equal to the second number. The > comparison
6069
 * will be true if and only if the first number is greater than the second
6070
 * number. The >= comparison will be true if and only if the first number
6071
 * is greater than or equal to the second number.
6072
 *
6073
 * Returns 1 if the comparison succeeded, 0 if it failed
6074
 */
6075
int
6076
0
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6077
0
    int ret = 0, arg1i = 0, arg2i = 0;
6078
0
    xmlXPathObjectPtr arg1, arg2;
6079
6080
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6081
0
    arg2 = valuePop(ctxt);
6082
0
    arg1 = valuePop(ctxt);
6083
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6084
0
  if (arg1 != NULL)
6085
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6086
0
  else
6087
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6088
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6089
0
    }
6090
6091
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6092
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6093
  /*
6094
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6095
   * are not freed from within this routine; they will be freed from the
6096
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6097
   */
6098
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6099
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6100
0
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
6101
0
  } else {
6102
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6103
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6104
0
                                arg1, arg2);
6105
0
      } else {
6106
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6107
0
                                arg2, arg1);
6108
0
      }
6109
0
  }
6110
0
  return(ret);
6111
0
    }
6112
6113
0
    if (arg1->type != XPATH_NUMBER) {
6114
0
  valuePush(ctxt, arg1);
6115
0
  xmlXPathNumberFunction(ctxt, 1);
6116
0
  arg1 = valuePop(ctxt);
6117
0
    }
6118
0
    if (arg2->type != XPATH_NUMBER) {
6119
0
  valuePush(ctxt, arg2);
6120
0
  xmlXPathNumberFunction(ctxt, 1);
6121
0
  arg2 = valuePop(ctxt);
6122
0
    }
6123
0
    if (ctxt->error)
6124
0
        goto error;
6125
    /*
6126
     * Add tests for infinity and nan
6127
     * => feedback on 3.4 for Inf and NaN
6128
     */
6129
    /* Hand check NaN and Infinity comparisons */
6130
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6131
0
  ret=0;
6132
0
    } else {
6133
0
  arg1i=xmlXPathIsInf(arg1->floatval);
6134
0
  arg2i=xmlXPathIsInf(arg2->floatval);
6135
0
  if (inf && strict) {
6136
0
      if ((arg1i == -1 && arg2i != -1) ||
6137
0
    (arg2i == 1 && arg1i != 1)) {
6138
0
    ret = 1;
6139
0
      } else if (arg1i == 0 && arg2i == 0) {
6140
0
    ret = (arg1->floatval < arg2->floatval);
6141
0
      } else {
6142
0
    ret = 0;
6143
0
      }
6144
0
  }
6145
0
  else if (inf && !strict) {
6146
0
      if (arg1i == -1 || arg2i == 1) {
6147
0
    ret = 1;
6148
0
      } else if (arg1i == 0 && arg2i == 0) {
6149
0
    ret = (arg1->floatval <= arg2->floatval);
6150
0
      } else {
6151
0
    ret = 0;
6152
0
      }
6153
0
  }
6154
0
  else if (!inf && strict) {
6155
0
      if ((arg1i == 1 && arg2i != 1) ||
6156
0
    (arg2i == -1 && arg1i != -1)) {
6157
0
    ret = 1;
6158
0
      } else if (arg1i == 0 && arg2i == 0) {
6159
0
    ret = (arg1->floatval > arg2->floatval);
6160
0
      } else {
6161
0
    ret = 0;
6162
0
      }
6163
0
  }
6164
0
  else if (!inf && !strict) {
6165
0
      if (arg1i == 1 || arg2i == -1) {
6166
0
    ret = 1;
6167
0
      } else if (arg1i == 0 && arg2i == 0) {
6168
0
    ret = (arg1->floatval >= arg2->floatval);
6169
0
      } else {
6170
0
    ret = 0;
6171
0
      }
6172
0
  }
6173
0
    }
6174
0
error:
6175
0
    xmlXPathReleaseObject(ctxt->context, arg1);
6176
0
    xmlXPathReleaseObject(ctxt->context, arg2);
6177
0
    return(ret);
6178
0
}
6179
6180
/**
6181
 * xmlXPathValueFlipSign:
6182
 * @ctxt:  the XPath Parser context
6183
 *
6184
 * Implement the unary - operation on an XPath object
6185
 * The numeric operators convert their operands to numbers as if
6186
 * by calling the number function.
6187
 */
6188
void
6189
0
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6190
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6191
0
    CAST_TO_NUMBER;
6192
0
    CHECK_TYPE(XPATH_NUMBER);
6193
0
    ctxt->value->floatval = -ctxt->value->floatval;
6194
0
}
6195
6196
/**
6197
 * xmlXPathAddValues:
6198
 * @ctxt:  the XPath Parser context
6199
 *
6200
 * Implement the add operation on XPath objects:
6201
 * The numeric operators convert their operands to numbers as if
6202
 * by calling the number function.
6203
 */
6204
void
6205
0
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6206
0
    xmlXPathObjectPtr arg;
6207
0
    double val;
6208
6209
0
    arg = valuePop(ctxt);
6210
0
    if (arg == NULL)
6211
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6212
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6213
0
    xmlXPathReleaseObject(ctxt->context, arg);
6214
0
    CAST_TO_NUMBER;
6215
0
    CHECK_TYPE(XPATH_NUMBER);
6216
0
    ctxt->value->floatval += val;
6217
0
}
6218
6219
/**
6220
 * xmlXPathSubValues:
6221
 * @ctxt:  the XPath Parser context
6222
 *
6223
 * Implement the subtraction operation on XPath objects:
6224
 * The numeric operators convert their operands to numbers as if
6225
 * by calling the number function.
6226
 */
6227
void
6228
0
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6229
0
    xmlXPathObjectPtr arg;
6230
0
    double val;
6231
6232
0
    arg = valuePop(ctxt);
6233
0
    if (arg == NULL)
6234
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6235
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6236
0
    xmlXPathReleaseObject(ctxt->context, arg);
6237
0
    CAST_TO_NUMBER;
6238
0
    CHECK_TYPE(XPATH_NUMBER);
6239
0
    ctxt->value->floatval -= val;
6240
0
}
6241
6242
/**
6243
 * xmlXPathMultValues:
6244
 * @ctxt:  the XPath Parser context
6245
 *
6246
 * Implement the multiply operation on XPath objects:
6247
 * The numeric operators convert their operands to numbers as if
6248
 * by calling the number function.
6249
 */
6250
void
6251
0
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6252
0
    xmlXPathObjectPtr arg;
6253
0
    double val;
6254
6255
0
    arg = valuePop(ctxt);
6256
0
    if (arg == NULL)
6257
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6258
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6259
0
    xmlXPathReleaseObject(ctxt->context, arg);
6260
0
    CAST_TO_NUMBER;
6261
0
    CHECK_TYPE(XPATH_NUMBER);
6262
0
    ctxt->value->floatval *= val;
6263
0
}
6264
6265
/**
6266
 * xmlXPathDivValues:
6267
 * @ctxt:  the XPath Parser context
6268
 *
6269
 * Implement the div operation on XPath objects @arg1 / @arg2:
6270
 * The numeric operators convert their operands to numbers as if
6271
 * by calling the number function.
6272
 */
6273
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6274
void
6275
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6276
0
    xmlXPathObjectPtr arg;
6277
0
    double val;
6278
6279
0
    arg = valuePop(ctxt);
6280
0
    if (arg == NULL)
6281
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6282
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6283
0
    xmlXPathReleaseObject(ctxt->context, arg);
6284
0
    CAST_TO_NUMBER;
6285
0
    CHECK_TYPE(XPATH_NUMBER);
6286
0
    ctxt->value->floatval /= val;
6287
0
}
6288
6289
/**
6290
 * xmlXPathModValues:
6291
 * @ctxt:  the XPath Parser context
6292
 *
6293
 * Implement the mod operation on XPath objects: @arg1 / @arg2
6294
 * The numeric operators convert their operands to numbers as if
6295
 * by calling the number function.
6296
 */
6297
void
6298
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6299
0
    xmlXPathObjectPtr arg;
6300
0
    double arg1, arg2;
6301
6302
0
    arg = valuePop(ctxt);
6303
0
    if (arg == NULL)
6304
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6305
0
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6306
0
    xmlXPathReleaseObject(ctxt->context, arg);
6307
0
    CAST_TO_NUMBER;
6308
0
    CHECK_TYPE(XPATH_NUMBER);
6309
0
    arg1 = ctxt->value->floatval;
6310
0
    if (arg2 == 0)
6311
0
  ctxt->value->floatval = xmlXPathNAN;
6312
0
    else {
6313
0
  ctxt->value->floatval = fmod(arg1, arg2);
6314
0
    }
6315
0
}
6316
6317
/************************************************************************
6318
 *                  *
6319
 *    The traversal functions         *
6320
 *                  *
6321
 ************************************************************************/
6322
6323
/*
6324
 * A traversal function enumerates nodes along an axis.
6325
 * Initially it must be called with NULL, and it indicates
6326
 * termination on the axis by returning NULL.
6327
 */
6328
typedef xmlNodePtr (*xmlXPathTraversalFunction)
6329
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6330
6331
/*
6332
 * xmlXPathTraversalFunctionExt:
6333
 * A traversal function enumerates nodes along an axis.
6334
 * Initially it must be called with NULL, and it indicates
6335
 * termination on the axis by returning NULL.
6336
 * The context node of the traversal is specified via @contextNode.
6337
 */
6338
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6339
                    (xmlNodePtr cur, xmlNodePtr contextNode);
6340
6341
/*
6342
 * xmlXPathNodeSetMergeFunction:
6343
 * Used for merging node sets in xmlXPathCollectAndTest().
6344
 */
6345
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6346
        (xmlNodeSetPtr, xmlNodeSetPtr);
6347
6348
6349
/**
6350
 * xmlXPathNextSelf:
6351
 * @ctxt:  the XPath Parser context
6352
 * @cur:  the current node in the traversal
6353
 *
6354
 * Traversal function for the "self" direction
6355
 * The self axis contains just the context node itself
6356
 *
6357
 * Returns the next element following that axis
6358
 */
6359
xmlNodePtr
6360
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6361
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6362
0
    if (cur == NULL)
6363
0
        return(ctxt->context->node);
6364
0
    return(NULL);
6365
0
}
6366
6367
/**
6368
 * xmlXPathNextChild:
6369
 * @ctxt:  the XPath Parser context
6370
 * @cur:  the current node in the traversal
6371
 *
6372
 * Traversal function for the "child" direction
6373
 * The child axis contains the children of the context node in document order.
6374
 *
6375
 * Returns the next element following that axis
6376
 */
6377
xmlNodePtr
6378
0
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6379
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6380
0
    if (cur == NULL) {
6381
0
  if (ctxt->context->node == NULL) return(NULL);
6382
0
  switch (ctxt->context->node->type) {
6383
0
            case XML_ELEMENT_NODE:
6384
0
            case XML_TEXT_NODE:
6385
0
            case XML_CDATA_SECTION_NODE:
6386
0
            case XML_ENTITY_REF_NODE:
6387
0
            case XML_ENTITY_NODE:
6388
0
            case XML_PI_NODE:
6389
0
            case XML_COMMENT_NODE:
6390
0
            case XML_NOTATION_NODE:
6391
0
            case XML_DTD_NODE:
6392
0
    return(ctxt->context->node->children);
6393
0
            case XML_DOCUMENT_NODE:
6394
0
            case XML_DOCUMENT_TYPE_NODE:
6395
0
            case XML_DOCUMENT_FRAG_NODE:
6396
0
            case XML_HTML_DOCUMENT_NODE:
6397
0
    return(((xmlDocPtr) ctxt->context->node)->children);
6398
0
      case XML_ELEMENT_DECL:
6399
0
      case XML_ATTRIBUTE_DECL:
6400
0
      case XML_ENTITY_DECL:
6401
0
            case XML_ATTRIBUTE_NODE:
6402
0
      case XML_NAMESPACE_DECL:
6403
0
      case XML_XINCLUDE_START:
6404
0
      case XML_XINCLUDE_END:
6405
0
    return(NULL);
6406
0
  }
6407
0
  return(NULL);
6408
0
    }
6409
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
6410
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
6411
0
  return(NULL);
6412
0
    return(cur->next);
6413
0
}
6414
6415
/**
6416
 * xmlXPathNextChildElement:
6417
 * @ctxt:  the XPath Parser context
6418
 * @cur:  the current node in the traversal
6419
 *
6420
 * Traversal function for the "child" direction and nodes of type element.
6421
 * The child axis contains the children of the context node in document order.
6422
 *
6423
 * Returns the next element following that axis
6424
 */
6425
static xmlNodePtr
6426
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6427
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6428
0
    if (cur == NULL) {
6429
0
  cur = ctxt->context->node;
6430
0
  if (cur == NULL) return(NULL);
6431
  /*
6432
  * Get the first element child.
6433
  */
6434
0
  switch (cur->type) {
6435
0
            case XML_ELEMENT_NODE:
6436
0
      case XML_DOCUMENT_FRAG_NODE:
6437
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6438
0
            case XML_ENTITY_NODE:
6439
0
    cur = cur->children;
6440
0
    if (cur != NULL) {
6441
0
        if (cur->type == XML_ELEMENT_NODE)
6442
0
      return(cur);
6443
0
        do {
6444
0
      cur = cur->next;
6445
0
        } while ((cur != NULL) &&
6446
0
      (cur->type != XML_ELEMENT_NODE));
6447
0
        return(cur);
6448
0
    }
6449
0
    return(NULL);
6450
0
            case XML_DOCUMENT_NODE:
6451
0
            case XML_HTML_DOCUMENT_NODE:
6452
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6453
0
      default:
6454
0
    return(NULL);
6455
0
  }
6456
0
  return(NULL);
6457
0
    }
6458
    /*
6459
    * Get the next sibling element node.
6460
    */
6461
0
    switch (cur->type) {
6462
0
  case XML_ELEMENT_NODE:
6463
0
  case XML_TEXT_NODE:
6464
0
  case XML_ENTITY_REF_NODE:
6465
0
  case XML_ENTITY_NODE:
6466
0
  case XML_CDATA_SECTION_NODE:
6467
0
  case XML_PI_NODE:
6468
0
  case XML_COMMENT_NODE:
6469
0
  case XML_XINCLUDE_END:
6470
0
      break;
6471
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6472
0
  default:
6473
0
      return(NULL);
6474
0
    }
6475
0
    if (cur->next != NULL) {
6476
0
  if (cur->next->type == XML_ELEMENT_NODE)
6477
0
      return(cur->next);
6478
0
  cur = cur->next;
6479
0
  do {
6480
0
      cur = cur->next;
6481
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6482
0
  return(cur);
6483
0
    }
6484
0
    return(NULL);
6485
0
}
6486
6487
/**
6488
 * xmlXPathNextDescendant:
6489
 * @ctxt:  the XPath Parser context
6490
 * @cur:  the current node in the traversal
6491
 *
6492
 * Traversal function for the "descendant" direction
6493
 * the descendant axis contains the descendants of the context node in document
6494
 * order; a descendant is a child or a child of a child and so on.
6495
 *
6496
 * Returns the next element following that axis
6497
 */
6498
xmlNodePtr
6499
0
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6500
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6501
0
    if (cur == NULL) {
6502
0
  if (ctxt->context->node == NULL)
6503
0
      return(NULL);
6504
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6505
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6506
0
      return(NULL);
6507
6508
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6509
0
      return(ctxt->context->doc->children);
6510
0
        return(ctxt->context->node->children);
6511
0
    }
6512
6513
0
    if (cur->type == XML_NAMESPACE_DECL)
6514
0
        return(NULL);
6515
0
    if (cur->children != NULL) {
6516
  /*
6517
   * Do not descend on entities declarations
6518
   */
6519
0
  if (cur->children->type != XML_ENTITY_DECL) {
6520
0
      cur = cur->children;
6521
      /*
6522
       * Skip DTDs
6523
       */
6524
0
      if (cur->type != XML_DTD_NODE)
6525
0
    return(cur);
6526
0
  }
6527
0
    }
6528
6529
0
    if (cur == ctxt->context->node) return(NULL);
6530
6531
0
    while (cur->next != NULL) {
6532
0
  cur = cur->next;
6533
0
  if ((cur->type != XML_ENTITY_DECL) &&
6534
0
      (cur->type != XML_DTD_NODE))
6535
0
      return(cur);
6536
0
    }
6537
6538
0
    do {
6539
0
        cur = cur->parent;
6540
0
  if (cur == NULL) break;
6541
0
  if (cur == ctxt->context->node) return(NULL);
6542
0
  if (cur->next != NULL) {
6543
0
      cur = cur->next;
6544
0
      return(cur);
6545
0
  }
6546
0
    } while (cur != NULL);
6547
0
    return(cur);
6548
0
}
6549
6550
/**
6551
 * xmlXPathNextDescendantOrSelf:
6552
 * @ctxt:  the XPath Parser context
6553
 * @cur:  the current node in the traversal
6554
 *
6555
 * Traversal function for the "descendant-or-self" direction
6556
 * the descendant-or-self axis contains the context node and the descendants
6557
 * of the context node in document order; thus the context node is the first
6558
 * node on the axis, and the first child of the context node is the second node
6559
 * on the axis
6560
 *
6561
 * Returns the next element following that axis
6562
 */
6563
xmlNodePtr
6564
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6565
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6566
0
    if (cur == NULL)
6567
0
        return(ctxt->context->node);
6568
6569
0
    if (ctxt->context->node == NULL)
6570
0
        return(NULL);
6571
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6572
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6573
0
        return(NULL);
6574
6575
0
    return(xmlXPathNextDescendant(ctxt, cur));
6576
0
}
6577
6578
/**
6579
 * xmlXPathNextParent:
6580
 * @ctxt:  the XPath Parser context
6581
 * @cur:  the current node in the traversal
6582
 *
6583
 * Traversal function for the "parent" direction
6584
 * The parent axis contains the parent of the context node, if there is one.
6585
 *
6586
 * Returns the next element following that axis
6587
 */
6588
xmlNodePtr
6589
0
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6590
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6591
    /*
6592
     * the parent of an attribute or namespace node is the element
6593
     * to which the attribute or namespace node is attached
6594
     * Namespace handling !!!
6595
     */
6596
0
    if (cur == NULL) {
6597
0
  if (ctxt->context->node == NULL) return(NULL);
6598
0
  switch (ctxt->context->node->type) {
6599
0
            case XML_ELEMENT_NODE:
6600
0
            case XML_TEXT_NODE:
6601
0
            case XML_CDATA_SECTION_NODE:
6602
0
            case XML_ENTITY_REF_NODE:
6603
0
            case XML_ENTITY_NODE:
6604
0
            case XML_PI_NODE:
6605
0
            case XML_COMMENT_NODE:
6606
0
            case XML_NOTATION_NODE:
6607
0
            case XML_DTD_NODE:
6608
0
      case XML_ELEMENT_DECL:
6609
0
      case XML_ATTRIBUTE_DECL:
6610
0
      case XML_XINCLUDE_START:
6611
0
      case XML_XINCLUDE_END:
6612
0
      case XML_ENTITY_DECL:
6613
0
    if (ctxt->context->node->parent == NULL)
6614
0
        return((xmlNodePtr) ctxt->context->doc);
6615
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6616
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6617
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6618
0
         BAD_CAST "fake node libxslt"))))
6619
0
        return(NULL);
6620
0
    return(ctxt->context->node->parent);
6621
0
            case XML_ATTRIBUTE_NODE: {
6622
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6623
6624
0
    return(att->parent);
6625
0
      }
6626
0
            case XML_DOCUMENT_NODE:
6627
0
            case XML_DOCUMENT_TYPE_NODE:
6628
0
            case XML_DOCUMENT_FRAG_NODE:
6629
0
            case XML_HTML_DOCUMENT_NODE:
6630
0
                return(NULL);
6631
0
      case XML_NAMESPACE_DECL: {
6632
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6633
6634
0
    if ((ns->next != NULL) &&
6635
0
        (ns->next->type != XML_NAMESPACE_DECL))
6636
0
        return((xmlNodePtr) ns->next);
6637
0
                return(NULL);
6638
0
      }
6639
0
  }
6640
0
    }
6641
0
    return(NULL);
6642
0
}
6643
6644
/**
6645
 * xmlXPathNextAncestor:
6646
 * @ctxt:  the XPath Parser context
6647
 * @cur:  the current node in the traversal
6648
 *
6649
 * Traversal function for the "ancestor" direction
6650
 * the ancestor axis contains the ancestors of the context node; the ancestors
6651
 * of the context node consist of the parent of context node and the parent's
6652
 * parent and so on; the nodes are ordered in reverse document order; thus the
6653
 * parent is the first node on the axis, and the parent's parent is the second
6654
 * node on the axis
6655
 *
6656
 * Returns the next element following that axis
6657
 */
6658
xmlNodePtr
6659
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6660
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6661
    /*
6662
     * the parent of an attribute or namespace node is the element
6663
     * to which the attribute or namespace node is attached
6664
     * !!!!!!!!!!!!!
6665
     */
6666
0
    if (cur == NULL) {
6667
0
  if (ctxt->context->node == NULL) return(NULL);
6668
0
  switch (ctxt->context->node->type) {
6669
0
            case XML_ELEMENT_NODE:
6670
0
            case XML_TEXT_NODE:
6671
0
            case XML_CDATA_SECTION_NODE:
6672
0
            case XML_ENTITY_REF_NODE:
6673
0
            case XML_ENTITY_NODE:
6674
0
            case XML_PI_NODE:
6675
0
            case XML_COMMENT_NODE:
6676
0
      case XML_DTD_NODE:
6677
0
      case XML_ELEMENT_DECL:
6678
0
      case XML_ATTRIBUTE_DECL:
6679
0
      case XML_ENTITY_DECL:
6680
0
            case XML_NOTATION_NODE:
6681
0
      case XML_XINCLUDE_START:
6682
0
      case XML_XINCLUDE_END:
6683
0
    if (ctxt->context->node->parent == NULL)
6684
0
        return((xmlNodePtr) ctxt->context->doc);
6685
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6686
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6687
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6688
0
         BAD_CAST "fake node libxslt"))))
6689
0
        return(NULL);
6690
0
    return(ctxt->context->node->parent);
6691
0
            case XML_ATTRIBUTE_NODE: {
6692
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6693
6694
0
    return(tmp->parent);
6695
0
      }
6696
0
            case XML_DOCUMENT_NODE:
6697
0
            case XML_DOCUMENT_TYPE_NODE:
6698
0
            case XML_DOCUMENT_FRAG_NODE:
6699
0
            case XML_HTML_DOCUMENT_NODE:
6700
0
                return(NULL);
6701
0
      case XML_NAMESPACE_DECL: {
6702
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6703
6704
0
    if ((ns->next != NULL) &&
6705
0
        (ns->next->type != XML_NAMESPACE_DECL))
6706
0
        return((xmlNodePtr) ns->next);
6707
    /* Bad, how did that namespace end up here ? */
6708
0
                return(NULL);
6709
0
      }
6710
0
  }
6711
0
  return(NULL);
6712
0
    }
6713
0
    if (cur == ctxt->context->doc->children)
6714
0
  return((xmlNodePtr) ctxt->context->doc);
6715
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6716
0
  return(NULL);
6717
0
    switch (cur->type) {
6718
0
  case XML_ELEMENT_NODE:
6719
0
  case XML_TEXT_NODE:
6720
0
  case XML_CDATA_SECTION_NODE:
6721
0
  case XML_ENTITY_REF_NODE:
6722
0
  case XML_ENTITY_NODE:
6723
0
  case XML_PI_NODE:
6724
0
  case XML_COMMENT_NODE:
6725
0
  case XML_NOTATION_NODE:
6726
0
  case XML_DTD_NODE:
6727
0
        case XML_ELEMENT_DECL:
6728
0
        case XML_ATTRIBUTE_DECL:
6729
0
        case XML_ENTITY_DECL:
6730
0
  case XML_XINCLUDE_START:
6731
0
  case XML_XINCLUDE_END:
6732
0
      if (cur->parent == NULL)
6733
0
    return(NULL);
6734
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6735
0
    ((cur->parent->name[0] == ' ') ||
6736
0
     (xmlStrEqual(cur->parent->name,
6737
0
            BAD_CAST "fake node libxslt"))))
6738
0
    return(NULL);
6739
0
      return(cur->parent);
6740
0
  case XML_ATTRIBUTE_NODE: {
6741
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
6742
6743
0
      return(att->parent);
6744
0
  }
6745
0
  case XML_NAMESPACE_DECL: {
6746
0
      xmlNsPtr ns = (xmlNsPtr) cur;
6747
6748
0
      if ((ns->next != NULL) &&
6749
0
          (ns->next->type != XML_NAMESPACE_DECL))
6750
0
          return((xmlNodePtr) ns->next);
6751
      /* Bad, how did that namespace end up here ? */
6752
0
            return(NULL);
6753
0
  }
6754
0
  case XML_DOCUMENT_NODE:
6755
0
  case XML_DOCUMENT_TYPE_NODE:
6756
0
  case XML_DOCUMENT_FRAG_NODE:
6757
0
  case XML_HTML_DOCUMENT_NODE:
6758
0
      return(NULL);
6759
0
    }
6760
0
    return(NULL);
6761
0
}
6762
6763
/**
6764
 * xmlXPathNextAncestorOrSelf:
6765
 * @ctxt:  the XPath Parser context
6766
 * @cur:  the current node in the traversal
6767
 *
6768
 * Traversal function for the "ancestor-or-self" direction
6769
 * he ancestor-or-self axis contains the context node and ancestors of
6770
 * the context node in reverse document order; thus the context node is
6771
 * the first node on the axis, and the context node's parent the second;
6772
 * parent here is defined the same as with the parent axis.
6773
 *
6774
 * Returns the next element following that axis
6775
 */
6776
xmlNodePtr
6777
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6778
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6779
0
    if (cur == NULL)
6780
0
        return(ctxt->context->node);
6781
0
    return(xmlXPathNextAncestor(ctxt, cur));
6782
0
}
6783
6784
/**
6785
 * xmlXPathNextFollowingSibling:
6786
 * @ctxt:  the XPath Parser context
6787
 * @cur:  the current node in the traversal
6788
 *
6789
 * Traversal function for the "following-sibling" direction
6790
 * The following-sibling axis contains the following siblings of the context
6791
 * node in document order.
6792
 *
6793
 * Returns the next element following that axis
6794
 */
6795
xmlNodePtr
6796
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6797
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6798
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6799
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6800
0
  return(NULL);
6801
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6802
0
        return(NULL);
6803
0
    if (cur == NULL)
6804
0
        return(ctxt->context->node->next);
6805
0
    return(cur->next);
6806
0
}
6807
6808
/**
6809
 * xmlXPathNextPrecedingSibling:
6810
 * @ctxt:  the XPath Parser context
6811
 * @cur:  the current node in the traversal
6812
 *
6813
 * Traversal function for the "preceding-sibling" direction
6814
 * The preceding-sibling axis contains the preceding siblings of the context
6815
 * node in reverse document order; the first preceding sibling is first on the
6816
 * axis; the sibling preceding that node is the second on the axis and so on.
6817
 *
6818
 * Returns the next element following that axis
6819
 */
6820
xmlNodePtr
6821
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6822
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6823
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6824
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6825
0
  return(NULL);
6826
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6827
0
        return(NULL);
6828
0
    if (cur == NULL)
6829
0
        return(ctxt->context->node->prev);
6830
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6831
0
  cur = cur->prev;
6832
0
  if (cur == NULL)
6833
0
      return(ctxt->context->node->prev);
6834
0
    }
6835
0
    return(cur->prev);
6836
0
}
6837
6838
/**
6839
 * xmlXPathNextFollowing:
6840
 * @ctxt:  the XPath Parser context
6841
 * @cur:  the current node in the traversal
6842
 *
6843
 * Traversal function for the "following" direction
6844
 * The following axis contains all nodes in the same document as the context
6845
 * node that are after the context node in document order, excluding any
6846
 * descendants and excluding attribute nodes and namespace nodes; the nodes
6847
 * are ordered in document order
6848
 *
6849
 * Returns the next element following that axis
6850
 */
6851
xmlNodePtr
6852
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6853
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6854
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6855
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6856
0
        return(cur->children);
6857
6858
0
    if (cur == NULL) {
6859
0
        cur = ctxt->context->node;
6860
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6861
0
            cur = cur->parent;
6862
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6863
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6864
6865
0
            if ((ns->next == NULL) ||
6866
0
                (ns->next->type == XML_NAMESPACE_DECL))
6867
0
                return (NULL);
6868
0
            cur = (xmlNodePtr) ns->next;
6869
0
        }
6870
0
    }
6871
0
    if (cur == NULL) return(NULL) ; /* ERROR */
6872
0
    if (cur->next != NULL) return(cur->next) ;
6873
0
    do {
6874
0
        cur = cur->parent;
6875
0
        if (cur == NULL) break;
6876
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6877
0
        if (cur->next != NULL) return(cur->next);
6878
0
    } while (cur != NULL);
6879
0
    return(cur);
6880
0
}
6881
6882
/*
6883
 * xmlXPathIsAncestor:
6884
 * @ancestor:  the ancestor node
6885
 * @node:  the current node
6886
 *
6887
 * Check that @ancestor is a @node's ancestor
6888
 *
6889
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
6890
 */
6891
static int
6892
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6893
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
6894
0
    if (node->type == XML_NAMESPACE_DECL)
6895
0
        return(0);
6896
0
    if (ancestor->type == XML_NAMESPACE_DECL)
6897
0
        return(0);
6898
    /* nodes need to be in the same document */
6899
0
    if (ancestor->doc != node->doc) return(0);
6900
    /* avoid searching if ancestor or node is the root node */
6901
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
6902
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
6903
0
    while (node->parent != NULL) {
6904
0
        if (node->parent == ancestor)
6905
0
            return(1);
6906
0
  node = node->parent;
6907
0
    }
6908
0
    return(0);
6909
0
}
6910
6911
/**
6912
 * xmlXPathNextPreceding:
6913
 * @ctxt:  the XPath Parser context
6914
 * @cur:  the current node in the traversal
6915
 *
6916
 * Traversal function for the "preceding" direction
6917
 * the preceding axis contains all nodes in the same document as the context
6918
 * node that are before the context node in document order, excluding any
6919
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6920
 * ordered in reverse document order
6921
 *
6922
 * Returns the next element following that axis
6923
 */
6924
xmlNodePtr
6925
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
6926
0
{
6927
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6928
0
    if (cur == NULL) {
6929
0
        cur = ctxt->context->node;
6930
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6931
0
            cur = cur->parent;
6932
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6933
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6934
6935
0
            if ((ns->next == NULL) ||
6936
0
                (ns->next->type == XML_NAMESPACE_DECL))
6937
0
                return (NULL);
6938
0
            cur = (xmlNodePtr) ns->next;
6939
0
        }
6940
0
    }
6941
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
6942
0
  return (NULL);
6943
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6944
0
  cur = cur->prev;
6945
0
    do {
6946
0
        if (cur->prev != NULL) {
6947
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6948
0
            return (cur);
6949
0
        }
6950
6951
0
        cur = cur->parent;
6952
0
        if (cur == NULL)
6953
0
            return (NULL);
6954
0
        if (cur == ctxt->context->doc->children)
6955
0
            return (NULL);
6956
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
6957
0
    return (cur);
6958
0
}
6959
6960
/**
6961
 * xmlXPathNextPrecedingInternal:
6962
 * @ctxt:  the XPath Parser context
6963
 * @cur:  the current node in the traversal
6964
 *
6965
 * Traversal function for the "preceding" direction
6966
 * the preceding axis contains all nodes in the same document as the context
6967
 * node that are before the context node in document order, excluding any
6968
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6969
 * ordered in reverse document order
6970
 * This is a faster implementation but internal only since it requires a
6971
 * state kept in the parser context: ctxt->ancestor.
6972
 *
6973
 * Returns the next element following that axis
6974
 */
6975
static xmlNodePtr
6976
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6977
                              xmlNodePtr cur)
6978
0
{
6979
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6980
0
    if (cur == NULL) {
6981
0
        cur = ctxt->context->node;
6982
0
        if (cur == NULL)
6983
0
            return (NULL);
6984
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6985
0
            cur = cur->parent;
6986
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6987
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6988
6989
0
            if ((ns->next == NULL) ||
6990
0
                (ns->next->type == XML_NAMESPACE_DECL))
6991
0
                return (NULL);
6992
0
            cur = (xmlNodePtr) ns->next;
6993
0
        }
6994
0
        ctxt->ancestor = cur->parent;
6995
0
    }
6996
0
    if (cur->type == XML_NAMESPACE_DECL)
6997
0
        return(NULL);
6998
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6999
0
  cur = cur->prev;
7000
0
    while (cur->prev == NULL) {
7001
0
        cur = cur->parent;
7002
0
        if (cur == NULL)
7003
0
            return (NULL);
7004
0
        if (cur == ctxt->context->doc->children)
7005
0
            return (NULL);
7006
0
        if (cur != ctxt->ancestor)
7007
0
            return (cur);
7008
0
        ctxt->ancestor = cur->parent;
7009
0
    }
7010
0
    cur = cur->prev;
7011
0
    while (cur->last != NULL)
7012
0
        cur = cur->last;
7013
0
    return (cur);
7014
0
}
7015
7016
/**
7017
 * xmlXPathNextNamespace:
7018
 * @ctxt:  the XPath Parser context
7019
 * @cur:  the current attribute in the traversal
7020
 *
7021
 * Traversal function for the "namespace" direction
7022
 * the namespace axis contains the namespace nodes of the context node;
7023
 * the order of nodes on this axis is implementation-defined; the axis will
7024
 * be empty unless the context node is an element
7025
 *
7026
 * We keep the XML namespace node at the end of the list.
7027
 *
7028
 * Returns the next element following that axis
7029
 */
7030
xmlNodePtr
7031
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7032
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7033
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7034
0
    if (cur == NULL) {
7035
0
        if (ctxt->context->tmpNsList != NULL)
7036
0
      xmlFree(ctxt->context->tmpNsList);
7037
0
  ctxt->context->tmpNsNr = 0;
7038
0
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
7039
0
                             &ctxt->context->tmpNsList) < 0) {
7040
0
            xmlXPathPErrMemory(ctxt);
7041
0
            return(NULL);
7042
0
        }
7043
0
        if (ctxt->context->tmpNsList != NULL) {
7044
0
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7045
0
                ctxt->context->tmpNsNr++;
7046
0
            }
7047
0
        }
7048
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
7049
0
    }
7050
0
    if (ctxt->context->tmpNsNr > 0) {
7051
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7052
0
    } else {
7053
0
  if (ctxt->context->tmpNsList != NULL)
7054
0
      xmlFree(ctxt->context->tmpNsList);
7055
0
  ctxt->context->tmpNsList = NULL;
7056
0
  return(NULL);
7057
0
    }
7058
0
}
7059
7060
/**
7061
 * xmlXPathNextAttribute:
7062
 * @ctxt:  the XPath Parser context
7063
 * @cur:  the current attribute in the traversal
7064
 *
7065
 * Traversal function for the "attribute" direction
7066
 * TODO: support DTD inherited default attributes
7067
 *
7068
 * Returns the next element following that axis
7069
 */
7070
xmlNodePtr
7071
0
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7072
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7073
0
    if (ctxt->context->node == NULL)
7074
0
  return(NULL);
7075
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
7076
0
  return(NULL);
7077
0
    if (cur == NULL) {
7078
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7079
0
      return(NULL);
7080
0
        return((xmlNodePtr)ctxt->context->node->properties);
7081
0
    }
7082
0
    return((xmlNodePtr)cur->next);
7083
0
}
7084
7085
/************************************************************************
7086
 *                  *
7087
 *    NodeTest Functions          *
7088
 *                  *
7089
 ************************************************************************/
7090
7091
#define IS_FUNCTION     200
7092
7093
7094
/************************************************************************
7095
 *                  *
7096
 *    Implicit tree core function library     *
7097
 *                  *
7098
 ************************************************************************/
7099
7100
/**
7101
 * xmlXPathRoot:
7102
 * @ctxt:  the XPath Parser context
7103
 *
7104
 * Initialize the context to the root of the document
7105
 */
7106
void
7107
0
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7108
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
7109
0
  return;
7110
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7111
0
                                            (xmlNodePtr) ctxt->context->doc));
7112
0
}
7113
7114
/************************************************************************
7115
 *                  *
7116
 *    The explicit core function library      *
7117
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7118
 *                  *
7119
 ************************************************************************/
7120
7121
7122
/**
7123
 * xmlXPathLastFunction:
7124
 * @ctxt:  the XPath Parser context
7125
 * @nargs:  the number of arguments
7126
 *
7127
 * Implement the last() XPath function
7128
 *    number last()
7129
 * The last function returns the number of nodes in the context node list.
7130
 */
7131
void
7132
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7133
0
    CHECK_ARITY(0);
7134
0
    if (ctxt->context->contextSize >= 0) {
7135
0
  valuePush(ctxt,
7136
0
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
7137
0
    } else {
7138
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7139
0
    }
7140
0
}
7141
7142
/**
7143
 * xmlXPathPositionFunction:
7144
 * @ctxt:  the XPath Parser context
7145
 * @nargs:  the number of arguments
7146
 *
7147
 * Implement the position() XPath function
7148
 *    number position()
7149
 * The position function returns the position of the context node in the
7150
 * context node list. The first position is 1, and so the last position
7151
 * will be equal to last().
7152
 */
7153
void
7154
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7155
0
    CHECK_ARITY(0);
7156
0
    if (ctxt->context->proximityPosition >= 0) {
7157
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7158
0
            (double) ctxt->context->proximityPosition));
7159
0
    } else {
7160
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7161
0
    }
7162
0
}
7163
7164
/**
7165
 * xmlXPathCountFunction:
7166
 * @ctxt:  the XPath Parser context
7167
 * @nargs:  the number of arguments
7168
 *
7169
 * Implement the count() XPath function
7170
 *    number count(node-set)
7171
 */
7172
void
7173
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7174
0
    xmlXPathObjectPtr cur;
7175
7176
0
    CHECK_ARITY(1);
7177
0
    if ((ctxt->value == NULL) ||
7178
0
  ((ctxt->value->type != XPATH_NODESET) &&
7179
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7180
0
  XP_ERROR(XPATH_INVALID_TYPE);
7181
0
    cur = valuePop(ctxt);
7182
7183
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
7184
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7185
0
    else
7186
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7187
0
      (double) cur->nodesetval->nodeNr));
7188
0
    xmlXPathReleaseObject(ctxt->context, cur);
7189
0
}
7190
7191
/**
7192
 * xmlXPathGetElementsByIds:
7193
 * @doc:  the document
7194
 * @ids:  a whitespace separated list of IDs
7195
 *
7196
 * Selects elements by their unique ID.
7197
 *
7198
 * Returns a node-set of selected elements.
7199
 */
7200
static xmlNodeSetPtr
7201
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7202
0
    xmlNodeSetPtr ret;
7203
0
    const xmlChar *cur = ids;
7204
0
    xmlChar *ID;
7205
0
    xmlAttrPtr attr;
7206
0
    xmlNodePtr elem = NULL;
7207
7208
0
    if (ids == NULL) return(NULL);
7209
7210
0
    ret = xmlXPathNodeSetCreate(NULL);
7211
0
    if (ret == NULL)
7212
0
        return(ret);
7213
7214
0
    while (IS_BLANK_CH(*cur)) cur++;
7215
0
    while (*cur != 0) {
7216
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7217
0
      cur++;
7218
7219
0
        ID = xmlStrndup(ids, cur - ids);
7220
0
  if (ID == NULL) {
7221
0
            xmlXPathFreeNodeSet(ret);
7222
0
            return(NULL);
7223
0
        }
7224
        /*
7225
         * We used to check the fact that the value passed
7226
         * was an NCName, but this generated much troubles for
7227
         * me and Aleksey Sanin, people blatantly violated that
7228
         * constraint, like Visa3D spec.
7229
         * if (xmlValidateNCName(ID, 1) == 0)
7230
         */
7231
0
        attr = xmlGetID(doc, ID);
7232
0
        xmlFree(ID);
7233
0
        if (attr != NULL) {
7234
0
            if (attr->type == XML_ATTRIBUTE_NODE)
7235
0
                elem = attr->parent;
7236
0
            else if (attr->type == XML_ELEMENT_NODE)
7237
0
                elem = (xmlNodePtr) attr;
7238
0
            else
7239
0
                elem = NULL;
7240
0
            if (elem != NULL) {
7241
0
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
7242
0
                    xmlXPathFreeNodeSet(ret);
7243
0
                    return(NULL);
7244
0
                }
7245
0
            }
7246
0
        }
7247
7248
0
  while (IS_BLANK_CH(*cur)) cur++;
7249
0
  ids = cur;
7250
0
    }
7251
0
    return(ret);
7252
0
}
7253
7254
/**
7255
 * xmlXPathIdFunction:
7256
 * @ctxt:  the XPath Parser context
7257
 * @nargs:  the number of arguments
7258
 *
7259
 * Implement the id() XPath function
7260
 *    node-set id(object)
7261
 * The id function selects elements by their unique ID
7262
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7263
 * then the result is the union of the result of applying id to the
7264
 * string value of each of the nodes in the argument node-set. When the
7265
 * argument to id is of any other type, the argument is converted to a
7266
 * string as if by a call to the string function; the string is split
7267
 * into a whitespace-separated list of tokens (whitespace is any sequence
7268
 * of characters matching the production S); the result is a node-set
7269
 * containing the elements in the same document as the context node that
7270
 * have a unique ID equal to any of the tokens in the list.
7271
 */
7272
void
7273
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7274
0
    xmlChar *tokens;
7275
0
    xmlNodeSetPtr ret;
7276
0
    xmlXPathObjectPtr obj;
7277
7278
0
    CHECK_ARITY(1);
7279
0
    obj = valuePop(ctxt);
7280
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7281
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7282
0
  xmlNodeSetPtr ns;
7283
0
  int i;
7284
7285
0
  ret = xmlXPathNodeSetCreate(NULL);
7286
0
        if (ret == NULL)
7287
0
            xmlXPathPErrMemory(ctxt);
7288
7289
0
  if (obj->nodesetval != NULL) {
7290
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7291
0
    tokens =
7292
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7293
0
                if (tokens == NULL)
7294
0
                    xmlXPathPErrMemory(ctxt);
7295
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7296
0
                if (ns == NULL)
7297
0
                    xmlXPathPErrMemory(ctxt);
7298
0
    ret = xmlXPathNodeSetMerge(ret, ns);
7299
0
                if (ret == NULL)
7300
0
                    xmlXPathPErrMemory(ctxt);
7301
0
    xmlXPathFreeNodeSet(ns);
7302
0
    if (tokens != NULL)
7303
0
        xmlFree(tokens);
7304
0
      }
7305
0
  }
7306
0
  xmlXPathReleaseObject(ctxt->context, obj);
7307
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7308
0
  return;
7309
0
    }
7310
0
    tokens = xmlXPathCastToString(obj);
7311
0
    if (tokens == NULL)
7312
0
        xmlXPathPErrMemory(ctxt);
7313
0
    xmlXPathReleaseObject(ctxt->context, obj);
7314
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7315
0
    if (ret == NULL)
7316
0
        xmlXPathPErrMemory(ctxt);
7317
0
    xmlFree(tokens);
7318
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7319
0
}
7320
7321
/**
7322
 * xmlXPathLocalNameFunction:
7323
 * @ctxt:  the XPath Parser context
7324
 * @nargs:  the number of arguments
7325
 *
7326
 * Implement the local-name() XPath function
7327
 *    string local-name(node-set?)
7328
 * The local-name function returns a string containing the local part
7329
 * of the name of the node in the argument node-set that is first in
7330
 * document order. If the node-set is empty or the first node has no
7331
 * name, an empty string is returned. If the argument is omitted it
7332
 * defaults to the context node.
7333
 */
7334
void
7335
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7336
0
    xmlXPathObjectPtr cur;
7337
7338
0
    if (ctxt == NULL) return;
7339
7340
0
    if (nargs == 0) {
7341
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7342
0
  nargs = 1;
7343
0
    }
7344
7345
0
    CHECK_ARITY(1);
7346
0
    if ((ctxt->value == NULL) ||
7347
0
  ((ctxt->value->type != XPATH_NODESET) &&
7348
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7349
0
  XP_ERROR(XPATH_INVALID_TYPE);
7350
0
    cur = valuePop(ctxt);
7351
7352
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7353
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7354
0
    } else {
7355
0
  int i = 0; /* Should be first in document order !!!!! */
7356
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7357
0
  case XML_ELEMENT_NODE:
7358
0
  case XML_ATTRIBUTE_NODE:
7359
0
  case XML_PI_NODE:
7360
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7361
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7362
0
      else
7363
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7364
0
      cur->nodesetval->nodeTab[i]->name));
7365
0
      break;
7366
0
  case XML_NAMESPACE_DECL:
7367
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7368
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7369
0
      break;
7370
0
  default:
7371
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7372
0
  }
7373
0
    }
7374
0
    xmlXPathReleaseObject(ctxt->context, cur);
7375
0
}
7376
7377
/**
7378
 * xmlXPathNamespaceURIFunction:
7379
 * @ctxt:  the XPath Parser context
7380
 * @nargs:  the number of arguments
7381
 *
7382
 * Implement the namespace-uri() XPath function
7383
 *    string namespace-uri(node-set?)
7384
 * The namespace-uri function returns a string containing the
7385
 * namespace URI of the expanded name of the node in the argument
7386
 * node-set that is first in document order. If the node-set is empty,
7387
 * the first node has no name, or the expanded name has no namespace
7388
 * URI, an empty string is returned. If the argument is omitted it
7389
 * defaults to the context node.
7390
 */
7391
void
7392
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7393
0
    xmlXPathObjectPtr cur;
7394
7395
0
    if (ctxt == NULL) return;
7396
7397
0
    if (nargs == 0) {
7398
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7399
0
  nargs = 1;
7400
0
    }
7401
0
    CHECK_ARITY(1);
7402
0
    if ((ctxt->value == NULL) ||
7403
0
  ((ctxt->value->type != XPATH_NODESET) &&
7404
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7405
0
  XP_ERROR(XPATH_INVALID_TYPE);
7406
0
    cur = valuePop(ctxt);
7407
7408
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7409
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7410
0
    } else {
7411
0
  int i = 0; /* Should be first in document order !!!!! */
7412
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7413
0
  case XML_ELEMENT_NODE:
7414
0
  case XML_ATTRIBUTE_NODE:
7415
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7416
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7417
0
      else
7418
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7419
0
        cur->nodesetval->nodeTab[i]->ns->href));
7420
0
      break;
7421
0
  default:
7422
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7423
0
  }
7424
0
    }
7425
0
    xmlXPathReleaseObject(ctxt->context, cur);
7426
0
}
7427
7428
/**
7429
 * xmlXPathNameFunction:
7430
 * @ctxt:  the XPath Parser context
7431
 * @nargs:  the number of arguments
7432
 *
7433
 * Implement the name() XPath function
7434
 *    string name(node-set?)
7435
 * The name function returns a string containing a QName representing
7436
 * the name of the node in the argument node-set that is first in document
7437
 * order. The QName must represent the name with respect to the namespace
7438
 * declarations in effect on the node whose name is being represented.
7439
 * Typically, this will be the form in which the name occurred in the XML
7440
 * source. This need not be the case if there are namespace declarations
7441
 * in effect on the node that associate multiple prefixes with the same
7442
 * namespace. However, an implementation may include information about
7443
 * the original prefix in its representation of nodes; in this case, an
7444
 * implementation can ensure that the returned string is always the same
7445
 * as the QName used in the XML source. If the argument it omitted it
7446
 * defaults to the context node.
7447
 * Libxml keep the original prefix so the "real qualified name" used is
7448
 * returned.
7449
 */
7450
static void
7451
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7452
0
{
7453
0
    xmlXPathObjectPtr cur;
7454
7455
0
    if (nargs == 0) {
7456
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7457
0
        nargs = 1;
7458
0
    }
7459
7460
0
    CHECK_ARITY(1);
7461
0
    if ((ctxt->value == NULL) ||
7462
0
        ((ctxt->value->type != XPATH_NODESET) &&
7463
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
7464
0
        XP_ERROR(XPATH_INVALID_TYPE);
7465
0
    cur = valuePop(ctxt);
7466
7467
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7468
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7469
0
    } else {
7470
0
        int i = 0;              /* Should be first in document order !!!!! */
7471
7472
0
        switch (cur->nodesetval->nodeTab[i]->type) {
7473
0
            case XML_ELEMENT_NODE:
7474
0
            case XML_ATTRIBUTE_NODE:
7475
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7476
0
        valuePush(ctxt,
7477
0
      xmlXPathCacheNewCString(ctxt, ""));
7478
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7479
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7480
0
        valuePush(ctxt, xmlXPathCacheNewString(ctxt,
7481
0
          cur->nodesetval->nodeTab[i]->name));
7482
0
    } else {
7483
0
        xmlChar *fullname;
7484
7485
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7486
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
7487
0
             NULL, 0);
7488
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7489
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7490
0
        if (fullname == NULL)
7491
0
                        xmlXPathPErrMemory(ctxt);
7492
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7493
0
                }
7494
0
                break;
7495
0
            default:
7496
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7497
0
        cur->nodesetval->nodeTab[i]));
7498
0
                xmlXPathLocalNameFunction(ctxt, 1);
7499
0
        }
7500
0
    }
7501
0
    xmlXPathReleaseObject(ctxt->context, cur);
7502
0
}
7503
7504
7505
/**
7506
 * xmlXPathStringFunction:
7507
 * @ctxt:  the XPath Parser context
7508
 * @nargs:  the number of arguments
7509
 *
7510
 * Implement the string() XPath function
7511
 *    string string(object?)
7512
 * The string function converts an object to a string as follows:
7513
 *    - A node-set is converted to a string by returning the value of
7514
 *      the node in the node-set that is first in document order.
7515
 *      If the node-set is empty, an empty string is returned.
7516
 *    - A number is converted to a string as follows
7517
 *      + NaN is converted to the string NaN
7518
 *      + positive zero is converted to the string 0
7519
 *      + negative zero is converted to the string 0
7520
 *      + positive infinity is converted to the string Infinity
7521
 *      + negative infinity is converted to the string -Infinity
7522
 *      + if the number is an integer, the number is represented in
7523
 *        decimal form as a Number with no decimal point and no leading
7524
 *        zeros, preceded by a minus sign (-) if the number is negative
7525
 *      + otherwise, the number is represented in decimal form as a
7526
 *        Number including a decimal point with at least one digit
7527
 *        before the decimal point and at least one digit after the
7528
 *        decimal point, preceded by a minus sign (-) if the number
7529
 *        is negative; there must be no leading zeros before the decimal
7530
 *        point apart possibly from the one required digit immediately
7531
 *        before the decimal point; beyond the one required digit
7532
 *        after the decimal point there must be as many, but only as
7533
 *        many, more digits as are needed to uniquely distinguish the
7534
 *        number from all other IEEE 754 numeric values.
7535
 *    - The boolean false value is converted to the string false.
7536
 *      The boolean true value is converted to the string true.
7537
 *
7538
 * If the argument is omitted, it defaults to a node-set with the
7539
 * context node as its only member.
7540
 */
7541
void
7542
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7543
0
    xmlXPathObjectPtr cur;
7544
0
    xmlChar *stringval;
7545
7546
0
    if (ctxt == NULL) return;
7547
0
    if (nargs == 0) {
7548
0
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7549
0
        if (stringval == NULL)
7550
0
            xmlXPathPErrMemory(ctxt);
7551
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7552
0
  return;
7553
0
    }
7554
7555
0
    CHECK_ARITY(1);
7556
0
    cur = valuePop(ctxt);
7557
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7558
0
    if (cur->type != XPATH_STRING) {
7559
0
        stringval = xmlXPathCastToString(cur);
7560
0
        if (stringval == NULL)
7561
0
            xmlXPathPErrMemory(ctxt);
7562
0
        xmlXPathReleaseObject(ctxt->context, cur);
7563
0
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7564
0
    }
7565
0
    valuePush(ctxt, cur);
7566
0
}
7567
7568
/**
7569
 * xmlXPathStringLengthFunction:
7570
 * @ctxt:  the XPath Parser context
7571
 * @nargs:  the number of arguments
7572
 *
7573
 * Implement the string-length() XPath function
7574
 *    number string-length(string?)
7575
 * The string-length returns the number of characters in the string
7576
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7577
 * the context node converted to a string, in other words the value
7578
 * of the context node.
7579
 */
7580
void
7581
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7582
0
    xmlXPathObjectPtr cur;
7583
7584
0
    if (nargs == 0) {
7585
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
7586
0
      return;
7587
0
  if (ctxt->context->node == NULL) {
7588
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7589
0
  } else {
7590
0
      xmlChar *content;
7591
7592
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
7593
0
            if (content == NULL)
7594
0
                xmlXPathPErrMemory(ctxt);
7595
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7596
0
    xmlUTF8Strlen(content)));
7597
0
      xmlFree(content);
7598
0
  }
7599
0
  return;
7600
0
    }
7601
0
    CHECK_ARITY(1);
7602
0
    CAST_TO_STRING;
7603
0
    CHECK_TYPE(XPATH_STRING);
7604
0
    cur = valuePop(ctxt);
7605
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7606
0
  xmlUTF8Strlen(cur->stringval)));
7607
0
    xmlXPathReleaseObject(ctxt->context, cur);
7608
0
}
7609
7610
/**
7611
 * xmlXPathConcatFunction:
7612
 * @ctxt:  the XPath Parser context
7613
 * @nargs:  the number of arguments
7614
 *
7615
 * Implement the concat() XPath function
7616
 *    string concat(string, string, string*)
7617
 * The concat function returns the concatenation of its arguments.
7618
 */
7619
void
7620
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7621
0
    xmlXPathObjectPtr cur, newobj;
7622
0
    xmlChar *tmp;
7623
7624
0
    if (ctxt == NULL) return;
7625
0
    if (nargs < 2) {
7626
0
  CHECK_ARITY(2);
7627
0
    }
7628
7629
0
    CAST_TO_STRING;
7630
0
    cur = valuePop(ctxt);
7631
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7632
0
  xmlXPathReleaseObject(ctxt->context, cur);
7633
0
  return;
7634
0
    }
7635
0
    nargs--;
7636
7637
0
    while (nargs > 0) {
7638
0
  CAST_TO_STRING;
7639
0
  newobj = valuePop(ctxt);
7640
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7641
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7642
0
      xmlXPathReleaseObject(ctxt->context, cur);
7643
0
      XP_ERROR(XPATH_INVALID_TYPE);
7644
0
  }
7645
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7646
0
        if (tmp == NULL)
7647
0
            xmlXPathPErrMemory(ctxt);
7648
0
  newobj->stringval = cur->stringval;
7649
0
  cur->stringval = tmp;
7650
0
  xmlXPathReleaseObject(ctxt->context, newobj);
7651
0
  nargs--;
7652
0
    }
7653
0
    valuePush(ctxt, cur);
7654
0
}
7655
7656
/**
7657
 * xmlXPathContainsFunction:
7658
 * @ctxt:  the XPath Parser context
7659
 * @nargs:  the number of arguments
7660
 *
7661
 * Implement the contains() XPath function
7662
 *    boolean contains(string, string)
7663
 * The contains function returns true if the first argument string
7664
 * contains the second argument string, and otherwise returns false.
7665
 */
7666
void
7667
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7668
0
    xmlXPathObjectPtr hay, needle;
7669
7670
0
    CHECK_ARITY(2);
7671
0
    CAST_TO_STRING;
7672
0
    CHECK_TYPE(XPATH_STRING);
7673
0
    needle = valuePop(ctxt);
7674
0
    CAST_TO_STRING;
7675
0
    hay = valuePop(ctxt);
7676
7677
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7678
0
  xmlXPathReleaseObject(ctxt->context, hay);
7679
0
  xmlXPathReleaseObject(ctxt->context, needle);
7680
0
  XP_ERROR(XPATH_INVALID_TYPE);
7681
0
    }
7682
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7683
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7684
0
    else
7685
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7686
0
    xmlXPathReleaseObject(ctxt->context, hay);
7687
0
    xmlXPathReleaseObject(ctxt->context, needle);
7688
0
}
7689
7690
/**
7691
 * xmlXPathStartsWithFunction:
7692
 * @ctxt:  the XPath Parser context
7693
 * @nargs:  the number of arguments
7694
 *
7695
 * Implement the starts-with() XPath function
7696
 *    boolean starts-with(string, string)
7697
 * The starts-with function returns true if the first argument string
7698
 * starts with the second argument string, and otherwise returns false.
7699
 */
7700
void
7701
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7702
0
    xmlXPathObjectPtr hay, needle;
7703
0
    int n;
7704
7705
0
    CHECK_ARITY(2);
7706
0
    CAST_TO_STRING;
7707
0
    CHECK_TYPE(XPATH_STRING);
7708
0
    needle = valuePop(ctxt);
7709
0
    CAST_TO_STRING;
7710
0
    hay = valuePop(ctxt);
7711
7712
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7713
0
  xmlXPathReleaseObject(ctxt->context, hay);
7714
0
  xmlXPathReleaseObject(ctxt->context, needle);
7715
0
  XP_ERROR(XPATH_INVALID_TYPE);
7716
0
    }
7717
0
    n = xmlStrlen(needle->stringval);
7718
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7719
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7720
0
    else
7721
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7722
0
    xmlXPathReleaseObject(ctxt->context, hay);
7723
0
    xmlXPathReleaseObject(ctxt->context, needle);
7724
0
}
7725
7726
/**
7727
 * xmlXPathSubstringFunction:
7728
 * @ctxt:  the XPath Parser context
7729
 * @nargs:  the number of arguments
7730
 *
7731
 * Implement the substring() XPath function
7732
 *    string substring(string, number, number?)
7733
 * The substring function returns the substring of the first argument
7734
 * starting at the position specified in the second argument with
7735
 * length specified in the third argument. For example,
7736
 * substring("12345",2,3) returns "234". If the third argument is not
7737
 * specified, it returns the substring starting at the position specified
7738
 * in the second argument and continuing to the end of the string. For
7739
 * example, substring("12345",2) returns "2345".  More precisely, each
7740
 * character in the string (see [3.6 Strings]) is considered to have a
7741
 * numeric position: the position of the first character is 1, the position
7742
 * of the second character is 2 and so on. The returned substring contains
7743
 * those characters for which the position of the character is greater than
7744
 * or equal to the second argument and, if the third argument is specified,
7745
 * less than the sum of the second and third arguments; the comparisons
7746
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7747
 *  - substring("12345", 1.5, 2.6) returns "234"
7748
 *  - substring("12345", 0, 3) returns "12"
7749
 *  - substring("12345", 0 div 0, 3) returns ""
7750
 *  - substring("12345", 1, 0 div 0) returns ""
7751
 *  - substring("12345", -42, 1 div 0) returns "12345"
7752
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
7753
 */
7754
void
7755
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7756
0
    xmlXPathObjectPtr str, start, len;
7757
0
    double le=0, in;
7758
0
    int i = 1, j = INT_MAX;
7759
7760
0
    if (nargs < 2) {
7761
0
  CHECK_ARITY(2);
7762
0
    }
7763
0
    if (nargs > 3) {
7764
0
  CHECK_ARITY(3);
7765
0
    }
7766
    /*
7767
     * take care of possible last (position) argument
7768
    */
7769
0
    if (nargs == 3) {
7770
0
  CAST_TO_NUMBER;
7771
0
  CHECK_TYPE(XPATH_NUMBER);
7772
0
  len = valuePop(ctxt);
7773
0
  le = len->floatval;
7774
0
  xmlXPathReleaseObject(ctxt->context, len);
7775
0
    }
7776
7777
0
    CAST_TO_NUMBER;
7778
0
    CHECK_TYPE(XPATH_NUMBER);
7779
0
    start = valuePop(ctxt);
7780
0
    in = start->floatval;
7781
0
    xmlXPathReleaseObject(ctxt->context, start);
7782
0
    CAST_TO_STRING;
7783
0
    CHECK_TYPE(XPATH_STRING);
7784
0
    str = valuePop(ctxt);
7785
7786
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7787
0
        i = INT_MAX;
7788
0
    } else if (in >= 1.0) {
7789
0
        i = (int)in;
7790
0
        if (in - floor(in) >= 0.5)
7791
0
            i += 1;
7792
0
    }
7793
7794
0
    if (nargs == 3) {
7795
0
        double rin, rle, end;
7796
7797
0
        rin = floor(in);
7798
0
        if (in - rin >= 0.5)
7799
0
            rin += 1.0;
7800
7801
0
        rle = floor(le);
7802
0
        if (le - rle >= 0.5)
7803
0
            rle += 1.0;
7804
7805
0
        end = rin + rle;
7806
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7807
0
            j = 1;
7808
0
        } else if (end < INT_MAX) {
7809
0
            j = (int)end;
7810
0
        }
7811
0
    }
7812
7813
0
    i -= 1;
7814
0
    j -= 1;
7815
7816
0
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7817
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7818
0
        if (ret == NULL)
7819
0
            xmlXPathPErrMemory(ctxt);
7820
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7821
0
  xmlFree(ret);
7822
0
    } else {
7823
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7824
0
    }
7825
7826
0
    xmlXPathReleaseObject(ctxt->context, str);
7827
0
}
7828
7829
/**
7830
 * xmlXPathSubstringBeforeFunction:
7831
 * @ctxt:  the XPath Parser context
7832
 * @nargs:  the number of arguments
7833
 *
7834
 * Implement the substring-before() XPath function
7835
 *    string substring-before(string, string)
7836
 * The substring-before function returns the substring of the first
7837
 * argument string that precedes the first occurrence of the second
7838
 * argument string in the first argument string, or the empty string
7839
 * if the first argument string does not contain the second argument
7840
 * string. For example, substring-before("1999/04/01","/") returns 1999.
7841
 */
7842
void
7843
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7844
0
    xmlXPathObjectPtr str = NULL;
7845
0
    xmlXPathObjectPtr find = NULL;
7846
0
    const xmlChar *point;
7847
0
    xmlChar *result;
7848
7849
0
    CHECK_ARITY(2);
7850
0
    CAST_TO_STRING;
7851
0
    find = valuePop(ctxt);
7852
0
    CAST_TO_STRING;
7853
0
    str = valuePop(ctxt);
7854
0
    if (ctxt->error != 0)
7855
0
        goto error;
7856
7857
0
    point = xmlStrstr(str->stringval, find->stringval);
7858
0
    if (point == NULL) {
7859
0
        result = xmlStrdup(BAD_CAST "");
7860
0
    } else {
7861
0
        result = xmlStrndup(str->stringval, point - str->stringval);
7862
0
    }
7863
0
    if (result == NULL) {
7864
0
        xmlXPathPErrMemory(ctxt);
7865
0
        goto error;
7866
0
    }
7867
0
    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7868
7869
0
error:
7870
0
    xmlXPathReleaseObject(ctxt->context, str);
7871
0
    xmlXPathReleaseObject(ctxt->context, find);
7872
0
}
7873
7874
/**
7875
 * xmlXPathSubstringAfterFunction:
7876
 * @ctxt:  the XPath Parser context
7877
 * @nargs:  the number of arguments
7878
 *
7879
 * Implement the substring-after() XPath function
7880
 *    string substring-after(string, string)
7881
 * The substring-after function returns the substring of the first
7882
 * argument string that follows the first occurrence of the second
7883
 * argument string in the first argument string, or the empty string
7884
 * if the first argument string does not contain the second argument
7885
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7886
 * and substring-after("1999/04/01","19") returns 99/04/01.
7887
 */
7888
void
7889
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7890
0
    xmlXPathObjectPtr str = NULL;
7891
0
    xmlXPathObjectPtr find = NULL;
7892
0
    const xmlChar *point;
7893
0
    xmlChar *result;
7894
7895
0
    CHECK_ARITY(2);
7896
0
    CAST_TO_STRING;
7897
0
    find = valuePop(ctxt);
7898
0
    CAST_TO_STRING;
7899
0
    str = valuePop(ctxt);
7900
0
    if (ctxt->error != 0)
7901
0
        goto error;
7902
7903
0
    point = xmlStrstr(str->stringval, find->stringval);
7904
0
    if (point == NULL) {
7905
0
        result = xmlStrdup(BAD_CAST "");
7906
0
    } else {
7907
0
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7908
0
    }
7909
0
    if (result == NULL) {
7910
0
        xmlXPathPErrMemory(ctxt);
7911
0
        goto error;
7912
0
    }
7913
0
    valuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7914
7915
0
error:
7916
0
    xmlXPathReleaseObject(ctxt->context, str);
7917
0
    xmlXPathReleaseObject(ctxt->context, find);
7918
0
}
7919
7920
/**
7921
 * xmlXPathNormalizeFunction:
7922
 * @ctxt:  the XPath Parser context
7923
 * @nargs:  the number of arguments
7924
 *
7925
 * Implement the normalize-space() XPath function
7926
 *    string normalize-space(string?)
7927
 * The normalize-space function returns the argument string with white
7928
 * space normalized by stripping leading and trailing whitespace
7929
 * and replacing sequences of whitespace characters by a single
7930
 * space. Whitespace characters are the same allowed by the S production
7931
 * in XML. If the argument is omitted, it defaults to the context
7932
 * node converted to a string, in other words the value of the context node.
7933
 */
7934
void
7935
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7936
0
    xmlChar *source, *target;
7937
0
    int blank;
7938
7939
0
    if (ctxt == NULL) return;
7940
0
    if (nargs == 0) {
7941
        /* Use current context node */
7942
0
        source = xmlXPathCastNodeToString(ctxt->context->node);
7943
0
        if (source == NULL)
7944
0
            xmlXPathPErrMemory(ctxt);
7945
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7946
0
        nargs = 1;
7947
0
    }
7948
7949
0
    CHECK_ARITY(1);
7950
0
    CAST_TO_STRING;
7951
0
    CHECK_TYPE(XPATH_STRING);
7952
0
    source = ctxt->value->stringval;
7953
0
    if (source == NULL)
7954
0
        return;
7955
0
    target = source;
7956
7957
    /* Skip leading whitespaces */
7958
0
    while (IS_BLANK_CH(*source))
7959
0
        source++;
7960
7961
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7962
0
    blank = 0;
7963
0
    while (*source) {
7964
0
        if (IS_BLANK_CH(*source)) {
7965
0
      blank = 1;
7966
0
        } else {
7967
0
            if (blank) {
7968
0
                *target++ = 0x20;
7969
0
                blank = 0;
7970
0
            }
7971
0
            *target++ = *source;
7972
0
        }
7973
0
        source++;
7974
0
    }
7975
0
    *target = 0;
7976
0
}
7977
7978
/**
7979
 * xmlXPathTranslateFunction:
7980
 * @ctxt:  the XPath Parser context
7981
 * @nargs:  the number of arguments
7982
 *
7983
 * Implement the translate() XPath function
7984
 *    string translate(string, string, string)
7985
 * The translate function returns the first argument string with
7986
 * occurrences of characters in the second argument string replaced
7987
 * by the character at the corresponding position in the third argument
7988
 * string. For example, translate("bar","abc","ABC") returns the string
7989
 * BAr. If there is a character in the second argument string with no
7990
 * character at a corresponding position in the third argument string
7991
 * (because the second argument string is longer than the third argument
7992
 * string), then occurrences of that character in the first argument
7993
 * string are removed. For example, translate("--aaa--","abc-","ABC")
7994
 * returns "AAA". If a character occurs more than once in second
7995
 * argument string, then the first occurrence determines the replacement
7996
 * character. If the third argument string is longer than the second
7997
 * argument string, then excess characters are ignored.
7998
 */
7999
void
8000
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8001
0
    xmlXPathObjectPtr str = NULL;
8002
0
    xmlXPathObjectPtr from = NULL;
8003
0
    xmlXPathObjectPtr to = NULL;
8004
0
    xmlBufPtr target;
8005
0
    int offset, max;
8006
0
    int ch;
8007
0
    const xmlChar *point;
8008
0
    xmlChar *cptr, *content;
8009
8010
0
    CHECK_ARITY(3);
8011
8012
0
    CAST_TO_STRING;
8013
0
    to = valuePop(ctxt);
8014
0
    CAST_TO_STRING;
8015
0
    from = valuePop(ctxt);
8016
0
    CAST_TO_STRING;
8017
0
    str = valuePop(ctxt);
8018
0
    if (ctxt->error != 0)
8019
0
        goto error;
8020
8021
    /*
8022
     * Account for quadratic runtime
8023
     */
8024
0
    if (ctxt->context->opLimit != 0) {
8025
0
        unsigned long f1 = xmlStrlen(from->stringval);
8026
0
        unsigned long f2 = xmlStrlen(str->stringval);
8027
8028
0
        if ((f1 > 0) && (f2 > 0)) {
8029
0
            unsigned long p;
8030
8031
0
            f1 = f1 / 10 + 1;
8032
0
            f2 = f2 / 10 + 1;
8033
0
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
8034
0
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
8035
0
                goto error;
8036
0
        }
8037
0
    }
8038
8039
0
    target = xmlBufCreate(50);
8040
0
    if (target == NULL) {
8041
0
        xmlXPathPErrMemory(ctxt);
8042
0
        goto error;
8043
0
    }
8044
8045
0
    max = xmlUTF8Strlen(to->stringval);
8046
0
    for (cptr = str->stringval; (ch=*cptr); ) {
8047
0
        offset = xmlUTF8Strloc(from->stringval, cptr);
8048
0
        if (offset >= 0) {
8049
0
            if (offset < max) {
8050
0
                point = xmlUTF8Strpos(to->stringval, offset);
8051
0
                if (point)
8052
0
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8053
0
            }
8054
0
        } else
8055
0
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8056
8057
        /* Step to next character in input */
8058
0
        cptr++;
8059
0
        if ( ch & 0x80 ) {
8060
            /* if not simple ascii, verify proper format */
8061
0
            if ( (ch & 0xc0) != 0xc0 ) {
8062
0
                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8063
0
                break;
8064
0
            }
8065
            /* then skip over remaining bytes for this char */
8066
0
            while ( (ch <<= 1) & 0x80 )
8067
0
                if ( (*cptr++ & 0xc0) != 0x80 ) {
8068
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
8069
0
                    break;
8070
0
                }
8071
0
            if (ch & 0x80) /* must have had error encountered */
8072
0
                break;
8073
0
        }
8074
0
    }
8075
8076
0
    content = xmlBufDetach(target);
8077
0
    if (content == NULL)
8078
0
        xmlXPathPErrMemory(ctxt);
8079
0
    else
8080
0
        valuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
8081
0
    xmlBufFree(target);
8082
0
error:
8083
0
    xmlXPathReleaseObject(ctxt->context, str);
8084
0
    xmlXPathReleaseObject(ctxt->context, from);
8085
0
    xmlXPathReleaseObject(ctxt->context, to);
8086
0
}
8087
8088
/**
8089
 * xmlXPathBooleanFunction:
8090
 * @ctxt:  the XPath Parser context
8091
 * @nargs:  the number of arguments
8092
 *
8093
 * Implement the boolean() XPath function
8094
 *    boolean boolean(object)
8095
 * The boolean function converts its argument to a boolean as follows:
8096
 *    - a number is true if and only if it is neither positive or
8097
 *      negative zero nor NaN
8098
 *    - a node-set is true if and only if it is non-empty
8099
 *    - a string is true if and only if its length is non-zero
8100
 */
8101
void
8102
0
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8103
0
    xmlXPathObjectPtr cur;
8104
8105
0
    CHECK_ARITY(1);
8106
0
    cur = valuePop(ctxt);
8107
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8108
0
    if (cur->type != XPATH_BOOLEAN) {
8109
0
        int boolval = xmlXPathCastToBoolean(cur);
8110
8111
0
        xmlXPathReleaseObject(ctxt->context, cur);
8112
0
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
8113
0
    }
8114
0
    valuePush(ctxt, cur);
8115
0
}
8116
8117
/**
8118
 * xmlXPathNotFunction:
8119
 * @ctxt:  the XPath Parser context
8120
 * @nargs:  the number of arguments
8121
 *
8122
 * Implement the not() XPath function
8123
 *    boolean not(boolean)
8124
 * The not function returns true if its argument is false,
8125
 * and false otherwise.
8126
 */
8127
void
8128
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8129
0
    CHECK_ARITY(1);
8130
0
    CAST_TO_BOOLEAN;
8131
0
    CHECK_TYPE(XPATH_BOOLEAN);
8132
0
    ctxt->value->boolval = ! ctxt->value->boolval;
8133
0
}
8134
8135
/**
8136
 * xmlXPathTrueFunction:
8137
 * @ctxt:  the XPath Parser context
8138
 * @nargs:  the number of arguments
8139
 *
8140
 * Implement the true() XPath function
8141
 *    boolean true()
8142
 */
8143
void
8144
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8145
0
    CHECK_ARITY(0);
8146
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
8147
0
}
8148
8149
/**
8150
 * xmlXPathFalseFunction:
8151
 * @ctxt:  the XPath Parser context
8152
 * @nargs:  the number of arguments
8153
 *
8154
 * Implement the false() XPath function
8155
 *    boolean false()
8156
 */
8157
void
8158
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8159
0
    CHECK_ARITY(0);
8160
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
8161
0
}
8162
8163
/**
8164
 * xmlXPathLangFunction:
8165
 * @ctxt:  the XPath Parser context
8166
 * @nargs:  the number of arguments
8167
 *
8168
 * Implement the lang() XPath function
8169
 *    boolean lang(string)
8170
 * The lang function returns true or false depending on whether the
8171
 * language of the context node as specified by xml:lang attributes
8172
 * is the same as or is a sublanguage of the language specified by
8173
 * the argument string. The language of the context node is determined
8174
 * by the value of the xml:lang attribute on the context node, or, if
8175
 * the context node has no xml:lang attribute, by the value of the
8176
 * xml:lang attribute on the nearest ancestor of the context node that
8177
 * has an xml:lang attribute. If there is no such attribute, then lang
8178
 * returns false. If there is such an attribute, then lang returns
8179
 * true if the attribute value is equal to the argument ignoring case,
8180
 * or if there is some suffix starting with - such that the attribute
8181
 * value is equal to the argument ignoring that suffix of the attribute
8182
 * value and ignoring case.
8183
 */
8184
void
8185
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8186
0
    xmlXPathObjectPtr val;
8187
0
    xmlNodePtr cur;
8188
0
    xmlChar *theLang;
8189
0
    const xmlChar *lang;
8190
0
    int ret = 0;
8191
0
    int i;
8192
8193
0
    CHECK_ARITY(1);
8194
0
    CAST_TO_STRING;
8195
0
    CHECK_TYPE(XPATH_STRING);
8196
0
    val = valuePop(ctxt);
8197
0
    lang = val->stringval;
8198
0
    cur = ctxt->context->node;
8199
0
    while (cur != NULL) {
8200
0
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
8201
0
                                &theLang) < 0)
8202
0
            xmlXPathPErrMemory(ctxt);
8203
0
        if (theLang != NULL)
8204
0
            break;
8205
0
        cur = cur->parent;
8206
0
    }
8207
0
    if ((theLang != NULL) && (lang != NULL)) {
8208
0
        for (i = 0;lang[i] != 0;i++)
8209
0
            if (toupper(lang[i]) != toupper(theLang[i]))
8210
0
                goto not_equal;
8211
0
        if ((theLang[i] == 0) || (theLang[i] == '-'))
8212
0
            ret = 1;
8213
0
    }
8214
0
not_equal:
8215
0
    if (theLang != NULL)
8216
0
  xmlFree((void *)theLang);
8217
8218
0
    xmlXPathReleaseObject(ctxt->context, val);
8219
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
8220
0
}
8221
8222
/**
8223
 * xmlXPathNumberFunction:
8224
 * @ctxt:  the XPath Parser context
8225
 * @nargs:  the number of arguments
8226
 *
8227
 * Implement the number() XPath function
8228
 *    number number(object?)
8229
 */
8230
void
8231
0
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8232
0
    xmlXPathObjectPtr cur;
8233
0
    double res;
8234
8235
0
    if (ctxt == NULL) return;
8236
0
    if (nargs == 0) {
8237
0
  if (ctxt->context->node == NULL) {
8238
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
8239
0
  } else {
8240
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8241
0
            if (content == NULL)
8242
0
                xmlXPathPErrMemory(ctxt);
8243
8244
0
      res = xmlXPathStringEvalNumber(content);
8245
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8246
0
      xmlFree(content);
8247
0
  }
8248
0
  return;
8249
0
    }
8250
8251
0
    CHECK_ARITY(1);
8252
0
    cur = valuePop(ctxt);
8253
0
    if (cur->type != XPATH_NUMBER) {
8254
0
        double floatval;
8255
8256
0
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
8257
0
        xmlXPathReleaseObject(ctxt->context, cur);
8258
0
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
8259
0
    }
8260
0
    valuePush(ctxt, cur);
8261
0
}
8262
8263
/**
8264
 * xmlXPathSumFunction:
8265
 * @ctxt:  the XPath Parser context
8266
 * @nargs:  the number of arguments
8267
 *
8268
 * Implement the sum() XPath function
8269
 *    number sum(node-set)
8270
 * The sum function returns the sum of the values of the nodes in
8271
 * the argument node-set.
8272
 */
8273
void
8274
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8275
0
    xmlXPathObjectPtr cur;
8276
0
    int i;
8277
0
    double res = 0.0;
8278
8279
0
    CHECK_ARITY(1);
8280
0
    if ((ctxt->value == NULL) ||
8281
0
  ((ctxt->value->type != XPATH_NODESET) &&
8282
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8283
0
  XP_ERROR(XPATH_INVALID_TYPE);
8284
0
    cur = valuePop(ctxt);
8285
8286
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8287
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8288
0
      res += xmlXPathNodeToNumberInternal(ctxt,
8289
0
                                                cur->nodesetval->nodeTab[i]);
8290
0
  }
8291
0
    }
8292
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8293
0
    xmlXPathReleaseObject(ctxt->context, cur);
8294
0
}
8295
8296
/**
8297
 * xmlXPathFloorFunction:
8298
 * @ctxt:  the XPath Parser context
8299
 * @nargs:  the number of arguments
8300
 *
8301
 * Implement the floor() XPath function
8302
 *    number floor(number)
8303
 * The floor function returns the largest (closest to positive infinity)
8304
 * number that is not greater than the argument and that is an integer.
8305
 */
8306
void
8307
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8308
0
    CHECK_ARITY(1);
8309
0
    CAST_TO_NUMBER;
8310
0
    CHECK_TYPE(XPATH_NUMBER);
8311
8312
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
8313
0
}
8314
8315
/**
8316
 * xmlXPathCeilingFunction:
8317
 * @ctxt:  the XPath Parser context
8318
 * @nargs:  the number of arguments
8319
 *
8320
 * Implement the ceiling() XPath function
8321
 *    number ceiling(number)
8322
 * The ceiling function returns the smallest (closest to negative infinity)
8323
 * number that is not less than the argument and that is an integer.
8324
 */
8325
void
8326
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8327
0
    CHECK_ARITY(1);
8328
0
    CAST_TO_NUMBER;
8329
0
    CHECK_TYPE(XPATH_NUMBER);
8330
8331
#ifdef _AIX
8332
    /* Work around buggy ceil() function on AIX */
8333
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8334
#else
8335
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8336
0
#endif
8337
0
}
8338
8339
/**
8340
 * xmlXPathRoundFunction:
8341
 * @ctxt:  the XPath Parser context
8342
 * @nargs:  the number of arguments
8343
 *
8344
 * Implement the round() XPath function
8345
 *    number round(number)
8346
 * The round function returns the number that is closest to the
8347
 * argument and that is an integer. If there are two such numbers,
8348
 * then the one that is closest to positive infinity is returned.
8349
 */
8350
void
8351
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8352
0
    double f;
8353
8354
0
    CHECK_ARITY(1);
8355
0
    CAST_TO_NUMBER;
8356
0
    CHECK_TYPE(XPATH_NUMBER);
8357
8358
0
    f = ctxt->value->floatval;
8359
8360
0
    if ((f >= -0.5) && (f < 0.5)) {
8361
        /* Handles negative zero. */
8362
0
        ctxt->value->floatval *= 0.0;
8363
0
    }
8364
0
    else {
8365
0
        double rounded = floor(f);
8366
0
        if (f - rounded >= 0.5)
8367
0
            rounded += 1.0;
8368
0
        ctxt->value->floatval = rounded;
8369
0
    }
8370
0
}
8371
8372
/************************************************************************
8373
 *                  *
8374
 *      The Parser          *
8375
 *                  *
8376
 ************************************************************************/
8377
8378
/*
8379
 * a few forward declarations since we use a recursive call based
8380
 * implementation.
8381
 */
8382
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8383
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8384
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8385
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8386
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8387
                                    int qualified);
8388
8389
/**
8390
 * xmlXPathCurrentChar:
8391
 * @ctxt:  the XPath parser context
8392
 * @cur:  pointer to the beginning of the char
8393
 * @len:  pointer to the length of the char read
8394
 *
8395
 * The current char value, if using UTF-8 this may actually span multiple
8396
 * bytes in the input buffer.
8397
 *
8398
 * Returns the current char value and its length
8399
 */
8400
8401
static int
8402
0
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8403
0
    unsigned char c;
8404
0
    unsigned int val;
8405
0
    const xmlChar *cur;
8406
8407
0
    if (ctxt == NULL)
8408
0
  return(0);
8409
0
    cur = ctxt->cur;
8410
8411
    /*
8412
     * We are supposed to handle UTF8, check it's valid
8413
     * From rfc2044: encoding of the Unicode values on UTF-8:
8414
     *
8415
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
8416
     * 0000 0000-0000 007F   0xxxxxxx
8417
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
8418
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
8419
     *
8420
     * Check for the 0x110000 limit too
8421
     */
8422
0
    c = *cur;
8423
0
    if (c & 0x80) {
8424
0
  if ((cur[1] & 0xc0) != 0x80)
8425
0
      goto encoding_error;
8426
0
  if ((c & 0xe0) == 0xe0) {
8427
8428
0
      if ((cur[2] & 0xc0) != 0x80)
8429
0
    goto encoding_error;
8430
0
      if ((c & 0xf0) == 0xf0) {
8431
0
    if (((c & 0xf8) != 0xf0) ||
8432
0
        ((cur[3] & 0xc0) != 0x80))
8433
0
        goto encoding_error;
8434
    /* 4-byte code */
8435
0
    *len = 4;
8436
0
    val = (cur[0] & 0x7) << 18;
8437
0
    val |= (cur[1] & 0x3f) << 12;
8438
0
    val |= (cur[2] & 0x3f) << 6;
8439
0
    val |= cur[3] & 0x3f;
8440
0
      } else {
8441
        /* 3-byte code */
8442
0
    *len = 3;
8443
0
    val = (cur[0] & 0xf) << 12;
8444
0
    val |= (cur[1] & 0x3f) << 6;
8445
0
    val |= cur[2] & 0x3f;
8446
0
      }
8447
0
  } else {
8448
    /* 2-byte code */
8449
0
      *len = 2;
8450
0
      val = (cur[0] & 0x1f) << 6;
8451
0
      val |= cur[1] & 0x3f;
8452
0
  }
8453
0
  if (!IS_CHAR(val)) {
8454
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
8455
0
  }
8456
0
  return(val);
8457
0
    } else {
8458
  /* 1-byte code */
8459
0
  *len = 1;
8460
0
  return(*cur);
8461
0
    }
8462
0
encoding_error:
8463
    /*
8464
     * If we detect an UTF8 error that probably means that the
8465
     * input encoding didn't get properly advertised in the
8466
     * declaration header. Report the error and switch the encoding
8467
     * to ISO-Latin-1 (if you don't like this policy, just declare the
8468
     * encoding !)
8469
     */
8470
0
    *len = 0;
8471
0
    XP_ERROR0(XPATH_ENCODING_ERROR);
8472
0
}
8473
8474
/**
8475
 * xmlXPathParseNCName:
8476
 * @ctxt:  the XPath Parser context
8477
 *
8478
 * parse an XML namespace non qualified name.
8479
 *
8480
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
8481
 *
8482
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
8483
 *                       CombiningChar | Extender
8484
 *
8485
 * Returns the namespace name or NULL
8486
 */
8487
8488
xmlChar *
8489
0
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
8490
0
    const xmlChar *in;
8491
0
    xmlChar *ret;
8492
0
    int count = 0;
8493
8494
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8495
    /*
8496
     * Accelerator for simple ASCII names
8497
     */
8498
0
    in = ctxt->cur;
8499
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
8500
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
8501
0
  (*in == '_')) {
8502
0
  in++;
8503
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
8504
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
8505
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
8506
0
         (*in == '_') || (*in == '.') ||
8507
0
         (*in == '-'))
8508
0
      in++;
8509
0
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
8510
0
            (*in == '[') || (*in == ']') || (*in == ':') ||
8511
0
            (*in == '@') || (*in == '*')) {
8512
0
      count = in - ctxt->cur;
8513
0
      if (count == 0)
8514
0
    return(NULL);
8515
0
      ret = xmlStrndup(ctxt->cur, count);
8516
0
            if (ret == NULL)
8517
0
                xmlXPathPErrMemory(ctxt);
8518
0
      ctxt->cur = in;
8519
0
      return(ret);
8520
0
  }
8521
0
    }
8522
0
    return(xmlXPathParseNameComplex(ctxt, 0));
8523
0
}
8524
8525
8526
/**
8527
 * xmlXPathParseQName:
8528
 * @ctxt:  the XPath Parser context
8529
 * @prefix:  a xmlChar **
8530
 *
8531
 * parse an XML qualified name
8532
 *
8533
 * [NS 5] QName ::= (Prefix ':')? LocalPart
8534
 *
8535
 * [NS 6] Prefix ::= NCName
8536
 *
8537
 * [NS 7] LocalPart ::= NCName
8538
 *
8539
 * Returns the function returns the local part, and prefix is updated
8540
 *   to get the Prefix if any.
8541
 */
8542
8543
static xmlChar *
8544
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8545
0
    xmlChar *ret = NULL;
8546
8547
0
    *prefix = NULL;
8548
0
    ret = xmlXPathParseNCName(ctxt);
8549
0
    if (ret && CUR == ':') {
8550
0
        *prefix = ret;
8551
0
  NEXT;
8552
0
  ret = xmlXPathParseNCName(ctxt);
8553
0
    }
8554
0
    return(ret);
8555
0
}
8556
8557
/**
8558
 * xmlXPathParseName:
8559
 * @ctxt:  the XPath Parser context
8560
 *
8561
 * parse an XML name
8562
 *
8563
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
8564
 *                  CombiningChar | Extender
8565
 *
8566
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
8567
 *
8568
 * Returns the namespace name or NULL
8569
 */
8570
8571
xmlChar *
8572
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
8573
0
    const xmlChar *in;
8574
0
    xmlChar *ret;
8575
0
    size_t count = 0;
8576
8577
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8578
    /*
8579
     * Accelerator for simple ASCII names
8580
     */
8581
0
    in = ctxt->cur;
8582
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
8583
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
8584
0
  (*in == '_') || (*in == ':')) {
8585
0
  in++;
8586
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
8587
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
8588
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
8589
0
         (*in == '_') || (*in == '-') ||
8590
0
         (*in == ':') || (*in == '.'))
8591
0
      in++;
8592
0
  if ((*in > 0) && (*in < 0x80)) {
8593
0
      count = in - ctxt->cur;
8594
0
            if (count > XML_MAX_NAME_LENGTH) {
8595
0
                ctxt->cur = in;
8596
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
8597
0
            }
8598
0
      ret = xmlStrndup(ctxt->cur, count);
8599
0
            if (ret == NULL)
8600
0
                xmlXPathPErrMemory(ctxt);
8601
0
      ctxt->cur = in;
8602
0
      return(ret);
8603
0
  }
8604
0
    }
8605
0
    return(xmlXPathParseNameComplex(ctxt, 1));
8606
0
}
8607
8608
static xmlChar *
8609
0
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
8610
0
    xmlChar *ret;
8611
0
    xmlChar buf[XML_MAX_NAMELEN + 5];
8612
0
    int len = 0, l;
8613
0
    int c;
8614
8615
    /*
8616
     * Handler for more complex cases
8617
     */
8618
0
    c = CUR_CHAR(l);
8619
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
8620
0
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
8621
0
        (c == '*') || /* accelerators */
8622
0
  (!IS_LETTER(c) && (c != '_') &&
8623
0
         ((!qualified) || (c != ':')))) {
8624
0
  return(NULL);
8625
0
    }
8626
8627
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
8628
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
8629
0
            (c == '.') || (c == '-') ||
8630
0
      (c == '_') || ((qualified) && (c == ':')) ||
8631
0
      (IS_COMBINING(c)) ||
8632
0
      (IS_EXTENDER(c)))) {
8633
0
  COPY_BUF(buf,len,c);
8634
0
  NEXTL(l);
8635
0
  c = CUR_CHAR(l);
8636
0
  if (len >= XML_MAX_NAMELEN) {
8637
      /*
8638
       * Okay someone managed to make a huge name, so he's ready to pay
8639
       * for the processing speed.
8640
       */
8641
0
      xmlChar *buffer;
8642
0
      int max = len * 2;
8643
8644
0
            if (len > XML_MAX_NAME_LENGTH) {
8645
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
8646
0
            }
8647
0
      buffer = xmlMalloc(max);
8648
0
      if (buffer == NULL) {
8649
0
                xmlXPathPErrMemory(ctxt);
8650
0
                return(NULL);
8651
0
      }
8652
0
      memcpy(buffer, buf, len);
8653
0
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
8654
0
       (c == '.') || (c == '-') ||
8655
0
       (c == '_') || ((qualified) && (c == ':')) ||
8656
0
       (IS_COMBINING(c)) ||
8657
0
       (IS_EXTENDER(c))) {
8658
0
    if (len + 10 > max) {
8659
0
                    xmlChar *tmp;
8660
0
                    if (max > XML_MAX_NAME_LENGTH) {
8661
0
                        xmlFree(buffer);
8662
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
8663
0
                    }
8664
0
        max *= 2;
8665
0
        tmp = (xmlChar *) xmlRealloc(buffer, max);
8666
0
        if (tmp == NULL) {
8667
0
                        xmlFree(buffer);
8668
0
                        xmlXPathPErrMemory(ctxt);
8669
0
                        return(NULL);
8670
0
        }
8671
0
                    buffer = tmp;
8672
0
    }
8673
0
    COPY_BUF(buffer,len,c);
8674
0
    NEXTL(l);
8675
0
    c = CUR_CHAR(l);
8676
0
      }
8677
0
      buffer[len] = 0;
8678
0
      return(buffer);
8679
0
  }
8680
0
    }
8681
0
    if (len == 0)
8682
0
  return(NULL);
8683
0
    ret = xmlStrndup(buf, len);
8684
0
    if (ret == NULL)
8685
0
        xmlXPathPErrMemory(ctxt);
8686
0
    return(ret);
8687
0
}
8688
8689
0
#define MAX_FRAC 20
8690
8691
/**
8692
 * xmlXPathStringEvalNumber:
8693
 * @str:  A string to scan
8694
 *
8695
 *  [30a]  Float  ::= Number ('e' Digits?)?
8696
 *
8697
 *  [30]   Number ::=   Digits ('.' Digits?)?
8698
 *                    | '.' Digits
8699
 *  [31]   Digits ::=   [0-9]+
8700
 *
8701
 * Compile a Number in the string
8702
 * In complement of the Number expression, this function also handles
8703
 * negative values : '-' Number.
8704
 *
8705
 * Returns the double value.
8706
 */
8707
double
8708
0
xmlXPathStringEvalNumber(const xmlChar *str) {
8709
0
    const xmlChar *cur = str;
8710
0
    double ret;
8711
0
    int ok = 0;
8712
0
    int isneg = 0;
8713
0
    int exponent = 0;
8714
0
    int is_exponent_negative = 0;
8715
0
#ifdef __GNUC__
8716
0
    unsigned long tmp = 0;
8717
0
    double temp;
8718
0
#endif
8719
0
    if (cur == NULL) return(0);
8720
0
    while (IS_BLANK_CH(*cur)) cur++;
8721
0
    if (*cur == '-') {
8722
0
  isneg = 1;
8723
0
  cur++;
8724
0
    }
8725
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8726
0
        return(xmlXPathNAN);
8727
0
    }
8728
8729
0
#ifdef __GNUC__
8730
    /*
8731
     * tmp/temp is a workaround against a gcc compiler bug
8732
     * http://veillard.com/gcc.bug
8733
     */
8734
0
    ret = 0;
8735
0
    while ((*cur >= '0') && (*cur <= '9')) {
8736
0
  ret = ret * 10;
8737
0
  tmp = (*cur - '0');
8738
0
  ok = 1;
8739
0
  cur++;
8740
0
  temp = (double) tmp;
8741
0
  ret = ret + temp;
8742
0
    }
8743
#else
8744
    ret = 0;
8745
    while ((*cur >= '0') && (*cur <= '9')) {
8746
  ret = ret * 10 + (*cur - '0');
8747
  ok = 1;
8748
  cur++;
8749
    }
8750
#endif
8751
8752
0
    if (*cur == '.') {
8753
0
  int v, frac = 0, max;
8754
0
  double fraction = 0;
8755
8756
0
        cur++;
8757
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8758
0
      return(xmlXPathNAN);
8759
0
  }
8760
0
        while (*cur == '0') {
8761
0
      frac = frac + 1;
8762
0
      cur++;
8763
0
        }
8764
0
        max = frac + MAX_FRAC;
8765
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8766
0
      v = (*cur - '0');
8767
0
      fraction = fraction * 10 + v;
8768
0
      frac = frac + 1;
8769
0
      cur++;
8770
0
  }
8771
0
  fraction /= pow(10.0, frac);
8772
0
  ret = ret + fraction;
8773
0
  while ((*cur >= '0') && (*cur <= '9'))
8774
0
      cur++;
8775
0
    }
8776
0
    if ((*cur == 'e') || (*cur == 'E')) {
8777
0
      cur++;
8778
0
      if (*cur == '-') {
8779
0
  is_exponent_negative = 1;
8780
0
  cur++;
8781
0
      } else if (*cur == '+') {
8782
0
        cur++;
8783
0
      }
8784
0
      while ((*cur >= '0') && (*cur <= '9')) {
8785
0
        if (exponent < 1000000)
8786
0
    exponent = exponent * 10 + (*cur - '0');
8787
0
  cur++;
8788
0
      }
8789
0
    }
8790
0
    while (IS_BLANK_CH(*cur)) cur++;
8791
0
    if (*cur != 0) return(xmlXPathNAN);
8792
0
    if (isneg) ret = -ret;
8793
0
    if (is_exponent_negative) exponent = -exponent;
8794
0
    ret *= pow(10.0, (double)exponent);
8795
0
    return(ret);
8796
0
}
8797
8798
/**
8799
 * xmlXPathCompNumber:
8800
 * @ctxt:  the XPath Parser context
8801
 *
8802
 *  [30]   Number ::=   Digits ('.' Digits?)?
8803
 *                    | '.' Digits
8804
 *  [31]   Digits ::=   [0-9]+
8805
 *
8806
 * Compile a Number, then push it on the stack
8807
 *
8808
 */
8809
static void
8810
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8811
0
{
8812
0
    double ret = 0.0;
8813
0
    int ok = 0;
8814
0
    int exponent = 0;
8815
0
    int is_exponent_negative = 0;
8816
0
    xmlXPathObjectPtr num;
8817
0
#ifdef __GNUC__
8818
0
    unsigned long tmp = 0;
8819
0
    double temp;
8820
0
#endif
8821
8822
0
    CHECK_ERROR;
8823
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8824
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8825
0
    }
8826
0
#ifdef __GNUC__
8827
    /*
8828
     * tmp/temp is a workaround against a gcc compiler bug
8829
     * http://veillard.com/gcc.bug
8830
     */
8831
0
    ret = 0;
8832
0
    while ((CUR >= '0') && (CUR <= '9')) {
8833
0
  ret = ret * 10;
8834
0
  tmp = (CUR - '0');
8835
0
        ok = 1;
8836
0
        NEXT;
8837
0
  temp = (double) tmp;
8838
0
  ret = ret + temp;
8839
0
    }
8840
#else
8841
    ret = 0;
8842
    while ((CUR >= '0') && (CUR <= '9')) {
8843
  ret = ret * 10 + (CUR - '0');
8844
  ok = 1;
8845
  NEXT;
8846
    }
8847
#endif
8848
0
    if (CUR == '.') {
8849
0
  int v, frac = 0, max;
8850
0
  double fraction = 0;
8851
8852
0
        NEXT;
8853
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8854
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8855
0
        }
8856
0
        while (CUR == '0') {
8857
0
            frac = frac + 1;
8858
0
            NEXT;
8859
0
        }
8860
0
        max = frac + MAX_FRAC;
8861
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8862
0
      v = (CUR - '0');
8863
0
      fraction = fraction * 10 + v;
8864
0
      frac = frac + 1;
8865
0
            NEXT;
8866
0
        }
8867
0
        fraction /= pow(10.0, frac);
8868
0
        ret = ret + fraction;
8869
0
        while ((CUR >= '0') && (CUR <= '9'))
8870
0
            NEXT;
8871
0
    }
8872
0
    if ((CUR == 'e') || (CUR == 'E')) {
8873
0
        NEXT;
8874
0
        if (CUR == '-') {
8875
0
            is_exponent_negative = 1;
8876
0
            NEXT;
8877
0
        } else if (CUR == '+') {
8878
0
      NEXT;
8879
0
  }
8880
0
        while ((CUR >= '0') && (CUR <= '9')) {
8881
0
            if (exponent < 1000000)
8882
0
                exponent = exponent * 10 + (CUR - '0');
8883
0
            NEXT;
8884
0
        }
8885
0
        if (is_exponent_negative)
8886
0
            exponent = -exponent;
8887
0
        ret *= pow(10.0, (double) exponent);
8888
0
    }
8889
0
    num = xmlXPathCacheNewFloat(ctxt, ret);
8890
0
    if (num == NULL) {
8891
0
  ctxt->error = XPATH_MEMORY_ERROR;
8892
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8893
0
                              NULL) == -1) {
8894
0
        xmlXPathReleaseObject(ctxt->context, num);
8895
0
    }
8896
0
}
8897
8898
/**
8899
 * xmlXPathParseLiteral:
8900
 * @ctxt:  the XPath Parser context
8901
 *
8902
 * Parse a Literal
8903
 *
8904
 *  [29]   Literal ::=   '"' [^"]* '"'
8905
 *                    | "'" [^']* "'"
8906
 *
8907
 * Returns the value found or NULL in case of error
8908
 */
8909
static xmlChar *
8910
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8911
0
    const xmlChar *q;
8912
0
    xmlChar *ret = NULL;
8913
0
    int quote;
8914
8915
0
    if (CUR == '"') {
8916
0
        quote = '"';
8917
0
    } else if (CUR == '\'') {
8918
0
        quote = '\'';
8919
0
    } else {
8920
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8921
0
    }
8922
8923
0
    NEXT;
8924
0
    q = CUR_PTR;
8925
0
    while (CUR != quote) {
8926
0
        int ch;
8927
0
        int len = 4;
8928
8929
0
        if (CUR == 0)
8930
0
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8931
0
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8932
0
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8933
0
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8934
0
        CUR_PTR += len;
8935
0
    }
8936
0
    ret = xmlStrndup(q, CUR_PTR - q);
8937
0
    if (ret == NULL)
8938
0
        xmlXPathPErrMemory(ctxt);
8939
0
    NEXT;
8940
0
    return(ret);
8941
0
}
8942
8943
/**
8944
 * xmlXPathCompLiteral:
8945
 * @ctxt:  the XPath Parser context
8946
 *
8947
 * Parse a Literal and push it on the stack.
8948
 *
8949
 *  [29]   Literal ::=   '"' [^"]* '"'
8950
 *                    | "'" [^']* "'"
8951
 *
8952
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
8953
 */
8954
static void
8955
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8956
0
    xmlChar *ret = NULL;
8957
0
    xmlXPathObjectPtr lit;
8958
8959
0
    ret = xmlXPathParseLiteral(ctxt);
8960
0
    if (ret == NULL)
8961
0
        return;
8962
0
    lit = xmlXPathCacheNewString(ctxt, ret);
8963
0
    if (lit == NULL) {
8964
0
        ctxt->error = XPATH_MEMORY_ERROR;
8965
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8966
0
                              NULL) == -1) {
8967
0
        xmlXPathReleaseObject(ctxt->context, lit);
8968
0
    }
8969
0
    xmlFree(ret);
8970
0
}
8971
8972
/**
8973
 * xmlXPathCompVariableReference:
8974
 * @ctxt:  the XPath Parser context
8975
 *
8976
 * Parse a VariableReference, evaluate it and push it on the stack.
8977
 *
8978
 * The variable bindings consist of a mapping from variable names
8979
 * to variable values. The value of a variable is an object, which can be
8980
 * of any of the types that are possible for the value of an expression,
8981
 * and may also be of additional types not specified here.
8982
 *
8983
 * Early evaluation is possible since:
8984
 * The variable bindings [...] used to evaluate a subexpression are
8985
 * always the same as those used to evaluate the containing expression.
8986
 *
8987
 *  [36]   VariableReference ::=   '$' QName
8988
 */
8989
static void
8990
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8991
0
    xmlChar *name;
8992
0
    xmlChar *prefix;
8993
8994
0
    SKIP_BLANKS;
8995
0
    if (CUR != '$') {
8996
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8997
0
    }
8998
0
    NEXT;
8999
0
    name = xmlXPathParseQName(ctxt, &prefix);
9000
0
    if (name == NULL) {
9001
0
        xmlFree(prefix);
9002
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9003
0
    }
9004
0
    ctxt->comp->last = -1;
9005
0
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9006
0
        xmlFree(prefix);
9007
0
        xmlFree(name);
9008
0
    }
9009
0
    SKIP_BLANKS;
9010
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9011
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9012
0
    }
9013
0
}
9014
9015
/**
9016
 * xmlXPathIsNodeType:
9017
 * @name:  a name string
9018
 *
9019
 * Is the name given a NodeType one.
9020
 *
9021
 *  [38]   NodeType ::=   'comment'
9022
 *                    | 'text'
9023
 *                    | 'processing-instruction'
9024
 *                    | 'node'
9025
 *
9026
 * Returns 1 if true 0 otherwise
9027
 */
9028
int
9029
0
xmlXPathIsNodeType(const xmlChar *name) {
9030
0
    if (name == NULL)
9031
0
  return(0);
9032
9033
0
    if (xmlStrEqual(name, BAD_CAST "node"))
9034
0
  return(1);
9035
0
    if (xmlStrEqual(name, BAD_CAST "text"))
9036
0
  return(1);
9037
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
9038
0
  return(1);
9039
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9040
0
  return(1);
9041
0
    return(0);
9042
0
}
9043
9044
/**
9045
 * xmlXPathCompFunctionCall:
9046
 * @ctxt:  the XPath Parser context
9047
 *
9048
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9049
 *  [17]   Argument ::=   Expr
9050
 *
9051
 * Compile a function call, the evaluation of all arguments are
9052
 * pushed on the stack
9053
 */
9054
static void
9055
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9056
0
    xmlChar *name;
9057
0
    xmlChar *prefix;
9058
0
    int nbargs = 0;
9059
0
    int sort = 1;
9060
9061
0
    name = xmlXPathParseQName(ctxt, &prefix);
9062
0
    if (name == NULL) {
9063
0
  xmlFree(prefix);
9064
0
  XP_ERROR(XPATH_EXPR_ERROR);
9065
0
    }
9066
0
    SKIP_BLANKS;
9067
9068
0
    if (CUR != '(') {
9069
0
  xmlFree(name);
9070
0
  xmlFree(prefix);
9071
0
  XP_ERROR(XPATH_EXPR_ERROR);
9072
0
    }
9073
0
    NEXT;
9074
0
    SKIP_BLANKS;
9075
9076
    /*
9077
    * Optimization for count(): we don't need the node-set to be sorted.
9078
    */
9079
0
    if ((prefix == NULL) && (name[0] == 'c') &&
9080
0
  xmlStrEqual(name, BAD_CAST "count"))
9081
0
    {
9082
0
  sort = 0;
9083
0
    }
9084
0
    ctxt->comp->last = -1;
9085
0
    if (CUR != ')') {
9086
0
  while (CUR != 0) {
9087
0
      int op1 = ctxt->comp->last;
9088
0
      ctxt->comp->last = -1;
9089
0
      xmlXPathCompileExpr(ctxt, sort);
9090
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
9091
0
    xmlFree(name);
9092
0
    xmlFree(prefix);
9093
0
    return;
9094
0
      }
9095
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9096
0
      nbargs++;
9097
0
      if (CUR == ')') break;
9098
0
      if (CUR != ',') {
9099
0
    xmlFree(name);
9100
0
    xmlFree(prefix);
9101
0
    XP_ERROR(XPATH_EXPR_ERROR);
9102
0
      }
9103
0
      NEXT;
9104
0
      SKIP_BLANKS;
9105
0
  }
9106
0
    }
9107
0
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9108
0
        xmlFree(prefix);
9109
0
        xmlFree(name);
9110
0
    }
9111
0
    NEXT;
9112
0
    SKIP_BLANKS;
9113
0
}
9114
9115
/**
9116
 * xmlXPathCompPrimaryExpr:
9117
 * @ctxt:  the XPath Parser context
9118
 *
9119
 *  [15]   PrimaryExpr ::=   VariableReference
9120
 *                | '(' Expr ')'
9121
 *                | Literal
9122
 *                | Number
9123
 *                | FunctionCall
9124
 *
9125
 * Compile a primary expression.
9126
 */
9127
static void
9128
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9129
0
    SKIP_BLANKS;
9130
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9131
0
    else if (CUR == '(') {
9132
0
  NEXT;
9133
0
  SKIP_BLANKS;
9134
0
  xmlXPathCompileExpr(ctxt, 1);
9135
0
  CHECK_ERROR;
9136
0
  if (CUR != ')') {
9137
0
      XP_ERROR(XPATH_EXPR_ERROR);
9138
0
  }
9139
0
  NEXT;
9140
0
  SKIP_BLANKS;
9141
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9142
0
  xmlXPathCompNumber(ctxt);
9143
0
    } else if ((CUR == '\'') || (CUR == '"')) {
9144
0
  xmlXPathCompLiteral(ctxt);
9145
0
    } else {
9146
0
  xmlXPathCompFunctionCall(ctxt);
9147
0
    }
9148
0
    SKIP_BLANKS;
9149
0
}
9150
9151
/**
9152
 * xmlXPathCompFilterExpr:
9153
 * @ctxt:  the XPath Parser context
9154
 *
9155
 *  [20]   FilterExpr ::=   PrimaryExpr
9156
 *               | FilterExpr Predicate
9157
 *
9158
 * Compile a filter expression.
9159
 * Square brackets are used to filter expressions in the same way that
9160
 * they are used in location paths. It is an error if the expression to
9161
 * be filtered does not evaluate to a node-set. The context node list
9162
 * used for evaluating the expression in square brackets is the node-set
9163
 * to be filtered listed in document order.
9164
 */
9165
9166
static void
9167
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9168
0
    xmlXPathCompPrimaryExpr(ctxt);
9169
0
    CHECK_ERROR;
9170
0
    SKIP_BLANKS;
9171
9172
0
    while (CUR == '[') {
9173
0
  xmlXPathCompPredicate(ctxt, 1);
9174
0
  SKIP_BLANKS;
9175
0
    }
9176
9177
9178
0
}
9179
9180
/**
9181
 * xmlXPathScanName:
9182
 * @ctxt:  the XPath Parser context
9183
 *
9184
 * Trickery: parse an XML name but without consuming the input flow
9185
 * Needed to avoid insanity in the parser state.
9186
 *
9187
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9188
 *                  CombiningChar | Extender
9189
 *
9190
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9191
 *
9192
 * [6] Names ::= Name (S Name)*
9193
 *
9194
 * Returns the Name parsed or NULL
9195
 */
9196
9197
static xmlChar *
9198
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9199
0
    int l;
9200
0
    int c;
9201
0
    const xmlChar *cur;
9202
0
    xmlChar *ret;
9203
9204
0
    cur = ctxt->cur;
9205
9206
0
    c = CUR_CHAR(l);
9207
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9208
0
  (!IS_LETTER(c) && (c != '_') &&
9209
0
         (c != ':'))) {
9210
0
  return(NULL);
9211
0
    }
9212
9213
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9214
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9215
0
            (c == '.') || (c == '-') ||
9216
0
      (c == '_') || (c == ':') ||
9217
0
      (IS_COMBINING(c)) ||
9218
0
      (IS_EXTENDER(c)))) {
9219
0
  NEXTL(l);
9220
0
  c = CUR_CHAR(l);
9221
0
    }
9222
0
    ret = xmlStrndup(cur, ctxt->cur - cur);
9223
0
    if (ret == NULL)
9224
0
        xmlXPathPErrMemory(ctxt);
9225
0
    ctxt->cur = cur;
9226
0
    return(ret);
9227
0
}
9228
9229
/**
9230
 * xmlXPathCompPathExpr:
9231
 * @ctxt:  the XPath Parser context
9232
 *
9233
 *  [19]   PathExpr ::=   LocationPath
9234
 *               | FilterExpr
9235
 *               | FilterExpr '/' RelativeLocationPath
9236
 *               | FilterExpr '//' RelativeLocationPath
9237
 *
9238
 * Compile a path expression.
9239
 * The / operator and // operators combine an arbitrary expression
9240
 * and a relative location path. It is an error if the expression
9241
 * does not evaluate to a node-set.
9242
 * The / operator does composition in the same way as when / is
9243
 * used in a location path. As in location paths, // is short for
9244
 * /descendant-or-self::node()/.
9245
 */
9246
9247
static void
9248
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9249
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
9250
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
9251
9252
0
    SKIP_BLANKS;
9253
0
    if ((CUR == '$') || (CUR == '(') ||
9254
0
  (IS_ASCII_DIGIT(CUR)) ||
9255
0
        (CUR == '\'') || (CUR == '"') ||
9256
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9257
0
  lc = 0;
9258
0
    } else if (CUR == '*') {
9259
  /* relative or absolute location path */
9260
0
  lc = 1;
9261
0
    } else if (CUR == '/') {
9262
  /* relative or absolute location path */
9263
0
  lc = 1;
9264
0
    } else if (CUR == '@') {
9265
  /* relative abbreviated attribute location path */
9266
0
  lc = 1;
9267
0
    } else if (CUR == '.') {
9268
  /* relative abbreviated attribute location path */
9269
0
  lc = 1;
9270
0
    } else {
9271
  /*
9272
   * Problem is finding if we have a name here whether it's:
9273
   *   - a nodetype
9274
   *   - a function call in which case it's followed by '('
9275
   *   - an axis in which case it's followed by ':'
9276
   *   - a element name
9277
   * We do an a priori analysis here rather than having to
9278
   * maintain parsed token content through the recursive function
9279
   * calls. This looks uglier but makes the code easier to
9280
   * read/write/debug.
9281
   */
9282
0
  SKIP_BLANKS;
9283
0
  name = xmlXPathScanName(ctxt);
9284
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9285
0
      lc = 1;
9286
0
      xmlFree(name);
9287
0
  } else if (name != NULL) {
9288
0
      int len =xmlStrlen(name);
9289
9290
9291
0
      while (NXT(len) != 0) {
9292
0
    if (NXT(len) == '/') {
9293
        /* element name */
9294
0
        lc = 1;
9295
0
        break;
9296
0
    } else if (IS_BLANK_CH(NXT(len))) {
9297
        /* ignore blanks */
9298
0
        ;
9299
0
    } else if (NXT(len) == ':') {
9300
0
        lc = 1;
9301
0
        break;
9302
0
    } else if ((NXT(len) == '(')) {
9303
        /* Node Type or Function */
9304
0
        if (xmlXPathIsNodeType(name)) {
9305
0
      lc = 1;
9306
0
        } else {
9307
0
      lc = 0;
9308
0
        }
9309
0
                    break;
9310
0
    } else if ((NXT(len) == '[')) {
9311
        /* element name */
9312
0
        lc = 1;
9313
0
        break;
9314
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9315
0
         (NXT(len) == '=')) {
9316
0
        lc = 1;
9317
0
        break;
9318
0
    } else {
9319
0
        lc = 1;
9320
0
        break;
9321
0
    }
9322
0
    len++;
9323
0
      }
9324
0
      if (NXT(len) == 0) {
9325
    /* element name */
9326
0
    lc = 1;
9327
0
      }
9328
0
      xmlFree(name);
9329
0
  } else {
9330
      /* make sure all cases are covered explicitly */
9331
0
      XP_ERROR(XPATH_EXPR_ERROR);
9332
0
  }
9333
0
    }
9334
9335
0
    if (lc) {
9336
0
  if (CUR == '/') {
9337
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9338
0
  } else {
9339
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9340
0
  }
9341
0
  xmlXPathCompLocationPath(ctxt);
9342
0
    } else {
9343
0
  xmlXPathCompFilterExpr(ctxt);
9344
0
  CHECK_ERROR;
9345
0
  if ((CUR == '/') && (NXT(1) == '/')) {
9346
0
      SKIP(2);
9347
0
      SKIP_BLANKS;
9348
9349
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9350
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9351
9352
0
      xmlXPathCompRelativeLocationPath(ctxt);
9353
0
  } else if (CUR == '/') {
9354
0
      xmlXPathCompRelativeLocationPath(ctxt);
9355
0
  }
9356
0
    }
9357
0
    SKIP_BLANKS;
9358
0
}
9359
9360
/**
9361
 * xmlXPathCompUnionExpr:
9362
 * @ctxt:  the XPath Parser context
9363
 *
9364
 *  [18]   UnionExpr ::=   PathExpr
9365
 *               | UnionExpr '|' PathExpr
9366
 *
9367
 * Compile an union expression.
9368
 */
9369
9370
static void
9371
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9372
0
    xmlXPathCompPathExpr(ctxt);
9373
0
    CHECK_ERROR;
9374
0
    SKIP_BLANKS;
9375
0
    while (CUR == '|') {
9376
0
  int op1 = ctxt->comp->last;
9377
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9378
9379
0
  NEXT;
9380
0
  SKIP_BLANKS;
9381
0
  xmlXPathCompPathExpr(ctxt);
9382
9383
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9384
9385
0
  SKIP_BLANKS;
9386
0
    }
9387
0
}
9388
9389
/**
9390
 * xmlXPathCompUnaryExpr:
9391
 * @ctxt:  the XPath Parser context
9392
 *
9393
 *  [27]   UnaryExpr ::=   UnionExpr
9394
 *                   | '-' UnaryExpr
9395
 *
9396
 * Compile an unary expression.
9397
 */
9398
9399
static void
9400
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9401
0
    int minus = 0;
9402
0
    int found = 0;
9403
9404
0
    SKIP_BLANKS;
9405
0
    while (CUR == '-') {
9406
0
        minus = 1 - minus;
9407
0
  found = 1;
9408
0
  NEXT;
9409
0
  SKIP_BLANKS;
9410
0
    }
9411
9412
0
    xmlXPathCompUnionExpr(ctxt);
9413
0
    CHECK_ERROR;
9414
0
    if (found) {
9415
0
  if (minus)
9416
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9417
0
  else
9418
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9419
0
    }
9420
0
}
9421
9422
/**
9423
 * xmlXPathCompMultiplicativeExpr:
9424
 * @ctxt:  the XPath Parser context
9425
 *
9426
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
9427
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
9428
 *                   | MultiplicativeExpr 'div' UnaryExpr
9429
 *                   | MultiplicativeExpr 'mod' UnaryExpr
9430
 *  [34]   MultiplyOperator ::=   '*'
9431
 *
9432
 * Compile an Additive expression.
9433
 */
9434
9435
static void
9436
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
9437
0
    xmlXPathCompUnaryExpr(ctxt);
9438
0
    CHECK_ERROR;
9439
0
    SKIP_BLANKS;
9440
0
    while ((CUR == '*') ||
9441
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
9442
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
9443
0
  int op = -1;
9444
0
  int op1 = ctxt->comp->last;
9445
9446
0
        if (CUR == '*') {
9447
0
      op = 0;
9448
0
      NEXT;
9449
0
  } else if (CUR == 'd') {
9450
0
      op = 1;
9451
0
      SKIP(3);
9452
0
  } else if (CUR == 'm') {
9453
0
      op = 2;
9454
0
      SKIP(3);
9455
0
  }
9456
0
  SKIP_BLANKS;
9457
0
        xmlXPathCompUnaryExpr(ctxt);
9458
0
  CHECK_ERROR;
9459
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
9460
0
  SKIP_BLANKS;
9461
0
    }
9462
0
}
9463
9464
/**
9465
 * xmlXPathCompAdditiveExpr:
9466
 * @ctxt:  the XPath Parser context
9467
 *
9468
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
9469
 *                   | AdditiveExpr '+' MultiplicativeExpr
9470
 *                   | AdditiveExpr '-' MultiplicativeExpr
9471
 *
9472
 * Compile an Additive expression.
9473
 */
9474
9475
static void
9476
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
9477
9478
0
    xmlXPathCompMultiplicativeExpr(ctxt);
9479
0
    CHECK_ERROR;
9480
0
    SKIP_BLANKS;
9481
0
    while ((CUR == '+') || (CUR == '-')) {
9482
0
  int plus;
9483
0
  int op1 = ctxt->comp->last;
9484
9485
0
        if (CUR == '+') plus = 1;
9486
0
  else plus = 0;
9487
0
  NEXT;
9488
0
  SKIP_BLANKS;
9489
0
        xmlXPathCompMultiplicativeExpr(ctxt);
9490
0
  CHECK_ERROR;
9491
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
9492
0
  SKIP_BLANKS;
9493
0
    }
9494
0
}
9495
9496
/**
9497
 * xmlXPathCompRelationalExpr:
9498
 * @ctxt:  the XPath Parser context
9499
 *
9500
 *  [24]   RelationalExpr ::=   AdditiveExpr
9501
 *                 | RelationalExpr '<' AdditiveExpr
9502
 *                 | RelationalExpr '>' AdditiveExpr
9503
 *                 | RelationalExpr '<=' AdditiveExpr
9504
 *                 | RelationalExpr '>=' AdditiveExpr
9505
 *
9506
 *  A <= B > C is allowed ? Answer from James, yes with
9507
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
9508
 *  which is basically what got implemented.
9509
 *
9510
 * Compile a Relational expression, then push the result
9511
 * on the stack
9512
 */
9513
9514
static void
9515
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
9516
0
    xmlXPathCompAdditiveExpr(ctxt);
9517
0
    CHECK_ERROR;
9518
0
    SKIP_BLANKS;
9519
0
    while ((CUR == '<') || (CUR == '>')) {
9520
0
  int inf, strict;
9521
0
  int op1 = ctxt->comp->last;
9522
9523
0
        if (CUR == '<') inf = 1;
9524
0
  else inf = 0;
9525
0
  if (NXT(1) == '=') strict = 0;
9526
0
  else strict = 1;
9527
0
  NEXT;
9528
0
  if (!strict) NEXT;
9529
0
  SKIP_BLANKS;
9530
0
        xmlXPathCompAdditiveExpr(ctxt);
9531
0
  CHECK_ERROR;
9532
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
9533
0
  SKIP_BLANKS;
9534
0
    }
9535
0
}
9536
9537
/**
9538
 * xmlXPathCompEqualityExpr:
9539
 * @ctxt:  the XPath Parser context
9540
 *
9541
 *  [23]   EqualityExpr ::=   RelationalExpr
9542
 *                 | EqualityExpr '=' RelationalExpr
9543
 *                 | EqualityExpr '!=' RelationalExpr
9544
 *
9545
 *  A != B != C is allowed ? Answer from James, yes with
9546
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
9547
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
9548
 *  which is basically what got implemented.
9549
 *
9550
 * Compile an Equality expression.
9551
 *
9552
 */
9553
static void
9554
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
9555
0
    xmlXPathCompRelationalExpr(ctxt);
9556
0
    CHECK_ERROR;
9557
0
    SKIP_BLANKS;
9558
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
9559
0
  int eq;
9560
0
  int op1 = ctxt->comp->last;
9561
9562
0
        if (CUR == '=') eq = 1;
9563
0
  else eq = 0;
9564
0
  NEXT;
9565
0
  if (!eq) NEXT;
9566
0
  SKIP_BLANKS;
9567
0
        xmlXPathCompRelationalExpr(ctxt);
9568
0
  CHECK_ERROR;
9569
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9570
0
  SKIP_BLANKS;
9571
0
    }
9572
0
}
9573
9574
/**
9575
 * xmlXPathCompAndExpr:
9576
 * @ctxt:  the XPath Parser context
9577
 *
9578
 *  [22]   AndExpr ::=   EqualityExpr
9579
 *                 | AndExpr 'and' EqualityExpr
9580
 *
9581
 * Compile an AND expression.
9582
 *
9583
 */
9584
static void
9585
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9586
0
    xmlXPathCompEqualityExpr(ctxt);
9587
0
    CHECK_ERROR;
9588
0
    SKIP_BLANKS;
9589
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9590
0
  int op1 = ctxt->comp->last;
9591
0
        SKIP(3);
9592
0
  SKIP_BLANKS;
9593
0
        xmlXPathCompEqualityExpr(ctxt);
9594
0
  CHECK_ERROR;
9595
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9596
0
  SKIP_BLANKS;
9597
0
    }
9598
0
}
9599
9600
/**
9601
 * xmlXPathCompileExpr:
9602
 * @ctxt:  the XPath Parser context
9603
 *
9604
 *  [14]   Expr ::=   OrExpr
9605
 *  [21]   OrExpr ::=   AndExpr
9606
 *                 | OrExpr 'or' AndExpr
9607
 *
9608
 * Parse and compile an expression
9609
 */
9610
static void
9611
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9612
0
    xmlXPathContextPtr xpctxt = ctxt->context;
9613
9614
0
    if (xpctxt != NULL) {
9615
0
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9616
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9617
        /*
9618
         * Parsing a single '(' pushes about 10 functions on the call stack
9619
         * before recursing!
9620
         */
9621
0
        xpctxt->depth += 10;
9622
0
    }
9623
9624
0
    xmlXPathCompAndExpr(ctxt);
9625
0
    CHECK_ERROR;
9626
0
    SKIP_BLANKS;
9627
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9628
0
  int op1 = ctxt->comp->last;
9629
0
        SKIP(2);
9630
0
  SKIP_BLANKS;
9631
0
        xmlXPathCompAndExpr(ctxt);
9632
0
  CHECK_ERROR;
9633
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9634
0
  SKIP_BLANKS;
9635
0
    }
9636
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9637
  /* more ops could be optimized too */
9638
  /*
9639
  * This is the main place to eliminate sorting for
9640
  * operations which don't require a sorted node-set.
9641
  * E.g. count().
9642
  */
9643
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9644
0
    }
9645
9646
0
    if (xpctxt != NULL)
9647
0
        xpctxt->depth -= 10;
9648
0
}
9649
9650
/**
9651
 * xmlXPathCompPredicate:
9652
 * @ctxt:  the XPath Parser context
9653
 * @filter:  act as a filter
9654
 *
9655
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
9656
 *  [9]   PredicateExpr ::=   Expr
9657
 *
9658
 * Compile a predicate expression
9659
 */
9660
static void
9661
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9662
0
    int op1 = ctxt->comp->last;
9663
9664
0
    SKIP_BLANKS;
9665
0
    if (CUR != '[') {
9666
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9667
0
    }
9668
0
    NEXT;
9669
0
    SKIP_BLANKS;
9670
9671
0
    ctxt->comp->last = -1;
9672
    /*
9673
    * This call to xmlXPathCompileExpr() will deactivate sorting
9674
    * of the predicate result.
9675
    * TODO: Sorting is still activated for filters, since I'm not
9676
    *  sure if needed. Normally sorting should not be needed, since
9677
    *  a filter can only diminish the number of items in a sequence,
9678
    *  but won't change its order; so if the initial sequence is sorted,
9679
    *  subsequent sorting is not needed.
9680
    */
9681
0
    if (! filter)
9682
0
  xmlXPathCompileExpr(ctxt, 0);
9683
0
    else
9684
0
  xmlXPathCompileExpr(ctxt, 1);
9685
0
    CHECK_ERROR;
9686
9687
0
    if (CUR != ']') {
9688
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9689
0
    }
9690
9691
0
    if (filter)
9692
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9693
0
    else
9694
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9695
9696
0
    NEXT;
9697
0
    SKIP_BLANKS;
9698
0
}
9699
9700
/**
9701
 * xmlXPathCompNodeTest:
9702
 * @ctxt:  the XPath Parser context
9703
 * @test:  pointer to a xmlXPathTestVal
9704
 * @type:  pointer to a xmlXPathTypeVal
9705
 * @prefix:  placeholder for a possible name prefix
9706
 *
9707
 * [7] NodeTest ::=   NameTest
9708
 *        | NodeType '(' ')'
9709
 *        | 'processing-instruction' '(' Literal ')'
9710
 *
9711
 * [37] NameTest ::=  '*'
9712
 *        | NCName ':' '*'
9713
 *        | QName
9714
 * [38] NodeType ::= 'comment'
9715
 *       | 'text'
9716
 *       | 'processing-instruction'
9717
 *       | 'node'
9718
 *
9719
 * Returns the name found and updates @test, @type and @prefix appropriately
9720
 */
9721
static xmlChar *
9722
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9723
               xmlXPathTypeVal *type, xmlChar **prefix,
9724
0
         xmlChar *name) {
9725
0
    int blanks;
9726
9727
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9728
0
  return(NULL);
9729
0
    }
9730
0
    *type = (xmlXPathTypeVal) 0;
9731
0
    *test = (xmlXPathTestVal) 0;
9732
0
    *prefix = NULL;
9733
0
    SKIP_BLANKS;
9734
9735
0
    if ((name == NULL) && (CUR == '*')) {
9736
  /*
9737
   * All elements
9738
   */
9739
0
  NEXT;
9740
0
  *test = NODE_TEST_ALL;
9741
0
  return(NULL);
9742
0
    }
9743
9744
0
    if (name == NULL)
9745
0
  name = xmlXPathParseNCName(ctxt);
9746
0
    if (name == NULL) {
9747
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9748
0
    }
9749
9750
0
    blanks = IS_BLANK_CH(CUR);
9751
0
    SKIP_BLANKS;
9752
0
    if (CUR == '(') {
9753
0
  NEXT;
9754
  /*
9755
   * NodeType or PI search
9756
   */
9757
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
9758
0
      *type = NODE_TYPE_COMMENT;
9759
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
9760
0
      *type = NODE_TYPE_NODE;
9761
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9762
0
      *type = NODE_TYPE_PI;
9763
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
9764
0
      *type = NODE_TYPE_TEXT;
9765
0
  else {
9766
0
      if (name != NULL)
9767
0
    xmlFree(name);
9768
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9769
0
  }
9770
9771
0
  *test = NODE_TEST_TYPE;
9772
9773
0
  SKIP_BLANKS;
9774
0
  if (*type == NODE_TYPE_PI) {
9775
      /*
9776
       * Specific case: search a PI by name.
9777
       */
9778
0
      if (name != NULL)
9779
0
    xmlFree(name);
9780
0
      name = NULL;
9781
0
      if (CUR != ')') {
9782
0
    name = xmlXPathParseLiteral(ctxt);
9783
0
    *test = NODE_TEST_PI;
9784
0
    SKIP_BLANKS;
9785
0
      }
9786
0
  }
9787
0
  if (CUR != ')') {
9788
0
      if (name != NULL)
9789
0
    xmlFree(name);
9790
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9791
0
  }
9792
0
  NEXT;
9793
0
  return(name);
9794
0
    }
9795
0
    *test = NODE_TEST_NAME;
9796
0
    if ((!blanks) && (CUR == ':')) {
9797
0
  NEXT;
9798
9799
  /*
9800
   * Since currently the parser context don't have a
9801
   * namespace list associated:
9802
   * The namespace name for this prefix can be computed
9803
   * only at evaluation time. The compilation is done
9804
   * outside of any context.
9805
   */
9806
0
  *prefix = name;
9807
9808
0
  if (CUR == '*') {
9809
      /*
9810
       * All elements
9811
       */
9812
0
      NEXT;
9813
0
      *test = NODE_TEST_ALL;
9814
0
      return(NULL);
9815
0
  }
9816
9817
0
  name = xmlXPathParseNCName(ctxt);
9818
0
  if (name == NULL) {
9819
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9820
0
  }
9821
0
    }
9822
0
    return(name);
9823
0
}
9824
9825
/**
9826
 * xmlXPathIsAxisName:
9827
 * @name:  a preparsed name token
9828
 *
9829
 * [6] AxisName ::=   'ancestor'
9830
 *                  | 'ancestor-or-self'
9831
 *                  | 'attribute'
9832
 *                  | 'child'
9833
 *                  | 'descendant'
9834
 *                  | 'descendant-or-self'
9835
 *                  | 'following'
9836
 *                  | 'following-sibling'
9837
 *                  | 'namespace'
9838
 *                  | 'parent'
9839
 *                  | 'preceding'
9840
 *                  | 'preceding-sibling'
9841
 *                  | 'self'
9842
 *
9843
 * Returns the axis or 0
9844
 */
9845
static xmlXPathAxisVal
9846
0
xmlXPathIsAxisName(const xmlChar *name) {
9847
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9848
0
    switch (name[0]) {
9849
0
  case 'a':
9850
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9851
0
    ret = AXIS_ANCESTOR;
9852
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9853
0
    ret = AXIS_ANCESTOR_OR_SELF;
9854
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9855
0
    ret = AXIS_ATTRIBUTE;
9856
0
      break;
9857
0
  case 'c':
9858
0
      if (xmlStrEqual(name, BAD_CAST "child"))
9859
0
    ret = AXIS_CHILD;
9860
0
      break;
9861
0
  case 'd':
9862
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9863
0
    ret = AXIS_DESCENDANT;
9864
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9865
0
    ret = AXIS_DESCENDANT_OR_SELF;
9866
0
      break;
9867
0
  case 'f':
9868
0
      if (xmlStrEqual(name, BAD_CAST "following"))
9869
0
    ret = AXIS_FOLLOWING;
9870
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9871
0
    ret = AXIS_FOLLOWING_SIBLING;
9872
0
      break;
9873
0
  case 'n':
9874
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9875
0
    ret = AXIS_NAMESPACE;
9876
0
      break;
9877
0
  case 'p':
9878
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
9879
0
    ret = AXIS_PARENT;
9880
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9881
0
    ret = AXIS_PRECEDING;
9882
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9883
0
    ret = AXIS_PRECEDING_SIBLING;
9884
0
      break;
9885
0
  case 's':
9886
0
      if (xmlStrEqual(name, BAD_CAST "self"))
9887
0
    ret = AXIS_SELF;
9888
0
      break;
9889
0
    }
9890
0
    return(ret);
9891
0
}
9892
9893
/**
9894
 * xmlXPathCompStep:
9895
 * @ctxt:  the XPath Parser context
9896
 *
9897
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
9898
 *                  | AbbreviatedStep
9899
 *
9900
 * [12] AbbreviatedStep ::=   '.' | '..'
9901
 *
9902
 * [5] AxisSpecifier ::= AxisName '::'
9903
 *                  | AbbreviatedAxisSpecifier
9904
 *
9905
 * [13] AbbreviatedAxisSpecifier ::= '@'?
9906
 *
9907
 * Modified for XPtr range support as:
9908
 *
9909
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9910
 *                     | AbbreviatedStep
9911
 *                     | 'range-to' '(' Expr ')' Predicate*
9912
 *
9913
 * Compile one step in a Location Path
9914
 * A location step of . is short for self::node(). This is
9915
 * particularly useful in conjunction with //. For example, the
9916
 * location path .//para is short for
9917
 * self::node()/descendant-or-self::node()/child::para
9918
 * and so will select all para descendant elements of the context
9919
 * node.
9920
 * Similarly, a location step of .. is short for parent::node().
9921
 * For example, ../title is short for parent::node()/child::title
9922
 * and so will select the title children of the parent of the context
9923
 * node.
9924
 */
9925
static void
9926
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9927
0
    SKIP_BLANKS;
9928
0
    if ((CUR == '.') && (NXT(1) == '.')) {
9929
0
  SKIP(2);
9930
0
  SKIP_BLANKS;
9931
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9932
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9933
0
    } else if (CUR == '.') {
9934
0
  NEXT;
9935
0
  SKIP_BLANKS;
9936
0
    } else {
9937
0
  xmlChar *name = NULL;
9938
0
  xmlChar *prefix = NULL;
9939
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9940
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9941
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9942
0
  int op1;
9943
9944
0
  if (CUR == '*') {
9945
0
      axis = AXIS_CHILD;
9946
0
  } else {
9947
0
      if (name == NULL)
9948
0
    name = xmlXPathParseNCName(ctxt);
9949
0
      if (name != NULL) {
9950
0
    axis = xmlXPathIsAxisName(name);
9951
0
    if (axis != 0) {
9952
0
        SKIP_BLANKS;
9953
0
        if ((CUR == ':') && (NXT(1) == ':')) {
9954
0
      SKIP(2);
9955
0
      xmlFree(name);
9956
0
      name = NULL;
9957
0
        } else {
9958
      /* an element name can conflict with an axis one :-\ */
9959
0
      axis = AXIS_CHILD;
9960
0
        }
9961
0
    } else {
9962
0
        axis = AXIS_CHILD;
9963
0
    }
9964
0
      } else if (CUR == '@') {
9965
0
    NEXT;
9966
0
    axis = AXIS_ATTRIBUTE;
9967
0
      } else {
9968
0
    axis = AXIS_CHILD;
9969
0
      }
9970
0
  }
9971
9972
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9973
0
            xmlFree(name);
9974
0
            return;
9975
0
        }
9976
9977
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9978
0
  if (test == 0)
9979
0
      return;
9980
9981
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9982
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9983
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9984
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
9985
0
      }
9986
0
  }
9987
9988
0
  op1 = ctxt->comp->last;
9989
0
  ctxt->comp->last = -1;
9990
9991
0
  SKIP_BLANKS;
9992
0
  while (CUR == '[') {
9993
0
      xmlXPathCompPredicate(ctxt, 0);
9994
0
  }
9995
9996
0
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9997
0
                           test, type, (void *)prefix, (void *)name) == -1) {
9998
0
            xmlFree(prefix);
9999
0
            xmlFree(name);
10000
0
        }
10001
0
    }
10002
0
}
10003
10004
/**
10005
 * xmlXPathCompRelativeLocationPath:
10006
 * @ctxt:  the XPath Parser context
10007
 *
10008
 *  [3]   RelativeLocationPath ::=   Step
10009
 *                     | RelativeLocationPath '/' Step
10010
 *                     | AbbreviatedRelativeLocationPath
10011
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
10012
 *
10013
 * Compile a relative location path.
10014
 */
10015
static void
10016
xmlXPathCompRelativeLocationPath
10017
0
(xmlXPathParserContextPtr ctxt) {
10018
0
    SKIP_BLANKS;
10019
0
    if ((CUR == '/') && (NXT(1) == '/')) {
10020
0
  SKIP(2);
10021
0
  SKIP_BLANKS;
10022
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10023
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10024
0
    } else if (CUR == '/') {
10025
0
      NEXT;
10026
0
  SKIP_BLANKS;
10027
0
    }
10028
0
    xmlXPathCompStep(ctxt);
10029
0
    CHECK_ERROR;
10030
0
    SKIP_BLANKS;
10031
0
    while (CUR == '/') {
10032
0
  if ((CUR == '/') && (NXT(1) == '/')) {
10033
0
      SKIP(2);
10034
0
      SKIP_BLANKS;
10035
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10036
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10037
0
      xmlXPathCompStep(ctxt);
10038
0
  } else if (CUR == '/') {
10039
0
      NEXT;
10040
0
      SKIP_BLANKS;
10041
0
      xmlXPathCompStep(ctxt);
10042
0
  }
10043
0
  SKIP_BLANKS;
10044
0
    }
10045
0
}
10046
10047
/**
10048
 * xmlXPathCompLocationPath:
10049
 * @ctxt:  the XPath Parser context
10050
 *
10051
 *  [1]   LocationPath ::=   RelativeLocationPath
10052
 *                     | AbsoluteLocationPath
10053
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
10054
 *                     | AbbreviatedAbsoluteLocationPath
10055
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
10056
 *                           '//' RelativeLocationPath
10057
 *
10058
 * Compile a location path
10059
 *
10060
 * // is short for /descendant-or-self::node()/. For example,
10061
 * //para is short for /descendant-or-self::node()/child::para and
10062
 * so will select any para element in the document (even a para element
10063
 * that is a document element will be selected by //para since the
10064
 * document element node is a child of the root node); div//para is
10065
 * short for div/descendant-or-self::node()/child::para and so will
10066
 * select all para descendants of div children.
10067
 */
10068
static void
10069
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10070
0
    SKIP_BLANKS;
10071
0
    if (CUR != '/') {
10072
0
        xmlXPathCompRelativeLocationPath(ctxt);
10073
0
    } else {
10074
0
  while (CUR == '/') {
10075
0
      if ((CUR == '/') && (NXT(1) == '/')) {
10076
0
    SKIP(2);
10077
0
    SKIP_BLANKS;
10078
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10079
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10080
0
    xmlXPathCompRelativeLocationPath(ctxt);
10081
0
      } else if (CUR == '/') {
10082
0
    NEXT;
10083
0
    SKIP_BLANKS;
10084
0
    if ((CUR != 0 ) &&
10085
0
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10086
0
         (CUR == '@') || (CUR == '*')))
10087
0
        xmlXPathCompRelativeLocationPath(ctxt);
10088
0
      }
10089
0
      CHECK_ERROR;
10090
0
  }
10091
0
    }
10092
0
}
10093
10094
/************************************************************************
10095
 *                  *
10096
 *    XPath precompiled expression evaluation     *
10097
 *                  *
10098
 ************************************************************************/
10099
10100
static int
10101
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10102
10103
/**
10104
 * xmlXPathNodeSetFilter:
10105
 * @ctxt:  the XPath Parser context
10106
 * @set: the node set to filter
10107
 * @filterOpIndex: the index of the predicate/filter op
10108
 * @minPos: minimum position in the filtered set (1-based)
10109
 * @maxPos: maximum position in the filtered set (1-based)
10110
 * @hasNsNodes: true if the node set may contain namespace nodes
10111
 *
10112
 * Filter a node set, keeping only nodes for which the predicate expression
10113
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10114
 * filtered result.
10115
 */
10116
static void
10117
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10118
          xmlNodeSetPtr set,
10119
          int filterOpIndex,
10120
                      int minPos, int maxPos,
10121
          int hasNsNodes)
10122
0
{
10123
0
    xmlXPathContextPtr xpctxt;
10124
0
    xmlNodePtr oldnode;
10125
0
    xmlDocPtr olddoc;
10126
0
    xmlXPathStepOpPtr filterOp;
10127
0
    int oldcs, oldpp;
10128
0
    int i, j, pos;
10129
10130
0
    if ((set == NULL) || (set->nodeNr == 0))
10131
0
        return;
10132
10133
    /*
10134
    * Check if the node set contains a sufficient number of nodes for
10135
    * the requested range.
10136
    */
10137
0
    if (set->nodeNr < minPos) {
10138
0
        xmlXPathNodeSetClear(set, hasNsNodes);
10139
0
        return;
10140
0
    }
10141
10142
0
    xpctxt = ctxt->context;
10143
0
    oldnode = xpctxt->node;
10144
0
    olddoc = xpctxt->doc;
10145
0
    oldcs = xpctxt->contextSize;
10146
0
    oldpp = xpctxt->proximityPosition;
10147
0
    filterOp = &ctxt->comp->steps[filterOpIndex];
10148
10149
0
    xpctxt->contextSize = set->nodeNr;
10150
10151
0
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10152
0
        xmlNodePtr node = set->nodeTab[i];
10153
0
        int res;
10154
10155
0
        xpctxt->node = node;
10156
0
        xpctxt->proximityPosition = i + 1;
10157
10158
        /*
10159
        * Also set the xpath document in case things like
10160
        * key() are evaluated in the predicate.
10161
        *
10162
        * TODO: Get real doc for namespace nodes.
10163
        */
10164
0
        if ((node->type != XML_NAMESPACE_DECL) &&
10165
0
            (node->doc != NULL))
10166
0
            xpctxt->doc = node->doc;
10167
10168
0
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10169
10170
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
10171
0
            break;
10172
0
        if (res < 0) {
10173
            /* Shouldn't happen */
10174
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10175
0
            break;
10176
0
        }
10177
10178
0
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10179
0
            if (i != j) {
10180
0
                set->nodeTab[j] = node;
10181
0
                set->nodeTab[i] = NULL;
10182
0
            }
10183
10184
0
            j += 1;
10185
0
        } else {
10186
            /* Remove the entry from the initial node set. */
10187
0
            set->nodeTab[i] = NULL;
10188
0
            if (node->type == XML_NAMESPACE_DECL)
10189
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10190
0
        }
10191
10192
0
        if (res != 0) {
10193
0
            if (pos == maxPos) {
10194
0
                i += 1;
10195
0
                break;
10196
0
            }
10197
10198
0
            pos += 1;
10199
0
        }
10200
0
    }
10201
10202
    /* Free remaining nodes. */
10203
0
    if (hasNsNodes) {
10204
0
        for (; i < set->nodeNr; i++) {
10205
0
            xmlNodePtr node = set->nodeTab[i];
10206
0
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10207
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10208
0
        }
10209
0
    }
10210
10211
0
    set->nodeNr = j;
10212
10213
    /* If too many elements were removed, shrink table to preserve memory. */
10214
0
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10215
0
        (set->nodeNr < set->nodeMax / 2)) {
10216
0
        xmlNodePtr *tmp;
10217
0
        int nodeMax = set->nodeNr;
10218
10219
0
        if (nodeMax < XML_NODESET_DEFAULT)
10220
0
            nodeMax = XML_NODESET_DEFAULT;
10221
0
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10222
0
                nodeMax * sizeof(xmlNodePtr));
10223
0
        if (tmp == NULL) {
10224
0
            xmlXPathPErrMemory(ctxt);
10225
0
        } else {
10226
0
            set->nodeTab = tmp;
10227
0
            set->nodeMax = nodeMax;
10228
0
        }
10229
0
    }
10230
10231
0
    xpctxt->node = oldnode;
10232
0
    xpctxt->doc = olddoc;
10233
0
    xpctxt->contextSize = oldcs;
10234
0
    xpctxt->proximityPosition = oldpp;
10235
0
}
10236
10237
/**
10238
 * xmlXPathCompOpEvalPredicate:
10239
 * @ctxt:  the XPath Parser context
10240
 * @op: the predicate op
10241
 * @set: the node set to filter
10242
 * @minPos: minimum position in the filtered set (1-based)
10243
 * @maxPos: maximum position in the filtered set (1-based)
10244
 * @hasNsNodes: true if the node set may contain namespace nodes
10245
 *
10246
 * Filter a node set, keeping only nodes for which the sequence of predicate
10247
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10248
 * in the filtered result.
10249
 */
10250
static void
10251
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
10252
          xmlXPathStepOpPtr op,
10253
          xmlNodeSetPtr set,
10254
                            int minPos, int maxPos,
10255
          int hasNsNodes)
10256
0
{
10257
0
    if (op->ch1 != -1) {
10258
0
  xmlXPathCompExprPtr comp = ctxt->comp;
10259
  /*
10260
  * Process inner predicates first.
10261
  */
10262
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
10263
0
            XP_ERROR(XPATH_INVALID_OPERAND);
10264
0
  }
10265
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10266
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10267
0
        ctxt->context->depth += 1;
10268
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
10269
0
                                    1, set->nodeNr, hasNsNodes);
10270
0
        ctxt->context->depth -= 1;
10271
0
  CHECK_ERROR;
10272
0
    }
10273
10274
0
    if (op->ch2 != -1)
10275
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
10276
0
}
10277
10278
static int
10279
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
10280
          xmlXPathStepOpPtr op,
10281
          int *maxPos)
10282
0
{
10283
10284
0
    xmlXPathStepOpPtr exprOp;
10285
10286
    /*
10287
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
10288
    */
10289
10290
    /*
10291
    * If not -1, then ch1 will point to:
10292
    * 1) For predicates (XPATH_OP_PREDICATE):
10293
    *    - an inner predicate operator
10294
    * 2) For filters (XPATH_OP_FILTER):
10295
    *    - an inner filter operator OR
10296
    *    - an expression selecting the node set.
10297
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
10298
    */
10299
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
10300
0
  return(0);
10301
10302
0
    if (op->ch2 != -1) {
10303
0
  exprOp = &ctxt->comp->steps[op->ch2];
10304
0
    } else
10305
0
  return(0);
10306
10307
0
    if ((exprOp != NULL) &&
10308
0
  (exprOp->op == XPATH_OP_VALUE) &&
10309
0
  (exprOp->value4 != NULL) &&
10310
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
10311
0
    {
10312
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
10313
10314
  /*
10315
  * We have a "[n]" predicate here.
10316
  * TODO: Unfortunately this simplistic test here is not
10317
  * able to detect a position() predicate in compound
10318
  * expressions like "[@attr = 'a" and position() = 1],
10319
  * and even not the usage of position() in
10320
  * "[position() = 1]"; thus - obviously - a position-range,
10321
  * like it "[position() < 5]", is also not detected.
10322
  * Maybe we could rewrite the AST to ease the optimization.
10323
  */
10324
10325
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
10326
0
      *maxPos = (int) floatval;
10327
0
            if (floatval == (double) *maxPos)
10328
0
                return(1);
10329
0
        }
10330
0
    }
10331
0
    return(0);
10332
0
}
10333
10334
static int
10335
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
10336
                           xmlXPathStepOpPtr op,
10337
         xmlNodePtr * first, xmlNodePtr * last,
10338
         int toBool)
10339
0
{
10340
10341
0
#define XP_TEST_HIT \
10342
0
    if (hasAxisRange != 0) { \
10343
0
  if (++pos == maxPos) { \
10344
0
      if (addNode(seq, cur) < 0) \
10345
0
          xmlXPathPErrMemory(ctxt); \
10346
0
      goto axis_range_end; } \
10347
0
    } else { \
10348
0
  if (addNode(seq, cur) < 0) \
10349
0
      xmlXPathPErrMemory(ctxt); \
10350
0
  if (breakOnFirstHit) goto first_hit; }
10351
10352
0
#define XP_TEST_HIT_NS \
10353
0
    if (hasAxisRange != 0) { \
10354
0
  if (++pos == maxPos) { \
10355
0
      hasNsNodes = 1; \
10356
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10357
0
          xmlXPathPErrMemory(ctxt); \
10358
0
  goto axis_range_end; } \
10359
0
    } else { \
10360
0
  hasNsNodes = 1; \
10361
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
10362
0
      xmlXPathPErrMemory(ctxt); \
10363
0
  if (breakOnFirstHit) goto first_hit; }
10364
10365
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
10366
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
10367
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
10368
0
    const xmlChar *prefix = op->value4;
10369
0
    const xmlChar *name = op->value5;
10370
0
    const xmlChar *URI = NULL;
10371
10372
0
    int total = 0, hasNsNodes = 0;
10373
    /* The popped object holding the context nodes */
10374
0
    xmlXPathObjectPtr obj;
10375
    /* The set of context nodes for the node tests */
10376
0
    xmlNodeSetPtr contextSeq;
10377
0
    int contextIdx;
10378
0
    xmlNodePtr contextNode;
10379
    /* The final resulting node set wrt to all context nodes */
10380
0
    xmlNodeSetPtr outSeq;
10381
    /*
10382
    * The temporary resulting node set wrt 1 context node.
10383
    * Used to feed predicate evaluation.
10384
    */
10385
0
    xmlNodeSetPtr seq;
10386
0
    xmlNodePtr cur;
10387
    /* First predicate operator */
10388
0
    xmlXPathStepOpPtr predOp;
10389
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
10390
0
    int hasPredicateRange, hasAxisRange, pos;
10391
0
    int breakOnFirstHit;
10392
10393
0
    xmlXPathTraversalFunction next = NULL;
10394
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
10395
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
10396
0
    xmlNodePtr oldContextNode;
10397
0
    xmlXPathContextPtr xpctxt = ctxt->context;
10398
10399
10400
0
    CHECK_TYPE0(XPATH_NODESET);
10401
0
    obj = valuePop(ctxt);
10402
    /*
10403
    * Setup namespaces.
10404
    */
10405
0
    if (prefix != NULL) {
10406
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
10407
0
        if (URI == NULL) {
10408
0
      xmlXPathReleaseObject(xpctxt, obj);
10409
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10410
0
  }
10411
0
    }
10412
    /*
10413
    * Setup axis.
10414
    *
10415
    * MAYBE FUTURE TODO: merging optimizations:
10416
    * - If the nodes to be traversed wrt to the initial nodes and
10417
    *   the current axis cannot overlap, then we could avoid searching
10418
    *   for duplicates during the merge.
10419
    *   But the question is how/when to evaluate if they cannot overlap.
10420
    *   Example: if we know that for two initial nodes, the one is
10421
    *   not in the ancestor-or-self axis of the other, then we could safely
10422
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
10423
    *   the descendant-or-self axis.
10424
    */
10425
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
10426
0
    switch (axis) {
10427
0
        case AXIS_ANCESTOR:
10428
0
            first = NULL;
10429
0
            next = xmlXPathNextAncestor;
10430
0
            break;
10431
0
        case AXIS_ANCESTOR_OR_SELF:
10432
0
            first = NULL;
10433
0
            next = xmlXPathNextAncestorOrSelf;
10434
0
            break;
10435
0
        case AXIS_ATTRIBUTE:
10436
0
            first = NULL;
10437
0
      last = NULL;
10438
0
            next = xmlXPathNextAttribute;
10439
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10440
0
            break;
10441
0
        case AXIS_CHILD:
10442
0
      last = NULL;
10443
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
10444
0
    (type == NODE_TYPE_NODE))
10445
0
      {
10446
    /*
10447
    * Optimization if an element node type is 'element'.
10448
    */
10449
0
    next = xmlXPathNextChildElement;
10450
0
      } else
10451
0
    next = xmlXPathNextChild;
10452
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10453
0
            break;
10454
0
        case AXIS_DESCENDANT:
10455
0
      last = NULL;
10456
0
            next = xmlXPathNextDescendant;
10457
0
            break;
10458
0
        case AXIS_DESCENDANT_OR_SELF:
10459
0
      last = NULL;
10460
0
            next = xmlXPathNextDescendantOrSelf;
10461
0
            break;
10462
0
        case AXIS_FOLLOWING:
10463
0
      last = NULL;
10464
0
            next = xmlXPathNextFollowing;
10465
0
            break;
10466
0
        case AXIS_FOLLOWING_SIBLING:
10467
0
      last = NULL;
10468
0
            next = xmlXPathNextFollowingSibling;
10469
0
            break;
10470
0
        case AXIS_NAMESPACE:
10471
0
            first = NULL;
10472
0
      last = NULL;
10473
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
10474
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10475
0
            break;
10476
0
        case AXIS_PARENT:
10477
0
            first = NULL;
10478
0
            next = xmlXPathNextParent;
10479
0
            break;
10480
0
        case AXIS_PRECEDING:
10481
0
            first = NULL;
10482
0
            next = xmlXPathNextPrecedingInternal;
10483
0
            break;
10484
0
        case AXIS_PRECEDING_SIBLING:
10485
0
            first = NULL;
10486
0
            next = xmlXPathNextPrecedingSibling;
10487
0
            break;
10488
0
        case AXIS_SELF:
10489
0
            first = NULL;
10490
0
      last = NULL;
10491
0
            next = xmlXPathNextSelf;
10492
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
10493
0
            break;
10494
0
    }
10495
10496
0
    if (next == NULL) {
10497
0
  xmlXPathReleaseObject(xpctxt, obj);
10498
0
        return(0);
10499
0
    }
10500
0
    contextSeq = obj->nodesetval;
10501
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
10502
0
        valuePush(ctxt, obj);
10503
0
        return(0);
10504
0
    }
10505
    /*
10506
    * Predicate optimization ---------------------------------------------
10507
    * If this step has a last predicate, which contains a position(),
10508
    * then we'll optimize (although not exactly "position()", but only
10509
    * the  short-hand form, i.e., "[n]".
10510
    *
10511
    * Example - expression "/foo[parent::bar][1]":
10512
    *
10513
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
10514
    *   ROOT                               -- op->ch1
10515
    *   PREDICATE                          -- op->ch2 (predOp)
10516
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
10517
    *       SORT
10518
    *         COLLECT  'parent' 'name' 'node' bar
10519
    *           NODE
10520
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
10521
    *
10522
    */
10523
0
    maxPos = 0;
10524
0
    predOp = NULL;
10525
0
    hasPredicateRange = 0;
10526
0
    hasAxisRange = 0;
10527
0
    if (op->ch2 != -1) {
10528
  /*
10529
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
10530
  */
10531
0
  predOp = &ctxt->comp->steps[op->ch2];
10532
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
10533
0
      if (predOp->ch1 != -1) {
10534
    /*
10535
    * Use the next inner predicate operator.
10536
    */
10537
0
    predOp = &ctxt->comp->steps[predOp->ch1];
10538
0
    hasPredicateRange = 1;
10539
0
      } else {
10540
    /*
10541
    * There's no other predicate than the [n] predicate.
10542
    */
10543
0
    predOp = NULL;
10544
0
    hasAxisRange = 1;
10545
0
      }
10546
0
  }
10547
0
    }
10548
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
10549
    /*
10550
    * Axis traversal -----------------------------------------------------
10551
    */
10552
    /*
10553
     * 2.3 Node Tests
10554
     *  - For the attribute axis, the principal node type is attribute.
10555
     *  - For the namespace axis, the principal node type is namespace.
10556
     *  - For other axes, the principal node type is element.
10557
     *
10558
     * A node test * is true for any node of the
10559
     * principal node type. For example, child::* will
10560
     * select all element children of the context node
10561
     */
10562
0
    oldContextNode = xpctxt->node;
10563
0
    addNode = xmlXPathNodeSetAddUnique;
10564
0
    outSeq = NULL;
10565
0
    seq = NULL;
10566
0
    contextNode = NULL;
10567
0
    contextIdx = 0;
10568
10569
10570
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
10571
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
10572
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
10573
10574
0
  if (seq == NULL) {
10575
0
      seq = xmlXPathNodeSetCreate(NULL);
10576
0
      if (seq == NULL) {
10577
0
                xmlXPathPErrMemory(ctxt);
10578
0
    total = 0;
10579
0
    goto error;
10580
0
      }
10581
0
  }
10582
  /*
10583
  * Traverse the axis and test the nodes.
10584
  */
10585
0
  pos = 0;
10586
0
  cur = NULL;
10587
0
  hasNsNodes = 0;
10588
0
        do {
10589
0
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
10590
0
                goto error;
10591
10592
0
            cur = next(ctxt, cur);
10593
0
            if (cur == NULL)
10594
0
                break;
10595
10596
      /*
10597
      * QUESTION TODO: What does the "first" and "last" stuff do?
10598
      */
10599
0
            if ((first != NULL) && (*first != NULL)) {
10600
0
    if (*first == cur)
10601
0
        break;
10602
0
    if (((total % 256) == 0) &&
10603
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10604
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10605
#else
10606
        (xmlXPathCmpNodes(*first, cur) >= 0))
10607
#endif
10608
0
    {
10609
0
        break;
10610
0
    }
10611
0
      }
10612
0
      if ((last != NULL) && (*last != NULL)) {
10613
0
    if (*last == cur)
10614
0
        break;
10615
0
    if (((total % 256) == 0) &&
10616
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10617
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10618
#else
10619
        (xmlXPathCmpNodes(cur, *last) >= 0))
10620
#endif
10621
0
    {
10622
0
        break;
10623
0
    }
10624
0
      }
10625
10626
0
            total++;
10627
10628
0
      switch (test) {
10629
0
                case NODE_TEST_NONE:
10630
0
        total = 0;
10631
0
        goto error;
10632
0
                case NODE_TEST_TYPE:
10633
0
        if (type == NODE_TYPE_NODE) {
10634
0
      switch (cur->type) {
10635
0
          case XML_DOCUMENT_NODE:
10636
0
          case XML_HTML_DOCUMENT_NODE:
10637
0
          case XML_ELEMENT_NODE:
10638
0
          case XML_ATTRIBUTE_NODE:
10639
0
          case XML_PI_NODE:
10640
0
          case XML_COMMENT_NODE:
10641
0
          case XML_CDATA_SECTION_NODE:
10642
0
          case XML_TEXT_NODE:
10643
0
        XP_TEST_HIT
10644
0
        break;
10645
0
          case XML_NAMESPACE_DECL: {
10646
0
        if (axis == AXIS_NAMESPACE) {
10647
0
            XP_TEST_HIT_NS
10648
0
        } else {
10649
0
                              hasNsNodes = 1;
10650
0
            XP_TEST_HIT
10651
0
        }
10652
0
        break;
10653
0
                            }
10654
0
          default:
10655
0
        break;
10656
0
      }
10657
0
        } else if (cur->type == (xmlElementType) type) {
10658
0
      if (cur->type == XML_NAMESPACE_DECL)
10659
0
          XP_TEST_HIT_NS
10660
0
      else
10661
0
          XP_TEST_HIT
10662
0
        } else if ((type == NODE_TYPE_TEXT) &&
10663
0
       (cur->type == XML_CDATA_SECTION_NODE))
10664
0
        {
10665
0
      XP_TEST_HIT
10666
0
        }
10667
0
        break;
10668
0
                case NODE_TEST_PI:
10669
0
                    if ((cur->type == XML_PI_NODE) &&
10670
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10671
0
        {
10672
0
      XP_TEST_HIT
10673
0
                    }
10674
0
                    break;
10675
0
                case NODE_TEST_ALL:
10676
0
                    if (axis == AXIS_ATTRIBUTE) {
10677
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
10678
0
      {
10679
0
                            if (prefix == NULL)
10680
0
          {
10681
0
        XP_TEST_HIT
10682
0
                            } else if ((cur->ns != NULL) &&
10683
0
        (xmlStrEqual(URI, cur->ns->href)))
10684
0
          {
10685
0
        XP_TEST_HIT
10686
0
                            }
10687
0
                        }
10688
0
                    } else if (axis == AXIS_NAMESPACE) {
10689
0
                        if (cur->type == XML_NAMESPACE_DECL)
10690
0
      {
10691
0
          XP_TEST_HIT_NS
10692
0
                        }
10693
0
                    } else {
10694
0
                        if (cur->type == XML_ELEMENT_NODE) {
10695
0
                            if (prefix == NULL)
10696
0
          {
10697
0
        XP_TEST_HIT
10698
10699
0
                            } else if ((cur->ns != NULL) &&
10700
0
        (xmlStrEqual(URI, cur->ns->href)))
10701
0
          {
10702
0
        XP_TEST_HIT
10703
0
                            }
10704
0
                        }
10705
0
                    }
10706
0
                    break;
10707
0
                case NODE_TEST_NS:{
10708
                        /* TODO */
10709
0
                        break;
10710
0
                    }
10711
0
                case NODE_TEST_NAME:
10712
0
                    if (axis == AXIS_ATTRIBUTE) {
10713
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
10714
0
          break;
10715
0
        } else if (axis == AXIS_NAMESPACE) {
10716
0
                        if (cur->type != XML_NAMESPACE_DECL)
10717
0
          break;
10718
0
        } else {
10719
0
            if (cur->type != XML_ELEMENT_NODE)
10720
0
          break;
10721
0
        }
10722
0
                    switch (cur->type) {
10723
0
                        case XML_ELEMENT_NODE:
10724
0
                            if (xmlStrEqual(name, cur->name)) {
10725
0
                                if (prefix == NULL) {
10726
0
                                    if (cur->ns == NULL)
10727
0
            {
10728
0
          XP_TEST_HIT
10729
0
                                    }
10730
0
                                } else {
10731
0
                                    if ((cur->ns != NULL) &&
10732
0
                                        (xmlStrEqual(URI, cur->ns->href)))
10733
0
            {
10734
0
          XP_TEST_HIT
10735
0
                                    }
10736
0
                                }
10737
0
                            }
10738
0
                            break;
10739
0
                        case XML_ATTRIBUTE_NODE:{
10740
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10741
10742
0
                                if (xmlStrEqual(name, attr->name)) {
10743
0
                                    if (prefix == NULL) {
10744
0
                                        if ((attr->ns == NULL) ||
10745
0
                                            (attr->ns->prefix == NULL))
10746
0
          {
10747
0
              XP_TEST_HIT
10748
0
                                        }
10749
0
                                    } else {
10750
0
                                        if ((attr->ns != NULL) &&
10751
0
                                            (xmlStrEqual(URI,
10752
0
                attr->ns->href)))
10753
0
          {
10754
0
              XP_TEST_HIT
10755
0
                                        }
10756
0
                                    }
10757
0
                                }
10758
0
                                break;
10759
0
                            }
10760
0
                        case XML_NAMESPACE_DECL:
10761
0
                            if (cur->type == XML_NAMESPACE_DECL) {
10762
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
10763
10764
0
                                if ((ns->prefix != NULL) && (name != NULL)
10765
0
                                    && (xmlStrEqual(ns->prefix, name)))
10766
0
        {
10767
0
            XP_TEST_HIT_NS
10768
0
                                }
10769
0
                            }
10770
0
                            break;
10771
0
                        default:
10772
0
                            break;
10773
0
                    }
10774
0
                    break;
10775
0
      } /* switch(test) */
10776
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10777
10778
0
  goto apply_predicates;
10779
10780
0
axis_range_end: /* ----------------------------------------------------- */
10781
  /*
10782
  * We have a "/foo[n]", and position() = n was reached.
10783
  * Note that we can have as well "/foo/::parent::foo[1]", so
10784
  * a duplicate-aware merge is still needed.
10785
  * Merge with the result.
10786
  */
10787
0
  if (outSeq == NULL) {
10788
0
      outSeq = seq;
10789
0
      seq = NULL;
10790
0
  } else {
10791
0
      outSeq = mergeAndClear(outSeq, seq);
10792
0
            if (outSeq == NULL)
10793
0
                xmlXPathPErrMemory(ctxt);
10794
0
        }
10795
  /*
10796
  * Break if only a true/false result was requested.
10797
  */
10798
0
  if (toBool)
10799
0
      break;
10800
0
  continue;
10801
10802
0
first_hit: /* ---------------------------------------------------------- */
10803
  /*
10804
  * Break if only a true/false result was requested and
10805
  * no predicates existed and a node test succeeded.
10806
  */
10807
0
  if (outSeq == NULL) {
10808
0
      outSeq = seq;
10809
0
      seq = NULL;
10810
0
  } else {
10811
0
      outSeq = mergeAndClear(outSeq, seq);
10812
0
            if (outSeq == NULL)
10813
0
                xmlXPathPErrMemory(ctxt);
10814
0
        }
10815
0
  break;
10816
10817
0
apply_predicates: /* --------------------------------------------------- */
10818
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
10819
0
      goto error;
10820
10821
        /*
10822
  * Apply predicates.
10823
  */
10824
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
10825
      /*
10826
      * E.g. when we have a "/foo[some expression][n]".
10827
      */
10828
      /*
10829
      * QUESTION TODO: The old predicate evaluation took into
10830
      *  account location-sets.
10831
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10832
      *  Do we expect such a set here?
10833
      *  All what I learned now from the evaluation semantics
10834
      *  does not indicate that a location-set will be processed
10835
      *  here, so this looks OK.
10836
      */
10837
      /*
10838
      * Iterate over all predicates, starting with the outermost
10839
      * predicate.
10840
      * TODO: Problem: we cannot execute the inner predicates first
10841
      *  since we cannot go back *up* the operator tree!
10842
      *  Options we have:
10843
      *  1) Use of recursive functions (like is it currently done
10844
      *     via xmlXPathCompOpEval())
10845
      *  2) Add a predicate evaluation information stack to the
10846
      *     context struct
10847
      *  3) Change the way the operators are linked; we need a
10848
      *     "parent" field on xmlXPathStepOp
10849
      *
10850
      * For the moment, I'll try to solve this with a recursive
10851
      * function: xmlXPathCompOpEvalPredicate().
10852
      */
10853
0
      if (hasPredicateRange != 0)
10854
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10855
0
              hasNsNodes);
10856
0
      else
10857
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10858
0
              hasNsNodes);
10859
10860
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10861
0
    total = 0;
10862
0
    goto error;
10863
0
      }
10864
0
        }
10865
10866
0
        if (seq->nodeNr > 0) {
10867
      /*
10868
      * Add to result set.
10869
      */
10870
0
      if (outSeq == NULL) {
10871
0
    outSeq = seq;
10872
0
    seq = NULL;
10873
0
      } else {
10874
0
    outSeq = mergeAndClear(outSeq, seq);
10875
0
                if (outSeq == NULL)
10876
0
                    xmlXPathPErrMemory(ctxt);
10877
0
      }
10878
10879
0
            if (toBool)
10880
0
                break;
10881
0
  }
10882
0
    }
10883
10884
0
error:
10885
0
    if ((obj->boolval) && (obj->user != NULL)) {
10886
  /*
10887
  * QUESTION TODO: What does this do and why?
10888
  * TODO: Do we have to do this also for the "error"
10889
  * cleanup further down?
10890
  */
10891
0
  ctxt->value->boolval = 1;
10892
0
  ctxt->value->user = obj->user;
10893
0
  obj->user = NULL;
10894
0
  obj->boolval = 0;
10895
0
    }
10896
0
    xmlXPathReleaseObject(xpctxt, obj);
10897
10898
    /*
10899
    * Ensure we return at least an empty set.
10900
    */
10901
0
    if (outSeq == NULL) {
10902
0
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10903
0
      outSeq = seq;
10904
0
        } else {
10905
0
      outSeq = xmlXPathNodeSetCreate(NULL);
10906
0
            if (outSeq == NULL)
10907
0
                xmlXPathPErrMemory(ctxt);
10908
0
        }
10909
0
    }
10910
0
    if ((seq != NULL) && (seq != outSeq)) {
10911
0
   xmlXPathFreeNodeSet(seq);
10912
0
    }
10913
    /*
10914
    * Hand over the result. Better to push the set also in
10915
    * case of errors.
10916
    */
10917
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10918
    /*
10919
    * Reset the context node.
10920
    */
10921
0
    xpctxt->node = oldContextNode;
10922
    /*
10923
    * When traversing the namespace axis in "toBool" mode, it's
10924
    * possible that tmpNsList wasn't freed.
10925
    */
10926
0
    if (xpctxt->tmpNsList != NULL) {
10927
0
        xmlFree(xpctxt->tmpNsList);
10928
0
        xpctxt->tmpNsList = NULL;
10929
0
    }
10930
10931
0
    return(total);
10932
0
}
10933
10934
static int
10935
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10936
            xmlXPathStepOpPtr op, xmlNodePtr * first);
10937
10938
/**
10939
 * xmlXPathCompOpEvalFirst:
10940
 * @ctxt:  the XPath parser context with the compiled expression
10941
 * @op:  an XPath compiled operation
10942
 * @first:  the first elem found so far
10943
 *
10944
 * Evaluate the Precompiled XPath operation searching only the first
10945
 * element in document order
10946
 *
10947
 * Returns the number of examined objects.
10948
 */
10949
static int
10950
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10951
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
10952
0
{
10953
0
    int total = 0, cur;
10954
0
    xmlXPathCompExprPtr comp;
10955
0
    xmlXPathObjectPtr arg1, arg2;
10956
10957
0
    CHECK_ERROR0;
10958
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10959
0
        return(0);
10960
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10961
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10962
0
    ctxt->context->depth += 1;
10963
0
    comp = ctxt->comp;
10964
0
    switch (op->op) {
10965
0
        case XPATH_OP_END:
10966
0
            break;
10967
0
        case XPATH_OP_UNION:
10968
0
            total =
10969
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10970
0
                                        first);
10971
0
      CHECK_ERROR0;
10972
0
            if ((ctxt->value != NULL)
10973
0
                && (ctxt->value->type == XPATH_NODESET)
10974
0
                && (ctxt->value->nodesetval != NULL)
10975
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10976
                /*
10977
                 * limit tree traversing to first node in the result
10978
                 */
10979
    /*
10980
    * OPTIMIZE TODO: This implicitly sorts
10981
    *  the result, even if not needed. E.g. if the argument
10982
    *  of the count() function, no sorting is needed.
10983
    * OPTIMIZE TODO: How do we know if the node-list wasn't
10984
    *  already sorted?
10985
    */
10986
0
    if (ctxt->value->nodesetval->nodeNr > 1)
10987
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10988
0
                *first = ctxt->value->nodesetval->nodeTab[0];
10989
0
            }
10990
0
            cur =
10991
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10992
0
                                        first);
10993
0
      CHECK_ERROR0;
10994
10995
0
            arg2 = valuePop(ctxt);
10996
0
            arg1 = valuePop(ctxt);
10997
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10998
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10999
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11000
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11001
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11002
0
            }
11003
0
            if ((ctxt->context->opLimit != 0) &&
11004
0
                (((arg1->nodesetval != NULL) &&
11005
0
                  (xmlXPathCheckOpLimit(ctxt,
11006
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11007
0
                 ((arg2->nodesetval != NULL) &&
11008
0
                  (xmlXPathCheckOpLimit(ctxt,
11009
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11010
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11011
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11012
0
                break;
11013
0
            }
11014
11015
0
            if ((arg2->nodesetval != NULL) &&
11016
0
                (arg2->nodesetval->nodeNr != 0)) {
11017
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11018
0
                                                        arg2->nodesetval);
11019
0
                if (arg1->nodesetval == NULL)
11020
0
                    xmlXPathPErrMemory(ctxt);
11021
0
            }
11022
0
            valuePush(ctxt, arg1);
11023
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11024
0
            total += cur;
11025
0
            break;
11026
0
        case XPATH_OP_ROOT:
11027
0
            xmlXPathRoot(ctxt);
11028
0
            break;
11029
0
        case XPATH_OP_NODE:
11030
0
            if (op->ch1 != -1)
11031
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11032
0
      CHECK_ERROR0;
11033
0
            if (op->ch2 != -1)
11034
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11035
0
      CHECK_ERROR0;
11036
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11037
0
    ctxt->context->node));
11038
0
            break;
11039
0
        case XPATH_OP_COLLECT:{
11040
0
                if (op->ch1 == -1)
11041
0
                    break;
11042
11043
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11044
0
    CHECK_ERROR0;
11045
11046
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11047
0
                break;
11048
0
            }
11049
0
        case XPATH_OP_VALUE:
11050
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11051
0
            break;
11052
0
        case XPATH_OP_SORT:
11053
0
            if (op->ch1 != -1)
11054
0
                total +=
11055
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11056
0
                                            first);
11057
0
      CHECK_ERROR0;
11058
0
            if ((ctxt->value != NULL)
11059
0
                && (ctxt->value->type == XPATH_NODESET)
11060
0
                && (ctxt->value->nodesetval != NULL)
11061
0
    && (ctxt->value->nodesetval->nodeNr > 1))
11062
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11063
0
            break;
11064
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
11065
0
  case XPATH_OP_FILTER:
11066
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11067
0
            break;
11068
0
#endif
11069
0
        default:
11070
0
            total += xmlXPathCompOpEval(ctxt, op);
11071
0
            break;
11072
0
    }
11073
11074
0
    ctxt->context->depth -= 1;
11075
0
    return(total);
11076
0
}
11077
11078
/**
11079
 * xmlXPathCompOpEvalLast:
11080
 * @ctxt:  the XPath parser context with the compiled expression
11081
 * @op:  an XPath compiled operation
11082
 * @last:  the last elem found so far
11083
 *
11084
 * Evaluate the Precompiled XPath operation searching only the last
11085
 * element in document order
11086
 *
11087
 * Returns the number of nodes traversed
11088
 */
11089
static int
11090
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11091
                       xmlNodePtr * last)
11092
0
{
11093
0
    int total = 0, cur;
11094
0
    xmlXPathCompExprPtr comp;
11095
0
    xmlXPathObjectPtr arg1, arg2;
11096
11097
0
    CHECK_ERROR0;
11098
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11099
0
        return(0);
11100
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11101
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11102
0
    ctxt->context->depth += 1;
11103
0
    comp = ctxt->comp;
11104
0
    switch (op->op) {
11105
0
        case XPATH_OP_END:
11106
0
            break;
11107
0
        case XPATH_OP_UNION:
11108
0
            total =
11109
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11110
0
      CHECK_ERROR0;
11111
0
            if ((ctxt->value != NULL)
11112
0
                && (ctxt->value->type == XPATH_NODESET)
11113
0
                && (ctxt->value->nodesetval != NULL)
11114
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
11115
                /*
11116
                 * limit tree traversing to first node in the result
11117
                 */
11118
0
    if (ctxt->value->nodesetval->nodeNr > 1)
11119
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
11120
0
                *last =
11121
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
11122
0
                                                     nodesetval->nodeNr -
11123
0
                                                     1];
11124
0
            }
11125
0
            cur =
11126
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11127
0
      CHECK_ERROR0;
11128
0
            if ((ctxt->value != NULL)
11129
0
                && (ctxt->value->type == XPATH_NODESET)
11130
0
                && (ctxt->value->nodesetval != NULL)
11131
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11132
0
            }
11133
11134
0
            arg2 = valuePop(ctxt);
11135
0
            arg1 = valuePop(ctxt);
11136
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11137
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11138
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11139
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11140
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11141
0
            }
11142
0
            if ((ctxt->context->opLimit != 0) &&
11143
0
                (((arg1->nodesetval != NULL) &&
11144
0
                  (xmlXPathCheckOpLimit(ctxt,
11145
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11146
0
                 ((arg2->nodesetval != NULL) &&
11147
0
                  (xmlXPathCheckOpLimit(ctxt,
11148
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11149
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11150
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11151
0
                break;
11152
0
            }
11153
11154
0
            if ((arg2->nodesetval != NULL) &&
11155
0
                (arg2->nodesetval->nodeNr != 0)) {
11156
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11157
0
                                                        arg2->nodesetval);
11158
0
                if (arg1->nodesetval == NULL)
11159
0
                    xmlXPathPErrMemory(ctxt);
11160
0
            }
11161
0
            valuePush(ctxt, arg1);
11162
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11163
0
            total += cur;
11164
0
            break;
11165
0
        case XPATH_OP_ROOT:
11166
0
            xmlXPathRoot(ctxt);
11167
0
            break;
11168
0
        case XPATH_OP_NODE:
11169
0
            if (op->ch1 != -1)
11170
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11171
0
      CHECK_ERROR0;
11172
0
            if (op->ch2 != -1)
11173
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11174
0
      CHECK_ERROR0;
11175
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11176
0
    ctxt->context->node));
11177
0
            break;
11178
0
        case XPATH_OP_COLLECT:{
11179
0
                if (op->ch1 == -1)
11180
0
                    break;
11181
11182
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11183
0
    CHECK_ERROR0;
11184
11185
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11186
0
                break;
11187
0
            }
11188
0
        case XPATH_OP_VALUE:
11189
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11190
0
            break;
11191
0
        case XPATH_OP_SORT:
11192
0
            if (op->ch1 != -1)
11193
0
                total +=
11194
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11195
0
                                           last);
11196
0
      CHECK_ERROR0;
11197
0
            if ((ctxt->value != NULL)
11198
0
                && (ctxt->value->type == XPATH_NODESET)
11199
0
                && (ctxt->value->nodesetval != NULL)
11200
0
    && (ctxt->value->nodesetval->nodeNr > 1))
11201
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11202
0
            break;
11203
0
        default:
11204
0
            total += xmlXPathCompOpEval(ctxt, op);
11205
0
            break;
11206
0
    }
11207
11208
0
    ctxt->context->depth -= 1;
11209
0
    return (total);
11210
0
}
11211
11212
#ifdef XP_OPTIMIZED_FILTER_FIRST
11213
static int
11214
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11215
            xmlXPathStepOpPtr op, xmlNodePtr * first)
11216
0
{
11217
0
    int total = 0;
11218
0
    xmlXPathCompExprPtr comp;
11219
0
    xmlXPathObjectPtr obj;
11220
0
    xmlNodeSetPtr set;
11221
11222
0
    CHECK_ERROR0;
11223
0
    comp = ctxt->comp;
11224
    /*
11225
    * Optimization for ()[last()] selection i.e. the last elem
11226
    */
11227
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
11228
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11229
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11230
0
  int f = comp->steps[op->ch2].ch1;
11231
11232
0
  if ((f != -1) &&
11233
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11234
0
      (comp->steps[f].value5 == NULL) &&
11235
0
      (comp->steps[f].value == 0) &&
11236
0
      (comp->steps[f].value4 != NULL) &&
11237
0
      (xmlStrEqual
11238
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
11239
0
      xmlNodePtr last = NULL;
11240
11241
0
      total +=
11242
0
    xmlXPathCompOpEvalLast(ctxt,
11243
0
        &comp->steps[op->ch1],
11244
0
        &last);
11245
0
      CHECK_ERROR0;
11246
      /*
11247
      * The nodeset should be in document order,
11248
      * Keep only the last value
11249
      */
11250
0
      if ((ctxt->value != NULL) &&
11251
0
    (ctxt->value->type == XPATH_NODESET) &&
11252
0
    (ctxt->value->nodesetval != NULL) &&
11253
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
11254
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
11255
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11256
0
    *first = *(ctxt->value->nodesetval->nodeTab);
11257
0
      }
11258
0
      return (total);
11259
0
  }
11260
0
    }
11261
11262
0
    if (op->ch1 != -1)
11263
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11264
0
    CHECK_ERROR0;
11265
0
    if (op->ch2 == -1)
11266
0
  return (total);
11267
0
    if (ctxt->value == NULL)
11268
0
  return (total);
11269
11270
    /*
11271
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
11272
     * the stack. We have to temporarily remove the nodeset object from the
11273
     * stack to avoid freeing it prematurely.
11274
     */
11275
0
    CHECK_TYPE0(XPATH_NODESET);
11276
0
    obj = valuePop(ctxt);
11277
0
    set = obj->nodesetval;
11278
0
    if (set != NULL) {
11279
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
11280
0
        if (set->nodeNr > 0)
11281
0
            *first = set->nodeTab[0];
11282
0
    }
11283
0
    valuePush(ctxt, obj);
11284
11285
0
    return (total);
11286
0
}
11287
#endif /* XP_OPTIMIZED_FILTER_FIRST */
11288
11289
/**
11290
 * xmlXPathCompOpEval:
11291
 * @ctxt:  the XPath parser context with the compiled expression
11292
 * @op:  an XPath compiled operation
11293
 *
11294
 * Evaluate the Precompiled XPath operation
11295
 * Returns the number of nodes traversed
11296
 */
11297
static int
11298
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
11299
0
{
11300
0
    int total = 0;
11301
0
    int equal, ret;
11302
0
    xmlXPathCompExprPtr comp;
11303
0
    xmlXPathObjectPtr arg1, arg2;
11304
11305
0
    CHECK_ERROR0;
11306
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11307
0
        return(0);
11308
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11309
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11310
0
    ctxt->context->depth += 1;
11311
0
    comp = ctxt->comp;
11312
0
    switch (op->op) {
11313
0
        case XPATH_OP_END:
11314
0
            break;
11315
0
        case XPATH_OP_AND:
11316
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11317
0
      CHECK_ERROR0;
11318
0
            xmlXPathBooleanFunction(ctxt, 1);
11319
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
11320
0
                break;
11321
0
            arg2 = valuePop(ctxt);
11322
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11323
0
      if (ctxt->error) {
11324
0
    xmlXPathFreeObject(arg2);
11325
0
    break;
11326
0
      }
11327
0
            xmlXPathBooleanFunction(ctxt, 1);
11328
0
            if (ctxt->value != NULL)
11329
0
                ctxt->value->boolval &= arg2->boolval;
11330
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11331
0
            break;
11332
0
        case XPATH_OP_OR:
11333
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11334
0
      CHECK_ERROR0;
11335
0
            xmlXPathBooleanFunction(ctxt, 1);
11336
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
11337
0
                break;
11338
0
            arg2 = valuePop(ctxt);
11339
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11340
0
      if (ctxt->error) {
11341
0
    xmlXPathFreeObject(arg2);
11342
0
    break;
11343
0
      }
11344
0
            xmlXPathBooleanFunction(ctxt, 1);
11345
0
            if (ctxt->value != NULL)
11346
0
                ctxt->value->boolval |= arg2->boolval;
11347
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11348
0
            break;
11349
0
        case XPATH_OP_EQUAL:
11350
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11351
0
      CHECK_ERROR0;
11352
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11353
0
      CHECK_ERROR0;
11354
0
      if (op->value)
11355
0
    equal = xmlXPathEqualValues(ctxt);
11356
0
      else
11357
0
    equal = xmlXPathNotEqualValues(ctxt);
11358
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
11359
0
            break;
11360
0
        case XPATH_OP_CMP:
11361
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11362
0
      CHECK_ERROR0;
11363
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11364
0
      CHECK_ERROR0;
11365
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
11366
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
11367
0
            break;
11368
0
        case XPATH_OP_PLUS:
11369
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11370
0
      CHECK_ERROR0;
11371
0
            if (op->ch2 != -1) {
11372
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11373
0
      }
11374
0
      CHECK_ERROR0;
11375
0
            if (op->value == 0)
11376
0
                xmlXPathSubValues(ctxt);
11377
0
            else if (op->value == 1)
11378
0
                xmlXPathAddValues(ctxt);
11379
0
            else if (op->value == 2)
11380
0
                xmlXPathValueFlipSign(ctxt);
11381
0
            else if (op->value == 3) {
11382
0
                CAST_TO_NUMBER;
11383
0
                CHECK_TYPE0(XPATH_NUMBER);
11384
0
            }
11385
0
            break;
11386
0
        case XPATH_OP_MULT:
11387
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11388
0
      CHECK_ERROR0;
11389
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11390
0
      CHECK_ERROR0;
11391
0
            if (op->value == 0)
11392
0
                xmlXPathMultValues(ctxt);
11393
0
            else if (op->value == 1)
11394
0
                xmlXPathDivValues(ctxt);
11395
0
            else if (op->value == 2)
11396
0
                xmlXPathModValues(ctxt);
11397
0
            break;
11398
0
        case XPATH_OP_UNION:
11399
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11400
0
      CHECK_ERROR0;
11401
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11402
0
      CHECK_ERROR0;
11403
11404
0
            arg2 = valuePop(ctxt);
11405
0
            arg1 = valuePop(ctxt);
11406
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11407
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11408
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11409
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11410
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11411
0
            }
11412
0
            if ((ctxt->context->opLimit != 0) &&
11413
0
                (((arg1->nodesetval != NULL) &&
11414
0
                  (xmlXPathCheckOpLimit(ctxt,
11415
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11416
0
                 ((arg2->nodesetval != NULL) &&
11417
0
                  (xmlXPathCheckOpLimit(ctxt,
11418
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11419
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11420
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11421
0
                break;
11422
0
            }
11423
11424
0
      if (((arg2->nodesetval != NULL) &&
11425
0
     (arg2->nodesetval->nodeNr != 0)))
11426
0
      {
11427
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11428
0
              arg2->nodesetval);
11429
0
                if (arg1->nodesetval == NULL)
11430
0
                    xmlXPathPErrMemory(ctxt);
11431
0
      }
11432
11433
0
            valuePush(ctxt, arg1);
11434
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11435
0
            break;
11436
0
        case XPATH_OP_ROOT:
11437
0
            xmlXPathRoot(ctxt);
11438
0
            break;
11439
0
        case XPATH_OP_NODE:
11440
0
            if (op->ch1 != -1)
11441
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11442
0
      CHECK_ERROR0;
11443
0
            if (op->ch2 != -1)
11444
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11445
0
      CHECK_ERROR0;
11446
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
11447
0
                                                    ctxt->context->node));
11448
0
            break;
11449
0
        case XPATH_OP_COLLECT:{
11450
0
                if (op->ch1 == -1)
11451
0
                    break;
11452
11453
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11454
0
    CHECK_ERROR0;
11455
11456
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
11457
0
                break;
11458
0
            }
11459
0
        case XPATH_OP_VALUE:
11460
0
            valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
11461
0
            break;
11462
0
        case XPATH_OP_VARIABLE:{
11463
0
    xmlXPathObjectPtr val;
11464
11465
0
                if (op->ch1 != -1)
11466
0
                    total +=
11467
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11468
0
                if (op->value5 == NULL) {
11469
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
11470
0
        if (val == NULL)
11471
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11472
0
                    valuePush(ctxt, val);
11473
0
    } else {
11474
0
                    const xmlChar *URI;
11475
11476
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
11477
0
                    if (URI == NULL) {
11478
0
                        XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11479
0
                        break;
11480
0
                    }
11481
0
        val = xmlXPathVariableLookupNS(ctxt->context,
11482
0
                                                       op->value4, URI);
11483
0
        if (val == NULL)
11484
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
11485
0
                    valuePush(ctxt, val);
11486
0
                }
11487
0
                break;
11488
0
            }
11489
0
        case XPATH_OP_FUNCTION:{
11490
0
                xmlXPathFunction func;
11491
0
                const xmlChar *oldFunc, *oldFuncURI;
11492
0
    int i;
11493
0
                int frame;
11494
11495
0
                frame = ctxt->valueNr;
11496
0
                if (op->ch1 != -1) {
11497
0
                    total +=
11498
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11499
0
                    if (ctxt->error != XPATH_EXPRESSION_OK)
11500
0
                        break;
11501
0
                }
11502
0
    if (ctxt->valueNr < frame + op->value)
11503
0
        XP_ERROR0(XPATH_INVALID_OPERAND);
11504
0
    for (i = 0; i < op->value; i++) {
11505
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
11506
0
      XP_ERROR0(XPATH_INVALID_OPERAND);
11507
0
                }
11508
0
                if (op->cache != NULL)
11509
0
                    func = op->cache;
11510
0
                else {
11511
0
                    const xmlChar *URI = NULL;
11512
11513
0
                    if (op->value5 == NULL)
11514
0
                        func =
11515
0
                            xmlXPathFunctionLookup(ctxt->context,
11516
0
                                                   op->value4);
11517
0
                    else {
11518
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
11519
0
                        if (URI == NULL)
11520
0
                            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11521
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
11522
0
                                                        op->value4, URI);
11523
0
                    }
11524
0
                    if (func == NULL)
11525
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
11526
0
                    op->cache = func;
11527
0
                    op->cacheURI = (void *) URI;
11528
0
                }
11529
0
                oldFunc = ctxt->context->function;
11530
0
                oldFuncURI = ctxt->context->functionURI;
11531
0
                ctxt->context->function = op->value4;
11532
0
                ctxt->context->functionURI = op->cacheURI;
11533
0
                func(ctxt, op->value);
11534
0
                ctxt->context->function = oldFunc;
11535
0
                ctxt->context->functionURI = oldFuncURI;
11536
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
11537
0
                    (ctxt->valueNr != frame + 1))
11538
0
                    XP_ERROR0(XPATH_STACK_ERROR);
11539
0
                break;
11540
0
            }
11541
0
        case XPATH_OP_ARG:
11542
0
            if (op->ch1 != -1) {
11543
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11544
0
          CHECK_ERROR0;
11545
0
            }
11546
0
            if (op->ch2 != -1) {
11547
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11548
0
          CHECK_ERROR0;
11549
0
      }
11550
0
            break;
11551
0
        case XPATH_OP_PREDICATE:
11552
0
        case XPATH_OP_FILTER:{
11553
0
                xmlXPathObjectPtr obj;
11554
0
                xmlNodeSetPtr set;
11555
11556
                /*
11557
                 * Optimization for ()[1] selection i.e. the first elem
11558
                 */
11559
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11560
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
11561
        /*
11562
        * FILTER TODO: Can we assume that the inner processing
11563
        *  will result in an ordered list if we have an
11564
        *  XPATH_OP_FILTER?
11565
        *  What about an additional field or flag on
11566
        *  xmlXPathObject like @sorted ? This way we wouldn't need
11567
        *  to assume anything, so it would be more robust and
11568
        *  easier to optimize.
11569
        */
11570
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
11571
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
11572
#else
11573
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11574
#endif
11575
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
11576
0
                    xmlXPathObjectPtr val;
11577
11578
0
                    val = comp->steps[op->ch2].value4;
11579
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
11580
0
                        (val->floatval == 1.0)) {
11581
0
                        xmlNodePtr first = NULL;
11582
11583
0
                        total +=
11584
0
                            xmlXPathCompOpEvalFirst(ctxt,
11585
0
                                                    &comp->steps[op->ch1],
11586
0
                                                    &first);
11587
0
      CHECK_ERROR0;
11588
                        /*
11589
                         * The nodeset should be in document order,
11590
                         * Keep only the first value
11591
                         */
11592
0
                        if ((ctxt->value != NULL) &&
11593
0
                            (ctxt->value->type == XPATH_NODESET) &&
11594
0
                            (ctxt->value->nodesetval != NULL) &&
11595
0
                            (ctxt->value->nodesetval->nodeNr > 1))
11596
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
11597
0
                                                        1, 1);
11598
0
                        break;
11599
0
                    }
11600
0
                }
11601
                /*
11602
                 * Optimization for ()[last()] selection i.e. the last elem
11603
                 */
11604
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11605
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11606
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11607
0
                    int f = comp->steps[op->ch2].ch1;
11608
11609
0
                    if ((f != -1) &&
11610
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11611
0
                        (comp->steps[f].value5 == NULL) &&
11612
0
                        (comp->steps[f].value == 0) &&
11613
0
                        (comp->steps[f].value4 != NULL) &&
11614
0
                        (xmlStrEqual
11615
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11616
0
                        xmlNodePtr last = NULL;
11617
11618
0
                        total +=
11619
0
                            xmlXPathCompOpEvalLast(ctxt,
11620
0
                                                   &comp->steps[op->ch1],
11621
0
                                                   &last);
11622
0
      CHECK_ERROR0;
11623
                        /*
11624
                         * The nodeset should be in document order,
11625
                         * Keep only the last value
11626
                         */
11627
0
                        if ((ctxt->value != NULL) &&
11628
0
                            (ctxt->value->type == XPATH_NODESET) &&
11629
0
                            (ctxt->value->nodesetval != NULL) &&
11630
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11631
0
                            (ctxt->value->nodesetval->nodeNr > 1))
11632
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11633
0
                        break;
11634
0
                    }
11635
0
                }
11636
    /*
11637
    * Process inner predicates first.
11638
    * Example "index[parent::book][1]":
11639
    * ...
11640
    *   PREDICATE   <-- we are here "[1]"
11641
    *     PREDICATE <-- process "[parent::book]" first
11642
    *       SORT
11643
    *         COLLECT  'parent' 'name' 'node' book
11644
    *           NODE
11645
    *     ELEM Object is a number : 1
11646
    */
11647
0
                if (op->ch1 != -1)
11648
0
                    total +=
11649
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11650
0
    CHECK_ERROR0;
11651
0
                if (op->ch2 == -1)
11652
0
                    break;
11653
0
                if (ctxt->value == NULL)
11654
0
                    break;
11655
11656
                /*
11657
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
11658
                 * nodes from the stack. We have to temporarily remove the
11659
                 * nodeset object from the stack to avoid freeing it
11660
                 * prematurely.
11661
                 */
11662
0
                CHECK_TYPE0(XPATH_NODESET);
11663
0
                obj = valuePop(ctxt);
11664
0
                set = obj->nodesetval;
11665
0
                if (set != NULL)
11666
0
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11667
0
                                          1, set->nodeNr, 1);
11668
0
                valuePush(ctxt, obj);
11669
0
                break;
11670
0
            }
11671
0
        case XPATH_OP_SORT:
11672
0
            if (op->ch1 != -1)
11673
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
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
      {
11680
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11681
0
      }
11682
0
            break;
11683
0
        default:
11684
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11685
0
            break;
11686
0
    }
11687
11688
0
    ctxt->context->depth -= 1;
11689
0
    return (total);
11690
0
}
11691
11692
/**
11693
 * xmlXPathCompOpEvalToBoolean:
11694
 * @ctxt:  the XPath parser context
11695
 *
11696
 * Evaluates if the expression evaluates to true.
11697
 *
11698
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
11699
 */
11700
static int
11701
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11702
          xmlXPathStepOpPtr op,
11703
          int isPredicate)
11704
0
{
11705
0
    xmlXPathObjectPtr resObj = NULL;
11706
11707
0
start:
11708
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11709
0
        return(0);
11710
    /* comp = ctxt->comp; */
11711
0
    switch (op->op) {
11712
0
        case XPATH_OP_END:
11713
0
            return (0);
11714
0
  case XPATH_OP_VALUE:
11715
0
      resObj = (xmlXPathObjectPtr) op->value4;
11716
0
      if (isPredicate)
11717
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11718
0
      return(xmlXPathCastToBoolean(resObj));
11719
0
  case XPATH_OP_SORT:
11720
      /*
11721
      * We don't need sorting for boolean results. Skip this one.
11722
      */
11723
0
            if (op->ch1 != -1) {
11724
0
    op = &ctxt->comp->steps[op->ch1];
11725
0
    goto start;
11726
0
      }
11727
0
      return(0);
11728
0
  case XPATH_OP_COLLECT:
11729
0
      if (op->ch1 == -1)
11730
0
    return(0);
11731
11732
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11733
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
11734
0
    return(-1);
11735
11736
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11737
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
11738
0
    return(-1);
11739
11740
0
      resObj = valuePop(ctxt);
11741
0
      if (resObj == NULL)
11742
0
    return(-1);
11743
0
      break;
11744
0
  default:
11745
      /*
11746
      * Fallback to call xmlXPathCompOpEval().
11747
      */
11748
0
      xmlXPathCompOpEval(ctxt, op);
11749
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
11750
0
    return(-1);
11751
11752
0
      resObj = valuePop(ctxt);
11753
0
      if (resObj == NULL)
11754
0
    return(-1);
11755
0
      break;
11756
0
    }
11757
11758
0
    if (resObj) {
11759
0
  int res;
11760
11761
0
  if (resObj->type == XPATH_BOOLEAN) {
11762
0
      res = resObj->boolval;
11763
0
  } else if (isPredicate) {
11764
      /*
11765
      * For predicates a result of type "number" is handled
11766
      * differently:
11767
      * SPEC XPath 1.0:
11768
      * "If the result is a number, the result will be converted
11769
      *  to true if the number is equal to the context position
11770
      *  and will be converted to false otherwise;"
11771
      */
11772
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11773
0
  } else {
11774
0
      res = xmlXPathCastToBoolean(resObj);
11775
0
  }
11776
0
  xmlXPathReleaseObject(ctxt->context, resObj);
11777
0
  return(res);
11778
0
    }
11779
11780
0
    return(0);
11781
0
}
11782
11783
#ifdef XPATH_STREAMING
11784
/**
11785
 * xmlXPathRunStreamEval:
11786
 * @pctxt:  the XPath parser context with the compiled expression
11787
 *
11788
 * Evaluate the Precompiled Streamable XPath expression in the given context.
11789
 */
11790
static int
11791
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11792
          xmlXPathObjectPtr *resultSeq, int toBool)
11793
{
11794
    int max_depth, min_depth;
11795
    int from_root;
11796
    int ret, depth;
11797
    int eval_all_nodes;
11798
    xmlNodePtr cur = NULL, limit = NULL;
11799
    xmlStreamCtxtPtr patstream = NULL;
11800
    xmlXPathContextPtr ctxt = pctxt->context;
11801
11802
    if ((ctxt == NULL) || (comp == NULL))
11803
        return(-1);
11804
    max_depth = xmlPatternMaxDepth(comp);
11805
    if (max_depth == -1)
11806
        return(-1);
11807
    if (max_depth == -2)
11808
        max_depth = 10000;
11809
    min_depth = xmlPatternMinDepth(comp);
11810
    if (min_depth == -1)
11811
        return(-1);
11812
    from_root = xmlPatternFromRoot(comp);
11813
    if (from_root < 0)
11814
        return(-1);
11815
11816
    if (! toBool) {
11817
  if (resultSeq == NULL)
11818
      return(-1);
11819
  *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11820
  if (*resultSeq == NULL)
11821
      return(-1);
11822
    }
11823
11824
    /*
11825
     * handle the special cases of "/" amd "." being matched
11826
     */
11827
    if (min_depth == 0) {
11828
        int res;
11829
11830
  if (from_root) {
11831
      /* Select "/" */
11832
      if (toBool)
11833
    return(1);
11834
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11835
                                           (xmlNodePtr) ctxt->doc);
11836
  } else {
11837
      /* Select "self::node()" */
11838
      if (toBool)
11839
    return(1);
11840
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11841
                                           ctxt->node);
11842
  }
11843
11844
        if (res < 0)
11845
            xmlXPathPErrMemory(pctxt);
11846
    }
11847
    if (max_depth == 0) {
11848
  return(0);
11849
    }
11850
11851
    if (from_root) {
11852
        cur = (xmlNodePtr)ctxt->doc;
11853
    } else if (ctxt->node != NULL) {
11854
        switch (ctxt->node->type) {
11855
            case XML_ELEMENT_NODE:
11856
            case XML_DOCUMENT_NODE:
11857
            case XML_DOCUMENT_FRAG_NODE:
11858
            case XML_HTML_DOCUMENT_NODE:
11859
          cur = ctxt->node;
11860
    break;
11861
            case XML_ATTRIBUTE_NODE:
11862
            case XML_TEXT_NODE:
11863
            case XML_CDATA_SECTION_NODE:
11864
            case XML_ENTITY_REF_NODE:
11865
            case XML_ENTITY_NODE:
11866
            case XML_PI_NODE:
11867
            case XML_COMMENT_NODE:
11868
            case XML_NOTATION_NODE:
11869
            case XML_DTD_NODE:
11870
            case XML_DOCUMENT_TYPE_NODE:
11871
            case XML_ELEMENT_DECL:
11872
            case XML_ATTRIBUTE_DECL:
11873
            case XML_ENTITY_DECL:
11874
            case XML_NAMESPACE_DECL:
11875
            case XML_XINCLUDE_START:
11876
            case XML_XINCLUDE_END:
11877
    break;
11878
  }
11879
  limit = cur;
11880
    }
11881
    if (cur == NULL) {
11882
        return(0);
11883
    }
11884
11885
    patstream = xmlPatternGetStreamCtxt(comp);
11886
    if (patstream == NULL) {
11887
        xmlXPathPErrMemory(pctxt);
11888
  return(-1);
11889
    }
11890
11891
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11892
11893
    if (from_root) {
11894
  ret = xmlStreamPush(patstream, NULL, NULL);
11895
  if (ret < 0) {
11896
  } else if (ret == 1) {
11897
      if (toBool)
11898
    goto return_1;
11899
      if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
11900
                xmlXPathPErrMemory(pctxt);
11901
  }
11902
    }
11903
    depth = 0;
11904
    goto scan_children;
11905
next_node:
11906
    do {
11907
        if (ctxt->opLimit != 0) {
11908
            if (ctxt->opCount >= ctxt->opLimit) {
11909
                xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
11910
                xmlFreeStreamCtxt(patstream);
11911
                return(-1);
11912
            }
11913
            ctxt->opCount++;
11914
        }
11915
11916
  switch (cur->type) {
11917
      case XML_ELEMENT_NODE:
11918
      case XML_TEXT_NODE:
11919
      case XML_CDATA_SECTION_NODE:
11920
      case XML_COMMENT_NODE:
11921
      case XML_PI_NODE:
11922
    if (cur->type == XML_ELEMENT_NODE) {
11923
        ret = xmlStreamPush(patstream, cur->name,
11924
        (cur->ns ? cur->ns->href : NULL));
11925
    } else if (eval_all_nodes)
11926
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11927
    else
11928
        break;
11929
11930
    if (ret < 0) {
11931
        xmlXPathPErrMemory(pctxt);
11932
    } else if (ret == 1) {
11933
        if (toBool)
11934
      goto return_1;
11935
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11936
                                                 cur) < 0)
11937
                        xmlXPathPErrMemory(pctxt);
11938
    }
11939
    if ((cur->children == NULL) || (depth >= max_depth)) {
11940
        ret = xmlStreamPop(patstream);
11941
        while (cur->next != NULL) {
11942
      cur = cur->next;
11943
      if ((cur->type != XML_ENTITY_DECL) &&
11944
          (cur->type != XML_DTD_NODE))
11945
          goto next_node;
11946
        }
11947
    }
11948
      default:
11949
    break;
11950
  }
11951
11952
scan_children:
11953
  if (cur->type == XML_NAMESPACE_DECL) break;
11954
  if ((cur->children != NULL) && (depth < max_depth)) {
11955
      /*
11956
       * Do not descend on entities declarations
11957
       */
11958
      if (cur->children->type != XML_ENTITY_DECL) {
11959
    cur = cur->children;
11960
    depth++;
11961
    /*
11962
     * Skip DTDs
11963
     */
11964
    if (cur->type != XML_DTD_NODE)
11965
        continue;
11966
      }
11967
  }
11968
11969
  if (cur == limit)
11970
      break;
11971
11972
  while (cur->next != NULL) {
11973
      cur = cur->next;
11974
      if ((cur->type != XML_ENTITY_DECL) &&
11975
    (cur->type != XML_DTD_NODE))
11976
    goto next_node;
11977
  }
11978
11979
  do {
11980
      cur = cur->parent;
11981
      depth--;
11982
      if ((cur == NULL) || (cur == limit) ||
11983
                (cur->type == XML_DOCUMENT_NODE))
11984
          goto done;
11985
      if (cur->type == XML_ELEMENT_NODE) {
11986
    ret = xmlStreamPop(patstream);
11987
      } else if ((eval_all_nodes) &&
11988
    ((cur->type == XML_TEXT_NODE) ||
11989
     (cur->type == XML_CDATA_SECTION_NODE) ||
11990
     (cur->type == XML_COMMENT_NODE) ||
11991
     (cur->type == XML_PI_NODE)))
11992
      {
11993
    ret = xmlStreamPop(patstream);
11994
      }
11995
      if (cur->next != NULL) {
11996
    cur = cur->next;
11997
    break;
11998
      }
11999
  } while (cur != NULL);
12000
12001
    } while ((cur != NULL) && (depth >= 0));
12002
12003
done:
12004
12005
    if (patstream)
12006
  xmlFreeStreamCtxt(patstream);
12007
    return(0);
12008
12009
return_1:
12010
    if (patstream)
12011
  xmlFreeStreamCtxt(patstream);
12012
    return(1);
12013
}
12014
#endif /* XPATH_STREAMING */
12015
12016
/**
12017
 * xmlXPathRunEval:
12018
 * @ctxt:  the XPath parser context with the compiled expression
12019
 * @toBool:  evaluate to a boolean result
12020
 *
12021
 * Evaluate the Precompiled XPath expression in the given context.
12022
 */
12023
static int
12024
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12025
0
{
12026
0
    xmlXPathCompExprPtr comp;
12027
0
    int oldDepth;
12028
12029
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
12030
0
  return(-1);
12031
12032
0
    if (ctxt->valueTab == NULL) {
12033
  /* Allocate the value stack */
12034
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
12035
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
12036
0
  if (ctxt->valueTab == NULL) {
12037
0
      xmlXPathPErrMemory(ctxt);
12038
0
      return(-1);
12039
0
  }
12040
0
  ctxt->valueNr = 0;
12041
0
  ctxt->valueMax = 10;
12042
0
  ctxt->value = NULL;
12043
0
    }
12044
#ifdef XPATH_STREAMING
12045
    if (ctxt->comp->stream) {
12046
  int res;
12047
12048
  if (toBool) {
12049
      /*
12050
      * Evaluation to boolean result.
12051
      */
12052
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
12053
      if (res != -1)
12054
    return(res);
12055
  } else {
12056
      xmlXPathObjectPtr resObj = NULL;
12057
12058
      /*
12059
      * Evaluation to a sequence.
12060
      */
12061
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
12062
12063
      if ((res != -1) && (resObj != NULL)) {
12064
    valuePush(ctxt, resObj);
12065
    return(0);
12066
      }
12067
      if (resObj != NULL)
12068
    xmlXPathReleaseObject(ctxt->context, resObj);
12069
  }
12070
  /*
12071
  * QUESTION TODO: This falls back to normal XPath evaluation
12072
  * if res == -1. Is this intended?
12073
  */
12074
    }
12075
#endif
12076
0
    comp = ctxt->comp;
12077
0
    if (comp->last < 0) {
12078
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12079
0
  return(-1);
12080
0
    }
12081
0
    oldDepth = ctxt->context->depth;
12082
0
    if (toBool)
12083
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
12084
0
      &comp->steps[comp->last], 0));
12085
0
    else
12086
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
12087
0
    ctxt->context->depth = oldDepth;
12088
12089
0
    return(0);
12090
0
}
12091
12092
/************************************************************************
12093
 *                  *
12094
 *      Public interfaces       *
12095
 *                  *
12096
 ************************************************************************/
12097
12098
/**
12099
 * xmlXPathEvalPredicate:
12100
 * @ctxt:  the XPath context
12101
 * @res:  the Predicate Expression evaluation result
12102
 *
12103
 * Evaluate a predicate result for the current node.
12104
 * A PredicateExpr is evaluated by evaluating the Expr and converting
12105
 * the result to a boolean. If the result is a number, the result will
12106
 * be converted to true if the number is equal to the position of the
12107
 * context node in the context node list (as returned by the position
12108
 * function) and will be converted to false otherwise; if the result
12109
 * is not a number, then the result will be converted as if by a call
12110
 * to the boolean function.
12111
 *
12112
 * Returns 1 if predicate is true, 0 otherwise
12113
 */
12114
int
12115
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
12116
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
12117
0
    switch (res->type) {
12118
0
        case XPATH_BOOLEAN:
12119
0
      return(res->boolval);
12120
0
        case XPATH_NUMBER:
12121
0
      return(res->floatval == ctxt->proximityPosition);
12122
0
        case XPATH_NODESET:
12123
0
        case XPATH_XSLT_TREE:
12124
0
      if (res->nodesetval == NULL)
12125
0
    return(0);
12126
0
      return(res->nodesetval->nodeNr != 0);
12127
0
        case XPATH_STRING:
12128
0
      return((res->stringval != NULL) &&
12129
0
             (xmlStrlen(res->stringval) != 0));
12130
0
        default:
12131
0
      break;
12132
0
    }
12133
0
    return(0);
12134
0
}
12135
12136
/**
12137
 * xmlXPathEvaluatePredicateResult:
12138
 * @ctxt:  the XPath Parser context
12139
 * @res:  the Predicate Expression evaluation result
12140
 *
12141
 * Evaluate a predicate result for the current node.
12142
 * A PredicateExpr is evaluated by evaluating the Expr and converting
12143
 * the result to a boolean. If the result is a number, the result will
12144
 * be converted to true if the number is equal to the position of the
12145
 * context node in the context node list (as returned by the position
12146
 * function) and will be converted to false otherwise; if the result
12147
 * is not a number, then the result will be converted as if by a call
12148
 * to the boolean function.
12149
 *
12150
 * Returns 1 if predicate is true, 0 otherwise
12151
 */
12152
int
12153
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
12154
0
                                xmlXPathObjectPtr res) {
12155
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
12156
0
    switch (res->type) {
12157
0
        case XPATH_BOOLEAN:
12158
0
      return(res->boolval);
12159
0
        case XPATH_NUMBER:
12160
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
12161
      return((res->floatval == ctxt->context->proximityPosition) &&
12162
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
12163
#else
12164
0
      return(res->floatval == ctxt->context->proximityPosition);
12165
0
#endif
12166
0
        case XPATH_NODESET:
12167
0
        case XPATH_XSLT_TREE:
12168
0
      if (res->nodesetval == NULL)
12169
0
    return(0);
12170
0
      return(res->nodesetval->nodeNr != 0);
12171
0
        case XPATH_STRING:
12172
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
12173
0
        default:
12174
0
      break;
12175
0
    }
12176
0
    return(0);
12177
0
}
12178
12179
#ifdef XPATH_STREAMING
12180
/**
12181
 * xmlXPathTryStreamCompile:
12182
 * @ctxt: an XPath context
12183
 * @str:  the XPath expression
12184
 *
12185
 * Try to compile the XPath expression as a streamable subset.
12186
 *
12187
 * Returns the compiled expression or NULL if failed to compile.
12188
 */
12189
static xmlXPathCompExprPtr
12190
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12191
    /*
12192
     * Optimization: use streaming patterns when the XPath expression can
12193
     * be compiled to a stream lookup
12194
     */
12195
    xmlPatternPtr stream;
12196
    xmlXPathCompExprPtr comp;
12197
    xmlDictPtr dict = NULL;
12198
    const xmlChar **namespaces = NULL;
12199
    xmlNsPtr ns;
12200
    int i, j;
12201
12202
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
12203
        (!xmlStrchr(str, '@'))) {
12204
  const xmlChar *tmp;
12205
        int res;
12206
12207
  /*
12208
   * We don't try to handle expressions using the verbose axis
12209
   * specifiers ("::"), just the simplified form at this point.
12210
   * Additionally, if there is no list of namespaces available and
12211
   *  there's a ":" in the expression, indicating a prefixed QName,
12212
   *  then we won't try to compile either. xmlPatterncompile() needs
12213
   *  to have a list of namespaces at compilation time in order to
12214
   *  compile prefixed name tests.
12215
   */
12216
  tmp = xmlStrchr(str, ':');
12217
  if ((tmp != NULL) &&
12218
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
12219
      return(NULL);
12220
12221
  if (ctxt != NULL) {
12222
      dict = ctxt->dict;
12223
      if (ctxt->nsNr > 0) {
12224
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
12225
    if (namespaces == NULL) {
12226
        xmlXPathErrMemory(ctxt);
12227
        return(NULL);
12228
    }
12229
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
12230
        ns = ctxt->namespaces[j];
12231
        namespaces[i++] = ns->href;
12232
        namespaces[i++] = ns->prefix;
12233
    }
12234
    namespaces[i++] = NULL;
12235
    namespaces[i] = NULL;
12236
      }
12237
  }
12238
12239
  res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
12240
                                    &stream);
12241
  if (namespaces != NULL) {
12242
      xmlFree((xmlChar **)namespaces);
12243
  }
12244
        if (res < 0) {
12245
            xmlXPathErrMemory(ctxt);
12246
            return(NULL);
12247
        }
12248
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
12249
      comp = xmlXPathNewCompExpr();
12250
      if (comp == NULL) {
12251
    xmlXPathErrMemory(ctxt);
12252
          xmlFreePattern(stream);
12253
    return(NULL);
12254
      }
12255
      comp->stream = stream;
12256
      comp->dict = dict;
12257
      if (comp->dict)
12258
    xmlDictReference(comp->dict);
12259
      return(comp);
12260
  }
12261
  xmlFreePattern(stream);
12262
    }
12263
    return(NULL);
12264
}
12265
#endif /* XPATH_STREAMING */
12266
12267
static void
12268
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
12269
                           xmlXPathStepOpPtr op)
12270
0
{
12271
0
    xmlXPathCompExprPtr comp = pctxt->comp;
12272
0
    xmlXPathContextPtr ctxt;
12273
12274
    /*
12275
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
12276
    * internal representation.
12277
    */
12278
12279
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
12280
0
        (op->ch1 != -1) &&
12281
0
        (op->ch2 == -1 /* no predicate */))
12282
0
    {
12283
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
12284
12285
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
12286
0
            ((xmlXPathAxisVal) prevop->value ==
12287
0
                AXIS_DESCENDANT_OR_SELF) &&
12288
0
            (prevop->ch2 == -1) &&
12289
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
12290
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
12291
0
        {
12292
            /*
12293
            * This is a "descendant-or-self::node()" without predicates.
12294
            * Try to eliminate it.
12295
            */
12296
12297
0
            switch ((xmlXPathAxisVal) op->value) {
12298
0
                case AXIS_CHILD:
12299
0
                case AXIS_DESCENDANT:
12300
                    /*
12301
                    * Convert "descendant-or-self::node()/child::" or
12302
                    * "descendant-or-self::node()/descendant::" to
12303
                    * "descendant::"
12304
                    */
12305
0
                    op->ch1   = prevop->ch1;
12306
0
                    op->value = AXIS_DESCENDANT;
12307
0
                    break;
12308
0
                case AXIS_SELF:
12309
0
                case AXIS_DESCENDANT_OR_SELF:
12310
                    /*
12311
                    * Convert "descendant-or-self::node()/self::" or
12312
                    * "descendant-or-self::node()/descendant-or-self::" to
12313
                    * to "descendant-or-self::"
12314
                    */
12315
0
                    op->ch1   = prevop->ch1;
12316
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
12317
0
                    break;
12318
0
                default:
12319
0
                    break;
12320
0
            }
12321
0
  }
12322
0
    }
12323
12324
    /* OP_VALUE has invalid ch1. */
12325
0
    if (op->op == XPATH_OP_VALUE)
12326
0
        return;
12327
12328
    /* Recurse */
12329
0
    ctxt = pctxt->context;
12330
0
    if (ctxt != NULL) {
12331
0
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
12332
0
            return;
12333
0
        ctxt->depth += 1;
12334
0
    }
12335
0
    if (op->ch1 != -1)
12336
0
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
12337
0
    if (op->ch2 != -1)
12338
0
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
12339
0
    if (ctxt != NULL)
12340
0
        ctxt->depth -= 1;
12341
0
}
12342
12343
/**
12344
 * xmlXPathCtxtCompile:
12345
 * @ctxt: an XPath context
12346
 * @str:  the XPath expression
12347
 *
12348
 * Compile an XPath expression
12349
 *
12350
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12351
 *         the caller has to free the object.
12352
 */
12353
xmlXPathCompExprPtr
12354
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
12355
0
    xmlXPathParserContextPtr pctxt;
12356
0
    xmlXPathCompExprPtr comp;
12357
0
    int oldDepth = 0;
12358
12359
#ifdef XPATH_STREAMING
12360
    comp = xmlXPathTryStreamCompile(ctxt, str);
12361
    if (comp != NULL)
12362
        return(comp);
12363
#endif
12364
12365
0
    xmlInitParser();
12366
12367
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
12368
0
    if (pctxt == NULL)
12369
0
        return NULL;
12370
0
    if (ctxt != NULL)
12371
0
        oldDepth = ctxt->depth;
12372
0
    xmlXPathCompileExpr(pctxt, 1);
12373
0
    if (ctxt != NULL)
12374
0
        ctxt->depth = oldDepth;
12375
12376
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
12377
0
    {
12378
0
        xmlXPathFreeParserContext(pctxt);
12379
0
        return(NULL);
12380
0
    }
12381
12382
0
    if (*pctxt->cur != 0) {
12383
  /*
12384
   * aleksey: in some cases this line prints *second* error message
12385
   * (see bug #78858) and probably this should be fixed.
12386
   * However, we are not sure that all error messages are printed
12387
   * out in other places. It's not critical so we leave it as-is for now
12388
   */
12389
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
12390
0
  comp = NULL;
12391
0
    } else {
12392
0
  comp = pctxt->comp;
12393
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
12394
0
            if (ctxt != NULL)
12395
0
                oldDepth = ctxt->depth;
12396
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
12397
0
            if (ctxt != NULL)
12398
0
                ctxt->depth = oldDepth;
12399
0
  }
12400
0
  pctxt->comp = NULL;
12401
0
    }
12402
0
    xmlXPathFreeParserContext(pctxt);
12403
12404
0
    if (comp != NULL) {
12405
0
  comp->expr = xmlStrdup(str);
12406
0
    }
12407
0
    return(comp);
12408
0
}
12409
12410
/**
12411
 * xmlXPathCompile:
12412
 * @str:  the XPath expression
12413
 *
12414
 * Compile an XPath expression
12415
 *
12416
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
12417
 *         the caller has to free the object.
12418
 */
12419
xmlXPathCompExprPtr
12420
0
xmlXPathCompile(const xmlChar *str) {
12421
0
    return(xmlXPathCtxtCompile(NULL, str));
12422
0
}
12423
12424
/**
12425
 * xmlXPathCompiledEvalInternal:
12426
 * @comp:  the compiled XPath expression
12427
 * @ctxt:  the XPath context
12428
 * @resObj: the resulting XPath object or NULL
12429
 * @toBool: 1 if only a boolean result is requested
12430
 *
12431
 * Evaluate the Precompiled XPath expression in the given context.
12432
 * The caller has to free @resObj.
12433
 *
12434
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12435
 *         the caller has to free the object.
12436
 */
12437
static int
12438
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
12439
           xmlXPathContextPtr ctxt,
12440
           xmlXPathObjectPtr *resObjPtr,
12441
           int toBool)
12442
0
{
12443
0
    xmlXPathParserContextPtr pctxt;
12444
0
    xmlXPathObjectPtr resObj = NULL;
12445
0
    int res;
12446
12447
0
    if (comp == NULL)
12448
0
  return(-1);
12449
0
    xmlInitParser();
12450
12451
0
    xmlResetError(&ctxt->lastError);
12452
12453
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
12454
0
    if (pctxt == NULL)
12455
0
        return(-1);
12456
0
    res = xmlXPathRunEval(pctxt, toBool);
12457
12458
0
    if (pctxt->error == XPATH_EXPRESSION_OK) {
12459
0
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
12460
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
12461
0
        else if (!toBool)
12462
0
            resObj = valuePop(pctxt);
12463
0
    }
12464
12465
0
    if (resObjPtr)
12466
0
        *resObjPtr = resObj;
12467
0
    else
12468
0
        xmlXPathReleaseObject(ctxt, resObj);
12469
12470
0
    pctxt->comp = NULL;
12471
0
    xmlXPathFreeParserContext(pctxt);
12472
12473
0
    return(res);
12474
0
}
12475
12476
/**
12477
 * xmlXPathCompiledEval:
12478
 * @comp:  the compiled XPath expression
12479
 * @ctx:  the XPath context
12480
 *
12481
 * Evaluate the Precompiled XPath expression in the given context.
12482
 *
12483
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12484
 *         the caller has to free the object.
12485
 */
12486
xmlXPathObjectPtr
12487
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
12488
0
{
12489
0
    xmlXPathObjectPtr res = NULL;
12490
12491
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
12492
0
    return(res);
12493
0
}
12494
12495
/**
12496
 * xmlXPathCompiledEvalToBoolean:
12497
 * @comp:  the compiled XPath expression
12498
 * @ctxt:  the XPath context
12499
 *
12500
 * Applies the XPath boolean() function on the result of the given
12501
 * compiled expression.
12502
 *
12503
 * Returns 1 if the expression evaluated to true, 0 if to false and
12504
 *         -1 in API and internal errors.
12505
 */
12506
int
12507
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
12508
            xmlXPathContextPtr ctxt)
12509
0
{
12510
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
12511
0
}
12512
12513
/**
12514
 * xmlXPathEvalExpr:
12515
 * @ctxt:  the XPath Parser context
12516
 *
12517
 * Parse and evaluate an XPath expression in the given context,
12518
 * then push the result on the context stack
12519
 */
12520
void
12521
0
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
12522
#ifdef XPATH_STREAMING
12523
    xmlXPathCompExprPtr comp;
12524
#endif
12525
0
    int oldDepth = 0;
12526
12527
0
    if (ctxt == NULL)
12528
0
        return;
12529
0
    if (ctxt->context->lastError.code != 0)
12530
0
        return;
12531
12532
#ifdef XPATH_STREAMING
12533
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
12534
    if ((comp == NULL) &&
12535
        (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
12536
        xmlXPathPErrMemory(ctxt);
12537
        return;
12538
    }
12539
    if (comp != NULL) {
12540
        if (ctxt->comp != NULL)
12541
      xmlXPathFreeCompExpr(ctxt->comp);
12542
        ctxt->comp = comp;
12543
    } else
12544
#endif
12545
0
    {
12546
0
        if (ctxt->context != NULL)
12547
0
            oldDepth = ctxt->context->depth;
12548
0
  xmlXPathCompileExpr(ctxt, 1);
12549
0
        if (ctxt->context != NULL)
12550
0
            ctxt->context->depth = oldDepth;
12551
0
        CHECK_ERROR;
12552
12553
        /* Check for trailing characters. */
12554
0
        if (*ctxt->cur != 0)
12555
0
            XP_ERROR(XPATH_EXPR_ERROR);
12556
12557
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
12558
0
            if (ctxt->context != NULL)
12559
0
                oldDepth = ctxt->context->depth;
12560
0
      xmlXPathOptimizeExpression(ctxt,
12561
0
    &ctxt->comp->steps[ctxt->comp->last]);
12562
0
            if (ctxt->context != NULL)
12563
0
                ctxt->context->depth = oldDepth;
12564
0
        }
12565
0
    }
12566
12567
0
    xmlXPathRunEval(ctxt, 0);
12568
0
}
12569
12570
/**
12571
 * xmlXPathEval:
12572
 * @str:  the XPath expression
12573
 * @ctx:  the XPath context
12574
 *
12575
 * Evaluate the XPath Location Path in the given context.
12576
 *
12577
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12578
 *         the caller has to free the object.
12579
 */
12580
xmlXPathObjectPtr
12581
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
12582
0
    xmlXPathParserContextPtr ctxt;
12583
0
    xmlXPathObjectPtr res;
12584
12585
0
    if (ctx == NULL)
12586
0
        return(NULL);
12587
12588
0
    xmlInitParser();
12589
12590
0
    xmlResetError(&ctx->lastError);
12591
12592
0
    ctxt = xmlXPathNewParserContext(str, ctx);
12593
0
    if (ctxt == NULL)
12594
0
        return NULL;
12595
0
    xmlXPathEvalExpr(ctxt);
12596
12597
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12598
0
  res = NULL;
12599
0
    } else if (ctxt->valueNr != 1) {
12600
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12601
0
  res = NULL;
12602
0
    } else {
12603
0
  res = valuePop(ctxt);
12604
0
    }
12605
12606
0
    xmlXPathFreeParserContext(ctxt);
12607
0
    return(res);
12608
0
}
12609
12610
/**
12611
 * xmlXPathSetContextNode:
12612
 * @node: the node to to use as the context node
12613
 * @ctx:  the XPath context
12614
 *
12615
 * Sets 'node' as the context node. The node must be in the same
12616
 * document as that associated with the context.
12617
 *
12618
 * Returns -1 in case of error or 0 if successful
12619
 */
12620
int
12621
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
12622
0
    if ((node == NULL) || (ctx == NULL))
12623
0
        return(-1);
12624
12625
0
    if (node->doc == ctx->doc) {
12626
0
        ctx->node = node;
12627
0
  return(0);
12628
0
    }
12629
0
    return(-1);
12630
0
}
12631
12632
/**
12633
 * xmlXPathNodeEval:
12634
 * @node: the node to to use as the context node
12635
 * @str:  the XPath expression
12636
 * @ctx:  the XPath context
12637
 *
12638
 * Evaluate the XPath Location Path in the given context. The node 'node'
12639
 * is set as the context node. The context node is not restored.
12640
 *
12641
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12642
 *         the caller has to free the object.
12643
 */
12644
xmlXPathObjectPtr
12645
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
12646
0
    if (str == NULL)
12647
0
        return(NULL);
12648
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
12649
0
        return(NULL);
12650
0
    return(xmlXPathEval(str, ctx));
12651
0
}
12652
12653
/**
12654
 * xmlXPathEvalExpression:
12655
 * @str:  the XPath expression
12656
 * @ctxt:  the XPath context
12657
 *
12658
 * Alias for xmlXPathEval().
12659
 *
12660
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
12661
 *         the caller has to free the object.
12662
 */
12663
xmlXPathObjectPtr
12664
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
12665
0
    return(xmlXPathEval(str, ctxt));
12666
0
}
12667
12668
/************************************************************************
12669
 *                  *
12670
 *  Extra functions not pertaining to the XPath spec    *
12671
 *                  *
12672
 ************************************************************************/
12673
/**
12674
 * xmlXPathEscapeUriFunction:
12675
 * @ctxt:  the XPath Parser context
12676
 * @nargs:  the number of arguments
12677
 *
12678
 * Implement the escape-uri() XPath function
12679
 *    string escape-uri(string $str, bool $escape-reserved)
12680
 *
12681
 * This function applies the URI escaping rules defined in section 2 of [RFC
12682
 * 2396] to the string supplied as $uri-part, which typically represents all
12683
 * or part of a URI. The effect of the function is to replace any special
12684
 * character in the string by an escape sequence of the form %xx%yy...,
12685
 * where xxyy... is the hexadecimal representation of the octets used to
12686
 * represent the character in UTF-8.
12687
 *
12688
 * The set of characters that are escaped depends on the setting of the
12689
 * boolean argument $escape-reserved.
12690
 *
12691
 * If $escape-reserved is true, all characters are escaped other than lower
12692
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
12693
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
12694
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
12695
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
12696
 * A-F).
12697
 *
12698
 * If $escape-reserved is false, the behavior differs in that characters
12699
 * referred to in [RFC 2396] as reserved characters are not escaped. These
12700
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
12701
 *
12702
 * [RFC 2396] does not define whether escaped URIs should use lower case or
12703
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
12704
 * compared using string comparison functions, this function must always use
12705
 * the upper-case letters A-F.
12706
 *
12707
 * Generally, $escape-reserved should be set to true when escaping a string
12708
 * that is to form a single part of a URI, and to false when escaping an
12709
 * entire URI or URI reference.
12710
 *
12711
 * In the case of non-ascii characters, the string is encoded according to
12712
 * utf-8 and then converted according to RFC 2396.
12713
 *
12714
 * Examples
12715
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
12716
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
12717
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
12718
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
12719
 *
12720
 */
12721
static void
12722
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
12723
0
    xmlXPathObjectPtr str;
12724
0
    int escape_reserved;
12725
0
    xmlBufPtr target;
12726
0
    xmlChar *cptr;
12727
0
    xmlChar escape[4];
12728
12729
0
    CHECK_ARITY(2);
12730
12731
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
12732
12733
0
    CAST_TO_STRING;
12734
0
    str = valuePop(ctxt);
12735
12736
0
    target = xmlBufCreate(50);
12737
12738
0
    escape[0] = '%';
12739
0
    escape[3] = 0;
12740
12741
0
    if (target) {
12742
0
  for (cptr = str->stringval; *cptr; cptr++) {
12743
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
12744
0
    (*cptr >= 'a' && *cptr <= 'z') ||
12745
0
    (*cptr >= '0' && *cptr <= '9') ||
12746
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
12747
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
12748
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
12749
0
    (*cptr == '%' &&
12750
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
12751
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
12752
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
12753
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
12754
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
12755
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
12756
0
    (!escape_reserved &&
12757
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
12758
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
12759
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
12760
0
      *cptr == ','))) {
12761
0
    xmlBufAdd(target, cptr, 1);
12762
0
      } else {
12763
0
    if ((*cptr >> 4) < 10)
12764
0
        escape[1] = '0' + (*cptr >> 4);
12765
0
    else
12766
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
12767
0
    if ((*cptr & 0xF) < 10)
12768
0
        escape[2] = '0' + (*cptr & 0xF);
12769
0
    else
12770
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
12771
12772
0
    xmlBufAdd(target, &escape[0], 3);
12773
0
      }
12774
0
  }
12775
0
    }
12776
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt, xmlBufContent(target)));
12777
0
    xmlBufFree(target);
12778
0
    xmlXPathReleaseObject(ctxt->context, str);
12779
0
}
12780
12781
/**
12782
 * xmlXPathRegisterAllFunctions:
12783
 * @ctxt:  the XPath context
12784
 *
12785
 * Registers all default XPath functions in this context
12786
 */
12787
void
12788
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
12789
0
{
12790
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
12791
0
                         xmlXPathBooleanFunction);
12792
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
12793
0
                         xmlXPathCeilingFunction);
12794
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
12795
0
                         xmlXPathCountFunction);
12796
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
12797
0
                         xmlXPathConcatFunction);
12798
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
12799
0
                         xmlXPathContainsFunction);
12800
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
12801
0
                         xmlXPathIdFunction);
12802
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
12803
0
                         xmlXPathFalseFunction);
12804
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
12805
0
                         xmlXPathFloorFunction);
12806
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
12807
0
                         xmlXPathLastFunction);
12808
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
12809
0
                         xmlXPathLangFunction);
12810
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
12811
0
                         xmlXPathLocalNameFunction);
12812
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
12813
0
                         xmlXPathNotFunction);
12814
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
12815
0
                         xmlXPathNameFunction);
12816
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
12817
0
                         xmlXPathNamespaceURIFunction);
12818
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
12819
0
                         xmlXPathNormalizeFunction);
12820
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
12821
0
                         xmlXPathNumberFunction);
12822
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
12823
0
                         xmlXPathPositionFunction);
12824
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
12825
0
                         xmlXPathRoundFunction);
12826
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
12827
0
                         xmlXPathStringFunction);
12828
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
12829
0
                         xmlXPathStringLengthFunction);
12830
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
12831
0
                         xmlXPathStartsWithFunction);
12832
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
12833
0
                         xmlXPathSubstringFunction);
12834
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
12835
0
                         xmlXPathSubstringBeforeFunction);
12836
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
12837
0
                         xmlXPathSubstringAfterFunction);
12838
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
12839
0
                         xmlXPathSumFunction);
12840
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
12841
0
                         xmlXPathTrueFunction);
12842
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
12843
0
                         xmlXPathTranslateFunction);
12844
12845
0
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
12846
0
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
12847
0
                         xmlXPathEscapeUriFunction);
12848
0
}
12849
12850
#endif /* LIBXML_XPATH_ENABLED */