Coverage Report

Created: 2025-07-23 08:13

/src/fontconfig/subprojects/libxml2-2.12.6/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/xpath.h>
35
#include <libxml/xpathInternals.h>
36
#include <libxml/parserInternals.h>
37
#include <libxml/hash.h>
38
#ifdef LIBXML_XPTR_LOCS_ENABLED
39
#include <libxml/xpointer.h>
40
#endif
41
#ifdef LIBXML_DEBUG_ENABLED
42
#include <libxml/debugXML.h>
43
#endif
44
#include <libxml/xmlerror.h>
45
#include <libxml/threads.h>
46
#ifdef LIBXML_PATTERN_ENABLED
47
#include <libxml/pattern.h>
48
#endif
49
50
#include "private/buf.h"
51
#include "private/error.h"
52
#include "private/xpath.h"
53
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
58
#define TODO                \
59
0
    xmlGenericError(xmlGenericErrorContext,       \
60
0
      "Unimplemented block at %s:%d\n",       \
61
0
            __FILE__, __LINE__);
62
63
/**
64
 * WITH_TIM_SORT:
65
 *
66
 * Use the Timsort algorithm provided in timsort.h to sort
67
 * nodeset as this is a great improvement over the old Shell sort
68
 * used in xmlXPathNodeSetSort()
69
 */
70
#define WITH_TIM_SORT
71
72
/*
73
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
74
* If defined, this will use xmlXPathCmpNodesExt() instead of
75
* xmlXPathCmpNodes(). The new function is optimized comparison of
76
* non-element nodes; actually it will speed up comparison only if
77
* xmlXPathOrderDocElems() was called in order to index the elements of
78
* a tree in document order; Libxslt does such an indexing, thus it will
79
* benefit from this optimization.
80
*/
81
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
82
83
/*
84
* XP_OPTIMIZED_FILTER_FIRST:
85
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86
* in a way, that it stop evaluation at the first node.
87
*/
88
#define XP_OPTIMIZED_FILTER_FIRST
89
90
/*
91
 * XPATH_MAX_STEPS:
92
 * when compiling an XPath expression we arbitrary limit the maximum
93
 * number of step operation in the compiled expression. 1000000 is
94
 * an insanely large value which should never be reached under normal
95
 * circumstances
96
 */
97
0
#define XPATH_MAX_STEPS 1000000
98
99
/*
100
 * XPATH_MAX_STACK_DEPTH:
101
 * when evaluating an XPath expression we arbitrary limit the maximum
102
 * number of object allowed to be pushed on the stack. 1000000 is
103
 * an insanely large value which should never be reached under normal
104
 * circumstances
105
 */
106
0
#define XPATH_MAX_STACK_DEPTH 1000000
107
108
/*
109
 * XPATH_MAX_NODESET_LENGTH:
110
 * when evaluating an XPath expression nodesets are created and we
111
 * arbitrary limit the maximum length of those node set. 10000000 is
112
 * an insanely large value which should never be reached under normal
113
 * circumstances, one would first need to construct an in memory tree
114
 * with more than 10 millions nodes.
115
 */
116
0
#define XPATH_MAX_NODESET_LENGTH 10000000
117
118
/*
119
 * XPATH_MAX_RECRUSION_DEPTH:
120
 * Maximum amount of nested functions calls when parsing or evaluating
121
 * expressions
122
 */
123
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
124
0
#define XPATH_MAX_RECURSION_DEPTH 500
125
#elif defined(_WIN32)
126
/* Windows typically limits stack size to 1MB. */
127
#define XPATH_MAX_RECURSION_DEPTH 1000
128
#else
129
#define XPATH_MAX_RECURSION_DEPTH 5000
130
#endif
131
132
/*
133
 * TODO:
134
 * There are a few spots where some tests are done which depend upon ascii
135
 * data.  These should be enhanced for full UTF8 support (see particularly
136
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
137
 */
138
139
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
140
141
/************************************************************************
142
 *                  *
143
 *      Floating point stuff        *
144
 *                  *
145
 ************************************************************************/
146
147
double xmlXPathNAN = 0.0;
148
double xmlXPathPINF = 0.0;
149
double xmlXPathNINF = 0.0;
150
151
/**
152
 * xmlXPathInit:
153
 *
154
 * DEPRECATED: Alias for xmlInitParser.
155
 */
156
void
157
0
xmlXPathInit(void) {
158
0
    xmlInitParser();
159
0
}
160
161
/**
162
 * xmlInitXPathInternal:
163
 *
164
 * Initialize the XPath environment
165
 */
166
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
167
void
168
11
xmlInitXPathInternal(void) {
169
11
#if defined(NAN) && defined(INFINITY)
170
11
    xmlXPathNAN = NAN;
171
11
    xmlXPathPINF = INFINITY;
172
11
    xmlXPathNINF = -INFINITY;
173
#else
174
    /* MSVC doesn't allow division by zero in constant expressions. */
175
    double zero = 0.0;
176
    xmlXPathNAN = 0.0 / zero;
177
    xmlXPathPINF = 1.0 / zero;
178
    xmlXPathNINF = -xmlXPathPINF;
179
#endif
180
11
}
181
182
/**
183
 * xmlXPathIsNaN:
184
 * @val:  a double value
185
 *
186
 * Checks whether a double is a NaN.
187
 *
188
 * Returns 1 if the value is a NaN, 0 otherwise
189
 */
190
int
191
0
xmlXPathIsNaN(double val) {
192
0
#ifdef isnan
193
0
    return isnan(val);
194
#else
195
    return !(val == val);
196
#endif
197
0
}
198
199
/**
200
 * xmlXPathIsInf:
201
 * @val:  a double value
202
 *
203
 * Checks whether a double is an infinity.
204
 *
205
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
206
 */
207
int
208
0
xmlXPathIsInf(double val) {
209
0
#ifdef isinf
210
0
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
211
#else
212
    if (val >= xmlXPathPINF)
213
        return 1;
214
    if (val <= -xmlXPathPINF)
215
        return -1;
216
    return 0;
217
#endif
218
0
}
219
220
#endif /* SCHEMAS or XPATH */
221
222
#ifdef LIBXML_XPATH_ENABLED
223
224
/*
225
 * TODO: when compatibility allows remove all "fake node libxslt" strings
226
 *       the test should just be name[0] = ' '
227
 */
228
229
static xmlNs xmlXPathXMLNamespaceStruct = {
230
    NULL,
231
    XML_NAMESPACE_DECL,
232
    XML_XML_NAMESPACE,
233
    BAD_CAST "xml",
234
    NULL,
235
    NULL
236
};
237
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
238
#ifndef LIBXML_THREAD_ENABLED
239
/*
240
 * Optimizer is disabled only when threaded apps are detected while
241
 * the library ain't compiled for thread safety.
242
 */
243
static int xmlXPathDisableOptimizer = 0;
244
#endif
245
246
static void
247
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
248
249
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
250
/**
251
 * xmlXPathCmpNodesExt:
252
 * @node1:  the first node
253
 * @node2:  the second node
254
 *
255
 * Compare two nodes w.r.t document order.
256
 * This one is optimized for handling of non-element nodes.
257
 *
258
 * Returns -2 in case of error 1 if first point < second point, 0 if
259
 *         it's the same node, -1 otherwise
260
 */
261
static int
262
0
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
263
0
    int depth1, depth2;
264
0
    int misc = 0, precedence1 = 0, precedence2 = 0;
265
0
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
266
0
    xmlNodePtr cur, root;
267
0
    ptrdiff_t l1, l2;
268
269
0
    if ((node1 == NULL) || (node2 == NULL))
270
0
  return(-2);
271
272
0
    if (node1 == node2)
273
0
  return(0);
274
275
    /*
276
     * a couple of optimizations which will avoid computations in most cases
277
     */
278
0
    switch (node1->type) {
279
0
  case XML_ELEMENT_NODE:
280
0
      if (node2->type == XML_ELEMENT_NODE) {
281
0
    if ((0 > (ptrdiff_t) node1->content) &&
282
0
        (0 > (ptrdiff_t) node2->content) &&
283
0
        (node1->doc == node2->doc))
284
0
    {
285
0
        l1 = -((ptrdiff_t) node1->content);
286
0
        l2 = -((ptrdiff_t) node2->content);
287
0
        if (l1 < l2)
288
0
      return(1);
289
0
        if (l1 > l2)
290
0
      return(-1);
291
0
    } else
292
0
        goto turtle_comparison;
293
0
      }
294
0
      break;
295
0
  case XML_ATTRIBUTE_NODE:
296
0
      precedence1 = 1; /* element is owner */
297
0
      miscNode1 = node1;
298
0
      node1 = node1->parent;
299
0
      misc = 1;
300
0
      break;
301
0
  case XML_TEXT_NODE:
302
0
  case XML_CDATA_SECTION_NODE:
303
0
  case XML_COMMENT_NODE:
304
0
  case XML_PI_NODE: {
305
0
      miscNode1 = node1;
306
      /*
307
      * Find nearest element node.
308
      */
309
0
      if (node1->prev != NULL) {
310
0
    do {
311
0
        node1 = node1->prev;
312
0
        if (node1->type == XML_ELEMENT_NODE) {
313
0
      precedence1 = 3; /* element in prev-sibl axis */
314
0
      break;
315
0
        }
316
0
        if (node1->prev == NULL) {
317
0
      precedence1 = 2; /* element is parent */
318
      /*
319
      * URGENT TODO: Are there any cases, where the
320
      * parent of such a node is not an element node?
321
      */
322
0
      node1 = node1->parent;
323
0
      break;
324
0
        }
325
0
    } while (1);
326
0
      } else {
327
0
    precedence1 = 2; /* element is parent */
328
0
    node1 = node1->parent;
329
0
      }
330
0
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
331
0
    (0 <= (ptrdiff_t) node1->content)) {
332
    /*
333
    * Fallback for whatever case.
334
    */
335
0
    node1 = miscNode1;
336
0
    precedence1 = 0;
337
0
      } else
338
0
    misc = 1;
339
0
  }
340
0
      break;
341
0
  case XML_NAMESPACE_DECL:
342
      /*
343
      * TODO: why do we return 1 for namespace nodes?
344
      */
345
0
      return(1);
346
0
  default:
347
0
      break;
348
0
    }
349
0
    switch (node2->type) {
350
0
  case XML_ELEMENT_NODE:
351
0
      break;
352
0
  case XML_ATTRIBUTE_NODE:
353
0
      precedence2 = 1; /* element is owner */
354
0
      miscNode2 = node2;
355
0
      node2 = node2->parent;
356
0
      misc = 1;
357
0
      break;
358
0
  case XML_TEXT_NODE:
359
0
  case XML_CDATA_SECTION_NODE:
360
0
  case XML_COMMENT_NODE:
361
0
  case XML_PI_NODE: {
362
0
      miscNode2 = node2;
363
0
      if (node2->prev != NULL) {
364
0
    do {
365
0
        node2 = node2->prev;
366
0
        if (node2->type == XML_ELEMENT_NODE) {
367
0
      precedence2 = 3; /* element in prev-sibl axis */
368
0
      break;
369
0
        }
370
0
        if (node2->prev == NULL) {
371
0
      precedence2 = 2; /* element is parent */
372
0
      node2 = node2->parent;
373
0
      break;
374
0
        }
375
0
    } while (1);
376
0
      } else {
377
0
    precedence2 = 2; /* element is parent */
378
0
    node2 = node2->parent;
379
0
      }
380
0
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
381
0
    (0 <= (ptrdiff_t) node2->content))
382
0
      {
383
0
    node2 = miscNode2;
384
0
    precedence2 = 0;
385
0
      } else
386
0
    misc = 1;
387
0
  }
388
0
      break;
389
0
  case XML_NAMESPACE_DECL:
390
0
      return(1);
391
0
  default:
392
0
      break;
393
0
    }
394
0
    if (misc) {
395
0
  if (node1 == node2) {
396
0
      if (precedence1 == precedence2) {
397
    /*
398
    * The ugly case; but normally there aren't many
399
    * adjacent non-element nodes around.
400
    */
401
0
    cur = miscNode2->prev;
402
0
    while (cur != NULL) {
403
0
        if (cur == miscNode1)
404
0
      return(1);
405
0
        if (cur->type == XML_ELEMENT_NODE)
406
0
      return(-1);
407
0
        cur = cur->prev;
408
0
    }
409
0
    return (-1);
410
0
      } else {
411
    /*
412
    * Evaluate based on higher precedence wrt to the element.
413
    * TODO: This assumes attributes are sorted before content.
414
    *   Is this 100% correct?
415
    */
416
0
    if (precedence1 < precedence2)
417
0
        return(1);
418
0
    else
419
0
        return(-1);
420
0
      }
421
0
  }
422
  /*
423
  * Special case: One of the helper-elements is contained by the other.
424
  * <foo>
425
  *   <node2>
426
  *     <node1>Text-1(precedence1 == 2)</node1>
427
  *   </node2>
428
  *   Text-6(precedence2 == 3)
429
  * </foo>
430
  */
431
0
  if ((precedence2 == 3) && (precedence1 > 1)) {
432
0
      cur = node1->parent;
433
0
      while (cur) {
434
0
    if (cur == node2)
435
0
        return(1);
436
0
    cur = cur->parent;
437
0
      }
438
0
  }
439
0
  if ((precedence1 == 3) && (precedence2 > 1)) {
440
0
      cur = node2->parent;
441
0
      while (cur) {
442
0
    if (cur == node1)
443
0
        return(-1);
444
0
    cur = cur->parent;
445
0
      }
446
0
  }
447
0
    }
448
449
    /*
450
     * Speedup using document order if available.
451
     */
452
0
    if ((node1->type == XML_ELEMENT_NODE) &&
453
0
  (node2->type == XML_ELEMENT_NODE) &&
454
0
  (0 > (ptrdiff_t) node1->content) &&
455
0
  (0 > (ptrdiff_t) node2->content) &&
456
0
  (node1->doc == node2->doc)) {
457
458
0
  l1 = -((ptrdiff_t) node1->content);
459
0
  l2 = -((ptrdiff_t) node2->content);
460
0
  if (l1 < l2)
461
0
      return(1);
462
0
  if (l1 > l2)
463
0
      return(-1);
464
0
    }
465
466
0
turtle_comparison:
467
468
0
    if (node1 == node2->prev)
469
0
  return(1);
470
0
    if (node1 == node2->next)
471
0
  return(-1);
472
    /*
473
     * compute depth to root
474
     */
475
0
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
476
0
  if (cur->parent == node1)
477
0
      return(1);
478
0
  depth2++;
479
0
    }
480
0
    root = cur;
481
0
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
482
0
  if (cur->parent == node2)
483
0
      return(-1);
484
0
  depth1++;
485
0
    }
486
    /*
487
     * Distinct document (or distinct entities :-( ) case.
488
     */
489
0
    if (root != cur) {
490
0
  return(-2);
491
0
    }
492
    /*
493
     * get the nearest common ancestor.
494
     */
495
0
    while (depth1 > depth2) {
496
0
  depth1--;
497
0
  node1 = node1->parent;
498
0
    }
499
0
    while (depth2 > depth1) {
500
0
  depth2--;
501
0
  node2 = node2->parent;
502
0
    }
503
0
    while (node1->parent != node2->parent) {
504
0
  node1 = node1->parent;
505
0
  node2 = node2->parent;
506
  /* should not happen but just in case ... */
507
0
  if ((node1 == NULL) || (node2 == NULL))
508
0
      return(-2);
509
0
    }
510
    /*
511
     * Find who's first.
512
     */
513
0
    if (node1 == node2->prev)
514
0
  return(1);
515
0
    if (node1 == node2->next)
516
0
  return(-1);
517
    /*
518
     * Speedup using document order if available.
519
     */
520
0
    if ((node1->type == XML_ELEMENT_NODE) &&
521
0
  (node2->type == XML_ELEMENT_NODE) &&
522
0
  (0 > (ptrdiff_t) node1->content) &&
523
0
  (0 > (ptrdiff_t) node2->content) &&
524
0
  (node1->doc == node2->doc)) {
525
526
0
  l1 = -((ptrdiff_t) node1->content);
527
0
  l2 = -((ptrdiff_t) node2->content);
528
0
  if (l1 < l2)
529
0
      return(1);
530
0
  if (l1 > l2)
531
0
      return(-1);
532
0
    }
533
534
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
535
0
  if (cur == node2)
536
0
      return(1);
537
0
    return(-1); /* assume there is no sibling list corruption */
538
0
}
539
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
540
541
/*
542
 * Wrapper for the Timsort algorithm from timsort.h
543
 */
544
#ifdef WITH_TIM_SORT
545
#define SORT_NAME libxml_domnode
546
0
#define SORT_TYPE xmlNodePtr
547
/**
548
 * wrap_cmp:
549
 * @x: a node
550
 * @y: another node
551
 *
552
 * Comparison function for the Timsort implementation
553
 *
554
 * Returns -2 in case of error -1 if first point < second point, 0 if
555
 *         it's the same node, +1 otherwise
556
 */
557
static
558
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
559
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
560
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
561
0
    {
562
0
        int res = xmlXPathCmpNodesExt(x, y);
563
0
        return res == -2 ? res : -res;
564
0
    }
565
#else
566
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
567
    {
568
        int res = xmlXPathCmpNodes(x, y);
569
        return res == -2 ? res : -res;
570
    }
571
#endif
572
0
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
573
#include "timsort.h"
574
#endif /* WITH_TIM_SORT */
575
576
/************************************************************************
577
 *                  *
578
 *      Error handling routines       *
579
 *                  *
580
 ************************************************************************/
581
582
/**
583
 * XP_ERRORNULL:
584
 * @X:  the error code
585
 *
586
 * Macro to raise an XPath error and return NULL.
587
 */
588
#define XP_ERRORNULL(X)             \
589
0
    { xmlXPathErr(ctxt, X); return(NULL); }
590
591
/*
592
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
593
 */
594
static const char* const xmlXPathErrorMessages[] = {
595
    "Ok\n",
596
    "Number encoding\n",
597
    "Unfinished literal\n",
598
    "Start of literal\n",
599
    "Expected $ for variable reference\n",
600
    "Undefined variable\n",
601
    "Invalid predicate\n",
602
    "Invalid expression\n",
603
    "Missing closing curly brace\n",
604
    "Unregistered function\n",
605
    "Invalid operand\n",
606
    "Invalid type\n",
607
    "Invalid number of arguments\n",
608
    "Invalid context size\n",
609
    "Invalid context position\n",
610
    "Memory allocation error\n",
611
    "Syntax error\n",
612
    "Resource error\n",
613
    "Sub resource error\n",
614
    "Undefined namespace prefix\n",
615
    "Encoding error\n",
616
    "Char out of XML range\n",
617
    "Invalid or incomplete context\n",
618
    "Stack usage error\n",
619
    "Forbidden variable\n",
620
    "Operation limit exceeded\n",
621
    "Recursion limit exceeded\n",
622
    "?? Unknown error ??\n" /* Must be last in the list! */
623
};
624
0
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
625
0
       sizeof(xmlXPathErrorMessages[0])) - 1)
626
/**
627
 * xmlXPathErrMemory:
628
 * @ctxt:  an XPath context
629
 * @extra:  extra information
630
 *
631
 * Handle a redefinition of attribute error
632
 */
633
static void
634
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
635
0
{
636
0
    if (ctxt != NULL) {
637
0
        xmlResetError(&ctxt->lastError);
638
0
        if (extra) {
639
0
            xmlChar buf[200];
640
641
0
            xmlStrPrintf(buf, 200,
642
0
                         "Memory allocation failed : %s\n",
643
0
                         extra);
644
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
645
0
        } else {
646
0
            ctxt->lastError.message = (char *)
647
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
648
0
        }
649
0
        ctxt->lastError.domain = XML_FROM_XPATH;
650
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
651
0
  if (ctxt->error != NULL)
652
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
653
0
    } else {
654
0
        if (extra)
655
0
            __xmlRaiseError(NULL, NULL, NULL,
656
0
                            NULL, NULL, XML_FROM_XPATH,
657
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
658
0
                            extra, NULL, NULL, 0, 0,
659
0
                            "Memory allocation failed : %s\n", extra);
660
0
        else
661
0
            __xmlRaiseError(NULL, NULL, NULL,
662
0
                            NULL, NULL, XML_FROM_XPATH,
663
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664
0
                            NULL, NULL, NULL, 0, 0,
665
0
                            "Memory allocation failed\n");
666
0
    }
667
0
}
668
669
/**
670
 * xmlXPathPErrMemory:
671
 * @ctxt:  an XPath parser context
672
 * @extra:  extra information
673
 *
674
 * Handle a redefinition of attribute error
675
 */
676
static void
677
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678
0
{
679
0
    if (ctxt == NULL)
680
0
  xmlXPathErrMemory(NULL, extra);
681
0
    else {
682
0
  ctxt->error = XPATH_MEMORY_ERROR;
683
0
  xmlXPathErrMemory(ctxt->context, extra);
684
0
    }
685
0
}
686
687
/**
688
 * xmlXPathErr:
689
 * @ctxt:  a XPath parser context
690
 * @error:  the error code
691
 *
692
 * Handle an XPath error
693
 */
694
void
695
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696
0
{
697
0
    if ((error < 0) || (error > MAXERRNO))
698
0
  error = MAXERRNO;
699
0
    if (ctxt == NULL) {
700
0
  __xmlRaiseError(NULL, NULL, NULL,
701
0
      NULL, NULL, XML_FROM_XPATH,
702
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
703
0
      XML_ERR_ERROR, NULL, 0,
704
0
      NULL, NULL, NULL, 0, 0,
705
0
      "%s", xmlXPathErrorMessages[error]);
706
0
  return;
707
0
    }
708
    /* Only report the first error */
709
0
    if (ctxt->error != 0)
710
0
        return;
711
0
    ctxt->error = error;
712
0
    if (ctxt->context == NULL) {
713
0
  __xmlRaiseError(NULL, NULL, NULL,
714
0
      NULL, NULL, XML_FROM_XPATH,
715
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
716
0
      XML_ERR_ERROR, NULL, 0,
717
0
      (const char *) ctxt->base, NULL, NULL,
718
0
      ctxt->cur - ctxt->base, 0,
719
0
      "%s", xmlXPathErrorMessages[error]);
720
0
  return;
721
0
    }
722
723
    /* cleanup current last error */
724
0
    xmlResetError(&ctxt->context->lastError);
725
726
0
    ctxt->context->lastError.domain = XML_FROM_XPATH;
727
0
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
728
0
                           XPATH_EXPRESSION_OK;
729
0
    ctxt->context->lastError.level = XML_ERR_ERROR;
730
0
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
731
0
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
732
0
    ctxt->context->lastError.node = ctxt->context->debugNode;
733
0
    if (ctxt->context->error != NULL) {
734
0
  ctxt->context->error(ctxt->context->userData,
735
0
                       &ctxt->context->lastError);
736
0
    } else {
737
0
  __xmlRaiseError(NULL, NULL, NULL,
738
0
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
739
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
740
0
      XML_ERR_ERROR, NULL, 0,
741
0
      (const char *) ctxt->base, NULL, NULL,
742
0
      ctxt->cur - ctxt->base, 0,
743
0
      "%s", xmlXPathErrorMessages[error]);
744
0
    }
745
746
0
}
747
748
/**
749
 * xmlXPatherror:
750
 * @ctxt:  the XPath Parser context
751
 * @file:  the file name
752
 * @line:  the line number
753
 * @no:  the error number
754
 *
755
 * Formats an error message.
756
 */
757
void
758
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
759
0
              int line ATTRIBUTE_UNUSED, int no) {
760
0
    xmlXPathErr(ctxt, no);
761
0
}
762
763
/**
764
 * xmlXPathCheckOpLimit:
765
 * @ctxt:  the XPath Parser context
766
 * @opCount:  the number of operations to be added
767
 *
768
 * Adds opCount to the running total of operations and returns -1 if the
769
 * operation limit is exceeded. Returns 0 otherwise.
770
 */
771
static int
772
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
773
0
    xmlXPathContextPtr xpctxt = ctxt->context;
774
775
0
    if ((opCount > xpctxt->opLimit) ||
776
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
777
0
        xpctxt->opCount = xpctxt->opLimit;
778
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
779
0
        return(-1);
780
0
    }
781
782
0
    xpctxt->opCount += opCount;
783
0
    return(0);
784
0
}
785
786
#define OP_LIMIT_EXCEEDED(ctxt, n) \
787
0
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
788
789
/************************************************************************
790
 *                  *
791
 *      Utilities         *
792
 *                  *
793
 ************************************************************************/
794
795
/**
796
 * xsltPointerList:
797
 *
798
 * Pointer-list for various purposes.
799
 */
800
typedef struct _xmlPointerList xmlPointerList;
801
typedef xmlPointerList *xmlPointerListPtr;
802
struct _xmlPointerList {
803
    void **items;
804
    int number;
805
    int size;
806
};
807
/*
808
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
809
* and here, we should make the functions public.
810
*/
811
static int
812
xmlPointerListAddSize(xmlPointerListPtr list,
813
           void *item,
814
           int initialSize)
815
0
{
816
0
    if (list->size <= list->number) {
817
0
        void **tmp;
818
0
        size_t newSize;
819
820
0
        if (list->size == 0) {
821
0
            if (initialSize <= 0)
822
0
                initialSize = 1;
823
0
            newSize = initialSize;
824
0
        } else {
825
0
            if (list->size > 50000000) {
826
0
                xmlXPathErrMemory(NULL,
827
0
                    "xmlPointerListAddSize: re-allocating item\n");
828
0
                return(-1);
829
0
            }
830
0
      newSize = list->size * 2;
831
0
        }
832
0
  tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
833
0
  if (tmp == NULL) {
834
0
      xmlXPathErrMemory(NULL,
835
0
    "xmlPointerListAddSize: re-allocating item\n");
836
0
      return(-1);
837
0
  }
838
0
        list->items = tmp;
839
0
        list->size = newSize;
840
0
    }
841
0
    list->items[list->number++] = item;
842
0
    return(0);
843
0
}
844
845
/**
846
 * xsltPointerListCreate:
847
 *
848
 * Creates an xsltPointerList structure.
849
 *
850
 * Returns a xsltPointerList structure or NULL in case of an error.
851
 */
852
static xmlPointerListPtr
853
xmlPointerListCreate(int initialSize)
854
0
{
855
0
    xmlPointerListPtr ret;
856
857
0
    ret = xmlMalloc(sizeof(xmlPointerList));
858
0
    if (ret == NULL) {
859
0
  xmlXPathErrMemory(NULL,
860
0
      "xmlPointerListCreate: allocating item\n");
861
0
  return (NULL);
862
0
    }
863
0
    memset(ret, 0, sizeof(xmlPointerList));
864
0
    if (initialSize > 0) {
865
0
  xmlPointerListAddSize(ret, NULL, initialSize);
866
0
  ret->number = 0;
867
0
    }
868
0
    return (ret);
869
0
}
870
871
/**
872
 * xsltPointerListFree:
873
 *
874
 * Frees the xsltPointerList structure. This does not free
875
 * the content of the list.
876
 */
877
static void
878
xmlPointerListFree(xmlPointerListPtr list)
879
0
{
880
0
    if (list == NULL)
881
0
  return;
882
0
    if (list->items != NULL)
883
0
  xmlFree(list->items);
884
0
    xmlFree(list);
885
0
}
886
887
/************************************************************************
888
 *                  *
889
 *      Parser Types          *
890
 *                  *
891
 ************************************************************************/
892
893
/*
894
 * Types are private:
895
 */
896
897
typedef enum {
898
    XPATH_OP_END=0,
899
    XPATH_OP_AND,
900
    XPATH_OP_OR,
901
    XPATH_OP_EQUAL,
902
    XPATH_OP_CMP,
903
    XPATH_OP_PLUS,
904
    XPATH_OP_MULT,
905
    XPATH_OP_UNION,
906
    XPATH_OP_ROOT,
907
    XPATH_OP_NODE,
908
    XPATH_OP_COLLECT,
909
    XPATH_OP_VALUE, /* 11 */
910
    XPATH_OP_VARIABLE,
911
    XPATH_OP_FUNCTION,
912
    XPATH_OP_ARG,
913
    XPATH_OP_PREDICATE,
914
    XPATH_OP_FILTER, /* 16 */
915
    XPATH_OP_SORT /* 17 */
916
#ifdef LIBXML_XPTR_LOCS_ENABLED
917
    ,XPATH_OP_RANGETO
918
#endif
919
} xmlXPathOp;
920
921
typedef enum {
922
    AXIS_ANCESTOR = 1,
923
    AXIS_ANCESTOR_OR_SELF,
924
    AXIS_ATTRIBUTE,
925
    AXIS_CHILD,
926
    AXIS_DESCENDANT,
927
    AXIS_DESCENDANT_OR_SELF,
928
    AXIS_FOLLOWING,
929
    AXIS_FOLLOWING_SIBLING,
930
    AXIS_NAMESPACE,
931
    AXIS_PARENT,
932
    AXIS_PRECEDING,
933
    AXIS_PRECEDING_SIBLING,
934
    AXIS_SELF
935
} xmlXPathAxisVal;
936
937
typedef enum {
938
    NODE_TEST_NONE = 0,
939
    NODE_TEST_TYPE = 1,
940
    NODE_TEST_PI = 2,
941
    NODE_TEST_ALL = 3,
942
    NODE_TEST_NS = 4,
943
    NODE_TEST_NAME = 5
944
} xmlXPathTestVal;
945
946
typedef enum {
947
    NODE_TYPE_NODE = 0,
948
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
949
    NODE_TYPE_TEXT = XML_TEXT_NODE,
950
    NODE_TYPE_PI = XML_PI_NODE
951
} xmlXPathTypeVal;
952
953
typedef struct _xmlXPathStepOp xmlXPathStepOp;
954
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
955
struct _xmlXPathStepOp {
956
    xmlXPathOp op;    /* The identifier of the operation */
957
    int ch1;      /* First child */
958
    int ch2;      /* Second child */
959
    int value;
960
    int value2;
961
    int value3;
962
    void *value4;
963
    void *value5;
964
    xmlXPathFunction cache;
965
    void *cacheURI;
966
};
967
968
struct _xmlXPathCompExpr {
969
    int nbStep;     /* Number of steps in this expression */
970
    int maxStep;    /* Maximum number of steps allocated */
971
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
972
    int last;     /* index of last step in expression */
973
    xmlChar *expr;    /* the expression being computed */
974
    xmlDictPtr dict;    /* the dictionary to use if any */
975
#ifdef XPATH_STREAMING
976
    xmlPatternPtr stream;
977
#endif
978
};
979
980
/************************************************************************
981
 *                  *
982
 *      Forward declarations        *
983
 *                  *
984
 ************************************************************************/
985
static void
986
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
987
static void
988
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
989
static int
990
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
991
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
992
static int
993
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
994
          xmlXPathStepOpPtr op,
995
          int isPredicate);
996
static void
997
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
998
999
/************************************************************************
1000
 *                  *
1001
 *      Parser Type functions       *
1002
 *                  *
1003
 ************************************************************************/
1004
1005
/**
1006
 * xmlXPathNewCompExpr:
1007
 *
1008
 * Create a new Xpath component
1009
 *
1010
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1011
 */
1012
static xmlXPathCompExprPtr
1013
0
xmlXPathNewCompExpr(void) {
1014
0
    xmlXPathCompExprPtr cur;
1015
1016
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1017
0
    if (cur == NULL) {
1018
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1019
0
  return(NULL);
1020
0
    }
1021
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1022
0
    cur->maxStep = 10;
1023
0
    cur->nbStep = 0;
1024
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1025
0
                                     sizeof(xmlXPathStepOp));
1026
0
    if (cur->steps == NULL) {
1027
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1028
0
  xmlFree(cur);
1029
0
  return(NULL);
1030
0
    }
1031
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1032
0
    cur->last = -1;
1033
0
    return(cur);
1034
0
}
1035
1036
/**
1037
 * xmlXPathFreeCompExpr:
1038
 * @comp:  an XPATH comp
1039
 *
1040
 * Free up the memory allocated by @comp
1041
 */
1042
void
1043
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1044
0
{
1045
0
    xmlXPathStepOpPtr op;
1046
0
    int i;
1047
1048
0
    if (comp == NULL)
1049
0
        return;
1050
0
    if (comp->dict == NULL) {
1051
0
  for (i = 0; i < comp->nbStep; i++) {
1052
0
      op = &comp->steps[i];
1053
0
      if (op->value4 != NULL) {
1054
0
    if (op->op == XPATH_OP_VALUE)
1055
0
        xmlXPathFreeObject(op->value4);
1056
0
    else
1057
0
        xmlFree(op->value4);
1058
0
      }
1059
0
      if (op->value5 != NULL)
1060
0
    xmlFree(op->value5);
1061
0
  }
1062
0
    } else {
1063
0
  for (i = 0; i < comp->nbStep; i++) {
1064
0
      op = &comp->steps[i];
1065
0
      if (op->value4 != NULL) {
1066
0
    if (op->op == XPATH_OP_VALUE)
1067
0
        xmlXPathFreeObject(op->value4);
1068
0
      }
1069
0
  }
1070
0
        xmlDictFree(comp->dict);
1071
0
    }
1072
0
    if (comp->steps != NULL) {
1073
0
        xmlFree(comp->steps);
1074
0
    }
1075
0
#ifdef XPATH_STREAMING
1076
0
    if (comp->stream != NULL) {
1077
0
        xmlFreePatternList(comp->stream);
1078
0
    }
1079
0
#endif
1080
0
    if (comp->expr != NULL) {
1081
0
        xmlFree(comp->expr);
1082
0
    }
1083
1084
0
    xmlFree(comp);
1085
0
}
1086
1087
/**
1088
 * xmlXPathCompExprAdd:
1089
 * @comp:  the compiled expression
1090
 * @ch1: first child index
1091
 * @ch2: second child index
1092
 * @op:  an op
1093
 * @value:  the first int value
1094
 * @value2:  the second int value
1095
 * @value3:  the third int value
1096
 * @value4:  the first string value
1097
 * @value5:  the second string value
1098
 *
1099
 * Add a step to an XPath Compiled Expression
1100
 *
1101
 * Returns -1 in case of failure, the index otherwise
1102
 */
1103
static int
1104
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1105
   xmlXPathOp op, int value,
1106
0
   int value2, int value3, void *value4, void *value5) {
1107
0
    xmlXPathCompExprPtr comp = ctxt->comp;
1108
0
    if (comp->nbStep >= comp->maxStep) {
1109
0
  xmlXPathStepOp *real;
1110
1111
0
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1112
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1113
0
      return(-1);
1114
0
        }
1115
0
  comp->maxStep *= 2;
1116
0
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1117
0
                          comp->maxStep * sizeof(xmlXPathStepOp));
1118
0
  if (real == NULL) {
1119
0
      comp->maxStep /= 2;
1120
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1121
0
      return(-1);
1122
0
  }
1123
0
  comp->steps = real;
1124
0
    }
1125
0
    comp->last = comp->nbStep;
1126
0
    comp->steps[comp->nbStep].ch1 = ch1;
1127
0
    comp->steps[comp->nbStep].ch2 = ch2;
1128
0
    comp->steps[comp->nbStep].op = op;
1129
0
    comp->steps[comp->nbStep].value = value;
1130
0
    comp->steps[comp->nbStep].value2 = value2;
1131
0
    comp->steps[comp->nbStep].value3 = value3;
1132
0
    if ((comp->dict != NULL) &&
1133
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1134
0
   (op == XPATH_OP_COLLECT))) {
1135
0
        if (value4 != NULL) {
1136
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1137
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1138
0
      xmlFree(value4);
1139
0
  } else
1140
0
      comp->steps[comp->nbStep].value4 = NULL;
1141
0
        if (value5 != NULL) {
1142
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1143
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1144
0
      xmlFree(value5);
1145
0
  } else
1146
0
      comp->steps[comp->nbStep].value5 = NULL;
1147
0
    } else {
1148
0
  comp->steps[comp->nbStep].value4 = value4;
1149
0
  comp->steps[comp->nbStep].value5 = value5;
1150
0
    }
1151
0
    comp->steps[comp->nbStep].cache = NULL;
1152
0
    return(comp->nbStep++);
1153
0
}
1154
1155
/**
1156
 * xmlXPathCompSwap:
1157
 * @comp:  the compiled expression
1158
 * @op: operation index
1159
 *
1160
 * Swaps 2 operations in the compiled expression
1161
 */
1162
static void
1163
0
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1164
0
    int tmp;
1165
1166
#ifndef LIBXML_THREAD_ENABLED
1167
    /*
1168
     * Since this manipulates possibly shared variables, this is
1169
     * disabled if one detects that the library is used in a multithreaded
1170
     * application
1171
     */
1172
    if (xmlXPathDisableOptimizer)
1173
  return;
1174
#endif
1175
1176
0
    tmp = op->ch1;
1177
0
    op->ch1 = op->ch2;
1178
0
    op->ch2 = tmp;
1179
0
}
1180
1181
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1182
0
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1183
0
                  (op), (val), (val2), (val3), (val4), (val5))
1184
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1185
0
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1186
0
                  (op), (val), (val2), (val3), (val4), (val5))
1187
1188
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1189
0
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1190
1191
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1192
0
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1193
1194
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1195
0
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1196
0
      (val), (val2), 0 ,NULL ,NULL)
1197
1198
/************************************************************************
1199
 *                  *
1200
 *    XPath object cache structures       *
1201
 *                  *
1202
 ************************************************************************/
1203
1204
/* #define XP_DEFAULT_CACHE_ON */
1205
1206
0
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1207
1208
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1209
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1210
struct _xmlXPathContextCache {
1211
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1212
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1213
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1214
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1215
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1216
    int maxNodeset;
1217
    int maxString;
1218
    int maxBoolean;
1219
    int maxNumber;
1220
    int maxMisc;
1221
};
1222
1223
/************************************************************************
1224
 *                  *
1225
 *    Debugging related functions       *
1226
 *                  *
1227
 ************************************************************************/
1228
1229
#define STRANGE             \
1230
0
    xmlGenericError(xmlGenericErrorContext,       \
1231
0
      "Internal error at %s:%d\n",        \
1232
0
            __FILE__, __LINE__);
1233
1234
#ifdef LIBXML_DEBUG_ENABLED
1235
static void
1236
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1237
0
    int i;
1238
0
    char shift[100];
1239
1240
0
    for (i = 0;((i < depth) && (i < 25));i++)
1241
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1242
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1243
0
    if (cur == NULL) {
1244
0
  fprintf(output, "%s", shift);
1245
0
  fprintf(output, "Node is NULL !\n");
1246
0
  return;
1247
1248
0
    }
1249
1250
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1251
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1252
0
  fprintf(output, "%s", shift);
1253
0
  fprintf(output, " /\n");
1254
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1255
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1256
0
    else
1257
0
  xmlDebugDumpOneNode(output, cur, depth);
1258
0
}
1259
static void
1260
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1261
0
    xmlNodePtr tmp;
1262
0
    int i;
1263
0
    char shift[100];
1264
1265
0
    for (i = 0;((i < depth) && (i < 25));i++)
1266
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1267
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1268
0
    if (cur == NULL) {
1269
0
  fprintf(output, "%s", shift);
1270
0
  fprintf(output, "Node is NULL !\n");
1271
0
  return;
1272
1273
0
    }
1274
1275
0
    while (cur != NULL) {
1276
0
  tmp = cur;
1277
0
  cur = cur->next;
1278
0
  xmlDebugDumpOneNode(output, tmp, depth);
1279
0
    }
1280
0
}
1281
1282
static void
1283
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1284
0
    int i;
1285
0
    char shift[100];
1286
1287
0
    for (i = 0;((i < depth) && (i < 25));i++)
1288
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1289
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1290
1291
0
    if (cur == NULL) {
1292
0
  fprintf(output, "%s", shift);
1293
0
  fprintf(output, "NodeSet is NULL !\n");
1294
0
  return;
1295
1296
0
    }
1297
1298
0
    if (cur != NULL) {
1299
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1300
0
  for (i = 0;i < cur->nodeNr;i++) {
1301
0
      fprintf(output, "%s", shift);
1302
0
      fprintf(output, "%d", i + 1);
1303
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1304
0
  }
1305
0
    }
1306
0
}
1307
1308
static void
1309
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1310
0
    int i;
1311
0
    char shift[100];
1312
1313
0
    for (i = 0;((i < depth) && (i < 25));i++)
1314
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1315
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1316
1317
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1318
0
  fprintf(output, "%s", shift);
1319
0
  fprintf(output, "Value Tree is NULL !\n");
1320
0
  return;
1321
1322
0
    }
1323
1324
0
    fprintf(output, "%s", shift);
1325
0
    fprintf(output, "%d", i + 1);
1326
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1327
0
}
1328
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1329
static void
1330
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1331
    int i;
1332
    char shift[100];
1333
1334
    for (i = 0;((i < depth) && (i < 25));i++)
1335
        shift[2 * i] = shift[2 * i + 1] = ' ';
1336
    shift[2 * i] = shift[2 * i + 1] = 0;
1337
1338
    if (cur == NULL) {
1339
  fprintf(output, "%s", shift);
1340
  fprintf(output, "LocationSet is NULL !\n");
1341
  return;
1342
1343
    }
1344
1345
    for (i = 0;i < cur->locNr;i++) {
1346
  fprintf(output, "%s", shift);
1347
        fprintf(output, "%d : ", i + 1);
1348
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1349
    }
1350
}
1351
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1352
1353
/**
1354
 * xmlXPathDebugDumpObject:
1355
 * @output:  the FILE * to dump the output
1356
 * @cur:  the object to inspect
1357
 * @depth:  indentation level
1358
 *
1359
 * Dump the content of the object for debugging purposes
1360
 */
1361
void
1362
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1363
0
    int i;
1364
0
    char shift[100];
1365
1366
0
    if (output == NULL) return;
1367
1368
0
    for (i = 0;((i < depth) && (i < 25));i++)
1369
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1370
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1371
1372
1373
0
    fprintf(output, "%s", shift);
1374
1375
0
    if (cur == NULL) {
1376
0
        fprintf(output, "Object is empty (NULL)\n");
1377
0
  return;
1378
0
    }
1379
0
    switch(cur->type) {
1380
0
        case XPATH_UNDEFINED:
1381
0
      fprintf(output, "Object is uninitialized\n");
1382
0
      break;
1383
0
        case XPATH_NODESET:
1384
0
      fprintf(output, "Object is a Node Set :\n");
1385
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1386
0
      break;
1387
0
  case XPATH_XSLT_TREE:
1388
0
      fprintf(output, "Object is an XSLT value tree :\n");
1389
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1390
0
      break;
1391
0
        case XPATH_BOOLEAN:
1392
0
      fprintf(output, "Object is a Boolean : ");
1393
0
      if (cur->boolval) fprintf(output, "true\n");
1394
0
      else fprintf(output, "false\n");
1395
0
      break;
1396
0
        case XPATH_NUMBER:
1397
0
      switch (xmlXPathIsInf(cur->floatval)) {
1398
0
      case 1:
1399
0
    fprintf(output, "Object is a number : Infinity\n");
1400
0
    break;
1401
0
      case -1:
1402
0
    fprintf(output, "Object is a number : -Infinity\n");
1403
0
    break;
1404
0
      default:
1405
0
    if (xmlXPathIsNaN(cur->floatval)) {
1406
0
        fprintf(output, "Object is a number : NaN\n");
1407
0
    } else if (cur->floatval == 0) {
1408
                    /* Omit sign for negative zero. */
1409
0
        fprintf(output, "Object is a number : 0\n");
1410
0
    } else {
1411
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1412
0
    }
1413
0
      }
1414
0
      break;
1415
0
        case XPATH_STRING:
1416
0
      fprintf(output, "Object is a string : ");
1417
0
      xmlDebugDumpString(output, cur->stringval);
1418
0
      fprintf(output, "\n");
1419
0
      break;
1420
#ifdef LIBXML_XPTR_LOCS_ENABLED
1421
  case XPATH_POINT:
1422
      fprintf(output, "Object is a point : index %d in node", cur->index);
1423
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424
      fprintf(output, "\n");
1425
      break;
1426
  case XPATH_RANGE:
1427
      if ((cur->user2 == NULL) ||
1428
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429
    fprintf(output, "Object is a collapsed range :\n");
1430
    fprintf(output, "%s", shift);
1431
    if (cur->index >= 0)
1432
        fprintf(output, "index %d in ", cur->index);
1433
    fprintf(output, "node\n");
1434
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435
                    depth + 1);
1436
      } else  {
1437
    fprintf(output, "Object is a range :\n");
1438
    fprintf(output, "%s", shift);
1439
    fprintf(output, "From ");
1440
    if (cur->index >= 0)
1441
        fprintf(output, "index %d in ", cur->index);
1442
    fprintf(output, "node\n");
1443
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444
                    depth + 1);
1445
    fprintf(output, "%s", shift);
1446
    fprintf(output, "To ");
1447
    if (cur->index2 >= 0)
1448
        fprintf(output, "index %d in ", cur->index2);
1449
    fprintf(output, "node\n");
1450
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451
                    depth + 1);
1452
    fprintf(output, "\n");
1453
      }
1454
      break;
1455
  case XPATH_LOCATIONSET:
1456
      fprintf(output, "Object is a Location Set:\n");
1457
      xmlXPathDebugDumpLocationSet(output,
1458
        (xmlLocationSetPtr) cur->user, depth);
1459
      break;
1460
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1461
0
  case XPATH_USERS:
1462
0
      fprintf(output, "Object is user defined\n");
1463
0
      break;
1464
0
    }
1465
0
}
1466
1467
static void
1468
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1469
0
                       xmlXPathStepOpPtr op, int depth) {
1470
0
    int i;
1471
0
    char shift[100];
1472
1473
0
    for (i = 0;((i < depth) && (i < 25));i++)
1474
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1475
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1476
1477
0
    fprintf(output, "%s", shift);
1478
0
    if (op == NULL) {
1479
0
  fprintf(output, "Step is NULL\n");
1480
0
  return;
1481
0
    }
1482
0
    switch (op->op) {
1483
0
        case XPATH_OP_END:
1484
0
      fprintf(output, "END"); break;
1485
0
        case XPATH_OP_AND:
1486
0
      fprintf(output, "AND"); break;
1487
0
        case XPATH_OP_OR:
1488
0
      fprintf(output, "OR"); break;
1489
0
        case XPATH_OP_EQUAL:
1490
0
       if (op->value)
1491
0
     fprintf(output, "EQUAL =");
1492
0
       else
1493
0
     fprintf(output, "EQUAL !=");
1494
0
       break;
1495
0
        case XPATH_OP_CMP:
1496
0
       if (op->value)
1497
0
     fprintf(output, "CMP <");
1498
0
       else
1499
0
     fprintf(output, "CMP >");
1500
0
       if (!op->value2)
1501
0
     fprintf(output, "=");
1502
0
       break;
1503
0
        case XPATH_OP_PLUS:
1504
0
       if (op->value == 0)
1505
0
     fprintf(output, "PLUS -");
1506
0
       else if (op->value == 1)
1507
0
     fprintf(output, "PLUS +");
1508
0
       else if (op->value == 2)
1509
0
     fprintf(output, "PLUS unary -");
1510
0
       else if (op->value == 3)
1511
0
     fprintf(output, "PLUS unary - -");
1512
0
       break;
1513
0
        case XPATH_OP_MULT:
1514
0
       if (op->value == 0)
1515
0
     fprintf(output, "MULT *");
1516
0
       else if (op->value == 1)
1517
0
     fprintf(output, "MULT div");
1518
0
       else
1519
0
     fprintf(output, "MULT mod");
1520
0
       break;
1521
0
        case XPATH_OP_UNION:
1522
0
       fprintf(output, "UNION"); break;
1523
0
        case XPATH_OP_ROOT:
1524
0
       fprintf(output, "ROOT"); break;
1525
0
        case XPATH_OP_NODE:
1526
0
       fprintf(output, "NODE"); break;
1527
0
        case XPATH_OP_SORT:
1528
0
       fprintf(output, "SORT"); break;
1529
0
        case XPATH_OP_COLLECT: {
1530
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1531
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1532
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1533
0
      const xmlChar *prefix = op->value4;
1534
0
      const xmlChar *name = op->value5;
1535
1536
0
      fprintf(output, "COLLECT ");
1537
0
      switch (axis) {
1538
0
    case AXIS_ANCESTOR:
1539
0
        fprintf(output, " 'ancestors' "); break;
1540
0
    case AXIS_ANCESTOR_OR_SELF:
1541
0
        fprintf(output, " 'ancestors-or-self' "); break;
1542
0
    case AXIS_ATTRIBUTE:
1543
0
        fprintf(output, " 'attributes' "); break;
1544
0
    case AXIS_CHILD:
1545
0
        fprintf(output, " 'child' "); break;
1546
0
    case AXIS_DESCENDANT:
1547
0
        fprintf(output, " 'descendant' "); break;
1548
0
    case AXIS_DESCENDANT_OR_SELF:
1549
0
        fprintf(output, " 'descendant-or-self' "); break;
1550
0
    case AXIS_FOLLOWING:
1551
0
        fprintf(output, " 'following' "); break;
1552
0
    case AXIS_FOLLOWING_SIBLING:
1553
0
        fprintf(output, " 'following-siblings' "); break;
1554
0
    case AXIS_NAMESPACE:
1555
0
        fprintf(output, " 'namespace' "); break;
1556
0
    case AXIS_PARENT:
1557
0
        fprintf(output, " 'parent' "); break;
1558
0
    case AXIS_PRECEDING:
1559
0
        fprintf(output, " 'preceding' "); break;
1560
0
    case AXIS_PRECEDING_SIBLING:
1561
0
        fprintf(output, " 'preceding-sibling' "); break;
1562
0
    case AXIS_SELF:
1563
0
        fprintf(output, " 'self' "); break;
1564
0
      }
1565
0
      switch (test) {
1566
0
                case NODE_TEST_NONE:
1567
0
        fprintf(output, "'none' "); break;
1568
0
                case NODE_TEST_TYPE:
1569
0
        fprintf(output, "'type' "); break;
1570
0
                case NODE_TEST_PI:
1571
0
        fprintf(output, "'PI' "); break;
1572
0
                case NODE_TEST_ALL:
1573
0
        fprintf(output, "'all' "); break;
1574
0
                case NODE_TEST_NS:
1575
0
        fprintf(output, "'namespace' "); break;
1576
0
                case NODE_TEST_NAME:
1577
0
        fprintf(output, "'name' "); break;
1578
0
      }
1579
0
      switch (type) {
1580
0
                case NODE_TYPE_NODE:
1581
0
        fprintf(output, "'node' "); break;
1582
0
                case NODE_TYPE_COMMENT:
1583
0
        fprintf(output, "'comment' "); break;
1584
0
                case NODE_TYPE_TEXT:
1585
0
        fprintf(output, "'text' "); break;
1586
0
                case NODE_TYPE_PI:
1587
0
        fprintf(output, "'PI' "); break;
1588
0
      }
1589
0
      if (prefix != NULL)
1590
0
    fprintf(output, "%s:", prefix);
1591
0
      if (name != NULL)
1592
0
    fprintf(output, "%s", (const char *) name);
1593
0
      break;
1594
1595
0
        }
1596
0
  case XPATH_OP_VALUE: {
1597
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1598
1599
0
      fprintf(output, "ELEM ");
1600
0
      xmlXPathDebugDumpObject(output, object, 0);
1601
0
      goto finish;
1602
0
  }
1603
0
  case XPATH_OP_VARIABLE: {
1604
0
      const xmlChar *prefix = op->value5;
1605
0
      const xmlChar *name = op->value4;
1606
1607
0
      if (prefix != NULL)
1608
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1609
0
      else
1610
0
    fprintf(output, "VARIABLE %s", name);
1611
0
      break;
1612
0
  }
1613
0
  case XPATH_OP_FUNCTION: {
1614
0
      int nbargs = op->value;
1615
0
      const xmlChar *prefix = op->value5;
1616
0
      const xmlChar *name = op->value4;
1617
1618
0
      if (prefix != NULL)
1619
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1620
0
      prefix, name, nbargs);
1621
0
      else
1622
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1623
0
      break;
1624
0
  }
1625
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1626
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1627
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1628
#ifdef LIBXML_XPTR_LOCS_ENABLED
1629
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1630
#endif
1631
0
  default:
1632
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1633
0
    }
1634
0
    fprintf(output, "\n");
1635
0
finish:
1636
0
    if (op->ch1 >= 0)
1637
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1638
0
    if (op->ch2 >= 0)
1639
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1640
0
}
1641
1642
/**
1643
 * xmlXPathDebugDumpCompExpr:
1644
 * @output:  the FILE * for the output
1645
 * @comp:  the precompiled XPath expression
1646
 * @depth:  the indentation level.
1647
 *
1648
 * Dumps the tree of the compiled XPath expression.
1649
 */
1650
void
1651
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1652
0
                    int depth) {
1653
0
    int i;
1654
0
    char shift[100];
1655
1656
0
    if ((output == NULL) || (comp == NULL)) return;
1657
1658
0
    for (i = 0;((i < depth) && (i < 25));i++)
1659
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1660
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1661
1662
0
    fprintf(output, "%s", shift);
1663
1664
0
#ifdef XPATH_STREAMING
1665
0
    if (comp->stream) {
1666
0
        fprintf(output, "Streaming Expression\n");
1667
0
    } else
1668
0
#endif
1669
0
    {
1670
0
        fprintf(output, "Compiled Expression : %d elements\n",
1671
0
                comp->nbStep);
1672
0
        i = comp->last;
1673
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1674
0
    }
1675
0
}
1676
1677
#endif /* LIBXML_DEBUG_ENABLED */
1678
1679
/************************************************************************
1680
 *                  *
1681
 *      XPath object caching        *
1682
 *                  *
1683
 ************************************************************************/
1684
1685
/**
1686
 * xmlXPathNewCache:
1687
 *
1688
 * Create a new object cache
1689
 *
1690
 * Returns the xmlXPathCache just allocated.
1691
 */
1692
static xmlXPathContextCachePtr
1693
xmlXPathNewCache(void)
1694
0
{
1695
0
    xmlXPathContextCachePtr ret;
1696
1697
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1698
0
    if (ret == NULL) {
1699
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
1700
0
  return(NULL);
1701
0
    }
1702
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1703
0
    ret->maxNodeset = 100;
1704
0
    ret->maxString = 100;
1705
0
    ret->maxBoolean = 100;
1706
0
    ret->maxNumber = 100;
1707
0
    ret->maxMisc = 100;
1708
0
    return(ret);
1709
0
}
1710
1711
static void
1712
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1713
0
{
1714
0
    int i;
1715
0
    xmlXPathObjectPtr obj;
1716
1717
0
    if (list == NULL)
1718
0
  return;
1719
1720
0
    for (i = 0; i < list->number; i++) {
1721
0
  obj = list->items[i];
1722
  /*
1723
  * Note that it is already assured that we don't need to
1724
  * look out for namespace nodes in the node-set.
1725
  */
1726
0
  if (obj->nodesetval != NULL) {
1727
0
      if (obj->nodesetval->nodeTab != NULL)
1728
0
    xmlFree(obj->nodesetval->nodeTab);
1729
0
      xmlFree(obj->nodesetval);
1730
0
  }
1731
0
  xmlFree(obj);
1732
0
    }
1733
0
    xmlPointerListFree(list);
1734
0
}
1735
1736
static void
1737
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1738
0
{
1739
0
    if (cache == NULL)
1740
0
  return;
1741
0
    if (cache->nodesetObjs)
1742
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1743
0
    if (cache->stringObjs)
1744
0
  xmlXPathCacheFreeObjectList(cache->stringObjs);
1745
0
    if (cache->booleanObjs)
1746
0
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
1747
0
    if (cache->numberObjs)
1748
0
  xmlXPathCacheFreeObjectList(cache->numberObjs);
1749
0
    if (cache->miscObjs)
1750
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1751
0
    xmlFree(cache);
1752
0
}
1753
1754
/**
1755
 * xmlXPathContextSetCache:
1756
 *
1757
 * @ctxt:  the XPath context
1758
 * @active: enables/disables (creates/frees) the cache
1759
 * @value: a value with semantics dependent on @options
1760
 * @options: options (currently only the value 0 is used)
1761
 *
1762
 * Creates/frees an object cache on the XPath context.
1763
 * If activates XPath objects (xmlXPathObject) will be cached internally
1764
 * to be reused.
1765
 * @options:
1766
 *   0: This will set the XPath object caching:
1767
 *      @value:
1768
 *        This will set the maximum number of XPath objects
1769
 *        to be cached per slot
1770
 *        There are 5 slots for: node-set, string, number, boolean, and
1771
 *        misc objects. Use <0 for the default number (100).
1772
 *   Other values for @options have currently no effect.
1773
 *
1774
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1775
 */
1776
int
1777
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1778
      int active,
1779
      int value,
1780
      int options)
1781
0
{
1782
0
    if (ctxt == NULL)
1783
0
  return(-1);
1784
0
    if (active) {
1785
0
  xmlXPathContextCachePtr cache;
1786
1787
0
  if (ctxt->cache == NULL) {
1788
0
      ctxt->cache = xmlXPathNewCache();
1789
0
      if (ctxt->cache == NULL)
1790
0
    return(-1);
1791
0
  }
1792
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1793
0
  if (options == 0) {
1794
0
      if (value < 0)
1795
0
    value = 100;
1796
0
      cache->maxNodeset = value;
1797
0
      cache->maxString = value;
1798
0
      cache->maxNumber = value;
1799
0
      cache->maxBoolean = value;
1800
0
      cache->maxMisc = value;
1801
0
  }
1802
0
    } else if (ctxt->cache != NULL) {
1803
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1804
0
  ctxt->cache = NULL;
1805
0
    }
1806
0
    return(0);
1807
0
}
1808
1809
/**
1810
 * xmlXPathCacheWrapNodeSet:
1811
 * @ctxt: the XPath context
1812
 * @val:  the NodePtr value
1813
 *
1814
 * This is the cached version of xmlXPathWrapNodeSet().
1815
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1816
 *
1817
 * Returns the created or reused object.
1818
 *
1819
 * In case of error the node set is destroyed and NULL is returned.
1820
 */
1821
static xmlXPathObjectPtr
1822
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1823
0
{
1824
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1825
0
  xmlXPathContextCachePtr cache =
1826
0
      (xmlXPathContextCachePtr) ctxt->cache;
1827
1828
0
  if ((cache->miscObjs != NULL) &&
1829
0
      (cache->miscObjs->number != 0))
1830
0
  {
1831
0
      xmlXPathObjectPtr ret;
1832
1833
0
      ret = (xmlXPathObjectPtr)
1834
0
    cache->miscObjs->items[--cache->miscObjs->number];
1835
0
      ret->type = XPATH_NODESET;
1836
0
      ret->nodesetval = val;
1837
0
      return(ret);
1838
0
  }
1839
0
    }
1840
1841
0
    return(xmlXPathWrapNodeSet(val));
1842
1843
0
}
1844
1845
/**
1846
 * xmlXPathCacheWrapString:
1847
 * @ctxt: the XPath context
1848
 * @val:  the xmlChar * value
1849
 *
1850
 * This is the cached version of xmlXPathWrapString().
1851
 * Wraps the @val string into an XPath object.
1852
 *
1853
 * Returns the created or reused object.
1854
 */
1855
static xmlXPathObjectPtr
1856
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1857
0
{
1858
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1859
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1860
1861
0
  if ((cache->stringObjs != NULL) &&
1862
0
      (cache->stringObjs->number != 0))
1863
0
  {
1864
1865
0
      xmlXPathObjectPtr ret;
1866
1867
0
      ret = (xmlXPathObjectPtr)
1868
0
    cache->stringObjs->items[--cache->stringObjs->number];
1869
0
      ret->type = XPATH_STRING;
1870
0
      ret->stringval = val;
1871
0
      return(ret);
1872
0
  } else if ((cache->miscObjs != NULL) &&
1873
0
      (cache->miscObjs->number != 0))
1874
0
  {
1875
0
      xmlXPathObjectPtr ret;
1876
      /*
1877
      * Fallback to misc-cache.
1878
      */
1879
0
      ret = (xmlXPathObjectPtr)
1880
0
    cache->miscObjs->items[--cache->miscObjs->number];
1881
1882
0
      ret->type = XPATH_STRING;
1883
0
      ret->stringval = val;
1884
0
      return(ret);
1885
0
  }
1886
0
    }
1887
0
    return(xmlXPathWrapString(val));
1888
0
}
1889
1890
/**
1891
 * xmlXPathCacheNewNodeSet:
1892
 * @ctxt: the XPath context
1893
 * @val:  the NodePtr value
1894
 *
1895
 * This is the cached version of xmlXPathNewNodeSet().
1896
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1897
 * it with the single Node @val
1898
 *
1899
 * Returns the created or reused object.
1900
 */
1901
static xmlXPathObjectPtr
1902
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
1903
0
{
1904
0
    if ((ctxt != NULL) && (ctxt->cache)) {
1905
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1906
1907
0
  if ((cache->nodesetObjs != NULL) &&
1908
0
      (cache->nodesetObjs->number != 0))
1909
0
  {
1910
0
      xmlXPathObjectPtr ret;
1911
      /*
1912
      * Use the nodeset-cache.
1913
      */
1914
0
      ret = (xmlXPathObjectPtr)
1915
0
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
1916
0
      ret->type = XPATH_NODESET;
1917
0
      ret->boolval = 0;
1918
0
      if (val) {
1919
0
    if ((ret->nodesetval->nodeMax == 0) ||
1920
0
        (val->type == XML_NAMESPACE_DECL))
1921
0
    {
1922
                    /* TODO: Check memory error. */
1923
0
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
1924
0
    } else {
1925
0
        ret->nodesetval->nodeTab[0] = val;
1926
0
        ret->nodesetval->nodeNr = 1;
1927
0
    }
1928
0
      }
1929
0
      return(ret);
1930
0
  } else if ((cache->miscObjs != NULL) &&
1931
0
      (cache->miscObjs->number != 0))
1932
0
  {
1933
0
      xmlXPathObjectPtr ret;
1934
0
            xmlNodeSetPtr set;
1935
      /*
1936
      * Fallback to misc-cache.
1937
      */
1938
1939
0
      set = xmlXPathNodeSetCreate(val);
1940
0
      if (set == NULL) {
1941
0
    ctxt->lastError.domain = XML_FROM_XPATH;
1942
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
1943
0
    return(NULL);
1944
0
      }
1945
1946
0
      ret = (xmlXPathObjectPtr)
1947
0
    cache->miscObjs->items[--cache->miscObjs->number];
1948
1949
0
      ret->type = XPATH_NODESET;
1950
0
      ret->boolval = 0;
1951
0
      ret->nodesetval = set;
1952
0
      return(ret);
1953
0
  }
1954
0
    }
1955
0
    return(xmlXPathNewNodeSet(val));
1956
0
}
1957
1958
/**
1959
 * xmlXPathCacheNewString:
1960
 * @ctxt: the XPath context
1961
 * @val:  the xmlChar * value
1962
 *
1963
 * This is the cached version of xmlXPathNewString().
1964
 * Acquire an xmlXPathObjectPtr of type string and of value @val
1965
 *
1966
 * Returns the created or reused object.
1967
 */
1968
static xmlXPathObjectPtr
1969
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
1970
0
{
1971
0
    if ((ctxt != NULL) && (ctxt->cache)) {
1972
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1973
1974
0
  if ((cache->stringObjs != NULL) &&
1975
0
      (cache->stringObjs->number != 0))
1976
0
  {
1977
0
      xmlXPathObjectPtr ret;
1978
0
            xmlChar *copy;
1979
1980
0
            if (val == NULL)
1981
0
                val = BAD_CAST "";
1982
0
            copy = xmlStrdup(val);
1983
0
            if (copy == NULL) {
1984
0
                xmlXPathErrMemory(ctxt, NULL);
1985
0
                return(NULL);
1986
0
            }
1987
1988
0
      ret = (xmlXPathObjectPtr)
1989
0
    cache->stringObjs->items[--cache->stringObjs->number];
1990
0
      ret->type = XPATH_STRING;
1991
0
            ret->stringval = copy;
1992
0
      return(ret);
1993
0
  } else if ((cache->miscObjs != NULL) &&
1994
0
      (cache->miscObjs->number != 0))
1995
0
  {
1996
0
      xmlXPathObjectPtr ret;
1997
0
            xmlChar *copy;
1998
1999
0
            if (val == NULL)
2000
0
                val = BAD_CAST "";
2001
0
            copy = xmlStrdup(val);
2002
0
            if (copy == NULL) {
2003
0
                xmlXPathErrMemory(ctxt, NULL);
2004
0
                return(NULL);
2005
0
            }
2006
2007
0
      ret = (xmlXPathObjectPtr)
2008
0
    cache->miscObjs->items[--cache->miscObjs->number];
2009
2010
0
      ret->type = XPATH_STRING;
2011
0
            ret->stringval = copy;
2012
0
      return(ret);
2013
0
  }
2014
0
    }
2015
0
    return(xmlXPathNewString(val));
2016
0
}
2017
2018
/**
2019
 * xmlXPathCacheNewCString:
2020
 * @ctxt: the XPath context
2021
 * @val:  the char * value
2022
 *
2023
 * This is the cached version of xmlXPathNewCString().
2024
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2025
 *
2026
 * Returns the created or reused object.
2027
 */
2028
static xmlXPathObjectPtr
2029
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2030
0
{
2031
0
    return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2032
0
}
2033
2034
/**
2035
 * xmlXPathCacheNewBoolean:
2036
 * @ctxt: the XPath context
2037
 * @val:  the boolean value
2038
 *
2039
 * This is the cached version of xmlXPathNewBoolean().
2040
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2041
 *
2042
 * Returns the created or reused object.
2043
 */
2044
static xmlXPathObjectPtr
2045
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2046
0
{
2047
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2048
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2049
2050
0
  if ((cache->booleanObjs != NULL) &&
2051
0
      (cache->booleanObjs->number != 0))
2052
0
  {
2053
0
      xmlXPathObjectPtr ret;
2054
2055
0
      ret = (xmlXPathObjectPtr)
2056
0
    cache->booleanObjs->items[--cache->booleanObjs->number];
2057
0
      ret->type = XPATH_BOOLEAN;
2058
0
      ret->boolval = (val != 0);
2059
0
      return(ret);
2060
0
  } else if ((cache->miscObjs != NULL) &&
2061
0
      (cache->miscObjs->number != 0))
2062
0
  {
2063
0
      xmlXPathObjectPtr ret;
2064
2065
0
      ret = (xmlXPathObjectPtr)
2066
0
    cache->miscObjs->items[--cache->miscObjs->number];
2067
2068
0
      ret->type = XPATH_BOOLEAN;
2069
0
      ret->boolval = (val != 0);
2070
0
      return(ret);
2071
0
  }
2072
0
    }
2073
0
    return(xmlXPathNewBoolean(val));
2074
0
}
2075
2076
/**
2077
 * xmlXPathCacheNewFloat:
2078
 * @ctxt: the XPath context
2079
 * @val:  the double value
2080
 *
2081
 * This is the cached version of xmlXPathNewFloat().
2082
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2083
 *
2084
 * Returns the created or reused object.
2085
 */
2086
static xmlXPathObjectPtr
2087
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2088
0
{
2089
0
     if ((ctxt != NULL) && (ctxt->cache)) {
2090
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2091
2092
0
  if ((cache->numberObjs != NULL) &&
2093
0
      (cache->numberObjs->number != 0))
2094
0
  {
2095
0
      xmlXPathObjectPtr ret;
2096
2097
0
      ret = (xmlXPathObjectPtr)
2098
0
    cache->numberObjs->items[--cache->numberObjs->number];
2099
0
      ret->type = XPATH_NUMBER;
2100
0
      ret->floatval = val;
2101
0
      return(ret);
2102
0
  } else if ((cache->miscObjs != NULL) &&
2103
0
      (cache->miscObjs->number != 0))
2104
0
  {
2105
0
      xmlXPathObjectPtr ret;
2106
2107
0
      ret = (xmlXPathObjectPtr)
2108
0
    cache->miscObjs->items[--cache->miscObjs->number];
2109
2110
0
      ret->type = XPATH_NUMBER;
2111
0
      ret->floatval = val;
2112
0
      return(ret);
2113
0
  }
2114
0
    }
2115
0
    return(xmlXPathNewFloat(val));
2116
0
}
2117
2118
/**
2119
 * xmlXPathCacheConvertString:
2120
 * @ctxt: the XPath context
2121
 * @val:  an XPath object
2122
 *
2123
 * This is the cached version of xmlXPathConvertString().
2124
 * Converts an existing object to its string() equivalent
2125
 *
2126
 * Returns a created or reused object, the old one is freed (cached)
2127
 *         (or the operation is done directly on @val)
2128
 */
2129
2130
static xmlXPathObjectPtr
2131
0
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2132
0
    xmlChar *res = NULL;
2133
2134
0
    if (val == NULL)
2135
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2136
2137
0
    switch (val->type) {
2138
0
    case XPATH_UNDEFINED:
2139
0
  break;
2140
0
    case XPATH_NODESET:
2141
0
    case XPATH_XSLT_TREE:
2142
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2143
0
  break;
2144
0
    case XPATH_STRING:
2145
0
  return(val);
2146
0
    case XPATH_BOOLEAN:
2147
0
  res = xmlXPathCastBooleanToString(val->boolval);
2148
0
  break;
2149
0
    case XPATH_NUMBER:
2150
0
  res = xmlXPathCastNumberToString(val->floatval);
2151
0
  break;
2152
0
    case XPATH_USERS:
2153
#ifdef LIBXML_XPTR_LOCS_ENABLED
2154
    case XPATH_POINT:
2155
    case XPATH_RANGE:
2156
    case XPATH_LOCATIONSET:
2157
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2158
0
  TODO;
2159
0
  break;
2160
0
    }
2161
0
    xmlXPathReleaseObject(ctxt, val);
2162
0
    if (res == NULL)
2163
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2164
0
    return(xmlXPathCacheWrapString(ctxt, res));
2165
0
}
2166
2167
/**
2168
 * xmlXPathCacheObjectCopy:
2169
 * @ctxt: the XPath context
2170
 * @val:  the original object
2171
 *
2172
 * This is the cached version of xmlXPathObjectCopy().
2173
 * Acquire a copy of a given object
2174
 *
2175
 * Returns a created or reused created object.
2176
 */
2177
static xmlXPathObjectPtr
2178
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2179
0
{
2180
0
    if (val == NULL)
2181
0
  return(NULL);
2182
2183
0
    if (XP_HAS_CACHE(ctxt)) {
2184
0
  switch (val->type) {
2185
0
      case XPATH_NODESET:
2186
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2187
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2188
0
      case XPATH_STRING:
2189
0
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2190
0
      case XPATH_BOOLEAN:
2191
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2192
0
      case XPATH_NUMBER:
2193
0
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2194
0
      default:
2195
0
    break;
2196
0
  }
2197
0
    }
2198
0
    return(xmlXPathObjectCopy(val));
2199
0
}
2200
2201
/**
2202
 * xmlXPathCacheConvertBoolean:
2203
 * @ctxt: the XPath context
2204
 * @val:  an XPath object
2205
 *
2206
 * This is the cached version of xmlXPathConvertBoolean().
2207
 * Converts an existing object to its boolean() equivalent
2208
 *
2209
 * Returns a created or reused object, the old one is freed (or the operation
2210
 *         is done directly on @val)
2211
 */
2212
static xmlXPathObjectPtr
2213
0
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2214
0
    xmlXPathObjectPtr ret;
2215
2216
0
    if (val == NULL)
2217
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2218
0
    if (val->type == XPATH_BOOLEAN)
2219
0
  return(val);
2220
0
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2221
0
    xmlXPathReleaseObject(ctxt, val);
2222
0
    return(ret);
2223
0
}
2224
2225
/**
2226
 * xmlXPathCacheConvertNumber:
2227
 * @ctxt: the XPath context
2228
 * @val:  an XPath object
2229
 *
2230
 * This is the cached version of xmlXPathConvertNumber().
2231
 * Converts an existing object to its number() equivalent
2232
 *
2233
 * Returns a created or reused object, the old one is freed (or the operation
2234
 *         is done directly on @val)
2235
 */
2236
static xmlXPathObjectPtr
2237
0
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2238
0
    xmlXPathObjectPtr ret;
2239
2240
0
    if (val == NULL)
2241
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2242
0
    if (val->type == XPATH_NUMBER)
2243
0
  return(val);
2244
0
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2245
0
    xmlXPathReleaseObject(ctxt, val);
2246
0
    return(ret);
2247
0
}
2248
2249
/************************************************************************
2250
 *                  *
2251
 *    Parser stacks related functions and macros    *
2252
 *                  *
2253
 ************************************************************************/
2254
2255
/**
2256
 * valuePop:
2257
 * @ctxt: an XPath evaluation context
2258
 *
2259
 * Pops the top XPath object from the value stack
2260
 *
2261
 * Returns the XPath object just removed
2262
 */
2263
xmlXPathObjectPtr
2264
valuePop(xmlXPathParserContextPtr ctxt)
2265
0
{
2266
0
    xmlXPathObjectPtr ret;
2267
2268
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2269
0
        return (NULL);
2270
2271
0
    ctxt->valueNr--;
2272
0
    if (ctxt->valueNr > 0)
2273
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2274
0
    else
2275
0
        ctxt->value = NULL;
2276
0
    ret = ctxt->valueTab[ctxt->valueNr];
2277
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
2278
0
    return (ret);
2279
0
}
2280
/**
2281
 * valuePush:
2282
 * @ctxt:  an XPath evaluation context
2283
 * @value:  the XPath object
2284
 *
2285
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2286
 * a memory error is recorded in the parser context.
2287
 *
2288
 * Returns the number of items on the value stack, or -1 in case of error.
2289
 *
2290
 * The object is destroyed in case of error.
2291
 */
2292
int
2293
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2294
0
{
2295
0
    if (ctxt == NULL) return(-1);
2296
0
    if (value == NULL) {
2297
        /*
2298
         * A NULL value typically indicates that a memory allocation failed,
2299
         * so we set ctxt->error here to propagate the error.
2300
         */
2301
0
  ctxt->error = XPATH_MEMORY_ERROR;
2302
0
        return(-1);
2303
0
    }
2304
0
    if (ctxt->valueNr >= ctxt->valueMax) {
2305
0
        xmlXPathObjectPtr *tmp;
2306
2307
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2308
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2309
0
            xmlXPathFreeObject(value);
2310
0
            return (-1);
2311
0
        }
2312
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2313
0
                                             2 * ctxt->valueMax *
2314
0
                                             sizeof(ctxt->valueTab[0]));
2315
0
        if (tmp == NULL) {
2316
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2317
0
            xmlXPathFreeObject(value);
2318
0
            return (-1);
2319
0
        }
2320
0
        ctxt->valueMax *= 2;
2321
0
  ctxt->valueTab = tmp;
2322
0
    }
2323
0
    ctxt->valueTab[ctxt->valueNr] = value;
2324
0
    ctxt->value = value;
2325
0
    return (ctxt->valueNr++);
2326
0
}
2327
2328
/**
2329
 * xmlXPathPopBoolean:
2330
 * @ctxt:  an XPath parser context
2331
 *
2332
 * Pops a boolean from the stack, handling conversion if needed.
2333
 * Check error with #xmlXPathCheckError.
2334
 *
2335
 * Returns the boolean
2336
 */
2337
int
2338
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2339
0
    xmlXPathObjectPtr obj;
2340
0
    int ret;
2341
2342
0
    obj = valuePop(ctxt);
2343
0
    if (obj == NULL) {
2344
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2345
0
  return(0);
2346
0
    }
2347
0
    if (obj->type != XPATH_BOOLEAN)
2348
0
  ret = xmlXPathCastToBoolean(obj);
2349
0
    else
2350
0
        ret = obj->boolval;
2351
0
    xmlXPathReleaseObject(ctxt->context, obj);
2352
0
    return(ret);
2353
0
}
2354
2355
/**
2356
 * xmlXPathPopNumber:
2357
 * @ctxt:  an XPath parser context
2358
 *
2359
 * Pops a number from the stack, handling conversion if needed.
2360
 * Check error with #xmlXPathCheckError.
2361
 *
2362
 * Returns the number
2363
 */
2364
double
2365
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2366
0
    xmlXPathObjectPtr obj;
2367
0
    double ret;
2368
2369
0
    obj = valuePop(ctxt);
2370
0
    if (obj == NULL) {
2371
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2372
0
  return(0);
2373
0
    }
2374
0
    if (obj->type != XPATH_NUMBER)
2375
0
  ret = xmlXPathCastToNumber(obj);
2376
0
    else
2377
0
        ret = obj->floatval;
2378
0
    xmlXPathReleaseObject(ctxt->context, obj);
2379
0
    return(ret);
2380
0
}
2381
2382
/**
2383
 * xmlXPathPopString:
2384
 * @ctxt:  an XPath parser context
2385
 *
2386
 * Pops a string from the stack, handling conversion if needed.
2387
 * Check error with #xmlXPathCheckError.
2388
 *
2389
 * Returns the string
2390
 */
2391
xmlChar *
2392
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2393
0
    xmlXPathObjectPtr obj;
2394
0
    xmlChar * ret;
2395
2396
0
    obj = valuePop(ctxt);
2397
0
    if (obj == NULL) {
2398
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2399
0
  return(NULL);
2400
0
    }
2401
0
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2402
    /* TODO: needs refactoring somewhere else */
2403
0
    if (obj->stringval == ret)
2404
0
  obj->stringval = NULL;
2405
0
    xmlXPathReleaseObject(ctxt->context, obj);
2406
0
    return(ret);
2407
0
}
2408
2409
/**
2410
 * xmlXPathPopNodeSet:
2411
 * @ctxt:  an XPath parser context
2412
 *
2413
 * Pops a node-set from the stack, handling conversion if needed.
2414
 * Check error with #xmlXPathCheckError.
2415
 *
2416
 * Returns the node-set
2417
 */
2418
xmlNodeSetPtr
2419
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2420
0
    xmlXPathObjectPtr obj;
2421
0
    xmlNodeSetPtr ret;
2422
2423
0
    if (ctxt == NULL) return(NULL);
2424
0
    if (ctxt->value == NULL) {
2425
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2426
0
  return(NULL);
2427
0
    }
2428
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2429
0
  xmlXPathSetTypeError(ctxt);
2430
0
  return(NULL);
2431
0
    }
2432
0
    obj = valuePop(ctxt);
2433
0
    ret = obj->nodesetval;
2434
#if 0
2435
    /* to fix memory leak of not clearing obj->user */
2436
    if (obj->boolval && obj->user != NULL)
2437
        xmlFreeNodeList((xmlNodePtr) obj->user);
2438
#endif
2439
0
    obj->nodesetval = NULL;
2440
0
    xmlXPathReleaseObject(ctxt->context, obj);
2441
0
    return(ret);
2442
0
}
2443
2444
/**
2445
 * xmlXPathPopExternal:
2446
 * @ctxt:  an XPath parser context
2447
 *
2448
 * Pops an external object from the stack, handling conversion if needed.
2449
 * Check error with #xmlXPathCheckError.
2450
 *
2451
 * Returns the object
2452
 */
2453
void *
2454
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2455
0
    xmlXPathObjectPtr obj;
2456
0
    void * ret;
2457
2458
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2459
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2460
0
  return(NULL);
2461
0
    }
2462
0
    if (ctxt->value->type != XPATH_USERS) {
2463
0
  xmlXPathSetTypeError(ctxt);
2464
0
  return(NULL);
2465
0
    }
2466
0
    obj = valuePop(ctxt);
2467
0
    ret = obj->user;
2468
0
    obj->user = NULL;
2469
0
    xmlXPathReleaseObject(ctxt->context, obj);
2470
0
    return(ret);
2471
0
}
2472
2473
/*
2474
 * Macros for accessing the content. Those should be used only by the parser,
2475
 * and not exported.
2476
 *
2477
 * Dirty macros, i.e. one need to make assumption on the context to use them
2478
 *
2479
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2480
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2481
 *           in ISO-Latin or UTF-8.
2482
 *           This should be used internally by the parser
2483
 *           only to compare to ASCII values otherwise it would break when
2484
 *           running with UTF-8 encoding.
2485
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2486
 *           to compare on ASCII based substring.
2487
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2488
 *           strings within the parser.
2489
 *   CURRENT Returns the current char value, with the full decoding of
2490
 *           UTF-8 if we are using this mode. It returns an int.
2491
 *   NEXT    Skip to the next character, this does the proper decoding
2492
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2493
 *           It returns the pointer to the current xmlChar.
2494
 */
2495
2496
0
#define CUR (*ctxt->cur)
2497
0
#define SKIP(val) ctxt->cur += (val)
2498
0
#define NXT(val) ctxt->cur[(val)]
2499
0
#define CUR_PTR ctxt->cur
2500
0
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2501
2502
#define COPY_BUF(l,b,i,v)                                              \
2503
0
    if (l == 1) b[i++] = v;                                            \
2504
0
    else i += xmlCopyChar(l,&b[i],v)
2505
2506
0
#define NEXTL(l)  ctxt->cur += l
2507
2508
#define SKIP_BLANKS             \
2509
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2510
2511
#define CURRENT (*ctxt->cur)
2512
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2513
2514
2515
#ifndef DBL_DIG
2516
#define DBL_DIG 16
2517
#endif
2518
#ifndef DBL_EPSILON
2519
#define DBL_EPSILON 1E-9
2520
#endif
2521
2522
0
#define UPPER_DOUBLE 1E9
2523
0
#define LOWER_DOUBLE 1E-5
2524
#define LOWER_DOUBLE_EXP 5
2525
2526
#define INTEGER_DIGITS DBL_DIG
2527
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2528
0
#define EXPONENT_DIGITS (3 + 2)
2529
2530
/**
2531
 * xmlXPathFormatNumber:
2532
 * @number:     number to format
2533
 * @buffer:     output buffer
2534
 * @buffersize: size of output buffer
2535
 *
2536
 * Convert the number into a string representation.
2537
 */
2538
static void
2539
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2540
0
{
2541
0
    switch (xmlXPathIsInf(number)) {
2542
0
    case 1:
2543
0
  if (buffersize > (int)sizeof("Infinity"))
2544
0
      snprintf(buffer, buffersize, "Infinity");
2545
0
  break;
2546
0
    case -1:
2547
0
  if (buffersize > (int)sizeof("-Infinity"))
2548
0
      snprintf(buffer, buffersize, "-Infinity");
2549
0
  break;
2550
0
    default:
2551
0
  if (xmlXPathIsNaN(number)) {
2552
0
      if (buffersize > (int)sizeof("NaN"))
2553
0
    snprintf(buffer, buffersize, "NaN");
2554
0
  } else if (number == 0) {
2555
            /* Omit sign for negative zero. */
2556
0
      snprintf(buffer, buffersize, "0");
2557
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2558
0
                   (number == (int) number)) {
2559
0
      char work[30];
2560
0
      char *ptr, *cur;
2561
0
      int value = (int) number;
2562
2563
0
            ptr = &buffer[0];
2564
0
      if (value == 0) {
2565
0
    *ptr++ = '0';
2566
0
      } else {
2567
0
    snprintf(work, 29, "%d", value);
2568
0
    cur = &work[0];
2569
0
    while ((*cur) && (ptr - buffer < buffersize)) {
2570
0
        *ptr++ = *cur++;
2571
0
    }
2572
0
      }
2573
0
      if (ptr - buffer < buffersize) {
2574
0
    *ptr = 0;
2575
0
      } else if (buffersize > 0) {
2576
0
    ptr--;
2577
0
    *ptr = 0;
2578
0
      }
2579
0
  } else {
2580
      /*
2581
        For the dimension of work,
2582
            DBL_DIG is number of significant digits
2583
      EXPONENT is only needed for "scientific notation"
2584
            3 is sign, decimal point, and terminating zero
2585
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2586
        Note that this dimension is slightly (a few characters)
2587
        larger than actually necessary.
2588
      */
2589
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2590
0
      int integer_place, fraction_place;
2591
0
      char *ptr;
2592
0
      char *after_fraction;
2593
0
      double absolute_value;
2594
0
      int size;
2595
2596
0
      absolute_value = fabs(number);
2597
2598
      /*
2599
       * First choose format - scientific or regular floating point.
2600
       * In either case, result is in work, and after_fraction points
2601
       * just past the fractional part.
2602
      */
2603
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
2604
0
      (absolute_value < LOWER_DOUBLE)) &&
2605
0
     (absolute_value != 0.0) ) {
2606
    /* Use scientific notation */
2607
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2608
0
    fraction_place = DBL_DIG - 1;
2609
0
    size = snprintf(work, sizeof(work),"%*.*e",
2610
0
       integer_place, fraction_place, number);
2611
0
    while ((size > 0) && (work[size] != 'e')) size--;
2612
2613
0
      }
2614
0
      else {
2615
    /* Use regular notation */
2616
0
    if (absolute_value > 0.0) {
2617
0
        integer_place = (int)log10(absolute_value);
2618
0
        if (integer_place > 0)
2619
0
            fraction_place = DBL_DIG - integer_place - 1;
2620
0
        else
2621
0
            fraction_place = DBL_DIG - integer_place;
2622
0
    } else {
2623
0
        fraction_place = 1;
2624
0
    }
2625
0
    size = snprintf(work, sizeof(work), "%0.*f",
2626
0
        fraction_place, number);
2627
0
      }
2628
2629
      /* Remove leading spaces sometimes inserted by snprintf */
2630
0
      while (work[0] == ' ') {
2631
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2632
0
    size--;
2633
0
      }
2634
2635
      /* Remove fractional trailing zeroes */
2636
0
      after_fraction = work + size;
2637
0
      ptr = after_fraction;
2638
0
      while (*(--ptr) == '0')
2639
0
    ;
2640
0
      if (*ptr != '.')
2641
0
          ptr++;
2642
0
      while ((*ptr++ = *after_fraction++) != 0);
2643
2644
      /* Finally copy result back to caller */
2645
0
      size = strlen(work) + 1;
2646
0
      if (size > buffersize) {
2647
0
    work[buffersize - 1] = 0;
2648
0
    size = buffersize;
2649
0
      }
2650
0
      memmove(buffer, work, size);
2651
0
  }
2652
0
  break;
2653
0
    }
2654
0
}
2655
2656
2657
/************************************************************************
2658
 *                  *
2659
 *      Routines to handle NodeSets     *
2660
 *                  *
2661
 ************************************************************************/
2662
2663
/**
2664
 * xmlXPathOrderDocElems:
2665
 * @doc:  an input document
2666
 *
2667
 * Call this routine to speed up XPath computation on static documents.
2668
 * This stamps all the element nodes with the document order
2669
 * Like for line information, the order is kept in the element->content
2670
 * field, the value stored is actually - the node number (starting at -1)
2671
 * to be able to differentiate from line numbers.
2672
 *
2673
 * Returns the number of elements found in the document or -1 in case
2674
 *    of error.
2675
 */
2676
long
2677
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
2678
0
    ptrdiff_t count = 0;
2679
0
    xmlNodePtr cur;
2680
2681
0
    if (doc == NULL)
2682
0
  return(-1);
2683
0
    cur = doc->children;
2684
0
    while (cur != NULL) {
2685
0
  if (cur->type == XML_ELEMENT_NODE) {
2686
0
      cur->content = (void *) (-(++count));
2687
0
      if (cur->children != NULL) {
2688
0
    cur = cur->children;
2689
0
    continue;
2690
0
      }
2691
0
  }
2692
0
  if (cur->next != NULL) {
2693
0
      cur = cur->next;
2694
0
      continue;
2695
0
  }
2696
0
  do {
2697
0
      cur = cur->parent;
2698
0
      if (cur == NULL)
2699
0
    break;
2700
0
      if (cur == (xmlNodePtr) doc) {
2701
0
    cur = NULL;
2702
0
    break;
2703
0
      }
2704
0
      if (cur->next != NULL) {
2705
0
    cur = cur->next;
2706
0
    break;
2707
0
      }
2708
0
  } while (cur != NULL);
2709
0
    }
2710
0
    return(count);
2711
0
}
2712
2713
/**
2714
 * xmlXPathCmpNodes:
2715
 * @node1:  the first node
2716
 * @node2:  the second node
2717
 *
2718
 * Compare two nodes w.r.t document order
2719
 *
2720
 * Returns -2 in case of error 1 if first point < second point, 0 if
2721
 *         it's the same node, -1 otherwise
2722
 */
2723
int
2724
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2725
0
    int depth1, depth2;
2726
0
    int attr1 = 0, attr2 = 0;
2727
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2728
0
    xmlNodePtr cur, root;
2729
2730
0
    if ((node1 == NULL) || (node2 == NULL))
2731
0
  return(-2);
2732
    /*
2733
     * a couple of optimizations which will avoid computations in most cases
2734
     */
2735
0
    if (node1 == node2)   /* trivial case */
2736
0
  return(0);
2737
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2738
0
  attr1 = 1;
2739
0
  attrNode1 = node1;
2740
0
  node1 = node1->parent;
2741
0
    }
2742
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2743
0
  attr2 = 1;
2744
0
  attrNode2 = node2;
2745
0
  node2 = node2->parent;
2746
0
    }
2747
0
    if (node1 == node2) {
2748
0
  if (attr1 == attr2) {
2749
      /* not required, but we keep attributes in order */
2750
0
      if (attr1 != 0) {
2751
0
          cur = attrNode2->prev;
2752
0
    while (cur != NULL) {
2753
0
        if (cur == attrNode1)
2754
0
            return (1);
2755
0
        cur = cur->prev;
2756
0
    }
2757
0
    return (-1);
2758
0
      }
2759
0
      return(0);
2760
0
  }
2761
0
  if (attr2 == 1)
2762
0
      return(1);
2763
0
  return(-1);
2764
0
    }
2765
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2766
0
        (node2->type == XML_NAMESPACE_DECL))
2767
0
  return(1);
2768
0
    if (node1 == node2->prev)
2769
0
  return(1);
2770
0
    if (node1 == node2->next)
2771
0
  return(-1);
2772
2773
    /*
2774
     * Speedup using document order if available.
2775
     */
2776
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2777
0
  (node2->type == XML_ELEMENT_NODE) &&
2778
0
  (0 > (ptrdiff_t) node1->content) &&
2779
0
  (0 > (ptrdiff_t) node2->content) &&
2780
0
  (node1->doc == node2->doc)) {
2781
0
  ptrdiff_t l1, l2;
2782
2783
0
  l1 = -((ptrdiff_t) node1->content);
2784
0
  l2 = -((ptrdiff_t) node2->content);
2785
0
  if (l1 < l2)
2786
0
      return(1);
2787
0
  if (l1 > l2)
2788
0
      return(-1);
2789
0
    }
2790
2791
    /*
2792
     * compute depth to root
2793
     */
2794
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2795
0
  if (cur->parent == node1)
2796
0
      return(1);
2797
0
  depth2++;
2798
0
    }
2799
0
    root = cur;
2800
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2801
0
  if (cur->parent == node2)
2802
0
      return(-1);
2803
0
  depth1++;
2804
0
    }
2805
    /*
2806
     * Distinct document (or distinct entities :-( ) case.
2807
     */
2808
0
    if (root != cur) {
2809
0
  return(-2);
2810
0
    }
2811
    /*
2812
     * get the nearest common ancestor.
2813
     */
2814
0
    while (depth1 > depth2) {
2815
0
  depth1--;
2816
0
  node1 = node1->parent;
2817
0
    }
2818
0
    while (depth2 > depth1) {
2819
0
  depth2--;
2820
0
  node2 = node2->parent;
2821
0
    }
2822
0
    while (node1->parent != node2->parent) {
2823
0
  node1 = node1->parent;
2824
0
  node2 = node2->parent;
2825
  /* should not happen but just in case ... */
2826
0
  if ((node1 == NULL) || (node2 == NULL))
2827
0
      return(-2);
2828
0
    }
2829
    /*
2830
     * Find who's first.
2831
     */
2832
0
    if (node1 == node2->prev)
2833
0
  return(1);
2834
0
    if (node1 == node2->next)
2835
0
  return(-1);
2836
    /*
2837
     * Speedup using document order if available.
2838
     */
2839
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2840
0
  (node2->type == XML_ELEMENT_NODE) &&
2841
0
  (0 > (ptrdiff_t) node1->content) &&
2842
0
  (0 > (ptrdiff_t) node2->content) &&
2843
0
  (node1->doc == node2->doc)) {
2844
0
  ptrdiff_t l1, l2;
2845
2846
0
  l1 = -((ptrdiff_t) node1->content);
2847
0
  l2 = -((ptrdiff_t) node2->content);
2848
0
  if (l1 < l2)
2849
0
      return(1);
2850
0
  if (l1 > l2)
2851
0
      return(-1);
2852
0
    }
2853
2854
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2855
0
  if (cur == node2)
2856
0
      return(1);
2857
0
    return(-1); /* assume there is no sibling list corruption */
2858
0
}
2859
2860
/**
2861
 * xmlXPathNodeSetSort:
2862
 * @set:  the node set
2863
 *
2864
 * Sort the node set in document order
2865
 */
2866
void
2867
0
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2868
#ifndef WITH_TIM_SORT
2869
    int i, j, incr, len;
2870
    xmlNodePtr tmp;
2871
#endif
2872
2873
0
    if (set == NULL)
2874
0
  return;
2875
2876
#ifndef WITH_TIM_SORT
2877
    /*
2878
     * Use the old Shell's sort implementation to sort the node-set
2879
     * Timsort ought to be quite faster
2880
     */
2881
    len = set->nodeNr;
2882
    for (incr = len / 2; incr > 0; incr /= 2) {
2883
  for (i = incr; i < len; i++) {
2884
      j = i - incr;
2885
      while (j >= 0) {
2886
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2887
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
2888
      set->nodeTab[j + incr]) == -1)
2889
#else
2890
    if (xmlXPathCmpNodes(set->nodeTab[j],
2891
      set->nodeTab[j + incr]) == -1)
2892
#endif
2893
    {
2894
        tmp = set->nodeTab[j];
2895
        set->nodeTab[j] = set->nodeTab[j + incr];
2896
        set->nodeTab[j + incr] = tmp;
2897
        j -= incr;
2898
    } else
2899
        break;
2900
      }
2901
  }
2902
    }
2903
#else /* WITH_TIM_SORT */
2904
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2905
0
#endif /* WITH_TIM_SORT */
2906
0
}
2907
2908
0
#define XML_NODESET_DEFAULT 10
2909
/**
2910
 * xmlXPathNodeSetDupNs:
2911
 * @node:  the parent node of the namespace XPath node
2912
 * @ns:  the libxml namespace declaration node.
2913
 *
2914
 * Namespace node in libxml don't match the XPath semantic. In a node set
2915
 * the namespace nodes are duplicated and the next pointer is set to the
2916
 * parent node in the XPath semantic.
2917
 *
2918
 * Returns the newly created object.
2919
 */
2920
static xmlNodePtr
2921
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2922
0
    xmlNsPtr cur;
2923
2924
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2925
0
  return(NULL);
2926
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2927
0
  return((xmlNodePtr) ns);
2928
2929
    /*
2930
     * Allocate a new Namespace and fill the fields.
2931
     */
2932
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2933
0
    if (cur == NULL) {
2934
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
2935
0
  return(NULL);
2936
0
    }
2937
0
    memset(cur, 0, sizeof(xmlNs));
2938
0
    cur->type = XML_NAMESPACE_DECL;
2939
0
    if (ns->href != NULL)
2940
0
  cur->href = xmlStrdup(ns->href);
2941
0
    if (ns->prefix != NULL)
2942
0
  cur->prefix = xmlStrdup(ns->prefix);
2943
0
    cur->next = (xmlNsPtr) node;
2944
0
    return((xmlNodePtr) cur);
2945
0
}
2946
2947
/**
2948
 * xmlXPathNodeSetFreeNs:
2949
 * @ns:  the XPath namespace node found in a nodeset.
2950
 *
2951
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2952
 * the namespace nodes are duplicated and the next pointer is set to the
2953
 * parent node in the XPath semantic. Check if such a node needs to be freed
2954
 */
2955
void
2956
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2957
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2958
0
  return;
2959
2960
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2961
0
  if (ns->href != NULL)
2962
0
      xmlFree((xmlChar *)ns->href);
2963
0
  if (ns->prefix != NULL)
2964
0
      xmlFree((xmlChar *)ns->prefix);
2965
0
  xmlFree(ns);
2966
0
    }
2967
0
}
2968
2969
/**
2970
 * xmlXPathNodeSetCreate:
2971
 * @val:  an initial xmlNodePtr, or NULL
2972
 *
2973
 * Create a new xmlNodeSetPtr of type double and of value @val
2974
 *
2975
 * Returns the newly created object.
2976
 */
2977
xmlNodeSetPtr
2978
0
xmlXPathNodeSetCreate(xmlNodePtr val) {
2979
0
    xmlNodeSetPtr ret;
2980
2981
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2982
0
    if (ret == NULL) {
2983
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
2984
0
  return(NULL);
2985
0
    }
2986
0
    memset(ret, 0 , sizeof(xmlNodeSet));
2987
0
    if (val != NULL) {
2988
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2989
0
               sizeof(xmlNodePtr));
2990
0
  if (ret->nodeTab == NULL) {
2991
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
2992
0
      xmlFree(ret);
2993
0
      return(NULL);
2994
0
  }
2995
0
  memset(ret->nodeTab, 0 ,
2996
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2997
0
        ret->nodeMax = XML_NODESET_DEFAULT;
2998
0
  if (val->type == XML_NAMESPACE_DECL) {
2999
0
      xmlNsPtr ns = (xmlNsPtr) val;
3000
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3001
3002
0
            if (nsNode == NULL) {
3003
0
                xmlXPathFreeNodeSet(ret);
3004
0
                return(NULL);
3005
0
            }
3006
0
      ret->nodeTab[ret->nodeNr++] = nsNode;
3007
0
  } else
3008
0
      ret->nodeTab[ret->nodeNr++] = val;
3009
0
    }
3010
0
    return(ret);
3011
0
}
3012
3013
/**
3014
 * xmlXPathNodeSetContains:
3015
 * @cur:  the node-set
3016
 * @val:  the node
3017
 *
3018
 * checks whether @cur contains @val
3019
 *
3020
 * Returns true (1) if @cur contains @val, false (0) otherwise
3021
 */
3022
int
3023
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3024
0
    int i;
3025
3026
0
    if ((cur == NULL) || (val == NULL)) return(0);
3027
0
    if (val->type == XML_NAMESPACE_DECL) {
3028
0
  for (i = 0; i < cur->nodeNr; i++) {
3029
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3030
0
    xmlNsPtr ns1, ns2;
3031
3032
0
    ns1 = (xmlNsPtr) val;
3033
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3034
0
    if (ns1 == ns2)
3035
0
        return(1);
3036
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3037
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3038
0
        return(1);
3039
0
      }
3040
0
  }
3041
0
    } else {
3042
0
  for (i = 0; i < cur->nodeNr; i++) {
3043
0
      if (cur->nodeTab[i] == val)
3044
0
    return(1);
3045
0
  }
3046
0
    }
3047
0
    return(0);
3048
0
}
3049
3050
/**
3051
 * xmlXPathNodeSetAddNs:
3052
 * @cur:  the initial node set
3053
 * @node:  the hosting node
3054
 * @ns:  a the namespace node
3055
 *
3056
 * add a new namespace node to an existing NodeSet
3057
 *
3058
 * Returns 0 in case of success and -1 in case of error
3059
 */
3060
int
3061
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3062
0
    int i;
3063
0
    xmlNodePtr nsNode;
3064
3065
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3066
0
        (ns->type != XML_NAMESPACE_DECL) ||
3067
0
  (node->type != XML_ELEMENT_NODE))
3068
0
  return(-1);
3069
3070
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3071
    /*
3072
     * prevent duplicates
3073
     */
3074
0
    for (i = 0;i < cur->nodeNr;i++) {
3075
0
        if ((cur->nodeTab[i] != NULL) &&
3076
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3077
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3078
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3079
0
      return(0);
3080
0
    }
3081
3082
    /*
3083
     * grow the nodeTab if needed
3084
     */
3085
0
    if (cur->nodeMax == 0) {
3086
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3087
0
               sizeof(xmlNodePtr));
3088
0
  if (cur->nodeTab == NULL) {
3089
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3090
0
      return(-1);
3091
0
  }
3092
0
  memset(cur->nodeTab, 0 ,
3093
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3094
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3095
0
    } else if (cur->nodeNr == cur->nodeMax) {
3096
0
        xmlNodePtr *temp;
3097
3098
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3099
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3100
0
            return(-1);
3101
0
        }
3102
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3103
0
              sizeof(xmlNodePtr));
3104
0
  if (temp == NULL) {
3105
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3106
0
      return(-1);
3107
0
  }
3108
0
        cur->nodeMax *= 2;
3109
0
  cur->nodeTab = temp;
3110
0
    }
3111
0
    nsNode = xmlXPathNodeSetDupNs(node, ns);
3112
0
    if(nsNode == NULL)
3113
0
        return(-1);
3114
0
    cur->nodeTab[cur->nodeNr++] = nsNode;
3115
0
    return(0);
3116
0
}
3117
3118
/**
3119
 * xmlXPathNodeSetAdd:
3120
 * @cur:  the initial node set
3121
 * @val:  a new xmlNodePtr
3122
 *
3123
 * add a new xmlNodePtr to an existing NodeSet
3124
 *
3125
 * Returns 0 in case of success, and -1 in case of error
3126
 */
3127
int
3128
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3129
0
    int i;
3130
3131
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3132
3133
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3134
    /*
3135
     * prevent duplicates
3136
     */
3137
0
    for (i = 0;i < cur->nodeNr;i++)
3138
0
        if (cur->nodeTab[i] == val) return(0);
3139
3140
    /*
3141
     * grow the nodeTab if needed
3142
     */
3143
0
    if (cur->nodeMax == 0) {
3144
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3145
0
               sizeof(xmlNodePtr));
3146
0
  if (cur->nodeTab == NULL) {
3147
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3148
0
      return(-1);
3149
0
  }
3150
0
  memset(cur->nodeTab, 0 ,
3151
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3152
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3153
0
    } else if (cur->nodeNr == cur->nodeMax) {
3154
0
        xmlNodePtr *temp;
3155
3156
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3157
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3158
0
            return(-1);
3159
0
        }
3160
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3161
0
              sizeof(xmlNodePtr));
3162
0
  if (temp == NULL) {
3163
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3164
0
      return(-1);
3165
0
  }
3166
0
        cur->nodeMax *= 2;
3167
0
  cur->nodeTab = temp;
3168
0
    }
3169
0
    if (val->type == XML_NAMESPACE_DECL) {
3170
0
  xmlNsPtr ns = (xmlNsPtr) val;
3171
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3172
3173
0
        if (nsNode == NULL)
3174
0
            return(-1);
3175
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
3176
0
    } else
3177
0
  cur->nodeTab[cur->nodeNr++] = val;
3178
0
    return(0);
3179
0
}
3180
3181
/**
3182
 * xmlXPathNodeSetAddUnique:
3183
 * @cur:  the initial node set
3184
 * @val:  a new xmlNodePtr
3185
 *
3186
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3187
 * when we are sure the node is not already in the set.
3188
 *
3189
 * Returns 0 in case of success and -1 in case of failure
3190
 */
3191
int
3192
0
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3193
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3194
3195
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3196
    /*
3197
     * grow the nodeTab if needed
3198
     */
3199
0
    if (cur->nodeMax == 0) {
3200
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3201
0
               sizeof(xmlNodePtr));
3202
0
  if (cur->nodeTab == NULL) {
3203
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3204
0
      return(-1);
3205
0
  }
3206
0
  memset(cur->nodeTab, 0 ,
3207
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3208
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3209
0
    } else if (cur->nodeNr == cur->nodeMax) {
3210
0
        xmlNodePtr *temp;
3211
3212
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3213
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3214
0
            return(-1);
3215
0
        }
3216
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3217
0
              sizeof(xmlNodePtr));
3218
0
  if (temp == NULL) {
3219
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3220
0
      return(-1);
3221
0
  }
3222
0
  cur->nodeTab = temp;
3223
0
        cur->nodeMax *= 2;
3224
0
    }
3225
0
    if (val->type == XML_NAMESPACE_DECL) {
3226
0
  xmlNsPtr ns = (xmlNsPtr) val;
3227
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3228
3229
0
        if (nsNode == NULL)
3230
0
            return(-1);
3231
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
3232
0
    } else
3233
0
  cur->nodeTab[cur->nodeNr++] = val;
3234
0
    return(0);
3235
0
}
3236
3237
/**
3238
 * xmlXPathNodeSetMerge:
3239
 * @val1:  the first NodeSet or NULL
3240
 * @val2:  the second NodeSet
3241
 *
3242
 * Merges two nodesets, all nodes from @val2 are added to @val1
3243
 * if @val1 is NULL, a new set is created and copied from @val2
3244
 *
3245
 * Returns @val1 once extended or NULL in case of error.
3246
 *
3247
 * Frees @val1 in case of error.
3248
 */
3249
xmlNodeSetPtr
3250
0
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3251
0
    int i, j, initNr, skip;
3252
0
    xmlNodePtr n1, n2;
3253
3254
0
    if (val2 == NULL) return(val1);
3255
0
    if (val1 == NULL) {
3256
0
  val1 = xmlXPathNodeSetCreate(NULL);
3257
0
        if (val1 == NULL)
3258
0
            return (NULL);
3259
0
    }
3260
3261
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3262
0
    initNr = val1->nodeNr;
3263
3264
0
    for (i = 0;i < val2->nodeNr;i++) {
3265
0
  n2 = val2->nodeTab[i];
3266
  /*
3267
   * check against duplicates
3268
   */
3269
0
  skip = 0;
3270
0
  for (j = 0; j < initNr; j++) {
3271
0
      n1 = val1->nodeTab[j];
3272
0
      if (n1 == n2) {
3273
0
    skip = 1;
3274
0
    break;
3275
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3276
0
           (n2->type == XML_NAMESPACE_DECL)) {
3277
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3278
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3279
0
      ((xmlNsPtr) n2)->prefix)))
3280
0
    {
3281
0
        skip = 1;
3282
0
        break;
3283
0
    }
3284
0
      }
3285
0
  }
3286
0
  if (skip)
3287
0
      continue;
3288
3289
  /*
3290
   * grow the nodeTab if needed
3291
   */
3292
0
  if (val1->nodeMax == 0) {
3293
0
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3294
0
                sizeof(xmlNodePtr));
3295
0
      if (val1->nodeTab == NULL) {
3296
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3297
0
    goto error;
3298
0
      }
3299
0
      memset(val1->nodeTab, 0 ,
3300
0
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3301
0
      val1->nodeMax = XML_NODESET_DEFAULT;
3302
0
  } else if (val1->nodeNr == val1->nodeMax) {
3303
0
      xmlNodePtr *temp;
3304
3305
0
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3306
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3307
0
                goto error;
3308
0
            }
3309
0
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3310
0
               sizeof(xmlNodePtr));
3311
0
      if (temp == NULL) {
3312
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3313
0
    goto error;
3314
0
      }
3315
0
      val1->nodeTab = temp;
3316
0
      val1->nodeMax *= 2;
3317
0
  }
3318
0
  if (n2->type == XML_NAMESPACE_DECL) {
3319
0
      xmlNsPtr ns = (xmlNsPtr) n2;
3320
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3321
3322
0
            if (nsNode == NULL)
3323
0
                goto error;
3324
0
      val1->nodeTab[val1->nodeNr++] = nsNode;
3325
0
  } else
3326
0
      val1->nodeTab[val1->nodeNr++] = n2;
3327
0
    }
3328
3329
0
    return(val1);
3330
3331
0
error:
3332
0
    xmlXPathFreeNodeSet(val1);
3333
0
    return(NULL);
3334
0
}
3335
3336
3337
/**
3338
 * xmlXPathNodeSetMergeAndClear:
3339
 * @set1:  the first NodeSet or NULL
3340
 * @set2:  the second NodeSet
3341
 *
3342
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3343
 * Checks for duplicate nodes. Clears set2.
3344
 *
3345
 * Returns @set1 once extended or NULL in case of error.
3346
 *
3347
 * Frees @set1 in case of error.
3348
 */
3349
static xmlNodeSetPtr
3350
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3351
0
{
3352
0
    {
3353
0
  int i, j, initNbSet1;
3354
0
  xmlNodePtr n1, n2;
3355
3356
0
  initNbSet1 = set1->nodeNr;
3357
0
  for (i = 0;i < set2->nodeNr;i++) {
3358
0
      n2 = set2->nodeTab[i];
3359
      /*
3360
      * Skip duplicates.
3361
      */
3362
0
      for (j = 0; j < initNbSet1; j++) {
3363
0
    n1 = set1->nodeTab[j];
3364
0
    if (n1 == n2) {
3365
0
        goto skip_node;
3366
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3367
0
        (n2->type == XML_NAMESPACE_DECL))
3368
0
    {
3369
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3370
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3371
0
      ((xmlNsPtr) n2)->prefix)))
3372
0
        {
3373
      /*
3374
      * Free the namespace node.
3375
      */
3376
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3377
0
      goto skip_node;
3378
0
        }
3379
0
    }
3380
0
      }
3381
      /*
3382
      * grow the nodeTab if needed
3383
      */
3384
0
      if (set1->nodeMax == 0) {
3385
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3386
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3387
0
    if (set1->nodeTab == NULL) {
3388
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3389
0
        goto error;
3390
0
    }
3391
0
    memset(set1->nodeTab, 0,
3392
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3393
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3394
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3395
0
    xmlNodePtr *temp;
3396
3397
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3398
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3399
0
                    goto error;
3400
0
                }
3401
0
    temp = (xmlNodePtr *) xmlRealloc(
3402
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3403
0
    if (temp == NULL) {
3404
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3405
0
        goto error;
3406
0
    }
3407
0
    set1->nodeTab = temp;
3408
0
    set1->nodeMax *= 2;
3409
0
      }
3410
0
      set1->nodeTab[set1->nodeNr++] = n2;
3411
0
skip_node:
3412
0
            set2->nodeTab[i] = NULL;
3413
0
  }
3414
0
    }
3415
0
    set2->nodeNr = 0;
3416
0
    return(set1);
3417
3418
0
error:
3419
0
    xmlXPathFreeNodeSet(set1);
3420
0
    xmlXPathNodeSetClear(set2, 1);
3421
0
    return(NULL);
3422
0
}
3423
3424
/**
3425
 * xmlXPathNodeSetMergeAndClearNoDupls:
3426
 * @set1:  the first NodeSet or NULL
3427
 * @set2:  the second NodeSet
3428
 *
3429
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3430
 * Doesn't check for duplicate nodes. Clears set2.
3431
 *
3432
 * Returns @set1 once extended or NULL in case of error.
3433
 *
3434
 * Frees @set1 in case of error.
3435
 */
3436
static xmlNodeSetPtr
3437
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3438
0
{
3439
0
    {
3440
0
  int i;
3441
0
  xmlNodePtr n2;
3442
3443
0
  for (i = 0;i < set2->nodeNr;i++) {
3444
0
      n2 = set2->nodeTab[i];
3445
0
      if (set1->nodeMax == 0) {
3446
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3447
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3448
0
    if (set1->nodeTab == NULL) {
3449
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3450
0
        goto error;
3451
0
    }
3452
0
    memset(set1->nodeTab, 0,
3453
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3454
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3455
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3456
0
    xmlNodePtr *temp;
3457
3458
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3459
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3460
0
                    goto error;
3461
0
                }
3462
0
    temp = (xmlNodePtr *) xmlRealloc(
3463
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3464
0
    if (temp == NULL) {
3465
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3466
0
        goto error;
3467
0
    }
3468
0
    set1->nodeTab = temp;
3469
0
    set1->nodeMax *= 2;
3470
0
      }
3471
0
      set1->nodeTab[set1->nodeNr++] = n2;
3472
0
            set2->nodeTab[i] = NULL;
3473
0
  }
3474
0
    }
3475
0
    set2->nodeNr = 0;
3476
0
    return(set1);
3477
3478
0
error:
3479
0
    xmlXPathFreeNodeSet(set1);
3480
0
    xmlXPathNodeSetClear(set2, 1);
3481
0
    return(NULL);
3482
0
}
3483
3484
/**
3485
 * xmlXPathNodeSetDel:
3486
 * @cur:  the initial node set
3487
 * @val:  an xmlNodePtr
3488
 *
3489
 * Removes an xmlNodePtr from an existing NodeSet
3490
 */
3491
void
3492
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3493
0
    int i;
3494
3495
0
    if (cur == NULL) return;
3496
0
    if (val == NULL) return;
3497
3498
    /*
3499
     * find node in nodeTab
3500
     */
3501
0
    for (i = 0;i < cur->nodeNr;i++)
3502
0
        if (cur->nodeTab[i] == val) break;
3503
3504
0
    if (i >= cur->nodeNr) { /* not found */
3505
0
        return;
3506
0
    }
3507
0
    if ((cur->nodeTab[i] != NULL) &&
3508
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3509
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3510
0
    cur->nodeNr--;
3511
0
    for (;i < cur->nodeNr;i++)
3512
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
3513
0
    cur->nodeTab[cur->nodeNr] = NULL;
3514
0
}
3515
3516
/**
3517
 * xmlXPathNodeSetRemove:
3518
 * @cur:  the initial node set
3519
 * @val:  the index to remove
3520
 *
3521
 * Removes an entry from an existing NodeSet list.
3522
 */
3523
void
3524
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3525
0
    if (cur == NULL) return;
3526
0
    if (val >= cur->nodeNr) return;
3527
0
    if ((cur->nodeTab[val] != NULL) &&
3528
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3529
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3530
0
    cur->nodeNr--;
3531
0
    for (;val < cur->nodeNr;val++)
3532
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
3533
0
    cur->nodeTab[cur->nodeNr] = NULL;
3534
0
}
3535
3536
/**
3537
 * xmlXPathFreeNodeSet:
3538
 * @obj:  the xmlNodeSetPtr to free
3539
 *
3540
 * Free the NodeSet compound (not the actual nodes !).
3541
 */
3542
void
3543
0
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3544
0
    if (obj == NULL) return;
3545
0
    if (obj->nodeTab != NULL) {
3546
0
  int i;
3547
3548
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3549
0
  for (i = 0;i < obj->nodeNr;i++)
3550
0
      if ((obj->nodeTab[i] != NULL) &&
3551
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3552
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3553
0
  xmlFree(obj->nodeTab);
3554
0
    }
3555
0
    xmlFree(obj);
3556
0
}
3557
3558
/**
3559
 * xmlXPathNodeSetClearFromPos:
3560
 * @set: the node set to be cleared
3561
 * @pos: the start position to clear from
3562
 *
3563
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3564
 * are feed) starting with the entry at @pos, but does *not* free the list
3565
 * itself. Sets the length of the list to @pos.
3566
 */
3567
static void
3568
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3569
0
{
3570
0
    if ((set == NULL) || (pos >= set->nodeNr))
3571
0
  return;
3572
0
    else if ((hasNsNodes)) {
3573
0
  int i;
3574
0
  xmlNodePtr node;
3575
3576
0
  for (i = pos; i < set->nodeNr; i++) {
3577
0
      node = set->nodeTab[i];
3578
0
      if ((node != NULL) &&
3579
0
    (node->type == XML_NAMESPACE_DECL))
3580
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3581
0
  }
3582
0
    }
3583
0
    set->nodeNr = pos;
3584
0
}
3585
3586
/**
3587
 * xmlXPathNodeSetClear:
3588
 * @set:  the node set to clear
3589
 *
3590
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3591
 * are feed), but does *not* free the list itself. Sets the length of the
3592
 * list to 0.
3593
 */
3594
static void
3595
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3596
0
{
3597
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3598
0
}
3599
3600
/**
3601
 * xmlXPathNodeSetKeepLast:
3602
 * @set: the node set to be cleared
3603
 *
3604
 * Move the last node to the first position and clear temporary XPath objects
3605
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3606
 * to 1.
3607
 */
3608
static void
3609
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3610
0
{
3611
0
    int i;
3612
0
    xmlNodePtr node;
3613
3614
0
    if ((set == NULL) || (set->nodeNr <= 1))
3615
0
  return;
3616
0
    for (i = 0; i < set->nodeNr - 1; i++) {
3617
0
        node = set->nodeTab[i];
3618
0
        if ((node != NULL) &&
3619
0
            (node->type == XML_NAMESPACE_DECL))
3620
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3621
0
    }
3622
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3623
0
    set->nodeNr = 1;
3624
0
}
3625
3626
/**
3627
 * xmlXPathFreeValueTree:
3628
 * @obj:  the xmlNodeSetPtr to free
3629
 *
3630
 * Free the NodeSet compound and the actual tree, this is different
3631
 * from xmlXPathFreeNodeSet()
3632
 */
3633
static void
3634
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3635
0
    int i;
3636
3637
0
    if (obj == NULL) return;
3638
3639
0
    if (obj->nodeTab != NULL) {
3640
0
  for (i = 0;i < obj->nodeNr;i++) {
3641
0
      if (obj->nodeTab[i] != NULL) {
3642
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3643
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3644
0
    } else {
3645
0
        xmlFreeNodeList(obj->nodeTab[i]);
3646
0
    }
3647
0
      }
3648
0
  }
3649
0
  xmlFree(obj->nodeTab);
3650
0
    }
3651
0
    xmlFree(obj);
3652
0
}
3653
3654
/**
3655
 * xmlXPathNewNodeSet:
3656
 * @val:  the NodePtr value
3657
 *
3658
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3659
 * it with the single Node @val
3660
 *
3661
 * Returns the newly created object.
3662
 */
3663
xmlXPathObjectPtr
3664
0
xmlXPathNewNodeSet(xmlNodePtr val) {
3665
0
    xmlXPathObjectPtr ret;
3666
3667
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3668
0
    if (ret == NULL) {
3669
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3670
0
  return(NULL);
3671
0
    }
3672
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3673
0
    ret->type = XPATH_NODESET;
3674
0
    ret->boolval = 0;
3675
    /* TODO: Check memory error. */
3676
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3677
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3678
0
    return(ret);
3679
0
}
3680
3681
/**
3682
 * xmlXPathNewValueTree:
3683
 * @val:  the NodePtr value
3684
 *
3685
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3686
 * it with the tree root @val
3687
 *
3688
 * Returns the newly created object.
3689
 */
3690
xmlXPathObjectPtr
3691
0
xmlXPathNewValueTree(xmlNodePtr val) {
3692
0
    xmlXPathObjectPtr ret;
3693
3694
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3695
0
    if (ret == NULL) {
3696
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
3697
0
  return(NULL);
3698
0
    }
3699
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3700
0
    ret->type = XPATH_XSLT_TREE;
3701
0
    ret->boolval = 1;
3702
0
    ret->user = (void *) val;
3703
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3704
0
    return(ret);
3705
0
}
3706
3707
/**
3708
 * xmlXPathNewNodeSetList:
3709
 * @val:  an existing NodeSet
3710
 *
3711
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
3712
 * it with the Nodeset @val
3713
 *
3714
 * Returns the newly created object.
3715
 */
3716
xmlXPathObjectPtr
3717
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3718
0
{
3719
0
    xmlXPathObjectPtr ret;
3720
0
    int i;
3721
3722
0
    if (val == NULL)
3723
0
        ret = NULL;
3724
0
    else if (val->nodeTab == NULL)
3725
0
        ret = xmlXPathNewNodeSet(NULL);
3726
0
    else {
3727
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3728
0
        if (ret) {
3729
0
            for (i = 1; i < val->nodeNr; ++i) {
3730
                /* TODO: Propagate memory error. */
3731
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
3732
0
        < 0) break;
3733
0
      }
3734
0
  }
3735
0
    }
3736
3737
0
    return (ret);
3738
0
}
3739
3740
/**
3741
 * xmlXPathWrapNodeSet:
3742
 * @val:  the NodePtr value
3743
 *
3744
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
3745
 *
3746
 * Returns the newly created object.
3747
 *
3748
 * In case of error the node set is destroyed and NULL is returned.
3749
 */
3750
xmlXPathObjectPtr
3751
0
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3752
0
    xmlXPathObjectPtr ret;
3753
3754
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3755
0
    if (ret == NULL) {
3756
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
3757
0
        xmlXPathFreeNodeSet(val);
3758
0
  return(NULL);
3759
0
    }
3760
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3761
0
    ret->type = XPATH_NODESET;
3762
0
    ret->nodesetval = val;
3763
0
    return(ret);
3764
0
}
3765
3766
/**
3767
 * xmlXPathFreeNodeSetList:
3768
 * @obj:  an existing NodeSetList object
3769
 *
3770
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3771
 * the list contrary to xmlXPathFreeObject().
3772
 */
3773
void
3774
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3775
0
    if (obj == NULL) return;
3776
0
    xmlFree(obj);
3777
0
}
3778
3779
/**
3780
 * xmlXPathDifference:
3781
 * @nodes1:  a node-set
3782
 * @nodes2:  a node-set
3783
 *
3784
 * Implements the EXSLT - Sets difference() function:
3785
 *    node-set set:difference (node-set, node-set)
3786
 *
3787
 * Returns the difference between the two node sets, or nodes1 if
3788
 *         nodes2 is empty
3789
 */
3790
xmlNodeSetPtr
3791
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3792
0
    xmlNodeSetPtr ret;
3793
0
    int i, l1;
3794
0
    xmlNodePtr cur;
3795
3796
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3797
0
  return(nodes1);
3798
3799
    /* TODO: Check memory error. */
3800
0
    ret = xmlXPathNodeSetCreate(NULL);
3801
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3802
0
  return(ret);
3803
3804
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3805
3806
0
    for (i = 0; i < l1; i++) {
3807
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3808
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3809
            /* TODO: Propagate memory error. */
3810
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3811
0
          break;
3812
0
  }
3813
0
    }
3814
0
    return(ret);
3815
0
}
3816
3817
/**
3818
 * xmlXPathIntersection:
3819
 * @nodes1:  a node-set
3820
 * @nodes2:  a node-set
3821
 *
3822
 * Implements the EXSLT - Sets intersection() function:
3823
 *    node-set set:intersection (node-set, node-set)
3824
 *
3825
 * Returns a node set comprising the nodes that are within both the
3826
 *         node sets passed as arguments
3827
 */
3828
xmlNodeSetPtr
3829
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3830
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3831
0
    int i, l1;
3832
0
    xmlNodePtr cur;
3833
3834
0
    if (ret == NULL)
3835
0
        return(ret);
3836
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3837
0
  return(ret);
3838
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3839
0
  return(ret);
3840
3841
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3842
3843
0
    for (i = 0; i < l1; i++) {
3844
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3845
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3846
            /* TODO: Propagate memory error. */
3847
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3848
0
          break;
3849
0
  }
3850
0
    }
3851
0
    return(ret);
3852
0
}
3853
3854
/**
3855
 * xmlXPathDistinctSorted:
3856
 * @nodes:  a node-set, sorted by document order
3857
 *
3858
 * Implements the EXSLT - Sets distinct() function:
3859
 *    node-set set:distinct (node-set)
3860
 *
3861
 * Returns a subset of the nodes contained in @nodes, or @nodes if
3862
 *         it is empty
3863
 */
3864
xmlNodeSetPtr
3865
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3866
0
    xmlNodeSetPtr ret;
3867
0
    xmlHashTablePtr hash;
3868
0
    int i, l;
3869
0
    xmlChar * strval;
3870
0
    xmlNodePtr cur;
3871
3872
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3873
0
  return(nodes);
3874
3875
0
    ret = xmlXPathNodeSetCreate(NULL);
3876
0
    if (ret == NULL)
3877
0
        return(ret);
3878
0
    l = xmlXPathNodeSetGetLength(nodes);
3879
0
    hash = xmlHashCreate (l);
3880
0
    for (i = 0; i < l; i++) {
3881
0
  cur = xmlXPathNodeSetItem(nodes, i);
3882
0
  strval = xmlXPathCastNodeToString(cur);
3883
0
  if (xmlHashLookup(hash, strval) == NULL) {
3884
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3885
0
                xmlFree(strval);
3886
0
                goto error;
3887
0
            }
3888
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3889
0
          goto error;
3890
0
  } else {
3891
0
      xmlFree(strval);
3892
0
  }
3893
0
    }
3894
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3895
0
    return(ret);
3896
3897
0
error:
3898
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3899
0
    xmlXPathFreeNodeSet(ret);
3900
0
    return(NULL);
3901
0
}
3902
3903
/**
3904
 * xmlXPathDistinct:
3905
 * @nodes:  a node-set
3906
 *
3907
 * Implements the EXSLT - Sets distinct() function:
3908
 *    node-set set:distinct (node-set)
3909
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
3910
 * is called with the sorted node-set
3911
 *
3912
 * Returns a subset of the nodes contained in @nodes, or @nodes if
3913
 *         it is empty
3914
 */
3915
xmlNodeSetPtr
3916
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
3917
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3918
0
  return(nodes);
3919
3920
0
    xmlXPathNodeSetSort(nodes);
3921
0
    return(xmlXPathDistinctSorted(nodes));
3922
0
}
3923
3924
/**
3925
 * xmlXPathHasSameNodes:
3926
 * @nodes1:  a node-set
3927
 * @nodes2:  a node-set
3928
 *
3929
 * Implements the EXSLT - Sets has-same-nodes function:
3930
 *    boolean set:has-same-node(node-set, node-set)
3931
 *
3932
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3933
 *         otherwise
3934
 */
3935
int
3936
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3937
0
    int i, l;
3938
0
    xmlNodePtr cur;
3939
3940
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3941
0
  xmlXPathNodeSetIsEmpty(nodes2))
3942
0
  return(0);
3943
3944
0
    l = xmlXPathNodeSetGetLength(nodes1);
3945
0
    for (i = 0; i < l; i++) {
3946
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3947
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3948
0
      return(1);
3949
0
    }
3950
0
    return(0);
3951
0
}
3952
3953
/**
3954
 * xmlXPathNodeLeadingSorted:
3955
 * @nodes: a node-set, sorted by document order
3956
 * @node: a node
3957
 *
3958
 * Implements the EXSLT - Sets leading() function:
3959
 *    node-set set:leading (node-set, node-set)
3960
 *
3961
 * Returns the nodes in @nodes that precede @node in document order,
3962
 *         @nodes if @node is NULL or an empty node-set if @nodes
3963
 *         doesn't contain @node
3964
 */
3965
xmlNodeSetPtr
3966
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3967
0
    int i, l;
3968
0
    xmlNodePtr cur;
3969
0
    xmlNodeSetPtr ret;
3970
3971
0
    if (node == NULL)
3972
0
  return(nodes);
3973
3974
0
    ret = xmlXPathNodeSetCreate(NULL);
3975
0
    if (ret == NULL)
3976
0
        return(ret);
3977
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3978
0
  (!xmlXPathNodeSetContains(nodes, node)))
3979
0
  return(ret);
3980
3981
0
    l = xmlXPathNodeSetGetLength(nodes);
3982
0
    for (i = 0; i < l; i++) {
3983
0
  cur = xmlXPathNodeSetItem(nodes, i);
3984
0
  if (cur == node)
3985
0
      break;
3986
        /* TODO: Propagate memory error. */
3987
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3988
0
      break;
3989
0
    }
3990
0
    return(ret);
3991
0
}
3992
3993
/**
3994
 * xmlXPathNodeLeading:
3995
 * @nodes:  a node-set
3996
 * @node:  a node
3997
 *
3998
 * Implements the EXSLT - Sets leading() function:
3999
 *    node-set set:leading (node-set, node-set)
4000
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4001
 * is called.
4002
 *
4003
 * Returns the nodes in @nodes that precede @node in document order,
4004
 *         @nodes if @node is NULL or an empty node-set if @nodes
4005
 *         doesn't contain @node
4006
 */
4007
xmlNodeSetPtr
4008
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4009
0
    xmlXPathNodeSetSort(nodes);
4010
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4011
0
}
4012
4013
/**
4014
 * xmlXPathLeadingSorted:
4015
 * @nodes1:  a node-set, sorted by document order
4016
 * @nodes2:  a node-set, sorted by document order
4017
 *
4018
 * Implements the EXSLT - Sets leading() function:
4019
 *    node-set set:leading (node-set, node-set)
4020
 *
4021
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4022
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4023
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4024
 */
4025
xmlNodeSetPtr
4026
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4027
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4028
0
  return(nodes1);
4029
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4030
0
             xmlXPathNodeSetItem(nodes2, 1)));
4031
0
}
4032
4033
/**
4034
 * xmlXPathLeading:
4035
 * @nodes1:  a node-set
4036
 * @nodes2:  a node-set
4037
 *
4038
 * Implements the EXSLT - Sets leading() function:
4039
 *    node-set set:leading (node-set, node-set)
4040
 * @nodes1 and @nodes2 are sorted by document order, then
4041
 * #exslSetsLeadingSorted is called.
4042
 *
4043
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4044
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4045
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4046
 */
4047
xmlNodeSetPtr
4048
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4049
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4050
0
  return(nodes1);
4051
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4052
0
  return(xmlXPathNodeSetCreate(NULL));
4053
0
    xmlXPathNodeSetSort(nodes1);
4054
0
    xmlXPathNodeSetSort(nodes2);
4055
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4056
0
             xmlXPathNodeSetItem(nodes2, 1)));
4057
0
}
4058
4059
/**
4060
 * xmlXPathNodeTrailingSorted:
4061
 * @nodes: a node-set, sorted by document order
4062
 * @node: a node
4063
 *
4064
 * Implements the EXSLT - Sets trailing() function:
4065
 *    node-set set:trailing (node-set, node-set)
4066
 *
4067
 * Returns the nodes in @nodes that follow @node in document order,
4068
 *         @nodes if @node is NULL or an empty node-set if @nodes
4069
 *         doesn't contain @node
4070
 */
4071
xmlNodeSetPtr
4072
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4073
0
    int i, l;
4074
0
    xmlNodePtr cur;
4075
0
    xmlNodeSetPtr ret;
4076
4077
0
    if (node == NULL)
4078
0
  return(nodes);
4079
4080
0
    ret = xmlXPathNodeSetCreate(NULL);
4081
0
    if (ret == NULL)
4082
0
        return(ret);
4083
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4084
0
  (!xmlXPathNodeSetContains(nodes, node)))
4085
0
  return(ret);
4086
4087
0
    l = xmlXPathNodeSetGetLength(nodes);
4088
0
    for (i = l - 1; i >= 0; i--) {
4089
0
  cur = xmlXPathNodeSetItem(nodes, i);
4090
0
  if (cur == node)
4091
0
      break;
4092
        /* TODO: Propagate memory error. */
4093
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4094
0
      break;
4095
0
    }
4096
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4097
0
    return(ret);
4098
0
}
4099
4100
/**
4101
 * xmlXPathNodeTrailing:
4102
 * @nodes:  a node-set
4103
 * @node:  a node
4104
 *
4105
 * Implements the EXSLT - Sets trailing() function:
4106
 *    node-set set:trailing (node-set, node-set)
4107
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4108
 * is called.
4109
 *
4110
 * Returns the nodes in @nodes that follow @node in document order,
4111
 *         @nodes if @node is NULL or an empty node-set if @nodes
4112
 *         doesn't contain @node
4113
 */
4114
xmlNodeSetPtr
4115
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4116
0
    xmlXPathNodeSetSort(nodes);
4117
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4118
0
}
4119
4120
/**
4121
 * xmlXPathTrailingSorted:
4122
 * @nodes1:  a node-set, sorted by document order
4123
 * @nodes2:  a node-set, sorted by document order
4124
 *
4125
 * Implements the EXSLT - Sets trailing() function:
4126
 *    node-set set:trailing (node-set, node-set)
4127
 *
4128
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4129
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4130
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4131
 */
4132
xmlNodeSetPtr
4133
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4134
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4135
0
  return(nodes1);
4136
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4137
0
              xmlXPathNodeSetItem(nodes2, 0)));
4138
0
}
4139
4140
/**
4141
 * xmlXPathTrailing:
4142
 * @nodes1:  a node-set
4143
 * @nodes2:  a node-set
4144
 *
4145
 * Implements the EXSLT - Sets trailing() function:
4146
 *    node-set set:trailing (node-set, node-set)
4147
 * @nodes1 and @nodes2 are sorted by document order, then
4148
 * #xmlXPathTrailingSorted is called.
4149
 *
4150
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4151
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4152
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4153
 */
4154
xmlNodeSetPtr
4155
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4156
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4157
0
  return(nodes1);
4158
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4159
0
  return(xmlXPathNodeSetCreate(NULL));
4160
0
    xmlXPathNodeSetSort(nodes1);
4161
0
    xmlXPathNodeSetSort(nodes2);
4162
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4163
0
              xmlXPathNodeSetItem(nodes2, 0)));
4164
0
}
4165
4166
/************************************************************************
4167
 *                  *
4168
 *    Routines to handle extra functions      *
4169
 *                  *
4170
 ************************************************************************/
4171
4172
/**
4173
 * xmlXPathRegisterFunc:
4174
 * @ctxt:  the XPath context
4175
 * @name:  the function name
4176
 * @f:  the function implementation or NULL
4177
 *
4178
 * Register a new function. If @f is NULL it unregisters the function
4179
 *
4180
 * Returns 0 in case of success, -1 in case of error
4181
 */
4182
int
4183
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4184
0
         xmlXPathFunction f) {
4185
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4186
0
}
4187
4188
/**
4189
 * xmlXPathRegisterFuncNS:
4190
 * @ctxt:  the XPath context
4191
 * @name:  the function name
4192
 * @ns_uri:  the function namespace URI
4193
 * @f:  the function implementation or NULL
4194
 *
4195
 * Register a new function. If @f is NULL it unregisters the function
4196
 *
4197
 * Returns 0 in case of success, -1 in case of error
4198
 */
4199
int
4200
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4201
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
4202
0
    if (ctxt == NULL)
4203
0
  return(-1);
4204
0
    if (name == NULL)
4205
0
  return(-1);
4206
4207
0
    if (ctxt->funcHash == NULL)
4208
0
  ctxt->funcHash = xmlHashCreate(0);
4209
0
    if (ctxt->funcHash == NULL)
4210
0
  return(-1);
4211
0
    if (f == NULL)
4212
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4213
0
XML_IGNORE_FPTR_CAST_WARNINGS
4214
0
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4215
0
XML_POP_WARNINGS
4216
0
}
4217
4218
/**
4219
 * xmlXPathRegisterFuncLookup:
4220
 * @ctxt:  the XPath context
4221
 * @f:  the lookup function
4222
 * @funcCtxt:  the lookup data
4223
 *
4224
 * Registers an external mechanism to do function lookup.
4225
 */
4226
void
4227
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4228
          xmlXPathFuncLookupFunc f,
4229
0
          void *funcCtxt) {
4230
0
    if (ctxt == NULL)
4231
0
  return;
4232
0
    ctxt->funcLookupFunc = f;
4233
0
    ctxt->funcLookupData = funcCtxt;
4234
0
}
4235
4236
/**
4237
 * xmlXPathFunctionLookup:
4238
 * @ctxt:  the XPath context
4239
 * @name:  the function name
4240
 *
4241
 * Search in the Function array of the context for the given
4242
 * function.
4243
 *
4244
 * Returns the xmlXPathFunction or NULL if not found
4245
 */
4246
xmlXPathFunction
4247
0
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4248
0
    if (ctxt == NULL)
4249
0
  return (NULL);
4250
4251
0
    if (ctxt->funcLookupFunc != NULL) {
4252
0
  xmlXPathFunction ret;
4253
0
  xmlXPathFuncLookupFunc f;
4254
4255
0
  f = ctxt->funcLookupFunc;
4256
0
  ret = f(ctxt->funcLookupData, name, NULL);
4257
0
  if (ret != NULL)
4258
0
      return(ret);
4259
0
    }
4260
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4261
0
}
4262
4263
/**
4264
 * xmlXPathFunctionLookupNS:
4265
 * @ctxt:  the XPath context
4266
 * @name:  the function name
4267
 * @ns_uri:  the function namespace URI
4268
 *
4269
 * Search in the Function array of the context for the given
4270
 * function.
4271
 *
4272
 * Returns the xmlXPathFunction or NULL if not found
4273
 */
4274
xmlXPathFunction
4275
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4276
0
       const xmlChar *ns_uri) {
4277
0
    xmlXPathFunction ret;
4278
4279
0
    if (ctxt == NULL)
4280
0
  return(NULL);
4281
0
    if (name == NULL)
4282
0
  return(NULL);
4283
4284
0
    if (ctxt->funcLookupFunc != NULL) {
4285
0
  xmlXPathFuncLookupFunc f;
4286
4287
0
  f = ctxt->funcLookupFunc;
4288
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
4289
0
  if (ret != NULL)
4290
0
      return(ret);
4291
0
    }
4292
4293
0
    if (ctxt->funcHash == NULL)
4294
0
  return(NULL);
4295
4296
0
XML_IGNORE_FPTR_CAST_WARNINGS
4297
0
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4298
0
XML_POP_WARNINGS
4299
0
    return(ret);
4300
0
}
4301
4302
/**
4303
 * xmlXPathRegisteredFuncsCleanup:
4304
 * @ctxt:  the XPath context
4305
 *
4306
 * Cleanup the XPath context data associated to registered functions
4307
 */
4308
void
4309
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4310
0
    if (ctxt == NULL)
4311
0
  return;
4312
4313
0
    xmlHashFree(ctxt->funcHash, NULL);
4314
0
    ctxt->funcHash = NULL;
4315
0
}
4316
4317
/************************************************************************
4318
 *                  *
4319
 *      Routines to handle Variables      *
4320
 *                  *
4321
 ************************************************************************/
4322
4323
/**
4324
 * xmlXPathRegisterVariable:
4325
 * @ctxt:  the XPath context
4326
 * @name:  the variable name
4327
 * @value:  the variable value or NULL
4328
 *
4329
 * Register a new variable value. If @value is NULL it unregisters
4330
 * the variable
4331
 *
4332
 * Returns 0 in case of success, -1 in case of error
4333
 */
4334
int
4335
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4336
0
       xmlXPathObjectPtr value) {
4337
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4338
0
}
4339
4340
/**
4341
 * xmlXPathRegisterVariableNS:
4342
 * @ctxt:  the XPath context
4343
 * @name:  the variable name
4344
 * @ns_uri:  the variable namespace URI
4345
 * @value:  the variable value or NULL
4346
 *
4347
 * Register a new variable value. If @value is NULL it unregisters
4348
 * the variable
4349
 *
4350
 * Returns 0 in case of success, -1 in case of error
4351
 */
4352
int
4353
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4354
         const xmlChar *ns_uri,
4355
0
         xmlXPathObjectPtr value) {
4356
0
    if (ctxt == NULL)
4357
0
  return(-1);
4358
0
    if (name == NULL)
4359
0
  return(-1);
4360
4361
0
    if (ctxt->varHash == NULL)
4362
0
  ctxt->varHash = xmlHashCreate(0);
4363
0
    if (ctxt->varHash == NULL)
4364
0
  return(-1);
4365
0
    if (value == NULL)
4366
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4367
0
                             xmlXPathFreeObjectEntry));
4368
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4369
0
             (void *) value, xmlXPathFreeObjectEntry));
4370
0
}
4371
4372
/**
4373
 * xmlXPathRegisterVariableLookup:
4374
 * @ctxt:  the XPath context
4375
 * @f:  the lookup function
4376
 * @data:  the lookup data
4377
 *
4378
 * register an external mechanism to do variable lookup
4379
 */
4380
void
4381
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4382
0
   xmlXPathVariableLookupFunc f, void *data) {
4383
0
    if (ctxt == NULL)
4384
0
  return;
4385
0
    ctxt->varLookupFunc = f;
4386
0
    ctxt->varLookupData = data;
4387
0
}
4388
4389
/**
4390
 * xmlXPathVariableLookup:
4391
 * @ctxt:  the XPath context
4392
 * @name:  the variable name
4393
 *
4394
 * Search in the Variable array of the context for the given
4395
 * variable value.
4396
 *
4397
 * Returns a copy of the value or NULL if not found
4398
 */
4399
xmlXPathObjectPtr
4400
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4401
0
    if (ctxt == NULL)
4402
0
  return(NULL);
4403
4404
0
    if (ctxt->varLookupFunc != NULL) {
4405
0
  xmlXPathObjectPtr ret;
4406
4407
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4408
0
          (ctxt->varLookupData, name, NULL);
4409
0
  return(ret);
4410
0
    }
4411
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4412
0
}
4413
4414
/**
4415
 * xmlXPathVariableLookupNS:
4416
 * @ctxt:  the XPath context
4417
 * @name:  the variable name
4418
 * @ns_uri:  the variable namespace URI
4419
 *
4420
 * Search in the Variable array of the context for the given
4421
 * variable value.
4422
 *
4423
 * Returns the a copy of the value or NULL if not found
4424
 */
4425
xmlXPathObjectPtr
4426
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4427
0
       const xmlChar *ns_uri) {
4428
0
    if (ctxt == NULL)
4429
0
  return(NULL);
4430
4431
0
    if (ctxt->varLookupFunc != NULL) {
4432
0
  xmlXPathObjectPtr ret;
4433
4434
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4435
0
          (ctxt->varLookupData, name, ns_uri);
4436
0
  if (ret != NULL) return(ret);
4437
0
    }
4438
4439
0
    if (ctxt->varHash == NULL)
4440
0
  return(NULL);
4441
0
    if (name == NULL)
4442
0
  return(NULL);
4443
4444
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4445
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4446
0
}
4447
4448
/**
4449
 * xmlXPathRegisteredVariablesCleanup:
4450
 * @ctxt:  the XPath context
4451
 *
4452
 * Cleanup the XPath context data associated to registered variables
4453
 */
4454
void
4455
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4456
0
    if (ctxt == NULL)
4457
0
  return;
4458
4459
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4460
0
    ctxt->varHash = NULL;
4461
0
}
4462
4463
/**
4464
 * xmlXPathRegisterNs:
4465
 * @ctxt:  the XPath context
4466
 * @prefix:  the namespace prefix cannot be NULL or empty string
4467
 * @ns_uri:  the namespace name
4468
 *
4469
 * Register a new namespace. If @ns_uri is NULL it unregisters
4470
 * the namespace
4471
 *
4472
 * Returns 0 in case of success, -1 in case of error
4473
 */
4474
int
4475
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4476
0
         const xmlChar *ns_uri) {
4477
0
    xmlChar *copy;
4478
4479
0
    if (ctxt == NULL)
4480
0
  return(-1);
4481
0
    if (prefix == NULL)
4482
0
  return(-1);
4483
0
    if (prefix[0] == 0)
4484
0
  return(-1);
4485
4486
0
    if (ctxt->nsHash == NULL)
4487
0
  ctxt->nsHash = xmlHashCreate(10);
4488
0
    if (ctxt->nsHash == NULL)
4489
0
  return(-1);
4490
0
    if (ns_uri == NULL)
4491
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4492
0
                            xmlHashDefaultDeallocator));
4493
4494
0
    copy = xmlStrdup(ns_uri);
4495
0
    if (copy == NULL)
4496
0
        return(-1);
4497
0
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4498
0
                           xmlHashDefaultDeallocator) < 0) {
4499
0
        xmlFree(copy);
4500
0
        return(-1);
4501
0
    }
4502
4503
0
    return(0);
4504
0
}
4505
4506
/**
4507
 * xmlXPathNsLookup:
4508
 * @ctxt:  the XPath context
4509
 * @prefix:  the namespace prefix value
4510
 *
4511
 * Search in the namespace declaration array of the context for the given
4512
 * namespace name associated to the given prefix
4513
 *
4514
 * Returns the value or NULL if not found
4515
 */
4516
const xmlChar *
4517
0
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4518
0
    if (ctxt == NULL)
4519
0
  return(NULL);
4520
0
    if (prefix == NULL)
4521
0
  return(NULL);
4522
4523
0
#ifdef XML_XML_NAMESPACE
4524
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4525
0
  return(XML_XML_NAMESPACE);
4526
0
#endif
4527
4528
0
    if (ctxt->namespaces != NULL) {
4529
0
  int i;
4530
4531
0
  for (i = 0;i < ctxt->nsNr;i++) {
4532
0
      if ((ctxt->namespaces[i] != NULL) &&
4533
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4534
0
    return(ctxt->namespaces[i]->href);
4535
0
  }
4536
0
    }
4537
4538
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4539
0
}
4540
4541
/**
4542
 * xmlXPathRegisteredNsCleanup:
4543
 * @ctxt:  the XPath context
4544
 *
4545
 * Cleanup the XPath context data associated to registered variables
4546
 */
4547
void
4548
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4549
0
    if (ctxt == NULL)
4550
0
  return;
4551
4552
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4553
0
    ctxt->nsHash = NULL;
4554
0
}
4555
4556
/************************************************************************
4557
 *                  *
4558
 *      Routines to handle Values     *
4559
 *                  *
4560
 ************************************************************************/
4561
4562
/* Allocations are terrible, one needs to optimize all this !!! */
4563
4564
/**
4565
 * xmlXPathNewFloat:
4566
 * @val:  the double value
4567
 *
4568
 * Create a new xmlXPathObjectPtr of type double and of value @val
4569
 *
4570
 * Returns the newly created object.
4571
 */
4572
xmlXPathObjectPtr
4573
0
xmlXPathNewFloat(double val) {
4574
0
    xmlXPathObjectPtr ret;
4575
4576
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4577
0
    if (ret == NULL) {
4578
0
        xmlXPathErrMemory(NULL, "creating float object\n");
4579
0
  return(NULL);
4580
0
    }
4581
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4582
0
    ret->type = XPATH_NUMBER;
4583
0
    ret->floatval = val;
4584
0
    return(ret);
4585
0
}
4586
4587
/**
4588
 * xmlXPathNewBoolean:
4589
 * @val:  the boolean value
4590
 *
4591
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
4592
 *
4593
 * Returns the newly created object.
4594
 */
4595
xmlXPathObjectPtr
4596
0
xmlXPathNewBoolean(int val) {
4597
0
    xmlXPathObjectPtr ret;
4598
4599
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4600
0
    if (ret == NULL) {
4601
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
4602
0
  return(NULL);
4603
0
    }
4604
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4605
0
    ret->type = XPATH_BOOLEAN;
4606
0
    ret->boolval = (val != 0);
4607
0
    return(ret);
4608
0
}
4609
4610
/**
4611
 * xmlXPathNewString:
4612
 * @val:  the xmlChar * value
4613
 *
4614
 * Create a new xmlXPathObjectPtr of type string and of value @val
4615
 *
4616
 * Returns the newly created object.
4617
 */
4618
xmlXPathObjectPtr
4619
0
xmlXPathNewString(const xmlChar *val) {
4620
0
    xmlXPathObjectPtr ret;
4621
4622
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4623
0
    if (ret == NULL) {
4624
0
        xmlXPathErrMemory(NULL, "creating string object\n");
4625
0
  return(NULL);
4626
0
    }
4627
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4628
0
    ret->type = XPATH_STRING;
4629
0
    if (val == NULL)
4630
0
        val = BAD_CAST "";
4631
0
    ret->stringval = xmlStrdup(val);
4632
0
    if (ret->stringval == NULL) {
4633
0
        xmlFree(ret);
4634
0
        return(NULL);
4635
0
    }
4636
0
    return(ret);
4637
0
}
4638
4639
/**
4640
 * xmlXPathWrapString:
4641
 * @val:  the xmlChar * value
4642
 *
4643
 * Wraps the @val string into an XPath object.
4644
 *
4645
 * Returns the newly created object.
4646
 *
4647
 * Frees @val in case of error.
4648
 */
4649
xmlXPathObjectPtr
4650
0
xmlXPathWrapString (xmlChar *val) {
4651
0
    xmlXPathObjectPtr ret;
4652
4653
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4654
0
    if (ret == NULL) {
4655
0
        xmlXPathErrMemory(NULL, "creating string object\n");
4656
0
        xmlFree(val);
4657
0
  return(NULL);
4658
0
    }
4659
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4660
0
    ret->type = XPATH_STRING;
4661
0
    ret->stringval = val;
4662
0
    return(ret);
4663
0
}
4664
4665
/**
4666
 * xmlXPathNewCString:
4667
 * @val:  the char * value
4668
 *
4669
 * Create a new xmlXPathObjectPtr of type string and of value @val
4670
 *
4671
 * Returns the newly created object.
4672
 */
4673
xmlXPathObjectPtr
4674
0
xmlXPathNewCString(const char *val) {
4675
0
    return(xmlXPathNewString(BAD_CAST val));
4676
0
}
4677
4678
/**
4679
 * xmlXPathWrapCString:
4680
 * @val:  the char * value
4681
 *
4682
 * Wraps a string into an XPath object.
4683
 *
4684
 * Returns the newly created object.
4685
 */
4686
xmlXPathObjectPtr
4687
0
xmlXPathWrapCString (char * val) {
4688
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4689
0
}
4690
4691
/**
4692
 * xmlXPathWrapExternal:
4693
 * @val:  the user data
4694
 *
4695
 * Wraps the @val data into an XPath object.
4696
 *
4697
 * Returns the newly created object.
4698
 */
4699
xmlXPathObjectPtr
4700
0
xmlXPathWrapExternal (void *val) {
4701
0
    xmlXPathObjectPtr ret;
4702
4703
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4704
0
    if (ret == NULL) {
4705
0
        xmlXPathErrMemory(NULL, "creating user object\n");
4706
0
  return(NULL);
4707
0
    }
4708
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4709
0
    ret->type = XPATH_USERS;
4710
0
    ret->user = val;
4711
0
    return(ret);
4712
0
}
4713
4714
/**
4715
 * xmlXPathObjectCopy:
4716
 * @val:  the original object
4717
 *
4718
 * allocate a new copy of a given object
4719
 *
4720
 * Returns the newly created object.
4721
 */
4722
xmlXPathObjectPtr
4723
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4724
0
    xmlXPathObjectPtr ret;
4725
4726
0
    if (val == NULL)
4727
0
  return(NULL);
4728
4729
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4730
0
    if (ret == NULL) {
4731
0
        xmlXPathErrMemory(NULL, "copying object\n");
4732
0
  return(NULL);
4733
0
    }
4734
0
    memcpy(ret, val , sizeof(xmlXPathObject));
4735
0
    switch (val->type) {
4736
0
  case XPATH_BOOLEAN:
4737
0
  case XPATH_NUMBER:
4738
#ifdef LIBXML_XPTR_LOCS_ENABLED
4739
  case XPATH_POINT:
4740
  case XPATH_RANGE:
4741
#endif /* LIBXML_XPTR_LOCS_ENABLED */
4742
0
      break;
4743
0
  case XPATH_STRING:
4744
0
      ret->stringval = xmlStrdup(val->stringval);
4745
0
            if (ret->stringval == NULL) {
4746
0
                xmlFree(ret);
4747
0
                return(NULL);
4748
0
            }
4749
0
      break;
4750
0
  case XPATH_XSLT_TREE:
4751
#if 0
4752
/*
4753
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4754
  this previous handling is no longer correct, and can cause some serious
4755
  problems (ref. bug 145547)
4756
*/
4757
      if ((val->nodesetval != NULL) &&
4758
    (val->nodesetval->nodeTab != NULL)) {
4759
    xmlNodePtr cur, tmp;
4760
    xmlDocPtr top;
4761
4762
    ret->boolval = 1;
4763
    top =  xmlNewDoc(NULL);
4764
    top->name = (char *)
4765
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
4766
    ret->user = top;
4767
    if (top != NULL) {
4768
        top->doc = top;
4769
        cur = val->nodesetval->nodeTab[0]->children;
4770
        while (cur != NULL) {
4771
      tmp = xmlDocCopyNode(cur, top, 1);
4772
      xmlAddChild((xmlNodePtr) top, tmp);
4773
      cur = cur->next;
4774
        }
4775
    }
4776
4777
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4778
      } else
4779
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4780
      /* Deallocate the copied tree value */
4781
      break;
4782
#endif
4783
0
  case XPATH_NODESET:
4784
            /* TODO: Check memory error. */
4785
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4786
      /* Do not deallocate the copied tree value */
4787
0
      ret->boolval = 0;
4788
0
      break;
4789
#ifdef LIBXML_XPTR_LOCS_ENABLED
4790
  case XPATH_LOCATIONSET:
4791
  {
4792
      xmlLocationSetPtr loc = val->user;
4793
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4794
      break;
4795
  }
4796
#endif
4797
0
        case XPATH_USERS:
4798
0
      ret->user = val->user;
4799
0
      break;
4800
0
        case XPATH_UNDEFINED:
4801
0
      xmlGenericError(xmlGenericErrorContext,
4802
0
        "xmlXPathObjectCopy: unsupported type %d\n",
4803
0
        val->type);
4804
0
      break;
4805
0
    }
4806
0
    return(ret);
4807
0
}
4808
4809
/**
4810
 * xmlXPathFreeObject:
4811
 * @obj:  the object to free
4812
 *
4813
 * Free up an xmlXPathObjectPtr object.
4814
 */
4815
void
4816
0
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4817
0
    if (obj == NULL) return;
4818
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4819
0
  if (obj->boolval) {
4820
#if 0
4821
      if (obj->user != NULL) {
4822
                xmlXPathFreeNodeSet(obj->nodesetval);
4823
    xmlFreeNodeList((xmlNodePtr) obj->user);
4824
      } else
4825
#endif
4826
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
4827
0
      if (obj->nodesetval != NULL)
4828
0
    xmlXPathFreeValueTree(obj->nodesetval);
4829
0
  } else {
4830
0
      if (obj->nodesetval != NULL)
4831
0
    xmlXPathFreeNodeSet(obj->nodesetval);
4832
0
  }
4833
#ifdef LIBXML_XPTR_LOCS_ENABLED
4834
    } else if (obj->type == XPATH_LOCATIONSET) {
4835
  if (obj->user != NULL)
4836
      xmlXPtrFreeLocationSet(obj->user);
4837
#endif
4838
0
    } else if (obj->type == XPATH_STRING) {
4839
0
  if (obj->stringval != NULL)
4840
0
      xmlFree(obj->stringval);
4841
0
    }
4842
0
    xmlFree(obj);
4843
0
}
4844
4845
static void
4846
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4847
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4848
0
}
4849
4850
/**
4851
 * xmlXPathReleaseObject:
4852
 * @obj:  the xmlXPathObjectPtr to free or to cache
4853
 *
4854
 * Depending on the state of the cache this frees the given
4855
 * XPath object or stores it in the cache.
4856
 */
4857
static void
4858
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4859
0
{
4860
0
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
4861
0
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
4862
0
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
4863
4864
0
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
4865
4866
0
    if (obj == NULL)
4867
0
  return;
4868
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4869
0
   xmlXPathFreeObject(obj);
4870
0
    } else {
4871
0
  xmlXPathContextCachePtr cache =
4872
0
      (xmlXPathContextCachePtr) ctxt->cache;
4873
4874
0
  switch (obj->type) {
4875
0
      case XPATH_NODESET:
4876
0
      case XPATH_XSLT_TREE:
4877
0
    if (obj->nodesetval != NULL) {
4878
0
        if (obj->boolval) {
4879
      /*
4880
      * It looks like the @boolval is used for
4881
      * evaluation if this an XSLT Result Tree Fragment.
4882
      * TODO: Check if this assumption is correct.
4883
      */
4884
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
4885
0
      xmlXPathFreeValueTree(obj->nodesetval);
4886
0
      obj->nodesetval = NULL;
4887
0
        } else if ((obj->nodesetval->nodeMax <= 40) &&
4888
0
      (XP_CACHE_WANTS(cache->nodesetObjs,
4889
0
          cache->maxNodeset)))
4890
0
        {
4891
0
      XP_CACHE_ADD(cache->nodesetObjs, obj);
4892
0
      goto obj_cached;
4893
0
        } else {
4894
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4895
0
      obj->nodesetval = NULL;
4896
0
        }
4897
0
    }
4898
0
    break;
4899
0
      case XPATH_STRING:
4900
0
    if (obj->stringval != NULL)
4901
0
        xmlFree(obj->stringval);
4902
4903
0
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
4904
0
        XP_CACHE_ADD(cache->stringObjs, obj);
4905
0
        goto obj_cached;
4906
0
    }
4907
0
    break;
4908
0
      case XPATH_BOOLEAN:
4909
0
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
4910
0
        XP_CACHE_ADD(cache->booleanObjs, obj);
4911
0
        goto obj_cached;
4912
0
    }
4913
0
    break;
4914
0
      case XPATH_NUMBER:
4915
0
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
4916
0
        XP_CACHE_ADD(cache->numberObjs, obj);
4917
0
        goto obj_cached;
4918
0
    }
4919
0
    break;
4920
#ifdef LIBXML_XPTR_LOCS_ENABLED
4921
      case XPATH_LOCATIONSET:
4922
    if (obj->user != NULL) {
4923
        xmlXPtrFreeLocationSet(obj->user);
4924
    }
4925
    goto free_obj;
4926
#endif
4927
0
      default:
4928
0
    goto free_obj;
4929
0
  }
4930
4931
  /*
4932
  * Fallback to adding to the misc-objects slot.
4933
  */
4934
0
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
4935
0
      XP_CACHE_ADD(cache->miscObjs, obj);
4936
0
  } else
4937
0
      goto free_obj;
4938
4939
0
obj_cached:
4940
0
  if (obj->nodesetval != NULL) {
4941
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
4942
4943
      /*
4944
      * TODO: Due to those nasty ns-nodes, we need to traverse
4945
      *  the list and free the ns-nodes.
4946
      * URGENT TODO: Check if it's actually slowing things down.
4947
      *  Maybe we shouldn't try to preserve the list.
4948
      */
4949
0
      if (tmpset->nodeNr > 1) {
4950
0
    int i;
4951
0
    xmlNodePtr node;
4952
4953
0
    for (i = 0; i < tmpset->nodeNr; i++) {
4954
0
        node = tmpset->nodeTab[i];
4955
0
        if ((node != NULL) &&
4956
0
      (node->type == XML_NAMESPACE_DECL))
4957
0
        {
4958
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4959
0
        }
4960
0
    }
4961
0
      } else if (tmpset->nodeNr == 1) {
4962
0
    if ((tmpset->nodeTab[0] != NULL) &&
4963
0
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
4964
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
4965
0
      }
4966
0
      tmpset->nodeNr = 0;
4967
0
      memset(obj, 0, sizeof(xmlXPathObject));
4968
0
      obj->nodesetval = tmpset;
4969
0
  } else
4970
0
      memset(obj, 0, sizeof(xmlXPathObject));
4971
4972
0
  return;
4973
4974
0
free_obj:
4975
  /*
4976
  * Cache is full; free the object.
4977
  */
4978
0
  if (obj->nodesetval != NULL)
4979
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4980
0
  xmlFree(obj);
4981
0
    }
4982
0
    return;
4983
0
}
4984
4985
4986
/************************************************************************
4987
 *                  *
4988
 *      Type Casting Routines       *
4989
 *                  *
4990
 ************************************************************************/
4991
4992
/**
4993
 * xmlXPathCastBooleanToString:
4994
 * @val:  a boolean
4995
 *
4996
 * Converts a boolean to its string value.
4997
 *
4998
 * Returns a newly allocated string.
4999
 */
5000
xmlChar *
5001
0
xmlXPathCastBooleanToString (int val) {
5002
0
    xmlChar *ret;
5003
0
    if (val)
5004
0
  ret = xmlStrdup((const xmlChar *) "true");
5005
0
    else
5006
0
  ret = xmlStrdup((const xmlChar *) "false");
5007
0
    return(ret);
5008
0
}
5009
5010
/**
5011
 * xmlXPathCastNumberToString:
5012
 * @val:  a number
5013
 *
5014
 * Converts a number to its string value.
5015
 *
5016
 * Returns a newly allocated string.
5017
 */
5018
xmlChar *
5019
0
xmlXPathCastNumberToString (double val) {
5020
0
    xmlChar *ret;
5021
0
    switch (xmlXPathIsInf(val)) {
5022
0
    case 1:
5023
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
5024
0
  break;
5025
0
    case -1:
5026
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5027
0
  break;
5028
0
    default:
5029
0
  if (xmlXPathIsNaN(val)) {
5030
0
      ret = xmlStrdup((const xmlChar *) "NaN");
5031
0
  } else if (val == 0) {
5032
            /* Omit sign for negative zero. */
5033
0
      ret = xmlStrdup((const xmlChar *) "0");
5034
0
  } else {
5035
      /* could be improved */
5036
0
      char buf[100];
5037
0
      xmlXPathFormatNumber(val, buf, 99);
5038
0
      buf[99] = 0;
5039
0
      ret = xmlStrdup((const xmlChar *) buf);
5040
0
  }
5041
0
    }
5042
0
    return(ret);
5043
0
}
5044
5045
/**
5046
 * xmlXPathCastNodeToString:
5047
 * @node:  a node
5048
 *
5049
 * Converts a node to its string value.
5050
 *
5051
 * Returns a newly allocated string.
5052
 */
5053
xmlChar *
5054
0
xmlXPathCastNodeToString (xmlNodePtr node) {
5055
0
xmlChar *ret;
5056
0
    if ((ret = xmlNodeGetContent(node)) == NULL)
5057
0
  ret = xmlStrdup((const xmlChar *) "");
5058
0
    return(ret);
5059
0
}
5060
5061
/**
5062
 * xmlXPathCastNodeSetToString:
5063
 * @ns:  a node-set
5064
 *
5065
 * Converts a node-set to its string value.
5066
 *
5067
 * Returns a newly allocated string.
5068
 */
5069
xmlChar *
5070
0
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5071
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5072
0
  return(xmlStrdup((const xmlChar *) ""));
5073
5074
0
    if (ns->nodeNr > 1)
5075
0
  xmlXPathNodeSetSort(ns);
5076
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5077
0
}
5078
5079
/**
5080
 * xmlXPathCastToString:
5081
 * @val:  an XPath object
5082
 *
5083
 * Converts an existing object to its string() equivalent
5084
 *
5085
 * Returns the allocated string value of the object, NULL in case of error.
5086
 *         It's up to the caller to free the string memory with xmlFree().
5087
 */
5088
xmlChar *
5089
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
5090
0
    xmlChar *ret = NULL;
5091
5092
0
    if (val == NULL)
5093
0
  return(xmlStrdup((const xmlChar *) ""));
5094
0
    switch (val->type) {
5095
0
  case XPATH_UNDEFINED:
5096
0
      ret = xmlStrdup((const xmlChar *) "");
5097
0
      break;
5098
0
        case XPATH_NODESET:
5099
0
        case XPATH_XSLT_TREE:
5100
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5101
0
      break;
5102
0
  case XPATH_STRING:
5103
0
      return(xmlStrdup(val->stringval));
5104
0
        case XPATH_BOOLEAN:
5105
0
      ret = xmlXPathCastBooleanToString(val->boolval);
5106
0
      break;
5107
0
  case XPATH_NUMBER: {
5108
0
      ret = xmlXPathCastNumberToString(val->floatval);
5109
0
      break;
5110
0
  }
5111
0
  case XPATH_USERS:
5112
#ifdef LIBXML_XPTR_LOCS_ENABLED
5113
  case XPATH_POINT:
5114
  case XPATH_RANGE:
5115
  case XPATH_LOCATIONSET:
5116
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5117
0
      TODO
5118
0
      ret = xmlStrdup((const xmlChar *) "");
5119
0
      break;
5120
0
    }
5121
0
    return(ret);
5122
0
}
5123
5124
/**
5125
 * xmlXPathConvertString:
5126
 * @val:  an XPath object
5127
 *
5128
 * Converts an existing object to its string() equivalent
5129
 *
5130
 * Returns the new object, the old one is freed (or the operation
5131
 *         is done directly on @val)
5132
 */
5133
xmlXPathObjectPtr
5134
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
5135
0
    xmlChar *res = NULL;
5136
5137
0
    if (val == NULL)
5138
0
  return(xmlXPathNewCString(""));
5139
5140
0
    switch (val->type) {
5141
0
    case XPATH_UNDEFINED:
5142
0
  break;
5143
0
    case XPATH_NODESET:
5144
0
    case XPATH_XSLT_TREE:
5145
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5146
0
  break;
5147
0
    case XPATH_STRING:
5148
0
  return(val);
5149
0
    case XPATH_BOOLEAN:
5150
0
  res = xmlXPathCastBooleanToString(val->boolval);
5151
0
  break;
5152
0
    case XPATH_NUMBER:
5153
0
  res = xmlXPathCastNumberToString(val->floatval);
5154
0
  break;
5155
0
    case XPATH_USERS:
5156
#ifdef LIBXML_XPTR_LOCS_ENABLED
5157
    case XPATH_POINT:
5158
    case XPATH_RANGE:
5159
    case XPATH_LOCATIONSET:
5160
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5161
0
  TODO;
5162
0
  break;
5163
0
    }
5164
0
    xmlXPathFreeObject(val);
5165
0
    if (res == NULL)
5166
0
  return(xmlXPathNewCString(""));
5167
0
    return(xmlXPathWrapString(res));
5168
0
}
5169
5170
/**
5171
 * xmlXPathCastBooleanToNumber:
5172
 * @val:  a boolean
5173
 *
5174
 * Converts a boolean to its number value
5175
 *
5176
 * Returns the number value
5177
 */
5178
double
5179
0
xmlXPathCastBooleanToNumber(int val) {
5180
0
    if (val)
5181
0
  return(1.0);
5182
0
    return(0.0);
5183
0
}
5184
5185
/**
5186
 * xmlXPathCastStringToNumber:
5187
 * @val:  a string
5188
 *
5189
 * Converts a string to its number value
5190
 *
5191
 * Returns the number value
5192
 */
5193
double
5194
0
xmlXPathCastStringToNumber(const xmlChar * val) {
5195
0
    return(xmlXPathStringEvalNumber(val));
5196
0
}
5197
5198
/**
5199
 * xmlXPathCastNodeToNumber:
5200
 * @node:  a node
5201
 *
5202
 * Converts a node to its number value
5203
 *
5204
 * Returns the number value
5205
 */
5206
double
5207
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5208
0
    xmlChar *strval;
5209
0
    double ret;
5210
5211
0
    if (node == NULL)
5212
0
  return(xmlXPathNAN);
5213
0
    strval = xmlXPathCastNodeToString(node);
5214
0
    if (strval == NULL)
5215
0
  return(xmlXPathNAN);
5216
0
    ret = xmlXPathCastStringToNumber(strval);
5217
0
    xmlFree(strval);
5218
5219
0
    return(ret);
5220
0
}
5221
5222
/**
5223
 * xmlXPathCastNodeSetToNumber:
5224
 * @ns:  a node-set
5225
 *
5226
 * Converts a node-set to its number value
5227
 *
5228
 * Returns the number value
5229
 */
5230
double
5231
0
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5232
0
    xmlChar *str;
5233
0
    double ret;
5234
5235
0
    if (ns == NULL)
5236
0
  return(xmlXPathNAN);
5237
0
    str = xmlXPathCastNodeSetToString(ns);
5238
0
    ret = xmlXPathCastStringToNumber(str);
5239
0
    xmlFree(str);
5240
0
    return(ret);
5241
0
}
5242
5243
/**
5244
 * xmlXPathCastToNumber:
5245
 * @val:  an XPath object
5246
 *
5247
 * Converts an XPath object to its number value
5248
 *
5249
 * Returns the number value
5250
 */
5251
double
5252
0
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5253
0
    double ret = 0.0;
5254
5255
0
    if (val == NULL)
5256
0
  return(xmlXPathNAN);
5257
0
    switch (val->type) {
5258
0
    case XPATH_UNDEFINED:
5259
0
  ret = xmlXPathNAN;
5260
0
  break;
5261
0
    case XPATH_NODESET:
5262
0
    case XPATH_XSLT_TREE:
5263
0
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5264
0
  break;
5265
0
    case XPATH_STRING:
5266
0
  ret = xmlXPathCastStringToNumber(val->stringval);
5267
0
  break;
5268
0
    case XPATH_NUMBER:
5269
0
  ret = val->floatval;
5270
0
  break;
5271
0
    case XPATH_BOOLEAN:
5272
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5273
0
  break;
5274
0
    case XPATH_USERS:
5275
#ifdef LIBXML_XPTR_LOCS_ENABLED
5276
    case XPATH_POINT:
5277
    case XPATH_RANGE:
5278
    case XPATH_LOCATIONSET:
5279
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5280
0
  TODO;
5281
0
  ret = xmlXPathNAN;
5282
0
  break;
5283
0
    }
5284
0
    return(ret);
5285
0
}
5286
5287
/**
5288
 * xmlXPathConvertNumber:
5289
 * @val:  an XPath object
5290
 *
5291
 * Converts an existing object to its number() equivalent
5292
 *
5293
 * Returns the new object, the old one is freed (or the operation
5294
 *         is done directly on @val)
5295
 */
5296
xmlXPathObjectPtr
5297
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5298
0
    xmlXPathObjectPtr ret;
5299
5300
0
    if (val == NULL)
5301
0
  return(xmlXPathNewFloat(0.0));
5302
0
    if (val->type == XPATH_NUMBER)
5303
0
  return(val);
5304
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5305
0
    xmlXPathFreeObject(val);
5306
0
    return(ret);
5307
0
}
5308
5309
/**
5310
 * xmlXPathCastNumberToBoolean:
5311
 * @val:  a number
5312
 *
5313
 * Converts a number to its boolean value
5314
 *
5315
 * Returns the boolean value
5316
 */
5317
int
5318
0
xmlXPathCastNumberToBoolean (double val) {
5319
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
5320
0
   return(0);
5321
0
     return(1);
5322
0
}
5323
5324
/**
5325
 * xmlXPathCastStringToBoolean:
5326
 * @val:  a string
5327
 *
5328
 * Converts a string to its boolean value
5329
 *
5330
 * Returns the boolean value
5331
 */
5332
int
5333
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
5334
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
5335
0
  return(0);
5336
0
    return(1);
5337
0
}
5338
5339
/**
5340
 * xmlXPathCastNodeSetToBoolean:
5341
 * @ns:  a node-set
5342
 *
5343
 * Converts a node-set to its boolean value
5344
 *
5345
 * Returns the boolean value
5346
 */
5347
int
5348
0
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5349
0
    if ((ns == NULL) || (ns->nodeNr == 0))
5350
0
  return(0);
5351
0
    return(1);
5352
0
}
5353
5354
/**
5355
 * xmlXPathCastToBoolean:
5356
 * @val:  an XPath object
5357
 *
5358
 * Converts an XPath object to its boolean value
5359
 *
5360
 * Returns the boolean value
5361
 */
5362
int
5363
0
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5364
0
    int ret = 0;
5365
5366
0
    if (val == NULL)
5367
0
  return(0);
5368
0
    switch (val->type) {
5369
0
    case XPATH_UNDEFINED:
5370
0
  ret = 0;
5371
0
  break;
5372
0
    case XPATH_NODESET:
5373
0
    case XPATH_XSLT_TREE:
5374
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5375
0
  break;
5376
0
    case XPATH_STRING:
5377
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
5378
0
  break;
5379
0
    case XPATH_NUMBER:
5380
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
5381
0
  break;
5382
0
    case XPATH_BOOLEAN:
5383
0
  ret = val->boolval;
5384
0
  break;
5385
0
    case XPATH_USERS:
5386
#ifdef LIBXML_XPTR_LOCS_ENABLED
5387
    case XPATH_POINT:
5388
    case XPATH_RANGE:
5389
    case XPATH_LOCATIONSET:
5390
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5391
0
  TODO;
5392
0
  ret = 0;
5393
0
  break;
5394
0
    }
5395
0
    return(ret);
5396
0
}
5397
5398
5399
/**
5400
 * xmlXPathConvertBoolean:
5401
 * @val:  an XPath object
5402
 *
5403
 * Converts an existing object to its boolean() equivalent
5404
 *
5405
 * Returns the new object, the old one is freed (or the operation
5406
 *         is done directly on @val)
5407
 */
5408
xmlXPathObjectPtr
5409
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5410
0
    xmlXPathObjectPtr ret;
5411
5412
0
    if (val == NULL)
5413
0
  return(xmlXPathNewBoolean(0));
5414
0
    if (val->type == XPATH_BOOLEAN)
5415
0
  return(val);
5416
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5417
0
    xmlXPathFreeObject(val);
5418
0
    return(ret);
5419
0
}
5420
5421
/************************************************************************
5422
 *                  *
5423
 *    Routines to handle XPath contexts     *
5424
 *                  *
5425
 ************************************************************************/
5426
5427
/**
5428
 * xmlXPathNewContext:
5429
 * @doc:  the XML document
5430
 *
5431
 * Create a new xmlXPathContext
5432
 *
5433
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5434
 */
5435
xmlXPathContextPtr
5436
0
xmlXPathNewContext(xmlDocPtr doc) {
5437
0
    xmlXPathContextPtr ret;
5438
5439
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5440
0
    if (ret == NULL) {
5441
0
        xmlXPathErrMemory(NULL, "creating context\n");
5442
0
  return(NULL);
5443
0
    }
5444
0
    memset(ret, 0 , sizeof(xmlXPathContext));
5445
0
    ret->doc = doc;
5446
0
    ret->node = NULL;
5447
5448
0
    ret->varHash = NULL;
5449
5450
0
    ret->nb_types = 0;
5451
0
    ret->max_types = 0;
5452
0
    ret->types = NULL;
5453
5454
0
    ret->funcHash = xmlHashCreate(0);
5455
5456
0
    ret->nb_axis = 0;
5457
0
    ret->max_axis = 0;
5458
0
    ret->axis = NULL;
5459
5460
0
    ret->nsHash = NULL;
5461
0
    ret->user = NULL;
5462
5463
0
    ret->contextSize = -1;
5464
0
    ret->proximityPosition = -1;
5465
5466
#ifdef XP_DEFAULT_CACHE_ON
5467
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5468
  xmlXPathFreeContext(ret);
5469
  return(NULL);
5470
    }
5471
#endif
5472
5473
0
    xmlXPathRegisterAllFunctions(ret);
5474
5475
0
    return(ret);
5476
0
}
5477
5478
/**
5479
 * xmlXPathFreeContext:
5480
 * @ctxt:  the context to free
5481
 *
5482
 * Free up an xmlXPathContext
5483
 */
5484
void
5485
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5486
0
    if (ctxt == NULL) return;
5487
5488
0
    if (ctxt->cache != NULL)
5489
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5490
0
    xmlXPathRegisteredNsCleanup(ctxt);
5491
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
5492
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
5493
0
    xmlResetError(&ctxt->lastError);
5494
0
    xmlFree(ctxt);
5495
0
}
5496
5497
/************************************************************************
5498
 *                  *
5499
 *    Routines to handle XPath parser contexts    *
5500
 *                  *
5501
 ************************************************************************/
5502
5503
#define CHECK_CTXT(ctxt)            \
5504
0
    if (ctxt == NULL) {           \
5505
0
  __xmlRaiseError(NULL, NULL, NULL,       \
5506
0
    NULL, NULL, XML_FROM_XPATH,       \
5507
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
5508
0
    __FILE__, __LINE__,         \
5509
0
    NULL, NULL, NULL, 0, 0,         \
5510
0
    "NULL context pointer\n");        \
5511
0
  return(NULL);             \
5512
0
    }                  \
5513
5514
#define CHECK_CTXT_NEG(ctxt)            \
5515
0
    if (ctxt == NULL) {           \
5516
0
  __xmlRaiseError(NULL, NULL, NULL,       \
5517
0
    NULL, NULL, XML_FROM_XPATH,       \
5518
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
5519
0
    __FILE__, __LINE__,         \
5520
0
    NULL, NULL, NULL, 0, 0,         \
5521
0
    "NULL context pointer\n");        \
5522
0
  return(-1);             \
5523
0
    }                  \
5524
5525
5526
#define CHECK_CONTEXT(ctxt)           \
5527
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
5528
        (ctxt->doc->children == NULL)) {        \
5529
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
5530
  return(NULL);             \
5531
    }
5532
5533
5534
/**
5535
 * xmlXPathNewParserContext:
5536
 * @str:  the XPath expression
5537
 * @ctxt:  the XPath context
5538
 *
5539
 * Create a new xmlXPathParserContext
5540
 *
5541
 * Returns the xmlXPathParserContext just allocated.
5542
 */
5543
xmlXPathParserContextPtr
5544
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5545
0
    xmlXPathParserContextPtr ret;
5546
5547
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5548
0
    if (ret == NULL) {
5549
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
5550
0
  return(NULL);
5551
0
    }
5552
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
5553
0
    ret->cur = ret->base = str;
5554
0
    ret->context = ctxt;
5555
5556
0
    ret->comp = xmlXPathNewCompExpr();
5557
0
    if (ret->comp == NULL) {
5558
0
  xmlFree(ret->valueTab);
5559
0
  xmlFree(ret);
5560
0
  return(NULL);
5561
0
    }
5562
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5563
0
        ret->comp->dict = ctxt->dict;
5564
0
  xmlDictReference(ret->comp->dict);
5565
0
    }
5566
5567
0
    return(ret);
5568
0
}
5569
5570
/**
5571
 * xmlXPathCompParserContext:
5572
 * @comp:  the XPath compiled expression
5573
 * @ctxt:  the XPath context
5574
 *
5575
 * Create a new xmlXPathParserContext when processing a compiled expression
5576
 *
5577
 * Returns the xmlXPathParserContext just allocated.
5578
 */
5579
static xmlXPathParserContextPtr
5580
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5581
0
    xmlXPathParserContextPtr ret;
5582
5583
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5584
0
    if (ret == NULL) {
5585
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5586
0
  return(NULL);
5587
0
    }
5588
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
5589
5590
    /* Allocate the value stack */
5591
0
    ret->valueTab = (xmlXPathObjectPtr *)
5592
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5593
0
    if (ret->valueTab == NULL) {
5594
0
  xmlFree(ret);
5595
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5596
0
  return(NULL);
5597
0
    }
5598
0
    ret->valueNr = 0;
5599
0
    ret->valueMax = 10;
5600
0
    ret->value = NULL;
5601
5602
0
    ret->context = ctxt;
5603
0
    ret->comp = comp;
5604
5605
0
    return(ret);
5606
0
}
5607
5608
/**
5609
 * xmlXPathFreeParserContext:
5610
 * @ctxt:  the context to free
5611
 *
5612
 * Free up an xmlXPathParserContext
5613
 */
5614
void
5615
0
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5616
0
    int i;
5617
5618
0
    if (ctxt->valueTab != NULL) {
5619
0
        for (i = 0; i < ctxt->valueNr; i++) {
5620
0
            if (ctxt->context)
5621
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5622
0
            else
5623
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
5624
0
        }
5625
0
        xmlFree(ctxt->valueTab);
5626
0
    }
5627
0
    if (ctxt->comp != NULL) {
5628
0
#ifdef XPATH_STREAMING
5629
0
  if (ctxt->comp->stream != NULL) {
5630
0
      xmlFreePatternList(ctxt->comp->stream);
5631
0
      ctxt->comp->stream = NULL;
5632
0
  }
5633
0
#endif
5634
0
  xmlXPathFreeCompExpr(ctxt->comp);
5635
0
    }
5636
0
    xmlFree(ctxt);
5637
0
}
5638
5639
/************************************************************************
5640
 *                  *
5641
 *    The implicit core function library      *
5642
 *                  *
5643
 ************************************************************************/
5644
5645
/**
5646
 * xmlXPathNodeValHash:
5647
 * @node:  a node pointer
5648
 *
5649
 * Function computing the beginning of the string value of the node,
5650
 * used to speed up comparisons
5651
 *
5652
 * Returns an int usable as a hash
5653
 */
5654
static unsigned int
5655
0
xmlXPathNodeValHash(xmlNodePtr node) {
5656
0
    int len = 2;
5657
0
    const xmlChar * string = NULL;
5658
0
    xmlNodePtr tmp = NULL;
5659
0
    unsigned int ret = 0;
5660
5661
0
    if (node == NULL)
5662
0
  return(0);
5663
5664
0
    if (node->type == XML_DOCUMENT_NODE) {
5665
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
5666
0
  if (tmp == NULL)
5667
0
      node = node->children;
5668
0
  else
5669
0
      node = tmp;
5670
5671
0
  if (node == NULL)
5672
0
      return(0);
5673
0
    }
5674
5675
0
    switch (node->type) {
5676
0
  case XML_COMMENT_NODE:
5677
0
  case XML_PI_NODE:
5678
0
  case XML_CDATA_SECTION_NODE:
5679
0
  case XML_TEXT_NODE:
5680
0
      string = node->content;
5681
0
      if (string == NULL)
5682
0
    return(0);
5683
0
      if (string[0] == 0)
5684
0
    return(0);
5685
0
      return(string[0] + (string[1] << 8));
5686
0
  case XML_NAMESPACE_DECL:
5687
0
      string = ((xmlNsPtr)node)->href;
5688
0
      if (string == NULL)
5689
0
    return(0);
5690
0
      if (string[0] == 0)
5691
0
    return(0);
5692
0
      return(string[0] + (string[1] << 8));
5693
0
  case XML_ATTRIBUTE_NODE:
5694
0
      tmp = ((xmlAttrPtr) node)->children;
5695
0
      break;
5696
0
  case XML_ELEMENT_NODE:
5697
0
      tmp = node->children;
5698
0
      break;
5699
0
  default:
5700
0
      return(0);
5701
0
    }
5702
0
    while (tmp != NULL) {
5703
0
  switch (tmp->type) {
5704
0
      case XML_CDATA_SECTION_NODE:
5705
0
      case XML_TEXT_NODE:
5706
0
    string = tmp->content;
5707
0
    break;
5708
0
      default:
5709
0
                string = NULL;
5710
0
    break;
5711
0
  }
5712
0
  if ((string != NULL) && (string[0] != 0)) {
5713
0
      if (len == 1) {
5714
0
    return(ret + (string[0] << 8));
5715
0
      }
5716
0
      if (string[1] == 0) {
5717
0
    len = 1;
5718
0
    ret = string[0];
5719
0
      } else {
5720
0
    return(string[0] + (string[1] << 8));
5721
0
      }
5722
0
  }
5723
  /*
5724
   * Skip to next node
5725
   */
5726
0
        if ((tmp->children != NULL) &&
5727
0
            (tmp->type != XML_DTD_NODE) &&
5728
0
            (tmp->type != XML_ENTITY_REF_NODE) &&
5729
0
            (tmp->children->type != XML_ENTITY_DECL)) {
5730
0
            tmp = tmp->children;
5731
0
            continue;
5732
0
  }
5733
0
  if (tmp == node)
5734
0
      break;
5735
5736
0
  if (tmp->next != NULL) {
5737
0
      tmp = tmp->next;
5738
0
      continue;
5739
0
  }
5740
5741
0
  do {
5742
0
      tmp = tmp->parent;
5743
0
      if (tmp == NULL)
5744
0
    break;
5745
0
      if (tmp == node) {
5746
0
    tmp = NULL;
5747
0
    break;
5748
0
      }
5749
0
      if (tmp->next != NULL) {
5750
0
    tmp = tmp->next;
5751
0
    break;
5752
0
      }
5753
0
  } while (tmp != NULL);
5754
0
    }
5755
0
    return(ret);
5756
0
}
5757
5758
/**
5759
 * xmlXPathStringHash:
5760
 * @string:  a string
5761
 *
5762
 * Function computing the beginning of the string value of the node,
5763
 * used to speed up comparisons
5764
 *
5765
 * Returns an int usable as a hash
5766
 */
5767
static unsigned int
5768
0
xmlXPathStringHash(const xmlChar * string) {
5769
0
    if (string == NULL)
5770
0
  return(0);
5771
0
    if (string[0] == 0)
5772
0
  return(0);
5773
0
    return(string[0] + (string[1] << 8));
5774
0
}
5775
5776
/**
5777
 * xmlXPathCompareNodeSetFloat:
5778
 * @ctxt:  the XPath Parser context
5779
 * @inf:  less than (1) or greater than (0)
5780
 * @strict:  is the comparison strict
5781
 * @arg:  the node set
5782
 * @f:  the value
5783
 *
5784
 * Implement the compare operation between a nodeset and a number
5785
 *     @ns < @val    (1, 1, ...
5786
 *     @ns <= @val   (1, 0, ...
5787
 *     @ns > @val    (0, 1, ...
5788
 *     @ns >= @val   (0, 0, ...
5789
 *
5790
 * If one object to be compared is a node-set and the other is a number,
5791
 * then the comparison will be true if and only if there is a node in the
5792
 * node-set such that the result of performing the comparison on the number
5793
 * to be compared and on the result of converting the string-value of that
5794
 * node to a number using the number function is true.
5795
 *
5796
 * Returns 0 or 1 depending on the results of the test.
5797
 */
5798
static int
5799
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5800
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5801
0
    int i, ret = 0;
5802
0
    xmlNodeSetPtr ns;
5803
0
    xmlChar *str2;
5804
5805
0
    if ((f == NULL) || (arg == NULL) ||
5806
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5807
0
  xmlXPathReleaseObject(ctxt->context, arg);
5808
0
  xmlXPathReleaseObject(ctxt->context, f);
5809
0
        return(0);
5810
0
    }
5811
0
    ns = arg->nodesetval;
5812
0
    if (ns != NULL) {
5813
0
  for (i = 0;i < ns->nodeNr;i++) {
5814
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5815
0
       if (str2 != NULL) {
5816
0
     valuePush(ctxt,
5817
0
         xmlXPathCacheNewString(ctxt->context, str2));
5818
0
     xmlFree(str2);
5819
0
     xmlXPathNumberFunction(ctxt, 1);
5820
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
5821
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5822
0
     if (ret)
5823
0
         break;
5824
0
       }
5825
0
  }
5826
0
    }
5827
0
    xmlXPathReleaseObject(ctxt->context, arg);
5828
0
    xmlXPathReleaseObject(ctxt->context, f);
5829
0
    return(ret);
5830
0
}
5831
5832
/**
5833
 * xmlXPathCompareNodeSetString:
5834
 * @ctxt:  the XPath Parser context
5835
 * @inf:  less than (1) or greater than (0)
5836
 * @strict:  is the comparison strict
5837
 * @arg:  the node set
5838
 * @s:  the value
5839
 *
5840
 * Implement the compare operation between a nodeset and a string
5841
 *     @ns < @val    (1, 1, ...
5842
 *     @ns <= @val   (1, 0, ...
5843
 *     @ns > @val    (0, 1, ...
5844
 *     @ns >= @val   (0, 0, ...
5845
 *
5846
 * If one object to be compared is a node-set and the other is a string,
5847
 * then the comparison will be true if and only if there is a node in
5848
 * the node-set such that the result of performing the comparison on the
5849
 * string-value of the node and the other string is true.
5850
 *
5851
 * Returns 0 or 1 depending on the results of the test.
5852
 */
5853
static int
5854
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5855
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5856
0
    int i, ret = 0;
5857
0
    xmlNodeSetPtr ns;
5858
0
    xmlChar *str2;
5859
5860
0
    if ((s == NULL) || (arg == NULL) ||
5861
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5862
0
  xmlXPathReleaseObject(ctxt->context, arg);
5863
0
  xmlXPathReleaseObject(ctxt->context, s);
5864
0
        return(0);
5865
0
    }
5866
0
    ns = arg->nodesetval;
5867
0
    if (ns != NULL) {
5868
0
  for (i = 0;i < ns->nodeNr;i++) {
5869
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5870
0
       if (str2 != NULL) {
5871
0
     valuePush(ctxt,
5872
0
         xmlXPathCacheNewString(ctxt->context, str2));
5873
0
     xmlFree(str2);
5874
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
5875
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5876
0
     if (ret)
5877
0
         break;
5878
0
       }
5879
0
  }
5880
0
    }
5881
0
    xmlXPathReleaseObject(ctxt->context, arg);
5882
0
    xmlXPathReleaseObject(ctxt->context, s);
5883
0
    return(ret);
5884
0
}
5885
5886
/**
5887
 * xmlXPathCompareNodeSets:
5888
 * @inf:  less than (1) or greater than (0)
5889
 * @strict:  is the comparison strict
5890
 * @arg1:  the first node set object
5891
 * @arg2:  the second node set object
5892
 *
5893
 * Implement the compare operation on nodesets:
5894
 *
5895
 * If both objects to be compared are node-sets, then the comparison
5896
 * will be true if and only if there is a node in the first node-set
5897
 * and a node in the second node-set such that the result of performing
5898
 * the comparison on the string-values of the two nodes is true.
5899
 * ....
5900
 * When neither object to be compared is a node-set and the operator
5901
 * is <=, <, >= or >, then the objects are compared by converting both
5902
 * objects to numbers and comparing the numbers according to IEEE 754.
5903
 * ....
5904
 * The number function converts its argument to a number as follows:
5905
 *  - a string that consists of optional whitespace followed by an
5906
 *    optional minus sign followed by a Number followed by whitespace
5907
 *    is converted to the IEEE 754 number that is nearest (according
5908
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5909
 *    represented by the string; any other string is converted to NaN
5910
 *
5911
 * Conclusion all nodes need to be converted first to their string value
5912
 * and then the comparison must be done when possible
5913
 */
5914
static int
5915
xmlXPathCompareNodeSets(int inf, int strict,
5916
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5917
0
    int i, j, init = 0;
5918
0
    double val1;
5919
0
    double *values2;
5920
0
    int ret = 0;
5921
0
    xmlNodeSetPtr ns1;
5922
0
    xmlNodeSetPtr ns2;
5923
5924
0
    if ((arg1 == NULL) ||
5925
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5926
0
  xmlXPathFreeObject(arg2);
5927
0
        return(0);
5928
0
    }
5929
0
    if ((arg2 == NULL) ||
5930
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5931
0
  xmlXPathFreeObject(arg1);
5932
0
  xmlXPathFreeObject(arg2);
5933
0
        return(0);
5934
0
    }
5935
5936
0
    ns1 = arg1->nodesetval;
5937
0
    ns2 = arg2->nodesetval;
5938
5939
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5940
0
  xmlXPathFreeObject(arg1);
5941
0
  xmlXPathFreeObject(arg2);
5942
0
  return(0);
5943
0
    }
5944
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5945
0
  xmlXPathFreeObject(arg1);
5946
0
  xmlXPathFreeObject(arg2);
5947
0
  return(0);
5948
0
    }
5949
5950
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5951
0
    if (values2 == NULL) {
5952
        /* TODO: Propagate memory error. */
5953
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
5954
0
  xmlXPathFreeObject(arg1);
5955
0
  xmlXPathFreeObject(arg2);
5956
0
  return(0);
5957
0
    }
5958
0
    for (i = 0;i < ns1->nodeNr;i++) {
5959
0
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
5960
0
  if (xmlXPathIsNaN(val1))
5961
0
      continue;
5962
0
  for (j = 0;j < ns2->nodeNr;j++) {
5963
0
      if (init == 0) {
5964
0
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
5965
0
      }
5966
0
      if (xmlXPathIsNaN(values2[j]))
5967
0
    continue;
5968
0
      if (inf && strict)
5969
0
    ret = (val1 < values2[j]);
5970
0
      else if (inf && !strict)
5971
0
    ret = (val1 <= values2[j]);
5972
0
      else if (!inf && strict)
5973
0
    ret = (val1 > values2[j]);
5974
0
      else if (!inf && !strict)
5975
0
    ret = (val1 >= values2[j]);
5976
0
      if (ret)
5977
0
    break;
5978
0
  }
5979
0
  if (ret)
5980
0
      break;
5981
0
  init = 1;
5982
0
    }
5983
0
    xmlFree(values2);
5984
0
    xmlXPathFreeObject(arg1);
5985
0
    xmlXPathFreeObject(arg2);
5986
0
    return(ret);
5987
0
}
5988
5989
/**
5990
 * xmlXPathCompareNodeSetValue:
5991
 * @ctxt:  the XPath Parser context
5992
 * @inf:  less than (1) or greater than (0)
5993
 * @strict:  is the comparison strict
5994
 * @arg:  the node set
5995
 * @val:  the value
5996
 *
5997
 * Implement the compare operation between a nodeset and a value
5998
 *     @ns < @val    (1, 1, ...
5999
 *     @ns <= @val   (1, 0, ...
6000
 *     @ns > @val    (0, 1, ...
6001
 *     @ns >= @val   (0, 0, ...
6002
 *
6003
 * If one object to be compared is a node-set and the other is a boolean,
6004
 * then the comparison will be true if and only if the result of performing
6005
 * the comparison on the boolean and on the result of converting
6006
 * the node-set to a boolean using the boolean function is true.
6007
 *
6008
 * Returns 0 or 1 depending on the results of the test.
6009
 */
6010
static int
6011
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6012
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6013
0
    if ((val == NULL) || (arg == NULL) ||
6014
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6015
0
        return(0);
6016
6017
0
    switch(val->type) {
6018
0
        case XPATH_NUMBER:
6019
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6020
0
        case XPATH_NODESET:
6021
0
        case XPATH_XSLT_TREE:
6022
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6023
0
        case XPATH_STRING:
6024
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6025
0
        case XPATH_BOOLEAN:
6026
0
      valuePush(ctxt, arg);
6027
0
      xmlXPathBooleanFunction(ctxt, 1);
6028
0
      valuePush(ctxt, val);
6029
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
6030
0
  default:
6031
0
            xmlGenericError(xmlGenericErrorContext,
6032
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6033
0
                    "and object of type %d\n",
6034
0
                    val->type);
6035
0
            xmlXPathReleaseObject(ctxt->context, arg);
6036
0
            xmlXPathReleaseObject(ctxt->context, val);
6037
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6038
0
    }
6039
0
    return(0);
6040
0
}
6041
6042
/**
6043
 * xmlXPathEqualNodeSetString:
6044
 * @arg:  the nodeset object argument
6045
 * @str:  the string to compare to.
6046
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6047
 *
6048
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6049
 * If one object to be compared is a node-set and the other is a string,
6050
 * then the comparison will be true if and only if there is a node in
6051
 * the node-set such that the result of performing the comparison on the
6052
 * string-value of the node and the other string is true.
6053
 *
6054
 * Returns 0 or 1 depending on the results of the test.
6055
 */
6056
static int
6057
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6058
0
{
6059
0
    int i;
6060
0
    xmlNodeSetPtr ns;
6061
0
    xmlChar *str2;
6062
0
    unsigned int hash;
6063
6064
0
    if ((str == NULL) || (arg == NULL) ||
6065
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6066
0
        return (0);
6067
0
    ns = arg->nodesetval;
6068
    /*
6069
     * A NULL nodeset compared with a string is always false
6070
     * (since there is no node equal, and no node not equal)
6071
     */
6072
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6073
0
        return (0);
6074
0
    hash = xmlXPathStringHash(str);
6075
0
    for (i = 0; i < ns->nodeNr; i++) {
6076
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6077
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6078
0
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6079
0
                xmlFree(str2);
6080
0
    if (neq)
6081
0
        continue;
6082
0
                return (1);
6083
0
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6084
0
    if (neq)
6085
0
        continue;
6086
0
                return (1);
6087
0
            } else if (neq) {
6088
0
    if (str2 != NULL)
6089
0
        xmlFree(str2);
6090
0
    return (1);
6091
0
      }
6092
0
            if (str2 != NULL)
6093
0
                xmlFree(str2);
6094
0
        } else if (neq)
6095
0
      return (1);
6096
0
    }
6097
0
    return (0);
6098
0
}
6099
6100
/**
6101
 * xmlXPathEqualNodeSetFloat:
6102
 * @arg:  the nodeset object argument
6103
 * @f:  the float to compare to
6104
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6105
 *
6106
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6107
 * If one object to be compared is a node-set and the other is a number,
6108
 * then the comparison will be true if and only if there is a node in
6109
 * the node-set such that the result of performing the comparison on the
6110
 * number to be compared and on the result of converting the string-value
6111
 * of that node to a number using the number function is true.
6112
 *
6113
 * Returns 0 or 1 depending on the results of the test.
6114
 */
6115
static int
6116
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6117
0
    xmlXPathObjectPtr arg, double f, int neq) {
6118
0
  int i, ret=0;
6119
0
  xmlNodeSetPtr ns;
6120
0
  xmlChar *str2;
6121
0
  xmlXPathObjectPtr val;
6122
0
  double v;
6123
6124
0
    if ((arg == NULL) ||
6125
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6126
0
        return(0);
6127
6128
0
    ns = arg->nodesetval;
6129
0
    if (ns != NULL) {
6130
0
  for (i=0;i<ns->nodeNr;i++) {
6131
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6132
0
      if (str2 != NULL) {
6133
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6134
0
    xmlFree(str2);
6135
0
    xmlXPathNumberFunction(ctxt, 1);
6136
0
                CHECK_ERROR0;
6137
0
    val = valuePop(ctxt);
6138
0
    v = val->floatval;
6139
0
    xmlXPathReleaseObject(ctxt->context, val);
6140
0
    if (!xmlXPathIsNaN(v)) {
6141
0
        if ((!neq) && (v==f)) {
6142
0
      ret = 1;
6143
0
      break;
6144
0
        } else if ((neq) && (v!=f)) {
6145
0
      ret = 1;
6146
0
      break;
6147
0
        }
6148
0
    } else { /* NaN is unequal to any value */
6149
0
        if (neq)
6150
0
      ret = 1;
6151
0
    }
6152
0
      }
6153
0
  }
6154
0
    }
6155
6156
0
    return(ret);
6157
0
}
6158
6159
6160
/**
6161
 * xmlXPathEqualNodeSets:
6162
 * @arg1:  first nodeset object argument
6163
 * @arg2:  second nodeset object argument
6164
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6165
 *
6166
 * Implement the equal / not equal operation on XPath nodesets:
6167
 * @arg1 == @arg2  or  @arg1 != @arg2
6168
 * If both objects to be compared are node-sets, then the comparison
6169
 * will be true if and only if there is a node in the first node-set and
6170
 * a node in the second node-set such that the result of performing the
6171
 * comparison on the string-values of the two nodes is true.
6172
 *
6173
 * (needless to say, this is a costly operation)
6174
 *
6175
 * Returns 0 or 1 depending on the results of the test.
6176
 */
6177
static int
6178
0
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6179
0
    int i, j;
6180
0
    unsigned int *hashs1;
6181
0
    unsigned int *hashs2;
6182
0
    xmlChar **values1;
6183
0
    xmlChar **values2;
6184
0
    int ret = 0;
6185
0
    xmlNodeSetPtr ns1;
6186
0
    xmlNodeSetPtr ns2;
6187
6188
0
    if ((arg1 == NULL) ||
6189
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6190
0
        return(0);
6191
0
    if ((arg2 == NULL) ||
6192
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6193
0
        return(0);
6194
6195
0
    ns1 = arg1->nodesetval;
6196
0
    ns2 = arg2->nodesetval;
6197
6198
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6199
0
  return(0);
6200
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6201
0
  return(0);
6202
6203
    /*
6204
     * for equal, check if there is a node pertaining to both sets
6205
     */
6206
0
    if (neq == 0)
6207
0
  for (i = 0;i < ns1->nodeNr;i++)
6208
0
      for (j = 0;j < ns2->nodeNr;j++)
6209
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6210
0
        return(1);
6211
6212
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6213
0
    if (values1 == NULL) {
6214
        /* TODO: Propagate memory error. */
6215
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6216
0
  return(0);
6217
0
    }
6218
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6219
0
    if (hashs1 == NULL) {
6220
        /* TODO: Propagate memory error. */
6221
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6222
0
  xmlFree(values1);
6223
0
  return(0);
6224
0
    }
6225
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6226
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6227
0
    if (values2 == NULL) {
6228
        /* TODO: Propagate memory error. */
6229
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6230
0
  xmlFree(hashs1);
6231
0
  xmlFree(values1);
6232
0
  return(0);
6233
0
    }
6234
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6235
0
    if (hashs2 == NULL) {
6236
        /* TODO: Propagate memory error. */
6237
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6238
0
  xmlFree(hashs1);
6239
0
  xmlFree(values1);
6240
0
  xmlFree(values2);
6241
0
  return(0);
6242
0
    }
6243
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6244
0
    for (i = 0;i < ns1->nodeNr;i++) {
6245
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6246
0
  for (j = 0;j < ns2->nodeNr;j++) {
6247
0
      if (i == 0)
6248
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6249
0
      if (hashs1[i] != hashs2[j]) {
6250
0
    if (neq) {
6251
0
        ret = 1;
6252
0
        break;
6253
0
    }
6254
0
      }
6255
0
      else {
6256
0
    if (values1[i] == NULL)
6257
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6258
0
    if (values2[j] == NULL)
6259
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6260
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6261
0
    if (ret)
6262
0
        break;
6263
0
      }
6264
0
  }
6265
0
  if (ret)
6266
0
      break;
6267
0
    }
6268
0
    for (i = 0;i < ns1->nodeNr;i++)
6269
0
  if (values1[i] != NULL)
6270
0
      xmlFree(values1[i]);
6271
0
    for (j = 0;j < ns2->nodeNr;j++)
6272
0
  if (values2[j] != NULL)
6273
0
      xmlFree(values2[j]);
6274
0
    xmlFree(values1);
6275
0
    xmlFree(values2);
6276
0
    xmlFree(hashs1);
6277
0
    xmlFree(hashs2);
6278
0
    return(ret);
6279
0
}
6280
6281
static int
6282
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6283
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6284
0
    int ret = 0;
6285
    /*
6286
     *At this point we are assured neither arg1 nor arg2
6287
     *is a nodeset, so we can just pick the appropriate routine.
6288
     */
6289
0
    switch (arg1->type) {
6290
0
        case XPATH_UNDEFINED:
6291
0
      break;
6292
0
        case XPATH_BOOLEAN:
6293
0
      switch (arg2->type) {
6294
0
          case XPATH_UNDEFINED:
6295
0
        break;
6296
0
    case XPATH_BOOLEAN:
6297
0
        ret = (arg1->boolval == arg2->boolval);
6298
0
        break;
6299
0
    case XPATH_NUMBER:
6300
0
        ret = (arg1->boolval ==
6301
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
6302
0
        break;
6303
0
    case XPATH_STRING:
6304
0
        if ((arg2->stringval == NULL) ||
6305
0
      (arg2->stringval[0] == 0)) ret = 0;
6306
0
        else
6307
0
      ret = 1;
6308
0
        ret = (arg1->boolval == ret);
6309
0
        break;
6310
0
    case XPATH_USERS:
6311
#ifdef LIBXML_XPTR_LOCS_ENABLED
6312
    case XPATH_POINT:
6313
    case XPATH_RANGE:
6314
    case XPATH_LOCATIONSET:
6315
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6316
0
        TODO
6317
0
        break;
6318
0
    case XPATH_NODESET:
6319
0
    case XPATH_XSLT_TREE:
6320
0
        break;
6321
0
      }
6322
0
      break;
6323
0
        case XPATH_NUMBER:
6324
0
      switch (arg2->type) {
6325
0
          case XPATH_UNDEFINED:
6326
0
        break;
6327
0
    case XPATH_BOOLEAN:
6328
0
        ret = (arg2->boolval==
6329
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
6330
0
        break;
6331
0
    case XPATH_STRING:
6332
0
        valuePush(ctxt, arg2);
6333
0
        xmlXPathNumberFunction(ctxt, 1);
6334
0
        arg2 = valuePop(ctxt);
6335
0
                    if (ctxt->error)
6336
0
                        break;
6337
                    /* Falls through. */
6338
0
    case XPATH_NUMBER:
6339
        /* Hand check NaN and Infinity equalities */
6340
0
        if (xmlXPathIsNaN(arg1->floatval) ||
6341
0
          xmlXPathIsNaN(arg2->floatval)) {
6342
0
            ret = 0;
6343
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6344
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
6345
0
          ret = 1;
6346
0
      else
6347
0
          ret = 0;
6348
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6349
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
6350
0
          ret = 1;
6351
0
      else
6352
0
          ret = 0;
6353
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6354
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
6355
0
          ret = 1;
6356
0
      else
6357
0
          ret = 0;
6358
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6359
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
6360
0
          ret = 1;
6361
0
      else
6362
0
          ret = 0;
6363
0
        } else {
6364
0
            ret = (arg1->floatval == arg2->floatval);
6365
0
        }
6366
0
        break;
6367
0
    case XPATH_USERS:
6368
#ifdef LIBXML_XPTR_LOCS_ENABLED
6369
    case XPATH_POINT:
6370
    case XPATH_RANGE:
6371
    case XPATH_LOCATIONSET:
6372
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6373
0
        TODO
6374
0
        break;
6375
0
    case XPATH_NODESET:
6376
0
    case XPATH_XSLT_TREE:
6377
0
        break;
6378
0
      }
6379
0
      break;
6380
0
        case XPATH_STRING:
6381
0
      switch (arg2->type) {
6382
0
          case XPATH_UNDEFINED:
6383
0
        break;
6384
0
    case XPATH_BOOLEAN:
6385
0
        if ((arg1->stringval == NULL) ||
6386
0
      (arg1->stringval[0] == 0)) ret = 0;
6387
0
        else
6388
0
      ret = 1;
6389
0
        ret = (arg2->boolval == ret);
6390
0
        break;
6391
0
    case XPATH_STRING:
6392
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6393
0
        break;
6394
0
    case XPATH_NUMBER:
6395
0
        valuePush(ctxt, arg1);
6396
0
        xmlXPathNumberFunction(ctxt, 1);
6397
0
        arg1 = valuePop(ctxt);
6398
0
                    if (ctxt->error)
6399
0
                        break;
6400
        /* Hand check NaN and Infinity equalities */
6401
0
        if (xmlXPathIsNaN(arg1->floatval) ||
6402
0
          xmlXPathIsNaN(arg2->floatval)) {
6403
0
            ret = 0;
6404
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6405
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
6406
0
          ret = 1;
6407
0
      else
6408
0
          ret = 0;
6409
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6410
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
6411
0
          ret = 1;
6412
0
      else
6413
0
          ret = 0;
6414
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6415
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
6416
0
          ret = 1;
6417
0
      else
6418
0
          ret = 0;
6419
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6420
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
6421
0
          ret = 1;
6422
0
      else
6423
0
          ret = 0;
6424
0
        } else {
6425
0
            ret = (arg1->floatval == arg2->floatval);
6426
0
        }
6427
0
        break;
6428
0
    case XPATH_USERS:
6429
#ifdef LIBXML_XPTR_LOCS_ENABLED
6430
    case XPATH_POINT:
6431
    case XPATH_RANGE:
6432
    case XPATH_LOCATIONSET:
6433
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6434
0
        TODO
6435
0
        break;
6436
0
    case XPATH_NODESET:
6437
0
    case XPATH_XSLT_TREE:
6438
0
        break;
6439
0
      }
6440
0
      break;
6441
0
        case XPATH_USERS:
6442
#ifdef LIBXML_XPTR_LOCS_ENABLED
6443
  case XPATH_POINT:
6444
  case XPATH_RANGE:
6445
  case XPATH_LOCATIONSET:
6446
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6447
0
      TODO
6448
0
      break;
6449
0
  case XPATH_NODESET:
6450
0
  case XPATH_XSLT_TREE:
6451
0
      break;
6452
0
    }
6453
0
    xmlXPathReleaseObject(ctxt->context, arg1);
6454
0
    xmlXPathReleaseObject(ctxt->context, arg2);
6455
0
    return(ret);
6456
0
}
6457
6458
/**
6459
 * xmlXPathEqualValues:
6460
 * @ctxt:  the XPath Parser context
6461
 *
6462
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6463
 *
6464
 * Returns 0 or 1 depending on the results of the test.
6465
 */
6466
int
6467
0
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6468
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
6469
0
    int ret = 0;
6470
6471
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6472
0
    arg2 = valuePop(ctxt);
6473
0
    arg1 = valuePop(ctxt);
6474
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6475
0
  if (arg1 != NULL)
6476
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6477
0
  else
6478
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6479
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6480
0
    }
6481
6482
0
    if (arg1 == arg2) {
6483
0
  xmlXPathFreeObject(arg1);
6484
0
        return(1);
6485
0
    }
6486
6487
    /*
6488
     *If either argument is a nodeset, it's a 'special case'
6489
     */
6490
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6491
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6492
  /*
6493
   *Hack it to assure arg1 is the nodeset
6494
   */
6495
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6496
0
    argtmp = arg2;
6497
0
    arg2 = arg1;
6498
0
    arg1 = argtmp;
6499
0
  }
6500
0
  switch (arg2->type) {
6501
0
      case XPATH_UNDEFINED:
6502
0
    break;
6503
0
      case XPATH_NODESET:
6504
0
      case XPATH_XSLT_TREE:
6505
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6506
0
    break;
6507
0
      case XPATH_BOOLEAN:
6508
0
    if ((arg1->nodesetval == NULL) ||
6509
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
6510
0
    else
6511
0
        ret = 1;
6512
0
    ret = (ret == arg2->boolval);
6513
0
    break;
6514
0
      case XPATH_NUMBER:
6515
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6516
0
    break;
6517
0
      case XPATH_STRING:
6518
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6519
0
    break;
6520
0
      case XPATH_USERS:
6521
#ifdef LIBXML_XPTR_LOCS_ENABLED
6522
      case XPATH_POINT:
6523
      case XPATH_RANGE:
6524
      case XPATH_LOCATIONSET:
6525
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6526
0
    TODO
6527
0
    break;
6528
0
  }
6529
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6530
0
  xmlXPathReleaseObject(ctxt->context, arg2);
6531
0
  return(ret);
6532
0
    }
6533
6534
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6535
0
}
6536
6537
/**
6538
 * xmlXPathNotEqualValues:
6539
 * @ctxt:  the XPath Parser context
6540
 *
6541
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6542
 *
6543
 * Returns 0 or 1 depending on the results of the test.
6544
 */
6545
int
6546
0
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6547
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
6548
0
    int ret = 0;
6549
6550
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6551
0
    arg2 = valuePop(ctxt);
6552
0
    arg1 = valuePop(ctxt);
6553
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6554
0
  if (arg1 != NULL)
6555
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6556
0
  else
6557
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6558
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6559
0
    }
6560
6561
0
    if (arg1 == arg2) {
6562
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6563
0
        return(0);
6564
0
    }
6565
6566
    /*
6567
     *If either argument is a nodeset, it's a 'special case'
6568
     */
6569
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6570
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6571
  /*
6572
   *Hack it to assure arg1 is the nodeset
6573
   */
6574
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6575
0
    argtmp = arg2;
6576
0
    arg2 = arg1;
6577
0
    arg1 = argtmp;
6578
0
  }
6579
0
  switch (arg2->type) {
6580
0
      case XPATH_UNDEFINED:
6581
0
    break;
6582
0
      case XPATH_NODESET:
6583
0
      case XPATH_XSLT_TREE:
6584
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6585
0
    break;
6586
0
      case XPATH_BOOLEAN:
6587
0
    if ((arg1->nodesetval == NULL) ||
6588
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
6589
0
    else
6590
0
        ret = 1;
6591
0
    ret = (ret != arg2->boolval);
6592
0
    break;
6593
0
      case XPATH_NUMBER:
6594
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6595
0
    break;
6596
0
      case XPATH_STRING:
6597
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6598
0
    break;
6599
0
      case XPATH_USERS:
6600
#ifdef LIBXML_XPTR_LOCS_ENABLED
6601
      case XPATH_POINT:
6602
      case XPATH_RANGE:
6603
      case XPATH_LOCATIONSET:
6604
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6605
0
    TODO
6606
0
    break;
6607
0
  }
6608
0
  xmlXPathReleaseObject(ctxt->context, arg1);
6609
0
  xmlXPathReleaseObject(ctxt->context, arg2);
6610
0
  return(ret);
6611
0
    }
6612
6613
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6614
0
}
6615
6616
/**
6617
 * xmlXPathCompareValues:
6618
 * @ctxt:  the XPath Parser context
6619
 * @inf:  less than (1) or greater than (0)
6620
 * @strict:  is the comparison strict
6621
 *
6622
 * Implement the compare operation on XPath objects:
6623
 *     @arg1 < @arg2    (1, 1, ...
6624
 *     @arg1 <= @arg2   (1, 0, ...
6625
 *     @arg1 > @arg2    (0, 1, ...
6626
 *     @arg1 >= @arg2   (0, 0, ...
6627
 *
6628
 * When neither object to be compared is a node-set and the operator is
6629
 * <=, <, >=, >, then the objects are compared by converted both objects
6630
 * to numbers and comparing the numbers according to IEEE 754. The <
6631
 * comparison will be true if and only if the first number is less than the
6632
 * second number. The <= comparison will be true if and only if the first
6633
 * number is less than or equal to the second number. The > comparison
6634
 * will be true if and only if the first number is greater than the second
6635
 * number. The >= comparison will be true if and only if the first number
6636
 * is greater than or equal to the second number.
6637
 *
6638
 * Returns 1 if the comparison succeeded, 0 if it failed
6639
 */
6640
int
6641
0
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6642
0
    int ret = 0, arg1i = 0, arg2i = 0;
6643
0
    xmlXPathObjectPtr arg1, arg2;
6644
6645
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6646
0
    arg2 = valuePop(ctxt);
6647
0
    arg1 = valuePop(ctxt);
6648
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
6649
0
  if (arg1 != NULL)
6650
0
      xmlXPathReleaseObject(ctxt->context, arg1);
6651
0
  else
6652
0
      xmlXPathReleaseObject(ctxt->context, arg2);
6653
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
6654
0
    }
6655
6656
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6657
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6658
  /*
6659
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6660
   * are not freed from within this routine; they will be freed from the
6661
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6662
   */
6663
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6664
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6665
0
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
6666
0
  } else {
6667
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6668
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6669
0
                                arg1, arg2);
6670
0
      } else {
6671
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6672
0
                                arg2, arg1);
6673
0
      }
6674
0
  }
6675
0
  return(ret);
6676
0
    }
6677
6678
0
    if (arg1->type != XPATH_NUMBER) {
6679
0
  valuePush(ctxt, arg1);
6680
0
  xmlXPathNumberFunction(ctxt, 1);
6681
0
  arg1 = valuePop(ctxt);
6682
0
    }
6683
0
    if (arg2->type != XPATH_NUMBER) {
6684
0
  valuePush(ctxt, arg2);
6685
0
  xmlXPathNumberFunction(ctxt, 1);
6686
0
  arg2 = valuePop(ctxt);
6687
0
    }
6688
0
    if (ctxt->error)
6689
0
        goto error;
6690
    /*
6691
     * Add tests for infinity and nan
6692
     * => feedback on 3.4 for Inf and NaN
6693
     */
6694
    /* Hand check NaN and Infinity comparisons */
6695
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6696
0
  ret=0;
6697
0
    } else {
6698
0
  arg1i=xmlXPathIsInf(arg1->floatval);
6699
0
  arg2i=xmlXPathIsInf(arg2->floatval);
6700
0
  if (inf && strict) {
6701
0
      if ((arg1i == -1 && arg2i != -1) ||
6702
0
    (arg2i == 1 && arg1i != 1)) {
6703
0
    ret = 1;
6704
0
      } else if (arg1i == 0 && arg2i == 0) {
6705
0
    ret = (arg1->floatval < arg2->floatval);
6706
0
      } else {
6707
0
    ret = 0;
6708
0
      }
6709
0
  }
6710
0
  else if (inf && !strict) {
6711
0
      if (arg1i == -1 || arg2i == 1) {
6712
0
    ret = 1;
6713
0
      } else if (arg1i == 0 && arg2i == 0) {
6714
0
    ret = (arg1->floatval <= arg2->floatval);
6715
0
      } else {
6716
0
    ret = 0;
6717
0
      }
6718
0
  }
6719
0
  else if (!inf && strict) {
6720
0
      if ((arg1i == 1 && arg2i != 1) ||
6721
0
    (arg2i == -1 && arg1i != -1)) {
6722
0
    ret = 1;
6723
0
      } else if (arg1i == 0 && arg2i == 0) {
6724
0
    ret = (arg1->floatval > arg2->floatval);
6725
0
      } else {
6726
0
    ret = 0;
6727
0
      }
6728
0
  }
6729
0
  else if (!inf && !strict) {
6730
0
      if (arg1i == 1 || arg2i == -1) {
6731
0
    ret = 1;
6732
0
      } else if (arg1i == 0 && arg2i == 0) {
6733
0
    ret = (arg1->floatval >= arg2->floatval);
6734
0
      } else {
6735
0
    ret = 0;
6736
0
      }
6737
0
  }
6738
0
    }
6739
0
error:
6740
0
    xmlXPathReleaseObject(ctxt->context, arg1);
6741
0
    xmlXPathReleaseObject(ctxt->context, arg2);
6742
0
    return(ret);
6743
0
}
6744
6745
/**
6746
 * xmlXPathValueFlipSign:
6747
 * @ctxt:  the XPath Parser context
6748
 *
6749
 * Implement the unary - operation on an XPath object
6750
 * The numeric operators convert their operands to numbers as if
6751
 * by calling the number function.
6752
 */
6753
void
6754
0
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6755
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6756
0
    CAST_TO_NUMBER;
6757
0
    CHECK_TYPE(XPATH_NUMBER);
6758
0
    ctxt->value->floatval = -ctxt->value->floatval;
6759
0
}
6760
6761
/**
6762
 * xmlXPathAddValues:
6763
 * @ctxt:  the XPath Parser context
6764
 *
6765
 * Implement the add operation on XPath objects:
6766
 * The numeric operators convert their operands to numbers as if
6767
 * by calling the number function.
6768
 */
6769
void
6770
0
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6771
0
    xmlXPathObjectPtr arg;
6772
0
    double val;
6773
6774
0
    arg = valuePop(ctxt);
6775
0
    if (arg == NULL)
6776
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6777
0
    val = xmlXPathCastToNumber(arg);
6778
0
    xmlXPathReleaseObject(ctxt->context, arg);
6779
0
    CAST_TO_NUMBER;
6780
0
    CHECK_TYPE(XPATH_NUMBER);
6781
0
    ctxt->value->floatval += val;
6782
0
}
6783
6784
/**
6785
 * xmlXPathSubValues:
6786
 * @ctxt:  the XPath Parser context
6787
 *
6788
 * Implement the subtraction operation on XPath objects:
6789
 * The numeric operators convert their operands to numbers as if
6790
 * by calling the number function.
6791
 */
6792
void
6793
0
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6794
0
    xmlXPathObjectPtr arg;
6795
0
    double val;
6796
6797
0
    arg = valuePop(ctxt);
6798
0
    if (arg == NULL)
6799
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6800
0
    val = xmlXPathCastToNumber(arg);
6801
0
    xmlXPathReleaseObject(ctxt->context, arg);
6802
0
    CAST_TO_NUMBER;
6803
0
    CHECK_TYPE(XPATH_NUMBER);
6804
0
    ctxt->value->floatval -= val;
6805
0
}
6806
6807
/**
6808
 * xmlXPathMultValues:
6809
 * @ctxt:  the XPath Parser context
6810
 *
6811
 * Implement the multiply operation on XPath objects:
6812
 * The numeric operators convert their operands to numbers as if
6813
 * by calling the number function.
6814
 */
6815
void
6816
0
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6817
0
    xmlXPathObjectPtr arg;
6818
0
    double val;
6819
6820
0
    arg = valuePop(ctxt);
6821
0
    if (arg == NULL)
6822
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6823
0
    val = xmlXPathCastToNumber(arg);
6824
0
    xmlXPathReleaseObject(ctxt->context, arg);
6825
0
    CAST_TO_NUMBER;
6826
0
    CHECK_TYPE(XPATH_NUMBER);
6827
0
    ctxt->value->floatval *= val;
6828
0
}
6829
6830
/**
6831
 * xmlXPathDivValues:
6832
 * @ctxt:  the XPath Parser context
6833
 *
6834
 * Implement the div operation on XPath objects @arg1 / @arg2:
6835
 * The numeric operators convert their operands to numbers as if
6836
 * by calling the number function.
6837
 */
6838
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6839
void
6840
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6841
0
    xmlXPathObjectPtr arg;
6842
0
    double val;
6843
6844
0
    arg = valuePop(ctxt);
6845
0
    if (arg == NULL)
6846
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6847
0
    val = xmlXPathCastToNumber(arg);
6848
0
    xmlXPathReleaseObject(ctxt->context, arg);
6849
0
    CAST_TO_NUMBER;
6850
0
    CHECK_TYPE(XPATH_NUMBER);
6851
0
    ctxt->value->floatval /= val;
6852
0
}
6853
6854
/**
6855
 * xmlXPathModValues:
6856
 * @ctxt:  the XPath Parser context
6857
 *
6858
 * Implement the mod operation on XPath objects: @arg1 / @arg2
6859
 * The numeric operators convert their operands to numbers as if
6860
 * by calling the number function.
6861
 */
6862
void
6863
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6864
0
    xmlXPathObjectPtr arg;
6865
0
    double arg1, arg2;
6866
6867
0
    arg = valuePop(ctxt);
6868
0
    if (arg == NULL)
6869
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6870
0
    arg2 = xmlXPathCastToNumber(arg);
6871
0
    xmlXPathReleaseObject(ctxt->context, arg);
6872
0
    CAST_TO_NUMBER;
6873
0
    CHECK_TYPE(XPATH_NUMBER);
6874
0
    arg1 = ctxt->value->floatval;
6875
0
    if (arg2 == 0)
6876
0
  ctxt->value->floatval = xmlXPathNAN;
6877
0
    else {
6878
0
  ctxt->value->floatval = fmod(arg1, arg2);
6879
0
    }
6880
0
}
6881
6882
/************************************************************************
6883
 *                  *
6884
 *    The traversal functions         *
6885
 *                  *
6886
 ************************************************************************/
6887
6888
/*
6889
 * A traversal function enumerates nodes along an axis.
6890
 * Initially it must be called with NULL, and it indicates
6891
 * termination on the axis by returning NULL.
6892
 */
6893
typedef xmlNodePtr (*xmlXPathTraversalFunction)
6894
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6895
6896
/*
6897
 * xmlXPathTraversalFunctionExt:
6898
 * A traversal function enumerates nodes along an axis.
6899
 * Initially it must be called with NULL, and it indicates
6900
 * termination on the axis by returning NULL.
6901
 * The context node of the traversal is specified via @contextNode.
6902
 */
6903
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6904
                    (xmlNodePtr cur, xmlNodePtr contextNode);
6905
6906
/*
6907
 * xmlXPathNodeSetMergeFunction:
6908
 * Used for merging node sets in xmlXPathCollectAndTest().
6909
 */
6910
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6911
        (xmlNodeSetPtr, xmlNodeSetPtr);
6912
6913
6914
/**
6915
 * xmlXPathNextSelf:
6916
 * @ctxt:  the XPath Parser context
6917
 * @cur:  the current node in the traversal
6918
 *
6919
 * Traversal function for the "self" direction
6920
 * The self axis contains just the context node itself
6921
 *
6922
 * Returns the next element following that axis
6923
 */
6924
xmlNodePtr
6925
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6926
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6927
0
    if (cur == NULL)
6928
0
        return(ctxt->context->node);
6929
0
    return(NULL);
6930
0
}
6931
6932
/**
6933
 * xmlXPathNextChild:
6934
 * @ctxt:  the XPath Parser context
6935
 * @cur:  the current node in the traversal
6936
 *
6937
 * Traversal function for the "child" direction
6938
 * The child axis contains the children of the context node in document order.
6939
 *
6940
 * Returns the next element following that axis
6941
 */
6942
xmlNodePtr
6943
0
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6944
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6945
0
    if (cur == NULL) {
6946
0
  if (ctxt->context->node == NULL) return(NULL);
6947
0
  switch (ctxt->context->node->type) {
6948
0
            case XML_ELEMENT_NODE:
6949
0
            case XML_TEXT_NODE:
6950
0
            case XML_CDATA_SECTION_NODE:
6951
0
            case XML_ENTITY_REF_NODE:
6952
0
            case XML_ENTITY_NODE:
6953
0
            case XML_PI_NODE:
6954
0
            case XML_COMMENT_NODE:
6955
0
            case XML_NOTATION_NODE:
6956
0
            case XML_DTD_NODE:
6957
0
    return(ctxt->context->node->children);
6958
0
            case XML_DOCUMENT_NODE:
6959
0
            case XML_DOCUMENT_TYPE_NODE:
6960
0
            case XML_DOCUMENT_FRAG_NODE:
6961
0
            case XML_HTML_DOCUMENT_NODE:
6962
0
    return(((xmlDocPtr) ctxt->context->node)->children);
6963
0
      case XML_ELEMENT_DECL:
6964
0
      case XML_ATTRIBUTE_DECL:
6965
0
      case XML_ENTITY_DECL:
6966
0
            case XML_ATTRIBUTE_NODE:
6967
0
      case XML_NAMESPACE_DECL:
6968
0
      case XML_XINCLUDE_START:
6969
0
      case XML_XINCLUDE_END:
6970
0
    return(NULL);
6971
0
  }
6972
0
  return(NULL);
6973
0
    }
6974
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
6975
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
6976
0
  return(NULL);
6977
0
    return(cur->next);
6978
0
}
6979
6980
/**
6981
 * xmlXPathNextChildElement:
6982
 * @ctxt:  the XPath Parser context
6983
 * @cur:  the current node in the traversal
6984
 *
6985
 * Traversal function for the "child" direction and nodes of type element.
6986
 * The child axis contains the children of the context node in document order.
6987
 *
6988
 * Returns the next element following that axis
6989
 */
6990
static xmlNodePtr
6991
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6992
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6993
0
    if (cur == NULL) {
6994
0
  cur = ctxt->context->node;
6995
0
  if (cur == NULL) return(NULL);
6996
  /*
6997
  * Get the first element child.
6998
  */
6999
0
  switch (cur->type) {
7000
0
            case XML_ELEMENT_NODE:
7001
0
      case XML_DOCUMENT_FRAG_NODE:
7002
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7003
0
            case XML_ENTITY_NODE:
7004
0
    cur = cur->children;
7005
0
    if (cur != NULL) {
7006
0
        if (cur->type == XML_ELEMENT_NODE)
7007
0
      return(cur);
7008
0
        do {
7009
0
      cur = cur->next;
7010
0
        } while ((cur != NULL) &&
7011
0
      (cur->type != XML_ELEMENT_NODE));
7012
0
        return(cur);
7013
0
    }
7014
0
    return(NULL);
7015
0
            case XML_DOCUMENT_NODE:
7016
0
            case XML_HTML_DOCUMENT_NODE:
7017
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7018
0
      default:
7019
0
    return(NULL);
7020
0
  }
7021
0
  return(NULL);
7022
0
    }
7023
    /*
7024
    * Get the next sibling element node.
7025
    */
7026
0
    switch (cur->type) {
7027
0
  case XML_ELEMENT_NODE:
7028
0
  case XML_TEXT_NODE:
7029
0
  case XML_ENTITY_REF_NODE:
7030
0
  case XML_ENTITY_NODE:
7031
0
  case XML_CDATA_SECTION_NODE:
7032
0
  case XML_PI_NODE:
7033
0
  case XML_COMMENT_NODE:
7034
0
  case XML_XINCLUDE_END:
7035
0
      break;
7036
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7037
0
  default:
7038
0
      return(NULL);
7039
0
    }
7040
0
    if (cur->next != NULL) {
7041
0
  if (cur->next->type == XML_ELEMENT_NODE)
7042
0
      return(cur->next);
7043
0
  cur = cur->next;
7044
0
  do {
7045
0
      cur = cur->next;
7046
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7047
0
  return(cur);
7048
0
    }
7049
0
    return(NULL);
7050
0
}
7051
7052
#if 0
7053
/**
7054
 * xmlXPathNextDescendantOrSelfElemParent:
7055
 * @ctxt:  the XPath Parser context
7056
 * @cur:  the current node in the traversal
7057
 *
7058
 * Traversal function for the "descendant-or-self" axis.
7059
 * Additionally it returns only nodes which can be parents of
7060
 * element nodes.
7061
 *
7062
 *
7063
 * Returns the next element following that axis
7064
 */
7065
static xmlNodePtr
7066
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7067
               xmlNodePtr contextNode)
7068
{
7069
    if (cur == NULL) {
7070
  if (contextNode == NULL)
7071
      return(NULL);
7072
  switch (contextNode->type) {
7073
      case XML_ELEMENT_NODE:
7074
      case XML_XINCLUDE_START:
7075
      case XML_DOCUMENT_FRAG_NODE:
7076
      case XML_DOCUMENT_NODE:
7077
      case XML_HTML_DOCUMENT_NODE:
7078
    return(contextNode);
7079
      default:
7080
    return(NULL);
7081
  }
7082
  return(NULL);
7083
    } else {
7084
  xmlNodePtr start = cur;
7085
7086
  while (cur != NULL) {
7087
      switch (cur->type) {
7088
    case XML_ELEMENT_NODE:
7089
    /* TODO: OK to have XInclude here? */
7090
    case XML_XINCLUDE_START:
7091
    case XML_DOCUMENT_FRAG_NODE:
7092
        if (cur != start)
7093
      return(cur);
7094
        if (cur->children != NULL) {
7095
      cur = cur->children;
7096
      continue;
7097
        }
7098
        break;
7099
    /* Not sure if we need those here. */
7100
    case XML_DOCUMENT_NODE:
7101
    case XML_HTML_DOCUMENT_NODE:
7102
        if (cur != start)
7103
      return(cur);
7104
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7105
    default:
7106
        break;
7107
      }
7108
7109
next_sibling:
7110
      if ((cur == NULL) || (cur == contextNode))
7111
    return(NULL);
7112
      if (cur->next != NULL) {
7113
    cur = cur->next;
7114
      } else {
7115
    cur = cur->parent;
7116
    goto next_sibling;
7117
      }
7118
  }
7119
    }
7120
    return(NULL);
7121
}
7122
#endif
7123
7124
/**
7125
 * xmlXPathNextDescendant:
7126
 * @ctxt:  the XPath Parser context
7127
 * @cur:  the current node in the traversal
7128
 *
7129
 * Traversal function for the "descendant" direction
7130
 * the descendant axis contains the descendants of the context node in document
7131
 * order; a descendant is a child or a child of a child and so on.
7132
 *
7133
 * Returns the next element following that axis
7134
 */
7135
xmlNodePtr
7136
0
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7137
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7138
0
    if (cur == NULL) {
7139
0
  if (ctxt->context->node == NULL)
7140
0
      return(NULL);
7141
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7142
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7143
0
      return(NULL);
7144
7145
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7146
0
      return(ctxt->context->doc->children);
7147
0
        return(ctxt->context->node->children);
7148
0
    }
7149
7150
0
    if (cur->type == XML_NAMESPACE_DECL)
7151
0
        return(NULL);
7152
0
    if (cur->children != NULL) {
7153
  /*
7154
   * Do not descend on entities declarations
7155
   */
7156
0
  if (cur->children->type != XML_ENTITY_DECL) {
7157
0
      cur = cur->children;
7158
      /*
7159
       * Skip DTDs
7160
       */
7161
0
      if (cur->type != XML_DTD_NODE)
7162
0
    return(cur);
7163
0
  }
7164
0
    }
7165
7166
0
    if (cur == ctxt->context->node) return(NULL);
7167
7168
0
    while (cur->next != NULL) {
7169
0
  cur = cur->next;
7170
0
  if ((cur->type != XML_ENTITY_DECL) &&
7171
0
      (cur->type != XML_DTD_NODE))
7172
0
      return(cur);
7173
0
    }
7174
7175
0
    do {
7176
0
        cur = cur->parent;
7177
0
  if (cur == NULL) break;
7178
0
  if (cur == ctxt->context->node) return(NULL);
7179
0
  if (cur->next != NULL) {
7180
0
      cur = cur->next;
7181
0
      return(cur);
7182
0
  }
7183
0
    } while (cur != NULL);
7184
0
    return(cur);
7185
0
}
7186
7187
/**
7188
 * xmlXPathNextDescendantOrSelf:
7189
 * @ctxt:  the XPath Parser context
7190
 * @cur:  the current node in the traversal
7191
 *
7192
 * Traversal function for the "descendant-or-self" direction
7193
 * the descendant-or-self axis contains the context node and the descendants
7194
 * of the context node in document order; thus the context node is the first
7195
 * node on the axis, and the first child of the context node is the second node
7196
 * on the axis
7197
 *
7198
 * Returns the next element following that axis
7199
 */
7200
xmlNodePtr
7201
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7202
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7203
0
    if (cur == NULL)
7204
0
        return(ctxt->context->node);
7205
7206
0
    if (ctxt->context->node == NULL)
7207
0
        return(NULL);
7208
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7209
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7210
0
        return(NULL);
7211
7212
0
    return(xmlXPathNextDescendant(ctxt, cur));
7213
0
}
7214
7215
/**
7216
 * xmlXPathNextParent:
7217
 * @ctxt:  the XPath Parser context
7218
 * @cur:  the current node in the traversal
7219
 *
7220
 * Traversal function for the "parent" direction
7221
 * The parent axis contains the parent of the context node, if there is one.
7222
 *
7223
 * Returns the next element following that axis
7224
 */
7225
xmlNodePtr
7226
0
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7227
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7228
    /*
7229
     * the parent of an attribute or namespace node is the element
7230
     * to which the attribute or namespace node is attached
7231
     * Namespace handling !!!
7232
     */
7233
0
    if (cur == NULL) {
7234
0
  if (ctxt->context->node == NULL) return(NULL);
7235
0
  switch (ctxt->context->node->type) {
7236
0
            case XML_ELEMENT_NODE:
7237
0
            case XML_TEXT_NODE:
7238
0
            case XML_CDATA_SECTION_NODE:
7239
0
            case XML_ENTITY_REF_NODE:
7240
0
            case XML_ENTITY_NODE:
7241
0
            case XML_PI_NODE:
7242
0
            case XML_COMMENT_NODE:
7243
0
            case XML_NOTATION_NODE:
7244
0
            case XML_DTD_NODE:
7245
0
      case XML_ELEMENT_DECL:
7246
0
      case XML_ATTRIBUTE_DECL:
7247
0
      case XML_XINCLUDE_START:
7248
0
      case XML_XINCLUDE_END:
7249
0
      case XML_ENTITY_DECL:
7250
0
    if (ctxt->context->node->parent == NULL)
7251
0
        return((xmlNodePtr) ctxt->context->doc);
7252
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7253
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
7254
0
         (xmlStrEqual(ctxt->context->node->parent->name,
7255
0
         BAD_CAST "fake node libxslt"))))
7256
0
        return(NULL);
7257
0
    return(ctxt->context->node->parent);
7258
0
            case XML_ATTRIBUTE_NODE: {
7259
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7260
7261
0
    return(att->parent);
7262
0
      }
7263
0
            case XML_DOCUMENT_NODE:
7264
0
            case XML_DOCUMENT_TYPE_NODE:
7265
0
            case XML_DOCUMENT_FRAG_NODE:
7266
0
            case XML_HTML_DOCUMENT_NODE:
7267
0
                return(NULL);
7268
0
      case XML_NAMESPACE_DECL: {
7269
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7270
7271
0
    if ((ns->next != NULL) &&
7272
0
        (ns->next->type != XML_NAMESPACE_DECL))
7273
0
        return((xmlNodePtr) ns->next);
7274
0
                return(NULL);
7275
0
      }
7276
0
  }
7277
0
    }
7278
0
    return(NULL);
7279
0
}
7280
7281
/**
7282
 * xmlXPathNextAncestor:
7283
 * @ctxt:  the XPath Parser context
7284
 * @cur:  the current node in the traversal
7285
 *
7286
 * Traversal function for the "ancestor" direction
7287
 * the ancestor axis contains the ancestors of the context node; the ancestors
7288
 * of the context node consist of the parent of context node and the parent's
7289
 * parent and so on; the nodes are ordered in reverse document order; thus the
7290
 * parent is the first node on the axis, and the parent's parent is the second
7291
 * node on the axis
7292
 *
7293
 * Returns the next element following that axis
7294
 */
7295
xmlNodePtr
7296
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7297
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7298
    /*
7299
     * the parent of an attribute or namespace node is the element
7300
     * to which the attribute or namespace node is attached
7301
     * !!!!!!!!!!!!!
7302
     */
7303
0
    if (cur == NULL) {
7304
0
  if (ctxt->context->node == NULL) return(NULL);
7305
0
  switch (ctxt->context->node->type) {
7306
0
            case XML_ELEMENT_NODE:
7307
0
            case XML_TEXT_NODE:
7308
0
            case XML_CDATA_SECTION_NODE:
7309
0
            case XML_ENTITY_REF_NODE:
7310
0
            case XML_ENTITY_NODE:
7311
0
            case XML_PI_NODE:
7312
0
            case XML_COMMENT_NODE:
7313
0
      case XML_DTD_NODE:
7314
0
      case XML_ELEMENT_DECL:
7315
0
      case XML_ATTRIBUTE_DECL:
7316
0
      case XML_ENTITY_DECL:
7317
0
            case XML_NOTATION_NODE:
7318
0
      case XML_XINCLUDE_START:
7319
0
      case XML_XINCLUDE_END:
7320
0
    if (ctxt->context->node->parent == NULL)
7321
0
        return((xmlNodePtr) ctxt->context->doc);
7322
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7323
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
7324
0
         (xmlStrEqual(ctxt->context->node->parent->name,
7325
0
         BAD_CAST "fake node libxslt"))))
7326
0
        return(NULL);
7327
0
    return(ctxt->context->node->parent);
7328
0
            case XML_ATTRIBUTE_NODE: {
7329
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7330
7331
0
    return(tmp->parent);
7332
0
      }
7333
0
            case XML_DOCUMENT_NODE:
7334
0
            case XML_DOCUMENT_TYPE_NODE:
7335
0
            case XML_DOCUMENT_FRAG_NODE:
7336
0
            case XML_HTML_DOCUMENT_NODE:
7337
0
                return(NULL);
7338
0
      case XML_NAMESPACE_DECL: {
7339
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7340
7341
0
    if ((ns->next != NULL) &&
7342
0
        (ns->next->type != XML_NAMESPACE_DECL))
7343
0
        return((xmlNodePtr) ns->next);
7344
    /* Bad, how did that namespace end up here ? */
7345
0
                return(NULL);
7346
0
      }
7347
0
  }
7348
0
  return(NULL);
7349
0
    }
7350
0
    if (cur == ctxt->context->doc->children)
7351
0
  return((xmlNodePtr) ctxt->context->doc);
7352
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7353
0
  return(NULL);
7354
0
    switch (cur->type) {
7355
0
  case XML_ELEMENT_NODE:
7356
0
  case XML_TEXT_NODE:
7357
0
  case XML_CDATA_SECTION_NODE:
7358
0
  case XML_ENTITY_REF_NODE:
7359
0
  case XML_ENTITY_NODE:
7360
0
  case XML_PI_NODE:
7361
0
  case XML_COMMENT_NODE:
7362
0
  case XML_NOTATION_NODE:
7363
0
  case XML_DTD_NODE:
7364
0
        case XML_ELEMENT_DECL:
7365
0
        case XML_ATTRIBUTE_DECL:
7366
0
        case XML_ENTITY_DECL:
7367
0
  case XML_XINCLUDE_START:
7368
0
  case XML_XINCLUDE_END:
7369
0
      if (cur->parent == NULL)
7370
0
    return(NULL);
7371
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
7372
0
    ((cur->parent->name[0] == ' ') ||
7373
0
     (xmlStrEqual(cur->parent->name,
7374
0
            BAD_CAST "fake node libxslt"))))
7375
0
    return(NULL);
7376
0
      return(cur->parent);
7377
0
  case XML_ATTRIBUTE_NODE: {
7378
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
7379
7380
0
      return(att->parent);
7381
0
  }
7382
0
  case XML_NAMESPACE_DECL: {
7383
0
      xmlNsPtr ns = (xmlNsPtr) cur;
7384
7385
0
      if ((ns->next != NULL) &&
7386
0
          (ns->next->type != XML_NAMESPACE_DECL))
7387
0
          return((xmlNodePtr) ns->next);
7388
      /* Bad, how did that namespace end up here ? */
7389
0
            return(NULL);
7390
0
  }
7391
0
  case XML_DOCUMENT_NODE:
7392
0
  case XML_DOCUMENT_TYPE_NODE:
7393
0
  case XML_DOCUMENT_FRAG_NODE:
7394
0
  case XML_HTML_DOCUMENT_NODE:
7395
0
      return(NULL);
7396
0
    }
7397
0
    return(NULL);
7398
0
}
7399
7400
/**
7401
 * xmlXPathNextAncestorOrSelf:
7402
 * @ctxt:  the XPath Parser context
7403
 * @cur:  the current node in the traversal
7404
 *
7405
 * Traversal function for the "ancestor-or-self" direction
7406
 * he ancestor-or-self axis contains the context node and ancestors of
7407
 * the context node in reverse document order; thus the context node is
7408
 * the first node on the axis, and the context node's parent the second;
7409
 * parent here is defined the same as with the parent axis.
7410
 *
7411
 * Returns the next element following that axis
7412
 */
7413
xmlNodePtr
7414
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7415
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7416
0
    if (cur == NULL)
7417
0
        return(ctxt->context->node);
7418
0
    return(xmlXPathNextAncestor(ctxt, cur));
7419
0
}
7420
7421
/**
7422
 * xmlXPathNextFollowingSibling:
7423
 * @ctxt:  the XPath Parser context
7424
 * @cur:  the current node in the traversal
7425
 *
7426
 * Traversal function for the "following-sibling" direction
7427
 * The following-sibling axis contains the following siblings of the context
7428
 * node in document order.
7429
 *
7430
 * Returns the next element following that axis
7431
 */
7432
xmlNodePtr
7433
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7434
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7435
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7436
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
7437
0
  return(NULL);
7438
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7439
0
        return(NULL);
7440
0
    if (cur == NULL)
7441
0
        return(ctxt->context->node->next);
7442
0
    return(cur->next);
7443
0
}
7444
7445
/**
7446
 * xmlXPathNextPrecedingSibling:
7447
 * @ctxt:  the XPath Parser context
7448
 * @cur:  the current node in the traversal
7449
 *
7450
 * Traversal function for the "preceding-sibling" direction
7451
 * The preceding-sibling axis contains the preceding siblings of the context
7452
 * node in reverse document order; the first preceding sibling is first on the
7453
 * axis; the sibling preceding that node is the second on the axis and so on.
7454
 *
7455
 * Returns the next element following that axis
7456
 */
7457
xmlNodePtr
7458
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7459
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7460
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7461
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
7462
0
  return(NULL);
7463
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
7464
0
        return(NULL);
7465
0
    if (cur == NULL)
7466
0
        return(ctxt->context->node->prev);
7467
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7468
0
  cur = cur->prev;
7469
0
  if (cur == NULL)
7470
0
      return(ctxt->context->node->prev);
7471
0
    }
7472
0
    return(cur->prev);
7473
0
}
7474
7475
/**
7476
 * xmlXPathNextFollowing:
7477
 * @ctxt:  the XPath Parser context
7478
 * @cur:  the current node in the traversal
7479
 *
7480
 * Traversal function for the "following" direction
7481
 * The following axis contains all nodes in the same document as the context
7482
 * node that are after the context node in document order, excluding any
7483
 * descendants and excluding attribute nodes and namespace nodes; the nodes
7484
 * are ordered in document order
7485
 *
7486
 * Returns the next element following that axis
7487
 */
7488
xmlNodePtr
7489
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7490
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7491
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
7492
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7493
0
        return(cur->children);
7494
7495
0
    if (cur == NULL) {
7496
0
        cur = ctxt->context->node;
7497
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7498
0
            cur = cur->parent;
7499
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7500
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7501
7502
0
            if ((ns->next == NULL) ||
7503
0
                (ns->next->type == XML_NAMESPACE_DECL))
7504
0
                return (NULL);
7505
0
            cur = (xmlNodePtr) ns->next;
7506
0
        }
7507
0
    }
7508
0
    if (cur == NULL) return(NULL) ; /* ERROR */
7509
0
    if (cur->next != NULL) return(cur->next) ;
7510
0
    do {
7511
0
        cur = cur->parent;
7512
0
        if (cur == NULL) break;
7513
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7514
0
        if (cur->next != NULL) return(cur->next);
7515
0
    } while (cur != NULL);
7516
0
    return(cur);
7517
0
}
7518
7519
/*
7520
 * xmlXPathIsAncestor:
7521
 * @ancestor:  the ancestor node
7522
 * @node:  the current node
7523
 *
7524
 * Check that @ancestor is a @node's ancestor
7525
 *
7526
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7527
 */
7528
static int
7529
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7530
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
7531
0
    if (node->type == XML_NAMESPACE_DECL)
7532
0
        return(0);
7533
0
    if (ancestor->type == XML_NAMESPACE_DECL)
7534
0
        return(0);
7535
    /* nodes need to be in the same document */
7536
0
    if (ancestor->doc != node->doc) return(0);
7537
    /* avoid searching if ancestor or node is the root node */
7538
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
7539
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
7540
0
    while (node->parent != NULL) {
7541
0
        if (node->parent == ancestor)
7542
0
            return(1);
7543
0
  node = node->parent;
7544
0
    }
7545
0
    return(0);
7546
0
}
7547
7548
/**
7549
 * xmlXPathNextPreceding:
7550
 * @ctxt:  the XPath Parser context
7551
 * @cur:  the current node in the traversal
7552
 *
7553
 * Traversal function for the "preceding" direction
7554
 * the preceding axis contains all nodes in the same document as the context
7555
 * node that are before the context node in document order, excluding any
7556
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7557
 * ordered in reverse document order
7558
 *
7559
 * Returns the next element following that axis
7560
 */
7561
xmlNodePtr
7562
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7563
0
{
7564
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7565
0
    if (cur == NULL) {
7566
0
        cur = ctxt->context->node;
7567
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7568
0
            cur = cur->parent;
7569
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7570
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7571
7572
0
            if ((ns->next == NULL) ||
7573
0
                (ns->next->type == XML_NAMESPACE_DECL))
7574
0
                return (NULL);
7575
0
            cur = (xmlNodePtr) ns->next;
7576
0
        }
7577
0
    }
7578
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7579
0
  return (NULL);
7580
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7581
0
  cur = cur->prev;
7582
0
    do {
7583
0
        if (cur->prev != NULL) {
7584
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7585
0
            return (cur);
7586
0
        }
7587
7588
0
        cur = cur->parent;
7589
0
        if (cur == NULL)
7590
0
            return (NULL);
7591
0
        if (cur == ctxt->context->doc->children)
7592
0
            return (NULL);
7593
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
7594
0
    return (cur);
7595
0
}
7596
7597
/**
7598
 * xmlXPathNextPrecedingInternal:
7599
 * @ctxt:  the XPath Parser context
7600
 * @cur:  the current node in the traversal
7601
 *
7602
 * Traversal function for the "preceding" direction
7603
 * the preceding axis contains all nodes in the same document as the context
7604
 * node that are before the context node in document order, excluding any
7605
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
7606
 * ordered in reverse document order
7607
 * This is a faster implementation but internal only since it requires a
7608
 * state kept in the parser context: ctxt->ancestor.
7609
 *
7610
 * Returns the next element following that axis
7611
 */
7612
static xmlNodePtr
7613
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7614
                              xmlNodePtr cur)
7615
0
{
7616
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7617
0
    if (cur == NULL) {
7618
0
        cur = ctxt->context->node;
7619
0
        if (cur == NULL)
7620
0
            return (NULL);
7621
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
7622
0
            cur = cur->parent;
7623
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
7624
0
            xmlNsPtr ns = (xmlNsPtr) cur;
7625
7626
0
            if ((ns->next == NULL) ||
7627
0
                (ns->next->type == XML_NAMESPACE_DECL))
7628
0
                return (NULL);
7629
0
            cur = (xmlNodePtr) ns->next;
7630
0
        }
7631
0
        ctxt->ancestor = cur->parent;
7632
0
    }
7633
0
    if (cur->type == XML_NAMESPACE_DECL)
7634
0
        return(NULL);
7635
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7636
0
  cur = cur->prev;
7637
0
    while (cur->prev == NULL) {
7638
0
        cur = cur->parent;
7639
0
        if (cur == NULL)
7640
0
            return (NULL);
7641
0
        if (cur == ctxt->context->doc->children)
7642
0
            return (NULL);
7643
0
        if (cur != ctxt->ancestor)
7644
0
            return (cur);
7645
0
        ctxt->ancestor = cur->parent;
7646
0
    }
7647
0
    cur = cur->prev;
7648
0
    while (cur->last != NULL)
7649
0
        cur = cur->last;
7650
0
    return (cur);
7651
0
}
7652
7653
/**
7654
 * xmlXPathNextNamespace:
7655
 * @ctxt:  the XPath Parser context
7656
 * @cur:  the current attribute in the traversal
7657
 *
7658
 * Traversal function for the "namespace" direction
7659
 * the namespace axis contains the namespace nodes of the context node;
7660
 * the order of nodes on this axis is implementation-defined; the axis will
7661
 * be empty unless the context node is an element
7662
 *
7663
 * We keep the XML namespace node at the end of the list.
7664
 *
7665
 * Returns the next element following that axis
7666
 */
7667
xmlNodePtr
7668
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7669
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7670
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7671
0
    if (cur == NULL) {
7672
0
        if (ctxt->context->tmpNsList != NULL)
7673
0
      xmlFree(ctxt->context->tmpNsList);
7674
0
  ctxt->context->tmpNsList =
7675
0
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
7676
0
  ctxt->context->tmpNsNr = 0;
7677
0
  if (ctxt->context->tmpNsList != NULL) {
7678
0
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7679
0
    ctxt->context->tmpNsNr++;
7680
0
      }
7681
0
  }
7682
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
7683
0
    }
7684
0
    if (ctxt->context->tmpNsNr > 0) {
7685
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7686
0
    } else {
7687
0
  if (ctxt->context->tmpNsList != NULL)
7688
0
      xmlFree(ctxt->context->tmpNsList);
7689
0
  ctxt->context->tmpNsList = NULL;
7690
0
  return(NULL);
7691
0
    }
7692
0
}
7693
7694
/**
7695
 * xmlXPathNextAttribute:
7696
 * @ctxt:  the XPath Parser context
7697
 * @cur:  the current attribute in the traversal
7698
 *
7699
 * Traversal function for the "attribute" direction
7700
 * TODO: support DTD inherited default attributes
7701
 *
7702
 * Returns the next element following that axis
7703
 */
7704
xmlNodePtr
7705
0
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7706
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7707
0
    if (ctxt->context->node == NULL)
7708
0
  return(NULL);
7709
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
7710
0
  return(NULL);
7711
0
    if (cur == NULL) {
7712
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7713
0
      return(NULL);
7714
0
        return((xmlNodePtr)ctxt->context->node->properties);
7715
0
    }
7716
0
    return((xmlNodePtr)cur->next);
7717
0
}
7718
7719
/************************************************************************
7720
 *                  *
7721
 *    NodeTest Functions          *
7722
 *                  *
7723
 ************************************************************************/
7724
7725
#define IS_FUNCTION     200
7726
7727
7728
/************************************************************************
7729
 *                  *
7730
 *    Implicit tree core function library     *
7731
 *                  *
7732
 ************************************************************************/
7733
7734
/**
7735
 * xmlXPathRoot:
7736
 * @ctxt:  the XPath Parser context
7737
 *
7738
 * Initialize the context to the root of the document
7739
 */
7740
void
7741
0
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7742
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
7743
0
  return;
7744
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7745
0
  (xmlNodePtr) ctxt->context->doc));
7746
0
}
7747
7748
/************************************************************************
7749
 *                  *
7750
 *    The explicit core function library      *
7751
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7752
 *                  *
7753
 ************************************************************************/
7754
7755
7756
/**
7757
 * xmlXPathLastFunction:
7758
 * @ctxt:  the XPath Parser context
7759
 * @nargs:  the number of arguments
7760
 *
7761
 * Implement the last() XPath function
7762
 *    number last()
7763
 * The last function returns the number of nodes in the context node list.
7764
 */
7765
void
7766
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7767
0
    CHECK_ARITY(0);
7768
0
    if (ctxt->context->contextSize >= 0) {
7769
0
  valuePush(ctxt,
7770
0
      xmlXPathCacheNewFloat(ctxt->context,
7771
0
    (double) ctxt->context->contextSize));
7772
0
    } else {
7773
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7774
0
    }
7775
0
}
7776
7777
/**
7778
 * xmlXPathPositionFunction:
7779
 * @ctxt:  the XPath Parser context
7780
 * @nargs:  the number of arguments
7781
 *
7782
 * Implement the position() XPath function
7783
 *    number position()
7784
 * The position function returns the position of the context node in the
7785
 * context node list. The first position is 1, and so the last position
7786
 * will be equal to last().
7787
 */
7788
void
7789
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7790
0
    CHECK_ARITY(0);
7791
0
    if (ctxt->context->proximityPosition >= 0) {
7792
0
  valuePush(ctxt,
7793
0
        xmlXPathCacheNewFloat(ctxt->context,
7794
0
    (double) ctxt->context->proximityPosition));
7795
0
    } else {
7796
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7797
0
    }
7798
0
}
7799
7800
/**
7801
 * xmlXPathCountFunction:
7802
 * @ctxt:  the XPath Parser context
7803
 * @nargs:  the number of arguments
7804
 *
7805
 * Implement the count() XPath function
7806
 *    number count(node-set)
7807
 */
7808
void
7809
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7810
0
    xmlXPathObjectPtr cur;
7811
7812
0
    CHECK_ARITY(1);
7813
0
    if ((ctxt->value == NULL) ||
7814
0
  ((ctxt->value->type != XPATH_NODESET) &&
7815
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7816
0
  XP_ERROR(XPATH_INVALID_TYPE);
7817
0
    cur = valuePop(ctxt);
7818
7819
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
7820
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
7821
0
    else
7822
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
7823
0
      (double) cur->nodesetval->nodeNr));
7824
0
    xmlXPathReleaseObject(ctxt->context, cur);
7825
0
}
7826
7827
/**
7828
 * xmlXPathGetElementsByIds:
7829
 * @doc:  the document
7830
 * @ids:  a whitespace separated list of IDs
7831
 *
7832
 * Selects elements by their unique ID.
7833
 *
7834
 * Returns a node-set of selected elements.
7835
 */
7836
static xmlNodeSetPtr
7837
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7838
0
    xmlNodeSetPtr ret;
7839
0
    const xmlChar *cur = ids;
7840
0
    xmlChar *ID;
7841
0
    xmlAttrPtr attr;
7842
0
    xmlNodePtr elem = NULL;
7843
7844
0
    if (ids == NULL) return(NULL);
7845
7846
0
    ret = xmlXPathNodeSetCreate(NULL);
7847
0
    if (ret == NULL)
7848
0
        return(ret);
7849
7850
0
    while (IS_BLANK_CH(*cur)) cur++;
7851
0
    while (*cur != 0) {
7852
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7853
0
      cur++;
7854
7855
0
        ID = xmlStrndup(ids, cur - ids);
7856
0
  if (ID != NULL) {
7857
      /*
7858
       * We used to check the fact that the value passed
7859
       * was an NCName, but this generated much troubles for
7860
       * me and Aleksey Sanin, people blatantly violated that
7861
       * constraint, like Visa3D spec.
7862
       * if (xmlValidateNCName(ID, 1) == 0)
7863
       */
7864
0
      attr = xmlGetID(doc, ID);
7865
0
      if (attr != NULL) {
7866
0
    if (attr->type == XML_ATTRIBUTE_NODE)
7867
0
        elem = attr->parent;
7868
0
    else if (attr->type == XML_ELEMENT_NODE)
7869
0
        elem = (xmlNodePtr) attr;
7870
0
    else
7871
0
        elem = NULL;
7872
                /* TODO: Check memory error. */
7873
0
    if (elem != NULL)
7874
0
        xmlXPathNodeSetAdd(ret, elem);
7875
0
      }
7876
0
      xmlFree(ID);
7877
0
  }
7878
7879
0
  while (IS_BLANK_CH(*cur)) cur++;
7880
0
  ids = cur;
7881
0
    }
7882
0
    return(ret);
7883
0
}
7884
7885
/**
7886
 * xmlXPathIdFunction:
7887
 * @ctxt:  the XPath Parser context
7888
 * @nargs:  the number of arguments
7889
 *
7890
 * Implement the id() XPath function
7891
 *    node-set id(object)
7892
 * The id function selects elements by their unique ID
7893
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7894
 * then the result is the union of the result of applying id to the
7895
 * string value of each of the nodes in the argument node-set. When the
7896
 * argument to id is of any other type, the argument is converted to a
7897
 * string as if by a call to the string function; the string is split
7898
 * into a whitespace-separated list of tokens (whitespace is any sequence
7899
 * of characters matching the production S); the result is a node-set
7900
 * containing the elements in the same document as the context node that
7901
 * have a unique ID equal to any of the tokens in the list.
7902
 */
7903
void
7904
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7905
0
    xmlChar *tokens;
7906
0
    xmlNodeSetPtr ret;
7907
0
    xmlXPathObjectPtr obj;
7908
7909
0
    CHECK_ARITY(1);
7910
0
    obj = valuePop(ctxt);
7911
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7912
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7913
0
  xmlNodeSetPtr ns;
7914
0
  int i;
7915
7916
        /* TODO: Check memory error. */
7917
0
  ret = xmlXPathNodeSetCreate(NULL);
7918
7919
0
  if (obj->nodesetval != NULL) {
7920
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7921
0
    tokens =
7922
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7923
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7924
                /* TODO: Check memory error. */
7925
0
    ret = xmlXPathNodeSetMerge(ret, ns);
7926
0
    xmlXPathFreeNodeSet(ns);
7927
0
    if (tokens != NULL)
7928
0
        xmlFree(tokens);
7929
0
      }
7930
0
  }
7931
0
  xmlXPathReleaseObject(ctxt->context, obj);
7932
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
7933
0
  return;
7934
0
    }
7935
0
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
7936
0
    if (obj == NULL) return;
7937
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
7938
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
7939
0
    xmlXPathReleaseObject(ctxt->context, obj);
7940
0
    return;
7941
0
}
7942
7943
/**
7944
 * xmlXPathLocalNameFunction:
7945
 * @ctxt:  the XPath Parser context
7946
 * @nargs:  the number of arguments
7947
 *
7948
 * Implement the local-name() XPath function
7949
 *    string local-name(node-set?)
7950
 * The local-name function returns a string containing the local part
7951
 * of the name of the node in the argument node-set that is first in
7952
 * document order. If the node-set is empty or the first node has no
7953
 * name, an empty string is returned. If the argument is omitted it
7954
 * defaults to the context node.
7955
 */
7956
void
7957
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7958
0
    xmlXPathObjectPtr cur;
7959
7960
0
    if (ctxt == NULL) return;
7961
7962
0
    if (nargs == 0) {
7963
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7964
0
      ctxt->context->node));
7965
0
  nargs = 1;
7966
0
    }
7967
7968
0
    CHECK_ARITY(1);
7969
0
    if ((ctxt->value == NULL) ||
7970
0
  ((ctxt->value->type != XPATH_NODESET) &&
7971
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7972
0
  XP_ERROR(XPATH_INVALID_TYPE);
7973
0
    cur = valuePop(ctxt);
7974
7975
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7976
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7977
0
    } else {
7978
0
  int i = 0; /* Should be first in document order !!!!! */
7979
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7980
0
  case XML_ELEMENT_NODE:
7981
0
  case XML_ATTRIBUTE_NODE:
7982
0
  case XML_PI_NODE:
7983
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7984
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7985
0
      else
7986
0
    valuePush(ctxt,
7987
0
          xmlXPathCacheNewString(ctxt->context,
7988
0
      cur->nodesetval->nodeTab[i]->name));
7989
0
      break;
7990
0
  case XML_NAMESPACE_DECL:
7991
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
7992
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7993
0
      break;
7994
0
  default:
7995
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7996
0
  }
7997
0
    }
7998
0
    xmlXPathReleaseObject(ctxt->context, cur);
7999
0
}
8000
8001
/**
8002
 * xmlXPathNamespaceURIFunction:
8003
 * @ctxt:  the XPath Parser context
8004
 * @nargs:  the number of arguments
8005
 *
8006
 * Implement the namespace-uri() XPath function
8007
 *    string namespace-uri(node-set?)
8008
 * The namespace-uri function returns a string containing the
8009
 * namespace URI of the expanded name of the node in the argument
8010
 * node-set that is first in document order. If the node-set is empty,
8011
 * the first node has no name, or the expanded name has no namespace
8012
 * URI, an empty string is returned. If the argument is omitted it
8013
 * defaults to the context node.
8014
 */
8015
void
8016
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8017
0
    xmlXPathObjectPtr cur;
8018
8019
0
    if (ctxt == NULL) return;
8020
8021
0
    if (nargs == 0) {
8022
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8023
0
      ctxt->context->node));
8024
0
  nargs = 1;
8025
0
    }
8026
0
    CHECK_ARITY(1);
8027
0
    if ((ctxt->value == NULL) ||
8028
0
  ((ctxt->value->type != XPATH_NODESET) &&
8029
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8030
0
  XP_ERROR(XPATH_INVALID_TYPE);
8031
0
    cur = valuePop(ctxt);
8032
8033
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8034
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8035
0
    } else {
8036
0
  int i = 0; /* Should be first in document order !!!!! */
8037
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8038
0
  case XML_ELEMENT_NODE:
8039
0
  case XML_ATTRIBUTE_NODE:
8040
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8041
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8042
0
      else
8043
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8044
0
        cur->nodesetval->nodeTab[i]->ns->href));
8045
0
      break;
8046
0
  default:
8047
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8048
0
  }
8049
0
    }
8050
0
    xmlXPathReleaseObject(ctxt->context, cur);
8051
0
}
8052
8053
/**
8054
 * xmlXPathNameFunction:
8055
 * @ctxt:  the XPath Parser context
8056
 * @nargs:  the number of arguments
8057
 *
8058
 * Implement the name() XPath function
8059
 *    string name(node-set?)
8060
 * The name function returns a string containing a QName representing
8061
 * the name of the node in the argument node-set that is first in document
8062
 * order. The QName must represent the name with respect to the namespace
8063
 * declarations in effect on the node whose name is being represented.
8064
 * Typically, this will be the form in which the name occurred in the XML
8065
 * source. This need not be the case if there are namespace declarations
8066
 * in effect on the node that associate multiple prefixes with the same
8067
 * namespace. However, an implementation may include information about
8068
 * the original prefix in its representation of nodes; in this case, an
8069
 * implementation can ensure that the returned string is always the same
8070
 * as the QName used in the XML source. If the argument it omitted it
8071
 * defaults to the context node.
8072
 * Libxml keep the original prefix so the "real qualified name" used is
8073
 * returned.
8074
 */
8075
static void
8076
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8077
0
{
8078
0
    xmlXPathObjectPtr cur;
8079
8080
0
    if (nargs == 0) {
8081
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8082
0
      ctxt->context->node));
8083
0
        nargs = 1;
8084
0
    }
8085
8086
0
    CHECK_ARITY(1);
8087
0
    if ((ctxt->value == NULL) ||
8088
0
        ((ctxt->value->type != XPATH_NODESET) &&
8089
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
8090
0
        XP_ERROR(XPATH_INVALID_TYPE);
8091
0
    cur = valuePop(ctxt);
8092
8093
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8094
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8095
0
    } else {
8096
0
        int i = 0;              /* Should be first in document order !!!!! */
8097
8098
0
        switch (cur->nodesetval->nodeTab[i]->type) {
8099
0
            case XML_ELEMENT_NODE:
8100
0
            case XML_ATTRIBUTE_NODE:
8101
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8102
0
        valuePush(ctxt,
8103
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8104
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8105
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8106
0
        valuePush(ctxt,
8107
0
            xmlXPathCacheNewString(ctxt->context,
8108
0
          cur->nodesetval->nodeTab[i]->name));
8109
0
    } else {
8110
0
        xmlChar *fullname;
8111
8112
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8113
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8114
0
             NULL, 0);
8115
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8116
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8117
0
        if (fullname == NULL)
8118
0
                        xmlXPathPErrMemory(ctxt, NULL);
8119
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8120
0
      ctxt->context, fullname));
8121
0
                }
8122
0
                break;
8123
0
            default:
8124
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8125
0
        cur->nodesetval->nodeTab[i]));
8126
0
                xmlXPathLocalNameFunction(ctxt, 1);
8127
0
        }
8128
0
    }
8129
0
    xmlXPathReleaseObject(ctxt->context, cur);
8130
0
}
8131
8132
8133
/**
8134
 * xmlXPathStringFunction:
8135
 * @ctxt:  the XPath Parser context
8136
 * @nargs:  the number of arguments
8137
 *
8138
 * Implement the string() XPath function
8139
 *    string string(object?)
8140
 * The string function converts an object to a string as follows:
8141
 *    - A node-set is converted to a string by returning the value of
8142
 *      the node in the node-set that is first in document order.
8143
 *      If the node-set is empty, an empty string is returned.
8144
 *    - A number is converted to a string as follows
8145
 *      + NaN is converted to the string NaN
8146
 *      + positive zero is converted to the string 0
8147
 *      + negative zero is converted to the string 0
8148
 *      + positive infinity is converted to the string Infinity
8149
 *      + negative infinity is converted to the string -Infinity
8150
 *      + if the number is an integer, the number is represented in
8151
 *        decimal form as a Number with no decimal point and no leading
8152
 *        zeros, preceded by a minus sign (-) if the number is negative
8153
 *      + otherwise, the number is represented in decimal form as a
8154
 *        Number including a decimal point with at least one digit
8155
 *        before the decimal point and at least one digit after the
8156
 *        decimal point, preceded by a minus sign (-) if the number
8157
 *        is negative; there must be no leading zeros before the decimal
8158
 *        point apart possibly from the one required digit immediately
8159
 *        before the decimal point; beyond the one required digit
8160
 *        after the decimal point there must be as many, but only as
8161
 *        many, more digits as are needed to uniquely distinguish the
8162
 *        number from all other IEEE 754 numeric values.
8163
 *    - The boolean false value is converted to the string false.
8164
 *      The boolean true value is converted to the string true.
8165
 *
8166
 * If the argument is omitted, it defaults to a node-set with the
8167
 * context node as its only member.
8168
 */
8169
void
8170
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8171
0
    xmlXPathObjectPtr cur;
8172
8173
0
    if (ctxt == NULL) return;
8174
0
    if (nargs == 0) {
8175
0
    valuePush(ctxt,
8176
0
  xmlXPathCacheWrapString(ctxt->context,
8177
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8178
0
  return;
8179
0
    }
8180
8181
0
    CHECK_ARITY(1);
8182
0
    cur = valuePop(ctxt);
8183
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8184
0
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8185
0
}
8186
8187
/**
8188
 * xmlXPathStringLengthFunction:
8189
 * @ctxt:  the XPath Parser context
8190
 * @nargs:  the number of arguments
8191
 *
8192
 * Implement the string-length() XPath function
8193
 *    number string-length(string?)
8194
 * The string-length returns the number of characters in the string
8195
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8196
 * the context node converted to a string, in other words the value
8197
 * of the context node.
8198
 */
8199
void
8200
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8201
0
    xmlXPathObjectPtr cur;
8202
8203
0
    if (nargs == 0) {
8204
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8205
0
      return;
8206
0
  if (ctxt->context->node == NULL) {
8207
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8208
0
  } else {
8209
0
      xmlChar *content;
8210
8211
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8212
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8213
0
    xmlUTF8Strlen(content)));
8214
0
      xmlFree(content);
8215
0
  }
8216
0
  return;
8217
0
    }
8218
0
    CHECK_ARITY(1);
8219
0
    CAST_TO_STRING;
8220
0
    CHECK_TYPE(XPATH_STRING);
8221
0
    cur = valuePop(ctxt);
8222
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8223
0
  xmlUTF8Strlen(cur->stringval)));
8224
0
    xmlXPathReleaseObject(ctxt->context, cur);
8225
0
}
8226
8227
/**
8228
 * xmlXPathConcatFunction:
8229
 * @ctxt:  the XPath Parser context
8230
 * @nargs:  the number of arguments
8231
 *
8232
 * Implement the concat() XPath function
8233
 *    string concat(string, string, string*)
8234
 * The concat function returns the concatenation of its arguments.
8235
 */
8236
void
8237
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8238
0
    xmlXPathObjectPtr cur, newobj;
8239
0
    xmlChar *tmp;
8240
8241
0
    if (ctxt == NULL) return;
8242
0
    if (nargs < 2) {
8243
0
  CHECK_ARITY(2);
8244
0
    }
8245
8246
0
    CAST_TO_STRING;
8247
0
    cur = valuePop(ctxt);
8248
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8249
0
  xmlXPathReleaseObject(ctxt->context, cur);
8250
0
  return;
8251
0
    }
8252
0
    nargs--;
8253
8254
0
    while (nargs > 0) {
8255
0
  CAST_TO_STRING;
8256
0
  newobj = valuePop(ctxt);
8257
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8258
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8259
0
      xmlXPathReleaseObject(ctxt->context, cur);
8260
0
      XP_ERROR(XPATH_INVALID_TYPE);
8261
0
  }
8262
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8263
0
  newobj->stringval = cur->stringval;
8264
0
  cur->stringval = tmp;
8265
0
  xmlXPathReleaseObject(ctxt->context, newobj);
8266
0
  nargs--;
8267
0
    }
8268
0
    valuePush(ctxt, cur);
8269
0
}
8270
8271
/**
8272
 * xmlXPathContainsFunction:
8273
 * @ctxt:  the XPath Parser context
8274
 * @nargs:  the number of arguments
8275
 *
8276
 * Implement the contains() XPath function
8277
 *    boolean contains(string, string)
8278
 * The contains function returns true if the first argument string
8279
 * contains the second argument string, and otherwise returns false.
8280
 */
8281
void
8282
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8283
0
    xmlXPathObjectPtr hay, needle;
8284
8285
0
    CHECK_ARITY(2);
8286
0
    CAST_TO_STRING;
8287
0
    CHECK_TYPE(XPATH_STRING);
8288
0
    needle = valuePop(ctxt);
8289
0
    CAST_TO_STRING;
8290
0
    hay = valuePop(ctxt);
8291
8292
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8293
0
  xmlXPathReleaseObject(ctxt->context, hay);
8294
0
  xmlXPathReleaseObject(ctxt->context, needle);
8295
0
  XP_ERROR(XPATH_INVALID_TYPE);
8296
0
    }
8297
0
    if (xmlStrstr(hay->stringval, needle->stringval))
8298
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8299
0
    else
8300
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8301
0
    xmlXPathReleaseObject(ctxt->context, hay);
8302
0
    xmlXPathReleaseObject(ctxt->context, needle);
8303
0
}
8304
8305
/**
8306
 * xmlXPathStartsWithFunction:
8307
 * @ctxt:  the XPath Parser context
8308
 * @nargs:  the number of arguments
8309
 *
8310
 * Implement the starts-with() XPath function
8311
 *    boolean starts-with(string, string)
8312
 * The starts-with function returns true if the first argument string
8313
 * starts with the second argument string, and otherwise returns false.
8314
 */
8315
void
8316
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8317
0
    xmlXPathObjectPtr hay, needle;
8318
0
    int n;
8319
8320
0
    CHECK_ARITY(2);
8321
0
    CAST_TO_STRING;
8322
0
    CHECK_TYPE(XPATH_STRING);
8323
0
    needle = valuePop(ctxt);
8324
0
    CAST_TO_STRING;
8325
0
    hay = valuePop(ctxt);
8326
8327
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8328
0
  xmlXPathReleaseObject(ctxt->context, hay);
8329
0
  xmlXPathReleaseObject(ctxt->context, needle);
8330
0
  XP_ERROR(XPATH_INVALID_TYPE);
8331
0
    }
8332
0
    n = xmlStrlen(needle->stringval);
8333
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
8334
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8335
0
    else
8336
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8337
0
    xmlXPathReleaseObject(ctxt->context, hay);
8338
0
    xmlXPathReleaseObject(ctxt->context, needle);
8339
0
}
8340
8341
/**
8342
 * xmlXPathSubstringFunction:
8343
 * @ctxt:  the XPath Parser context
8344
 * @nargs:  the number of arguments
8345
 *
8346
 * Implement the substring() XPath function
8347
 *    string substring(string, number, number?)
8348
 * The substring function returns the substring of the first argument
8349
 * starting at the position specified in the second argument with
8350
 * length specified in the third argument. For example,
8351
 * substring("12345",2,3) returns "234". If the third argument is not
8352
 * specified, it returns the substring starting at the position specified
8353
 * in the second argument and continuing to the end of the string. For
8354
 * example, substring("12345",2) returns "2345".  More precisely, each
8355
 * character in the string (see [3.6 Strings]) is considered to have a
8356
 * numeric position: the position of the first character is 1, the position
8357
 * of the second character is 2 and so on. The returned substring contains
8358
 * those characters for which the position of the character is greater than
8359
 * or equal to the second argument and, if the third argument is specified,
8360
 * less than the sum of the second and third arguments; the comparisons
8361
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8362
 *  - substring("12345", 1.5, 2.6) returns "234"
8363
 *  - substring("12345", 0, 3) returns "12"
8364
 *  - substring("12345", 0 div 0, 3) returns ""
8365
 *  - substring("12345", 1, 0 div 0) returns ""
8366
 *  - substring("12345", -42, 1 div 0) returns "12345"
8367
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
8368
 */
8369
void
8370
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8371
0
    xmlXPathObjectPtr str, start, len;
8372
0
    double le=0, in;
8373
0
    int i = 1, j = INT_MAX;
8374
8375
0
    if (nargs < 2) {
8376
0
  CHECK_ARITY(2);
8377
0
    }
8378
0
    if (nargs > 3) {
8379
0
  CHECK_ARITY(3);
8380
0
    }
8381
    /*
8382
     * take care of possible last (position) argument
8383
    */
8384
0
    if (nargs == 3) {
8385
0
  CAST_TO_NUMBER;
8386
0
  CHECK_TYPE(XPATH_NUMBER);
8387
0
  len = valuePop(ctxt);
8388
0
  le = len->floatval;
8389
0
  xmlXPathReleaseObject(ctxt->context, len);
8390
0
    }
8391
8392
0
    CAST_TO_NUMBER;
8393
0
    CHECK_TYPE(XPATH_NUMBER);
8394
0
    start = valuePop(ctxt);
8395
0
    in = start->floatval;
8396
0
    xmlXPathReleaseObject(ctxt->context, start);
8397
0
    CAST_TO_STRING;
8398
0
    CHECK_TYPE(XPATH_STRING);
8399
0
    str = valuePop(ctxt);
8400
8401
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8402
0
        i = INT_MAX;
8403
0
    } else if (in >= 1.0) {
8404
0
        i = (int)in;
8405
0
        if (in - floor(in) >= 0.5)
8406
0
            i += 1;
8407
0
    }
8408
8409
0
    if (nargs == 3) {
8410
0
        double rin, rle, end;
8411
8412
0
        rin = floor(in);
8413
0
        if (in - rin >= 0.5)
8414
0
            rin += 1.0;
8415
8416
0
        rle = floor(le);
8417
0
        if (le - rle >= 0.5)
8418
0
            rle += 1.0;
8419
8420
0
        end = rin + rle;
8421
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8422
0
            j = 1;
8423
0
        } else if (end < INT_MAX) {
8424
0
            j = (int)end;
8425
0
        }
8426
0
    }
8427
8428
0
    if (i < j) {
8429
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
8430
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
8431
0
  xmlFree(ret);
8432
0
    } else {
8433
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8434
0
    }
8435
8436
0
    xmlXPathReleaseObject(ctxt->context, str);
8437
0
}
8438
8439
/**
8440
 * xmlXPathSubstringBeforeFunction:
8441
 * @ctxt:  the XPath Parser context
8442
 * @nargs:  the number of arguments
8443
 *
8444
 * Implement the substring-before() XPath function
8445
 *    string substring-before(string, string)
8446
 * The substring-before function returns the substring of the first
8447
 * argument string that precedes the first occurrence of the second
8448
 * argument string in the first argument string, or the empty string
8449
 * if the first argument string does not contain the second argument
8450
 * string. For example, substring-before("1999/04/01","/") returns 1999.
8451
 */
8452
void
8453
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8454
0
  xmlXPathObjectPtr str;
8455
0
  xmlXPathObjectPtr find;
8456
0
  xmlBufPtr target;
8457
0
  const xmlChar *point;
8458
0
  int offset;
8459
8460
0
  CHECK_ARITY(2);
8461
0
  CAST_TO_STRING;
8462
0
  find = valuePop(ctxt);
8463
0
  CAST_TO_STRING;
8464
0
  str = valuePop(ctxt);
8465
8466
0
  target = xmlBufCreate();
8467
0
  if (target) {
8468
0
    point = xmlStrstr(str->stringval, find->stringval);
8469
0
    if (point) {
8470
0
      offset = point - str->stringval;
8471
0
      xmlBufAdd(target, str->stringval, offset);
8472
0
    }
8473
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8474
0
  xmlBufContent(target)));
8475
0
    xmlBufFree(target);
8476
0
  }
8477
0
  xmlXPathReleaseObject(ctxt->context, str);
8478
0
  xmlXPathReleaseObject(ctxt->context, find);
8479
0
}
8480
8481
/**
8482
 * xmlXPathSubstringAfterFunction:
8483
 * @ctxt:  the XPath Parser context
8484
 * @nargs:  the number of arguments
8485
 *
8486
 * Implement the substring-after() XPath function
8487
 *    string substring-after(string, string)
8488
 * The substring-after function returns the substring of the first
8489
 * argument string that follows the first occurrence of the second
8490
 * argument string in the first argument string, or the empty stringi
8491
 * if the first argument string does not contain the second argument
8492
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
8493
 * and substring-after("1999/04/01","19") returns 99/04/01.
8494
 */
8495
void
8496
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8497
0
  xmlXPathObjectPtr str;
8498
0
  xmlXPathObjectPtr find;
8499
0
  xmlBufPtr target;
8500
0
  const xmlChar *point;
8501
0
  int offset;
8502
8503
0
  CHECK_ARITY(2);
8504
0
  CAST_TO_STRING;
8505
0
  find = valuePop(ctxt);
8506
0
  CAST_TO_STRING;
8507
0
  str = valuePop(ctxt);
8508
8509
0
  target = xmlBufCreate();
8510
0
  if (target) {
8511
0
    point = xmlStrstr(str->stringval, find->stringval);
8512
0
    if (point) {
8513
0
      offset = point - str->stringval + xmlStrlen(find->stringval);
8514
0
      xmlBufAdd(target, &str->stringval[offset],
8515
0
       xmlStrlen(str->stringval) - offset);
8516
0
    }
8517
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8518
0
  xmlBufContent(target)));
8519
0
    xmlBufFree(target);
8520
0
  }
8521
0
  xmlXPathReleaseObject(ctxt->context, str);
8522
0
  xmlXPathReleaseObject(ctxt->context, find);
8523
0
}
8524
8525
/**
8526
 * xmlXPathNormalizeFunction:
8527
 * @ctxt:  the XPath Parser context
8528
 * @nargs:  the number of arguments
8529
 *
8530
 * Implement the normalize-space() XPath function
8531
 *    string normalize-space(string?)
8532
 * The normalize-space function returns the argument string with white
8533
 * space normalized by stripping leading and trailing whitespace
8534
 * and replacing sequences of whitespace characters by a single
8535
 * space. Whitespace characters are the same allowed by the S production
8536
 * in XML. If the argument is omitted, it defaults to the context
8537
 * node converted to a string, in other words the value of the context node.
8538
 */
8539
void
8540
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8541
0
    xmlChar *source, *target;
8542
0
    int blank;
8543
8544
0
    if (ctxt == NULL) return;
8545
0
    if (nargs == 0) {
8546
        /* Use current context node */
8547
0
        valuePush(ctxt,
8548
0
            xmlXPathCacheWrapString(ctxt->context,
8549
0
                xmlXPathCastNodeToString(ctxt->context->node)));
8550
0
        nargs = 1;
8551
0
    }
8552
8553
0
    CHECK_ARITY(1);
8554
0
    CAST_TO_STRING;
8555
0
    CHECK_TYPE(XPATH_STRING);
8556
0
    source = ctxt->value->stringval;
8557
0
    if (source == NULL)
8558
0
        return;
8559
0
    target = source;
8560
8561
    /* Skip leading whitespaces */
8562
0
    while (IS_BLANK_CH(*source))
8563
0
        source++;
8564
8565
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
8566
0
    blank = 0;
8567
0
    while (*source) {
8568
0
        if (IS_BLANK_CH(*source)) {
8569
0
      blank = 1;
8570
0
        } else {
8571
0
            if (blank) {
8572
0
                *target++ = 0x20;
8573
0
                blank = 0;
8574
0
            }
8575
0
            *target++ = *source;
8576
0
        }
8577
0
        source++;
8578
0
    }
8579
0
    *target = 0;
8580
0
}
8581
8582
/**
8583
 * xmlXPathTranslateFunction:
8584
 * @ctxt:  the XPath Parser context
8585
 * @nargs:  the number of arguments
8586
 *
8587
 * Implement the translate() XPath function
8588
 *    string translate(string, string, string)
8589
 * The translate function returns the first argument string with
8590
 * occurrences of characters in the second argument string replaced
8591
 * by the character at the corresponding position in the third argument
8592
 * string. For example, translate("bar","abc","ABC") returns the string
8593
 * BAr. If there is a character in the second argument string with no
8594
 * character at a corresponding position in the third argument string
8595
 * (because the second argument string is longer than the third argument
8596
 * string), then occurrences of that character in the first argument
8597
 * string are removed. For example, translate("--aaa--","abc-","ABC")
8598
 * returns "AAA". If a character occurs more than once in second
8599
 * argument string, then the first occurrence determines the replacement
8600
 * character. If the third argument string is longer than the second
8601
 * argument string, then excess characters are ignored.
8602
 */
8603
void
8604
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8605
0
    xmlXPathObjectPtr str;
8606
0
    xmlXPathObjectPtr from;
8607
0
    xmlXPathObjectPtr to;
8608
0
    xmlBufPtr target;
8609
0
    int offset, max;
8610
0
    int ch;
8611
0
    const xmlChar *point;
8612
0
    xmlChar *cptr;
8613
8614
0
    CHECK_ARITY(3);
8615
8616
0
    CAST_TO_STRING;
8617
0
    to = valuePop(ctxt);
8618
0
    CAST_TO_STRING;
8619
0
    from = valuePop(ctxt);
8620
0
    CAST_TO_STRING;
8621
0
    str = valuePop(ctxt);
8622
8623
0
    target = xmlBufCreate();
8624
0
    if (target) {
8625
0
  max = xmlUTF8Strlen(to->stringval);
8626
0
  for (cptr = str->stringval; (ch=*cptr); ) {
8627
0
      offset = xmlUTF8Strloc(from->stringval, cptr);
8628
0
      if (offset >= 0) {
8629
0
    if (offset < max) {
8630
0
        point = xmlUTF8Strpos(to->stringval, offset);
8631
0
        if (point)
8632
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8633
0
    }
8634
0
      } else
8635
0
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8636
8637
      /* Step to next character in input */
8638
0
      cptr++;
8639
0
      if ( ch & 0x80 ) {
8640
    /* if not simple ascii, verify proper format */
8641
0
    if ( (ch & 0xc0) != 0xc0 ) {
8642
0
        xmlGenericError(xmlGenericErrorContext,
8643
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8644
                    /* not asserting an XPath error is probably better */
8645
0
        break;
8646
0
    }
8647
    /* then skip over remaining bytes for this char */
8648
0
    while ( (ch <<= 1) & 0x80 )
8649
0
        if ( (*cptr++ & 0xc0) != 0x80 ) {
8650
0
      xmlGenericError(xmlGenericErrorContext,
8651
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
8652
                        /* not asserting an XPath error is probably better */
8653
0
      break;
8654
0
        }
8655
0
    if (ch & 0x80) /* must have had error encountered */
8656
0
        break;
8657
0
      }
8658
0
  }
8659
0
    }
8660
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8661
0
  xmlBufContent(target)));
8662
0
    xmlBufFree(target);
8663
0
    xmlXPathReleaseObject(ctxt->context, str);
8664
0
    xmlXPathReleaseObject(ctxt->context, from);
8665
0
    xmlXPathReleaseObject(ctxt->context, to);
8666
0
}
8667
8668
/**
8669
 * xmlXPathBooleanFunction:
8670
 * @ctxt:  the XPath Parser context
8671
 * @nargs:  the number of arguments
8672
 *
8673
 * Implement the boolean() XPath function
8674
 *    boolean boolean(object)
8675
 * The boolean function converts its argument to a boolean as follows:
8676
 *    - a number is true if and only if it is neither positive or
8677
 *      negative zero nor NaN
8678
 *    - a node-set is true if and only if it is non-empty
8679
 *    - a string is true if and only if its length is non-zero
8680
 */
8681
void
8682
0
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683
0
    xmlXPathObjectPtr cur;
8684
8685
0
    CHECK_ARITY(1);
8686
0
    cur = valuePop(ctxt);
8687
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8688
0
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
8689
0
    valuePush(ctxt, cur);
8690
0
}
8691
8692
/**
8693
 * xmlXPathNotFunction:
8694
 * @ctxt:  the XPath Parser context
8695
 * @nargs:  the number of arguments
8696
 *
8697
 * Implement the not() XPath function
8698
 *    boolean not(boolean)
8699
 * The not function returns true if its argument is false,
8700
 * and false otherwise.
8701
 */
8702
void
8703
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8704
0
    CHECK_ARITY(1);
8705
0
    CAST_TO_BOOLEAN;
8706
0
    CHECK_TYPE(XPATH_BOOLEAN);
8707
0
    ctxt->value->boolval = ! ctxt->value->boolval;
8708
0
}
8709
8710
/**
8711
 * xmlXPathTrueFunction:
8712
 * @ctxt:  the XPath Parser context
8713
 * @nargs:  the number of arguments
8714
 *
8715
 * Implement the true() XPath function
8716
 *    boolean true()
8717
 */
8718
void
8719
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8720
0
    CHECK_ARITY(0);
8721
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8722
0
}
8723
8724
/**
8725
 * xmlXPathFalseFunction:
8726
 * @ctxt:  the XPath Parser context
8727
 * @nargs:  the number of arguments
8728
 *
8729
 * Implement the false() XPath function
8730
 *    boolean false()
8731
 */
8732
void
8733
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8734
0
    CHECK_ARITY(0);
8735
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8736
0
}
8737
8738
/**
8739
 * xmlXPathLangFunction:
8740
 * @ctxt:  the XPath Parser context
8741
 * @nargs:  the number of arguments
8742
 *
8743
 * Implement the lang() XPath function
8744
 *    boolean lang(string)
8745
 * The lang function returns true or false depending on whether the
8746
 * language of the context node as specified by xml:lang attributes
8747
 * is the same as or is a sublanguage of the language specified by
8748
 * the argument string. The language of the context node is determined
8749
 * by the value of the xml:lang attribute on the context node, or, if
8750
 * the context node has no xml:lang attribute, by the value of the
8751
 * xml:lang attribute on the nearest ancestor of the context node that
8752
 * has an xml:lang attribute. If there is no such attribute, then lang
8753
 * returns false. If there is such an attribute, then lang returns
8754
 * true if the attribute value is equal to the argument ignoring case,
8755
 * or if there is some suffix starting with - such that the attribute
8756
 * value is equal to the argument ignoring that suffix of the attribute
8757
 * value and ignoring case.
8758
 */
8759
void
8760
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761
0
    xmlXPathObjectPtr val = NULL;
8762
0
    const xmlChar *theLang = NULL;
8763
0
    const xmlChar *lang;
8764
0
    int ret = 0;
8765
0
    int i;
8766
8767
0
    CHECK_ARITY(1);
8768
0
    CAST_TO_STRING;
8769
0
    CHECK_TYPE(XPATH_STRING);
8770
0
    val = valuePop(ctxt);
8771
0
    lang = val->stringval;
8772
0
    theLang = xmlNodeGetLang(ctxt->context->node);
8773
0
    if ((theLang != NULL) && (lang != NULL)) {
8774
0
        for (i = 0;lang[i] != 0;i++)
8775
0
      if (toupper(lang[i]) != toupper(theLang[i]))
8776
0
          goto not_equal;
8777
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
8778
0
      ret = 1;
8779
0
    }
8780
0
not_equal:
8781
0
    if (theLang != NULL)
8782
0
  xmlFree((void *)theLang);
8783
8784
0
    xmlXPathReleaseObject(ctxt->context, val);
8785
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
8786
0
}
8787
8788
/**
8789
 * xmlXPathNumberFunction:
8790
 * @ctxt:  the XPath Parser context
8791
 * @nargs:  the number of arguments
8792
 *
8793
 * Implement the number() XPath function
8794
 *    number number(object?)
8795
 */
8796
void
8797
0
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8798
0
    xmlXPathObjectPtr cur;
8799
0
    double res;
8800
8801
0
    if (ctxt == NULL) return;
8802
0
    if (nargs == 0) {
8803
0
  if (ctxt->context->node == NULL) {
8804
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
8805
0
  } else {
8806
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8807
8808
0
      res = xmlXPathStringEvalNumber(content);
8809
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
8810
0
      xmlFree(content);
8811
0
  }
8812
0
  return;
8813
0
    }
8814
8815
0
    CHECK_ARITY(1);
8816
0
    cur = valuePop(ctxt);
8817
0
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
8818
0
}
8819
8820
/**
8821
 * xmlXPathSumFunction:
8822
 * @ctxt:  the XPath Parser context
8823
 * @nargs:  the number of arguments
8824
 *
8825
 * Implement the sum() XPath function
8826
 *    number sum(node-set)
8827
 * The sum function returns the sum of the values of the nodes in
8828
 * the argument node-set.
8829
 */
8830
void
8831
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8832
0
    xmlXPathObjectPtr cur;
8833
0
    int i;
8834
0
    double res = 0.0;
8835
8836
0
    CHECK_ARITY(1);
8837
0
    if ((ctxt->value == NULL) ||
8838
0
  ((ctxt->value->type != XPATH_NODESET) &&
8839
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8840
0
  XP_ERROR(XPATH_INVALID_TYPE);
8841
0
    cur = valuePop(ctxt);
8842
8843
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8844
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8845
0
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
8846
0
  }
8847
0
    }
8848
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
8849
0
    xmlXPathReleaseObject(ctxt->context, cur);
8850
0
}
8851
8852
/**
8853
 * xmlXPathFloorFunction:
8854
 * @ctxt:  the XPath Parser context
8855
 * @nargs:  the number of arguments
8856
 *
8857
 * Implement the floor() XPath function
8858
 *    number floor(number)
8859
 * The floor function returns the largest (closest to positive infinity)
8860
 * number that is not greater than the argument and that is an integer.
8861
 */
8862
void
8863
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8864
0
    CHECK_ARITY(1);
8865
0
    CAST_TO_NUMBER;
8866
0
    CHECK_TYPE(XPATH_NUMBER);
8867
8868
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
8869
0
}
8870
8871
/**
8872
 * xmlXPathCeilingFunction:
8873
 * @ctxt:  the XPath Parser context
8874
 * @nargs:  the number of arguments
8875
 *
8876
 * Implement the ceiling() XPath function
8877
 *    number ceiling(number)
8878
 * The ceiling function returns the smallest (closest to negative infinity)
8879
 * number that is not less than the argument and that is an integer.
8880
 */
8881
void
8882
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8883
0
    CHECK_ARITY(1);
8884
0
    CAST_TO_NUMBER;
8885
0
    CHECK_TYPE(XPATH_NUMBER);
8886
8887
#ifdef _AIX
8888
    /* Work around buggy ceil() function on AIX */
8889
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8890
#else
8891
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8892
0
#endif
8893
0
}
8894
8895
/**
8896
 * xmlXPathRoundFunction:
8897
 * @ctxt:  the XPath Parser context
8898
 * @nargs:  the number of arguments
8899
 *
8900
 * Implement the round() XPath function
8901
 *    number round(number)
8902
 * The round function returns the number that is closest to the
8903
 * argument and that is an integer. If there are two such numbers,
8904
 * then the one that is closest to positive infinity is returned.
8905
 */
8906
void
8907
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8908
0
    double f;
8909
8910
0
    CHECK_ARITY(1);
8911
0
    CAST_TO_NUMBER;
8912
0
    CHECK_TYPE(XPATH_NUMBER);
8913
8914
0
    f = ctxt->value->floatval;
8915
8916
0
    if ((f >= -0.5) && (f < 0.5)) {
8917
        /* Handles negative zero. */
8918
0
        ctxt->value->floatval *= 0.0;
8919
0
    }
8920
0
    else {
8921
0
        double rounded = floor(f);
8922
0
        if (f - rounded >= 0.5)
8923
0
            rounded += 1.0;
8924
0
        ctxt->value->floatval = rounded;
8925
0
    }
8926
0
}
8927
8928
/************************************************************************
8929
 *                  *
8930
 *      The Parser          *
8931
 *                  *
8932
 ************************************************************************/
8933
8934
/*
8935
 * a few forward declarations since we use a recursive call based
8936
 * implementation.
8937
 */
8938
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8939
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8940
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8941
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8942
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8943
                                    int qualified);
8944
8945
/**
8946
 * xmlXPathCurrentChar:
8947
 * @ctxt:  the XPath parser context
8948
 * @cur:  pointer to the beginning of the char
8949
 * @len:  pointer to the length of the char read
8950
 *
8951
 * The current char value, if using UTF-8 this may actually span multiple
8952
 * bytes in the input buffer.
8953
 *
8954
 * Returns the current char value and its length
8955
 */
8956
8957
static int
8958
0
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8959
0
    unsigned char c;
8960
0
    unsigned int val;
8961
0
    const xmlChar *cur;
8962
8963
0
    if (ctxt == NULL)
8964
0
  return(0);
8965
0
    cur = ctxt->cur;
8966
8967
    /*
8968
     * We are supposed to handle UTF8, check it's valid
8969
     * From rfc2044: encoding of the Unicode values on UTF-8:
8970
     *
8971
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
8972
     * 0000 0000-0000 007F   0xxxxxxx
8973
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
8974
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
8975
     *
8976
     * Check for the 0x110000 limit too
8977
     */
8978
0
    c = *cur;
8979
0
    if (c & 0x80) {
8980
0
  if ((cur[1] & 0xc0) != 0x80)
8981
0
      goto encoding_error;
8982
0
  if ((c & 0xe0) == 0xe0) {
8983
8984
0
      if ((cur[2] & 0xc0) != 0x80)
8985
0
    goto encoding_error;
8986
0
      if ((c & 0xf0) == 0xf0) {
8987
0
    if (((c & 0xf8) != 0xf0) ||
8988
0
        ((cur[3] & 0xc0) != 0x80))
8989
0
        goto encoding_error;
8990
    /* 4-byte code */
8991
0
    *len = 4;
8992
0
    val = (cur[0] & 0x7) << 18;
8993
0
    val |= (cur[1] & 0x3f) << 12;
8994
0
    val |= (cur[2] & 0x3f) << 6;
8995
0
    val |= cur[3] & 0x3f;
8996
0
      } else {
8997
        /* 3-byte code */
8998
0
    *len = 3;
8999
0
    val = (cur[0] & 0xf) << 12;
9000
0
    val |= (cur[1] & 0x3f) << 6;
9001
0
    val |= cur[2] & 0x3f;
9002
0
      }
9003
0
  } else {
9004
    /* 2-byte code */
9005
0
      *len = 2;
9006
0
      val = (cur[0] & 0x1f) << 6;
9007
0
      val |= cur[1] & 0x3f;
9008
0
  }
9009
0
  if (!IS_CHAR(val)) {
9010
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9011
0
  }
9012
0
  return(val);
9013
0
    } else {
9014
  /* 1-byte code */
9015
0
  *len = 1;
9016
0
  return(*cur);
9017
0
    }
9018
0
encoding_error:
9019
    /*
9020
     * If we detect an UTF8 error that probably means that the
9021
     * input encoding didn't get properly advertised in the
9022
     * declaration header. Report the error and switch the encoding
9023
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9024
     * encoding !)
9025
     */
9026
0
    *len = 0;
9027
0
    XP_ERROR0(XPATH_ENCODING_ERROR);
9028
0
}
9029
9030
/**
9031
 * xmlXPathParseNCName:
9032
 * @ctxt:  the XPath Parser context
9033
 *
9034
 * parse an XML namespace non qualified name.
9035
 *
9036
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9037
 *
9038
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9039
 *                       CombiningChar | Extender
9040
 *
9041
 * Returns the namespace name or NULL
9042
 */
9043
9044
xmlChar *
9045
0
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9046
0
    const xmlChar *in;
9047
0
    xmlChar *ret;
9048
0
    int count = 0;
9049
9050
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9051
    /*
9052
     * Accelerator for simple ASCII names
9053
     */
9054
0
    in = ctxt->cur;
9055
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9056
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9057
0
  (*in == '_')) {
9058
0
  in++;
9059
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9060
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9061
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9062
0
         (*in == '_') || (*in == '.') ||
9063
0
         (*in == '-'))
9064
0
      in++;
9065
0
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9066
0
            (*in == '[') || (*in == ']') || (*in == ':') ||
9067
0
            (*in == '@') || (*in == '*')) {
9068
0
      count = in - ctxt->cur;
9069
0
      if (count == 0)
9070
0
    return(NULL);
9071
0
      ret = xmlStrndup(ctxt->cur, count);
9072
0
      ctxt->cur = in;
9073
0
      return(ret);
9074
0
  }
9075
0
    }
9076
0
    return(xmlXPathParseNameComplex(ctxt, 0));
9077
0
}
9078
9079
9080
/**
9081
 * xmlXPathParseQName:
9082
 * @ctxt:  the XPath Parser context
9083
 * @prefix:  a xmlChar **
9084
 *
9085
 * parse an XML qualified name
9086
 *
9087
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9088
 *
9089
 * [NS 6] Prefix ::= NCName
9090
 *
9091
 * [NS 7] LocalPart ::= NCName
9092
 *
9093
 * Returns the function returns the local part, and prefix is updated
9094
 *   to get the Prefix if any.
9095
 */
9096
9097
static xmlChar *
9098
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9099
0
    xmlChar *ret = NULL;
9100
9101
0
    *prefix = NULL;
9102
0
    ret = xmlXPathParseNCName(ctxt);
9103
0
    if (ret && CUR == ':') {
9104
0
        *prefix = ret;
9105
0
  NEXT;
9106
0
  ret = xmlXPathParseNCName(ctxt);
9107
0
    }
9108
0
    return(ret);
9109
0
}
9110
9111
/**
9112
 * xmlXPathParseName:
9113
 * @ctxt:  the XPath Parser context
9114
 *
9115
 * parse an XML name
9116
 *
9117
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9118
 *                  CombiningChar | Extender
9119
 *
9120
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9121
 *
9122
 * Returns the namespace name or NULL
9123
 */
9124
9125
xmlChar *
9126
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9127
0
    const xmlChar *in;
9128
0
    xmlChar *ret;
9129
0
    size_t count = 0;
9130
9131
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9132
    /*
9133
     * Accelerator for simple ASCII names
9134
     */
9135
0
    in = ctxt->cur;
9136
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9137
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9138
0
  (*in == '_') || (*in == ':')) {
9139
0
  in++;
9140
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9141
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9142
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9143
0
         (*in == '_') || (*in == '-') ||
9144
0
         (*in == ':') || (*in == '.'))
9145
0
      in++;
9146
0
  if ((*in > 0) && (*in < 0x80)) {
9147
0
      count = in - ctxt->cur;
9148
0
            if (count > XML_MAX_NAME_LENGTH) {
9149
0
                ctxt->cur = in;
9150
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9151
0
            }
9152
0
      ret = xmlStrndup(ctxt->cur, count);
9153
0
      ctxt->cur = in;
9154
0
      return(ret);
9155
0
  }
9156
0
    }
9157
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9158
0
}
9159
9160
static xmlChar *
9161
0
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9162
0
    xmlChar buf[XML_MAX_NAMELEN + 5];
9163
0
    int len = 0, l;
9164
0
    int c;
9165
9166
    /*
9167
     * Handler for more complex cases
9168
     */
9169
0
    c = CUR_CHAR(l);
9170
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9171
0
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9172
0
        (c == '*') || /* accelerators */
9173
0
  (!IS_LETTER(c) && (c != '_') &&
9174
0
         ((!qualified) || (c != ':')))) {
9175
0
  return(NULL);
9176
0
    }
9177
9178
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9179
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9180
0
            (c == '.') || (c == '-') ||
9181
0
      (c == '_') || ((qualified) && (c == ':')) ||
9182
0
      (IS_COMBINING(c)) ||
9183
0
      (IS_EXTENDER(c)))) {
9184
0
  COPY_BUF(l,buf,len,c);
9185
0
  NEXTL(l);
9186
0
  c = CUR_CHAR(l);
9187
0
  if (len >= XML_MAX_NAMELEN) {
9188
      /*
9189
       * Okay someone managed to make a huge name, so he's ready to pay
9190
       * for the processing speed.
9191
       */
9192
0
      xmlChar *buffer;
9193
0
      int max = len * 2;
9194
9195
0
            if (len > XML_MAX_NAME_LENGTH) {
9196
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9197
0
            }
9198
0
      buffer = (xmlChar *) xmlMallocAtomic(max);
9199
0
      if (buffer == NULL) {
9200
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9201
0
      }
9202
0
      memcpy(buffer, buf, len);
9203
0
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9204
0
       (c == '.') || (c == '-') ||
9205
0
       (c == '_') || ((qualified) && (c == ':')) ||
9206
0
       (IS_COMBINING(c)) ||
9207
0
       (IS_EXTENDER(c))) {
9208
0
    if (len + 10 > max) {
9209
0
                    xmlChar *tmp;
9210
0
                    if (max > XML_MAX_NAME_LENGTH) {
9211
0
                        xmlFree(buffer);
9212
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9213
0
                    }
9214
0
        max *= 2;
9215
0
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9216
0
        if (tmp == NULL) {
9217
0
                        xmlFree(buffer);
9218
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9219
0
        }
9220
0
                    buffer = tmp;
9221
0
    }
9222
0
    COPY_BUF(l,buffer,len,c);
9223
0
    NEXTL(l);
9224
0
    c = CUR_CHAR(l);
9225
0
      }
9226
0
      buffer[len] = 0;
9227
0
      return(buffer);
9228
0
  }
9229
0
    }
9230
0
    if (len == 0)
9231
0
  return(NULL);
9232
0
    return(xmlStrndup(buf, len));
9233
0
}
9234
9235
0
#define MAX_FRAC 20
9236
9237
/**
9238
 * xmlXPathStringEvalNumber:
9239
 * @str:  A string to scan
9240
 *
9241
 *  [30a]  Float  ::= Number ('e' Digits?)?
9242
 *
9243
 *  [30]   Number ::=   Digits ('.' Digits?)?
9244
 *                    | '.' Digits
9245
 *  [31]   Digits ::=   [0-9]+
9246
 *
9247
 * Compile a Number in the string
9248
 * In complement of the Number expression, this function also handles
9249
 * negative values : '-' Number.
9250
 *
9251
 * Returns the double value.
9252
 */
9253
double
9254
0
xmlXPathStringEvalNumber(const xmlChar *str) {
9255
0
    const xmlChar *cur = str;
9256
0
    double ret;
9257
0
    int ok = 0;
9258
0
    int isneg = 0;
9259
0
    int exponent = 0;
9260
0
    int is_exponent_negative = 0;
9261
0
#ifdef __GNUC__
9262
0
    unsigned long tmp = 0;
9263
0
    double temp;
9264
0
#endif
9265
0
    if (cur == NULL) return(0);
9266
0
    while (IS_BLANK_CH(*cur)) cur++;
9267
0
    if (*cur == '-') {
9268
0
  isneg = 1;
9269
0
  cur++;
9270
0
    }
9271
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9272
0
        return(xmlXPathNAN);
9273
0
    }
9274
9275
0
#ifdef __GNUC__
9276
    /*
9277
     * tmp/temp is a workaround against a gcc compiler bug
9278
     * http://veillard.com/gcc.bug
9279
     */
9280
0
    ret = 0;
9281
0
    while ((*cur >= '0') && (*cur <= '9')) {
9282
0
  ret = ret * 10;
9283
0
  tmp = (*cur - '0');
9284
0
  ok = 1;
9285
0
  cur++;
9286
0
  temp = (double) tmp;
9287
0
  ret = ret + temp;
9288
0
    }
9289
#else
9290
    ret = 0;
9291
    while ((*cur >= '0') && (*cur <= '9')) {
9292
  ret = ret * 10 + (*cur - '0');
9293
  ok = 1;
9294
  cur++;
9295
    }
9296
#endif
9297
9298
0
    if (*cur == '.') {
9299
0
  int v, frac = 0, max;
9300
0
  double fraction = 0;
9301
9302
0
        cur++;
9303
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9304
0
      return(xmlXPathNAN);
9305
0
  }
9306
0
        while (*cur == '0') {
9307
0
      frac = frac + 1;
9308
0
      cur++;
9309
0
        }
9310
0
        max = frac + MAX_FRAC;
9311
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9312
0
      v = (*cur - '0');
9313
0
      fraction = fraction * 10 + v;
9314
0
      frac = frac + 1;
9315
0
      cur++;
9316
0
  }
9317
0
  fraction /= pow(10.0, frac);
9318
0
  ret = ret + fraction;
9319
0
  while ((*cur >= '0') && (*cur <= '9'))
9320
0
      cur++;
9321
0
    }
9322
0
    if ((*cur == 'e') || (*cur == 'E')) {
9323
0
      cur++;
9324
0
      if (*cur == '-') {
9325
0
  is_exponent_negative = 1;
9326
0
  cur++;
9327
0
      } else if (*cur == '+') {
9328
0
        cur++;
9329
0
      }
9330
0
      while ((*cur >= '0') && (*cur <= '9')) {
9331
0
        if (exponent < 1000000)
9332
0
    exponent = exponent * 10 + (*cur - '0');
9333
0
  cur++;
9334
0
      }
9335
0
    }
9336
0
    while (IS_BLANK_CH(*cur)) cur++;
9337
0
    if (*cur != 0) return(xmlXPathNAN);
9338
0
    if (isneg) ret = -ret;
9339
0
    if (is_exponent_negative) exponent = -exponent;
9340
0
    ret *= pow(10.0, (double)exponent);
9341
0
    return(ret);
9342
0
}
9343
9344
/**
9345
 * xmlXPathCompNumber:
9346
 * @ctxt:  the XPath Parser context
9347
 *
9348
 *  [30]   Number ::=   Digits ('.' Digits?)?
9349
 *                    | '.' Digits
9350
 *  [31]   Digits ::=   [0-9]+
9351
 *
9352
 * Compile a Number, then push it on the stack
9353
 *
9354
 */
9355
static void
9356
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9357
0
{
9358
0
    double ret = 0.0;
9359
0
    int ok = 0;
9360
0
    int exponent = 0;
9361
0
    int is_exponent_negative = 0;
9362
0
    xmlXPathObjectPtr num;
9363
0
#ifdef __GNUC__
9364
0
    unsigned long tmp = 0;
9365
0
    double temp;
9366
0
#endif
9367
9368
0
    CHECK_ERROR;
9369
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9370
0
        XP_ERROR(XPATH_NUMBER_ERROR);
9371
0
    }
9372
0
#ifdef __GNUC__
9373
    /*
9374
     * tmp/temp is a workaround against a gcc compiler bug
9375
     * http://veillard.com/gcc.bug
9376
     */
9377
0
    ret = 0;
9378
0
    while ((CUR >= '0') && (CUR <= '9')) {
9379
0
  ret = ret * 10;
9380
0
  tmp = (CUR - '0');
9381
0
        ok = 1;
9382
0
        NEXT;
9383
0
  temp = (double) tmp;
9384
0
  ret = ret + temp;
9385
0
    }
9386
#else
9387
    ret = 0;
9388
    while ((CUR >= '0') && (CUR <= '9')) {
9389
  ret = ret * 10 + (CUR - '0');
9390
  ok = 1;
9391
  NEXT;
9392
    }
9393
#endif
9394
0
    if (CUR == '.') {
9395
0
  int v, frac = 0, max;
9396
0
  double fraction = 0;
9397
9398
0
        NEXT;
9399
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9400
0
            XP_ERROR(XPATH_NUMBER_ERROR);
9401
0
        }
9402
0
        while (CUR == '0') {
9403
0
            frac = frac + 1;
9404
0
            NEXT;
9405
0
        }
9406
0
        max = frac + MAX_FRAC;
9407
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9408
0
      v = (CUR - '0');
9409
0
      fraction = fraction * 10 + v;
9410
0
      frac = frac + 1;
9411
0
            NEXT;
9412
0
        }
9413
0
        fraction /= pow(10.0, frac);
9414
0
        ret = ret + fraction;
9415
0
        while ((CUR >= '0') && (CUR <= '9'))
9416
0
            NEXT;
9417
0
    }
9418
0
    if ((CUR == 'e') || (CUR == 'E')) {
9419
0
        NEXT;
9420
0
        if (CUR == '-') {
9421
0
            is_exponent_negative = 1;
9422
0
            NEXT;
9423
0
        } else if (CUR == '+') {
9424
0
      NEXT;
9425
0
  }
9426
0
        while ((CUR >= '0') && (CUR <= '9')) {
9427
0
            if (exponent < 1000000)
9428
0
                exponent = exponent * 10 + (CUR - '0');
9429
0
            NEXT;
9430
0
        }
9431
0
        if (is_exponent_negative)
9432
0
            exponent = -exponent;
9433
0
        ret *= pow(10.0, (double) exponent);
9434
0
    }
9435
0
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
9436
0
    if (num == NULL) {
9437
0
  ctxt->error = XPATH_MEMORY_ERROR;
9438
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9439
0
                              NULL) == -1) {
9440
0
        xmlXPathReleaseObject(ctxt->context, num);
9441
0
    }
9442
0
}
9443
9444
/**
9445
 * xmlXPathParseLiteral:
9446
 * @ctxt:  the XPath Parser context
9447
 *
9448
 * Parse a Literal
9449
 *
9450
 *  [29]   Literal ::=   '"' [^"]* '"'
9451
 *                    | "'" [^']* "'"
9452
 *
9453
 * Returns the value found or NULL in case of error
9454
 */
9455
static xmlChar *
9456
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9457
0
    const xmlChar *q;
9458
0
    xmlChar *ret = NULL;
9459
9460
0
    if (CUR == '"') {
9461
0
        NEXT;
9462
0
  q = CUR_PTR;
9463
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9464
0
      NEXT;
9465
0
  if (!IS_CHAR_CH(CUR)) {
9466
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9467
0
  } else {
9468
0
      ret = xmlStrndup(q, CUR_PTR - q);
9469
0
      NEXT;
9470
0
        }
9471
0
    } else if (CUR == '\'') {
9472
0
        NEXT;
9473
0
  q = CUR_PTR;
9474
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9475
0
      NEXT;
9476
0
  if (!IS_CHAR_CH(CUR)) {
9477
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9478
0
  } else {
9479
0
      ret = xmlStrndup(q, CUR_PTR - q);
9480
0
      NEXT;
9481
0
        }
9482
0
    } else {
9483
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9484
0
    }
9485
0
    return(ret);
9486
0
}
9487
9488
/**
9489
 * xmlXPathCompLiteral:
9490
 * @ctxt:  the XPath Parser context
9491
 *
9492
 * Parse a Literal and push it on the stack.
9493
 *
9494
 *  [29]   Literal ::=   '"' [^"]* '"'
9495
 *                    | "'" [^']* "'"
9496
 *
9497
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
9498
 */
9499
static void
9500
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9501
0
    const xmlChar *q;
9502
0
    xmlChar *ret = NULL;
9503
0
    xmlXPathObjectPtr lit;
9504
9505
0
    if (CUR == '"') {
9506
0
        NEXT;
9507
0
  q = CUR_PTR;
9508
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9509
0
      NEXT;
9510
0
  if (!IS_CHAR_CH(CUR)) {
9511
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9512
0
  } else {
9513
0
      ret = xmlStrndup(q, CUR_PTR - q);
9514
0
      NEXT;
9515
0
        }
9516
0
    } else if (CUR == '\'') {
9517
0
        NEXT;
9518
0
  q = CUR_PTR;
9519
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9520
0
      NEXT;
9521
0
  if (!IS_CHAR_CH(CUR)) {
9522
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9523
0
  } else {
9524
0
      ret = xmlStrndup(q, CUR_PTR - q);
9525
0
      NEXT;
9526
0
        }
9527
0
    } else {
9528
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
9529
0
    }
9530
0
    if (ret == NULL) {
9531
0
        xmlXPathPErrMemory(ctxt, NULL);
9532
0
        return;
9533
0
    }
9534
0
    lit = xmlXPathCacheNewString(ctxt->context, ret);
9535
0
    if (lit == NULL) {
9536
0
  ctxt->error = XPATH_MEMORY_ERROR;
9537
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9538
0
                              NULL) == -1) {
9539
0
        xmlXPathReleaseObject(ctxt->context, lit);
9540
0
    }
9541
0
    xmlFree(ret);
9542
0
}
9543
9544
/**
9545
 * xmlXPathCompVariableReference:
9546
 * @ctxt:  the XPath Parser context
9547
 *
9548
 * Parse a VariableReference, evaluate it and push it on the stack.
9549
 *
9550
 * The variable bindings consist of a mapping from variable names
9551
 * to variable values. The value of a variable is an object, which can be
9552
 * of any of the types that are possible for the value of an expression,
9553
 * and may also be of additional types not specified here.
9554
 *
9555
 * Early evaluation is possible since:
9556
 * The variable bindings [...] used to evaluate a subexpression are
9557
 * always the same as those used to evaluate the containing expression.
9558
 *
9559
 *  [36]   VariableReference ::=   '$' QName
9560
 */
9561
static void
9562
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9563
0
    xmlChar *name;
9564
0
    xmlChar *prefix;
9565
9566
0
    SKIP_BLANKS;
9567
0
    if (CUR != '$') {
9568
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9569
0
    }
9570
0
    NEXT;
9571
0
    name = xmlXPathParseQName(ctxt, &prefix);
9572
0
    if (name == NULL) {
9573
0
        xmlFree(prefix);
9574
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9575
0
    }
9576
0
    ctxt->comp->last = -1;
9577
0
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9578
0
        xmlFree(prefix);
9579
0
        xmlFree(name);
9580
0
    }
9581
0
    SKIP_BLANKS;
9582
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9583
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9584
0
    }
9585
0
}
9586
9587
/**
9588
 * xmlXPathIsNodeType:
9589
 * @name:  a name string
9590
 *
9591
 * Is the name given a NodeType one.
9592
 *
9593
 *  [38]   NodeType ::=   'comment'
9594
 *                    | 'text'
9595
 *                    | 'processing-instruction'
9596
 *                    | 'node'
9597
 *
9598
 * Returns 1 if true 0 otherwise
9599
 */
9600
int
9601
0
xmlXPathIsNodeType(const xmlChar *name) {
9602
0
    if (name == NULL)
9603
0
  return(0);
9604
9605
0
    if (xmlStrEqual(name, BAD_CAST "node"))
9606
0
  return(1);
9607
0
    if (xmlStrEqual(name, BAD_CAST "text"))
9608
0
  return(1);
9609
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
9610
0
  return(1);
9611
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9612
0
  return(1);
9613
0
    return(0);
9614
0
}
9615
9616
/**
9617
 * xmlXPathCompFunctionCall:
9618
 * @ctxt:  the XPath Parser context
9619
 *
9620
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9621
 *  [17]   Argument ::=   Expr
9622
 *
9623
 * Compile a function call, the evaluation of all arguments are
9624
 * pushed on the stack
9625
 */
9626
static void
9627
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9628
0
    xmlChar *name;
9629
0
    xmlChar *prefix;
9630
0
    int nbargs = 0;
9631
0
    int sort = 1;
9632
9633
0
    name = xmlXPathParseQName(ctxt, &prefix);
9634
0
    if (name == NULL) {
9635
0
  xmlFree(prefix);
9636
0
  XP_ERROR(XPATH_EXPR_ERROR);
9637
0
    }
9638
0
    SKIP_BLANKS;
9639
9640
0
    if (CUR != '(') {
9641
0
  xmlFree(name);
9642
0
  xmlFree(prefix);
9643
0
  XP_ERROR(XPATH_EXPR_ERROR);
9644
0
    }
9645
0
    NEXT;
9646
0
    SKIP_BLANKS;
9647
9648
    /*
9649
    * Optimization for count(): we don't need the node-set to be sorted.
9650
    */
9651
0
    if ((prefix == NULL) && (name[0] == 'c') &&
9652
0
  xmlStrEqual(name, BAD_CAST "count"))
9653
0
    {
9654
0
  sort = 0;
9655
0
    }
9656
0
    ctxt->comp->last = -1;
9657
0
    if (CUR != ')') {
9658
0
  while (CUR != 0) {
9659
0
      int op1 = ctxt->comp->last;
9660
0
      ctxt->comp->last = -1;
9661
0
      xmlXPathCompileExpr(ctxt, sort);
9662
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
9663
0
    xmlFree(name);
9664
0
    xmlFree(prefix);
9665
0
    return;
9666
0
      }
9667
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9668
0
      nbargs++;
9669
0
      if (CUR == ')') break;
9670
0
      if (CUR != ',') {
9671
0
    xmlFree(name);
9672
0
    xmlFree(prefix);
9673
0
    XP_ERROR(XPATH_EXPR_ERROR);
9674
0
      }
9675
0
      NEXT;
9676
0
      SKIP_BLANKS;
9677
0
  }
9678
0
    }
9679
0
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9680
0
        xmlFree(prefix);
9681
0
        xmlFree(name);
9682
0
    }
9683
0
    NEXT;
9684
0
    SKIP_BLANKS;
9685
0
}
9686
9687
/**
9688
 * xmlXPathCompPrimaryExpr:
9689
 * @ctxt:  the XPath Parser context
9690
 *
9691
 *  [15]   PrimaryExpr ::=   VariableReference
9692
 *                | '(' Expr ')'
9693
 *                | Literal
9694
 *                | Number
9695
 *                | FunctionCall
9696
 *
9697
 * Compile a primary expression.
9698
 */
9699
static void
9700
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9701
0
    SKIP_BLANKS;
9702
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9703
0
    else if (CUR == '(') {
9704
0
  NEXT;
9705
0
  SKIP_BLANKS;
9706
0
  xmlXPathCompileExpr(ctxt, 1);
9707
0
  CHECK_ERROR;
9708
0
  if (CUR != ')') {
9709
0
      XP_ERROR(XPATH_EXPR_ERROR);
9710
0
  }
9711
0
  NEXT;
9712
0
  SKIP_BLANKS;
9713
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9714
0
  xmlXPathCompNumber(ctxt);
9715
0
    } else if ((CUR == '\'') || (CUR == '"')) {
9716
0
  xmlXPathCompLiteral(ctxt);
9717
0
    } else {
9718
0
  xmlXPathCompFunctionCall(ctxt);
9719
0
    }
9720
0
    SKIP_BLANKS;
9721
0
}
9722
9723
/**
9724
 * xmlXPathCompFilterExpr:
9725
 * @ctxt:  the XPath Parser context
9726
 *
9727
 *  [20]   FilterExpr ::=   PrimaryExpr
9728
 *               | FilterExpr Predicate
9729
 *
9730
 * Compile a filter expression.
9731
 * Square brackets are used to filter expressions in the same way that
9732
 * they are used in location paths. It is an error if the expression to
9733
 * be filtered does not evaluate to a node-set. The context node list
9734
 * used for evaluating the expression in square brackets is the node-set
9735
 * to be filtered listed in document order.
9736
 */
9737
9738
static void
9739
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9740
0
    xmlXPathCompPrimaryExpr(ctxt);
9741
0
    CHECK_ERROR;
9742
0
    SKIP_BLANKS;
9743
9744
0
    while (CUR == '[') {
9745
0
  xmlXPathCompPredicate(ctxt, 1);
9746
0
  SKIP_BLANKS;
9747
0
    }
9748
9749
9750
0
}
9751
9752
/**
9753
 * xmlXPathScanName:
9754
 * @ctxt:  the XPath Parser context
9755
 *
9756
 * Trickery: parse an XML name but without consuming the input flow
9757
 * Needed to avoid insanity in the parser state.
9758
 *
9759
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9760
 *                  CombiningChar | Extender
9761
 *
9762
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9763
 *
9764
 * [6] Names ::= Name (S Name)*
9765
 *
9766
 * Returns the Name parsed or NULL
9767
 */
9768
9769
static xmlChar *
9770
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9771
0
    int l;
9772
0
    int c;
9773
0
    const xmlChar *cur;
9774
0
    xmlChar *ret;
9775
9776
0
    cur = ctxt->cur;
9777
9778
0
    c = CUR_CHAR(l);
9779
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9780
0
  (!IS_LETTER(c) && (c != '_') &&
9781
0
         (c != ':'))) {
9782
0
  return(NULL);
9783
0
    }
9784
9785
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9786
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9787
0
            (c == '.') || (c == '-') ||
9788
0
      (c == '_') || (c == ':') ||
9789
0
      (IS_COMBINING(c)) ||
9790
0
      (IS_EXTENDER(c)))) {
9791
0
  NEXTL(l);
9792
0
  c = CUR_CHAR(l);
9793
0
    }
9794
0
    ret = xmlStrndup(cur, ctxt->cur - cur);
9795
0
    ctxt->cur = cur;
9796
0
    return(ret);
9797
0
}
9798
9799
/**
9800
 * xmlXPathCompPathExpr:
9801
 * @ctxt:  the XPath Parser context
9802
 *
9803
 *  [19]   PathExpr ::=   LocationPath
9804
 *               | FilterExpr
9805
 *               | FilterExpr '/' RelativeLocationPath
9806
 *               | FilterExpr '//' RelativeLocationPath
9807
 *
9808
 * Compile a path expression.
9809
 * The / operator and // operators combine an arbitrary expression
9810
 * and a relative location path. It is an error if the expression
9811
 * does not evaluate to a node-set.
9812
 * The / operator does composition in the same way as when / is
9813
 * used in a location path. As in location paths, // is short for
9814
 * /descendant-or-self::node()/.
9815
 */
9816
9817
static void
9818
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9819
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
9820
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
9821
9822
0
    SKIP_BLANKS;
9823
0
    if ((CUR == '$') || (CUR == '(') ||
9824
0
  (IS_ASCII_DIGIT(CUR)) ||
9825
0
        (CUR == '\'') || (CUR == '"') ||
9826
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9827
0
  lc = 0;
9828
0
    } else if (CUR == '*') {
9829
  /* relative or absolute location path */
9830
0
  lc = 1;
9831
0
    } else if (CUR == '/') {
9832
  /* relative or absolute location path */
9833
0
  lc = 1;
9834
0
    } else if (CUR == '@') {
9835
  /* relative abbreviated attribute location path */
9836
0
  lc = 1;
9837
0
    } else if (CUR == '.') {
9838
  /* relative abbreviated attribute location path */
9839
0
  lc = 1;
9840
0
    } else {
9841
  /*
9842
   * Problem is finding if we have a name here whether it's:
9843
   *   - a nodetype
9844
   *   - a function call in which case it's followed by '('
9845
   *   - an axis in which case it's followed by ':'
9846
   *   - a element name
9847
   * We do an a priori analysis here rather than having to
9848
   * maintain parsed token content through the recursive function
9849
   * calls. This looks uglier but makes the code easier to
9850
   * read/write/debug.
9851
   */
9852
0
  SKIP_BLANKS;
9853
0
  name = xmlXPathScanName(ctxt);
9854
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9855
0
      lc = 1;
9856
0
      xmlFree(name);
9857
0
  } else if (name != NULL) {
9858
0
      int len =xmlStrlen(name);
9859
9860
9861
0
      while (NXT(len) != 0) {
9862
0
    if (NXT(len) == '/') {
9863
        /* element name */
9864
0
        lc = 1;
9865
0
        break;
9866
0
    } else if (IS_BLANK_CH(NXT(len))) {
9867
        /* ignore blanks */
9868
0
        ;
9869
0
    } else if (NXT(len) == ':') {
9870
0
        lc = 1;
9871
0
        break;
9872
0
    } else if ((NXT(len) == '(')) {
9873
        /* Node Type or Function */
9874
0
        if (xmlXPathIsNodeType(name)) {
9875
0
      lc = 1;
9876
#ifdef LIBXML_XPTR_LOCS_ENABLED
9877
                    } else if (ctxt->xptr &&
9878
                               xmlStrEqual(name, BAD_CAST "range-to")) {
9879
                        lc = 1;
9880
#endif
9881
0
        } else {
9882
0
      lc = 0;
9883
0
        }
9884
0
                    break;
9885
0
    } else if ((NXT(len) == '[')) {
9886
        /* element name */
9887
0
        lc = 1;
9888
0
        break;
9889
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9890
0
         (NXT(len) == '=')) {
9891
0
        lc = 1;
9892
0
        break;
9893
0
    } else {
9894
0
        lc = 1;
9895
0
        break;
9896
0
    }
9897
0
    len++;
9898
0
      }
9899
0
      if (NXT(len) == 0) {
9900
    /* element name */
9901
0
    lc = 1;
9902
0
      }
9903
0
      xmlFree(name);
9904
0
  } else {
9905
      /* make sure all cases are covered explicitly */
9906
0
      XP_ERROR(XPATH_EXPR_ERROR);
9907
0
  }
9908
0
    }
9909
9910
0
    if (lc) {
9911
0
  if (CUR == '/') {
9912
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9913
0
  } else {
9914
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9915
0
  }
9916
0
  xmlXPathCompLocationPath(ctxt);
9917
0
    } else {
9918
0
  xmlXPathCompFilterExpr(ctxt);
9919
0
  CHECK_ERROR;
9920
0
  if ((CUR == '/') && (NXT(1) == '/')) {
9921
0
      SKIP(2);
9922
0
      SKIP_BLANKS;
9923
9924
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9925
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9926
9927
0
      xmlXPathCompRelativeLocationPath(ctxt);
9928
0
  } else if (CUR == '/') {
9929
0
      xmlXPathCompRelativeLocationPath(ctxt);
9930
0
  }
9931
0
    }
9932
0
    SKIP_BLANKS;
9933
0
}
9934
9935
/**
9936
 * xmlXPathCompUnionExpr:
9937
 * @ctxt:  the XPath Parser context
9938
 *
9939
 *  [18]   UnionExpr ::=   PathExpr
9940
 *               | UnionExpr '|' PathExpr
9941
 *
9942
 * Compile an union expression.
9943
 */
9944
9945
static void
9946
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9947
0
    xmlXPathCompPathExpr(ctxt);
9948
0
    CHECK_ERROR;
9949
0
    SKIP_BLANKS;
9950
0
    while (CUR == '|') {
9951
0
  int op1 = ctxt->comp->last;
9952
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9953
9954
0
  NEXT;
9955
0
  SKIP_BLANKS;
9956
0
  xmlXPathCompPathExpr(ctxt);
9957
9958
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9959
9960
0
  SKIP_BLANKS;
9961
0
    }
9962
0
}
9963
9964
/**
9965
 * xmlXPathCompUnaryExpr:
9966
 * @ctxt:  the XPath Parser context
9967
 *
9968
 *  [27]   UnaryExpr ::=   UnionExpr
9969
 *                   | '-' UnaryExpr
9970
 *
9971
 * Compile an unary expression.
9972
 */
9973
9974
static void
9975
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9976
0
    int minus = 0;
9977
0
    int found = 0;
9978
9979
0
    SKIP_BLANKS;
9980
0
    while (CUR == '-') {
9981
0
        minus = 1 - minus;
9982
0
  found = 1;
9983
0
  NEXT;
9984
0
  SKIP_BLANKS;
9985
0
    }
9986
9987
0
    xmlXPathCompUnionExpr(ctxt);
9988
0
    CHECK_ERROR;
9989
0
    if (found) {
9990
0
  if (minus)
9991
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9992
0
  else
9993
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9994
0
    }
9995
0
}
9996
9997
/**
9998
 * xmlXPathCompMultiplicativeExpr:
9999
 * @ctxt:  the XPath Parser context
10000
 *
10001
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10002
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10003
 *                   | MultiplicativeExpr 'div' UnaryExpr
10004
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10005
 *  [34]   MultiplyOperator ::=   '*'
10006
 *
10007
 * Compile an Additive expression.
10008
 */
10009
10010
static void
10011
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10012
0
    xmlXPathCompUnaryExpr(ctxt);
10013
0
    CHECK_ERROR;
10014
0
    SKIP_BLANKS;
10015
0
    while ((CUR == '*') ||
10016
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10017
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10018
0
  int op = -1;
10019
0
  int op1 = ctxt->comp->last;
10020
10021
0
        if (CUR == '*') {
10022
0
      op = 0;
10023
0
      NEXT;
10024
0
  } else if (CUR == 'd') {
10025
0
      op = 1;
10026
0
      SKIP(3);
10027
0
  } else if (CUR == 'm') {
10028
0
      op = 2;
10029
0
      SKIP(3);
10030
0
  }
10031
0
  SKIP_BLANKS;
10032
0
        xmlXPathCompUnaryExpr(ctxt);
10033
0
  CHECK_ERROR;
10034
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10035
0
  SKIP_BLANKS;
10036
0
    }
10037
0
}
10038
10039
/**
10040
 * xmlXPathCompAdditiveExpr:
10041
 * @ctxt:  the XPath Parser context
10042
 *
10043
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10044
 *                   | AdditiveExpr '+' MultiplicativeExpr
10045
 *                   | AdditiveExpr '-' MultiplicativeExpr
10046
 *
10047
 * Compile an Additive expression.
10048
 */
10049
10050
static void
10051
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10052
10053
0
    xmlXPathCompMultiplicativeExpr(ctxt);
10054
0
    CHECK_ERROR;
10055
0
    SKIP_BLANKS;
10056
0
    while ((CUR == '+') || (CUR == '-')) {
10057
0
  int plus;
10058
0
  int op1 = ctxt->comp->last;
10059
10060
0
        if (CUR == '+') plus = 1;
10061
0
  else plus = 0;
10062
0
  NEXT;
10063
0
  SKIP_BLANKS;
10064
0
        xmlXPathCompMultiplicativeExpr(ctxt);
10065
0
  CHECK_ERROR;
10066
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10067
0
  SKIP_BLANKS;
10068
0
    }
10069
0
}
10070
10071
/**
10072
 * xmlXPathCompRelationalExpr:
10073
 * @ctxt:  the XPath Parser context
10074
 *
10075
 *  [24]   RelationalExpr ::=   AdditiveExpr
10076
 *                 | RelationalExpr '<' AdditiveExpr
10077
 *                 | RelationalExpr '>' AdditiveExpr
10078
 *                 | RelationalExpr '<=' AdditiveExpr
10079
 *                 | RelationalExpr '>=' AdditiveExpr
10080
 *
10081
 *  A <= B > C is allowed ? Answer from James, yes with
10082
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10083
 *  which is basically what got implemented.
10084
 *
10085
 * Compile a Relational expression, then push the result
10086
 * on the stack
10087
 */
10088
10089
static void
10090
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10091
0
    xmlXPathCompAdditiveExpr(ctxt);
10092
0
    CHECK_ERROR;
10093
0
    SKIP_BLANKS;
10094
0
    while ((CUR == '<') || (CUR == '>')) {
10095
0
  int inf, strict;
10096
0
  int op1 = ctxt->comp->last;
10097
10098
0
        if (CUR == '<') inf = 1;
10099
0
  else inf = 0;
10100
0
  if (NXT(1) == '=') strict = 0;
10101
0
  else strict = 1;
10102
0
  NEXT;
10103
0
  if (!strict) NEXT;
10104
0
  SKIP_BLANKS;
10105
0
        xmlXPathCompAdditiveExpr(ctxt);
10106
0
  CHECK_ERROR;
10107
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10108
0
  SKIP_BLANKS;
10109
0
    }
10110
0
}
10111
10112
/**
10113
 * xmlXPathCompEqualityExpr:
10114
 * @ctxt:  the XPath Parser context
10115
 *
10116
 *  [23]   EqualityExpr ::=   RelationalExpr
10117
 *                 | EqualityExpr '=' RelationalExpr
10118
 *                 | EqualityExpr '!=' RelationalExpr
10119
 *
10120
 *  A != B != C is allowed ? Answer from James, yes with
10121
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10122
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10123
 *  which is basically what got implemented.
10124
 *
10125
 * Compile an Equality expression.
10126
 *
10127
 */
10128
static void
10129
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10130
0
    xmlXPathCompRelationalExpr(ctxt);
10131
0
    CHECK_ERROR;
10132
0
    SKIP_BLANKS;
10133
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10134
0
  int eq;
10135
0
  int op1 = ctxt->comp->last;
10136
10137
0
        if (CUR == '=') eq = 1;
10138
0
  else eq = 0;
10139
0
  NEXT;
10140
0
  if (!eq) NEXT;
10141
0
  SKIP_BLANKS;
10142
0
        xmlXPathCompRelationalExpr(ctxt);
10143
0
  CHECK_ERROR;
10144
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10145
0
  SKIP_BLANKS;
10146
0
    }
10147
0
}
10148
10149
/**
10150
 * xmlXPathCompAndExpr:
10151
 * @ctxt:  the XPath Parser context
10152
 *
10153
 *  [22]   AndExpr ::=   EqualityExpr
10154
 *                 | AndExpr 'and' EqualityExpr
10155
 *
10156
 * Compile an AND expression.
10157
 *
10158
 */
10159
static void
10160
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10161
0
    xmlXPathCompEqualityExpr(ctxt);
10162
0
    CHECK_ERROR;
10163
0
    SKIP_BLANKS;
10164
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10165
0
  int op1 = ctxt->comp->last;
10166
0
        SKIP(3);
10167
0
  SKIP_BLANKS;
10168
0
        xmlXPathCompEqualityExpr(ctxt);
10169
0
  CHECK_ERROR;
10170
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10171
0
  SKIP_BLANKS;
10172
0
    }
10173
0
}
10174
10175
/**
10176
 * xmlXPathCompileExpr:
10177
 * @ctxt:  the XPath Parser context
10178
 *
10179
 *  [14]   Expr ::=   OrExpr
10180
 *  [21]   OrExpr ::=   AndExpr
10181
 *                 | OrExpr 'or' AndExpr
10182
 *
10183
 * Parse and compile an expression
10184
 */
10185
static void
10186
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10187
0
    xmlXPathContextPtr xpctxt = ctxt->context;
10188
10189
0
    if (xpctxt != NULL) {
10190
0
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10191
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10192
        /*
10193
         * Parsing a single '(' pushes about 10 functions on the call stack
10194
         * before recursing!
10195
         */
10196
0
        xpctxt->depth += 10;
10197
0
    }
10198
10199
0
    xmlXPathCompAndExpr(ctxt);
10200
0
    CHECK_ERROR;
10201
0
    SKIP_BLANKS;
10202
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10203
0
  int op1 = ctxt->comp->last;
10204
0
        SKIP(2);
10205
0
  SKIP_BLANKS;
10206
0
        xmlXPathCompAndExpr(ctxt);
10207
0
  CHECK_ERROR;
10208
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10209
0
  SKIP_BLANKS;
10210
0
    }
10211
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10212
  /* more ops could be optimized too */
10213
  /*
10214
  * This is the main place to eliminate sorting for
10215
  * operations which don't require a sorted node-set.
10216
  * E.g. count().
10217
  */
10218
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10219
0
    }
10220
10221
0
    if (xpctxt != NULL)
10222
0
        xpctxt->depth -= 10;
10223
0
}
10224
10225
/**
10226
 * xmlXPathCompPredicate:
10227
 * @ctxt:  the XPath Parser context
10228
 * @filter:  act as a filter
10229
 *
10230
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10231
 *  [9]   PredicateExpr ::=   Expr
10232
 *
10233
 * Compile a predicate expression
10234
 */
10235
static void
10236
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10237
0
    int op1 = ctxt->comp->last;
10238
10239
0
    SKIP_BLANKS;
10240
0
    if (CUR != '[') {
10241
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10242
0
    }
10243
0
    NEXT;
10244
0
    SKIP_BLANKS;
10245
10246
0
    ctxt->comp->last = -1;
10247
    /*
10248
    * This call to xmlXPathCompileExpr() will deactivate sorting
10249
    * of the predicate result.
10250
    * TODO: Sorting is still activated for filters, since I'm not
10251
    *  sure if needed. Normally sorting should not be needed, since
10252
    *  a filter can only diminish the number of items in a sequence,
10253
    *  but won't change its order; so if the initial sequence is sorted,
10254
    *  subsequent sorting is not needed.
10255
    */
10256
0
    if (! filter)
10257
0
  xmlXPathCompileExpr(ctxt, 0);
10258
0
    else
10259
0
  xmlXPathCompileExpr(ctxt, 1);
10260
0
    CHECK_ERROR;
10261
10262
0
    if (CUR != ']') {
10263
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10264
0
    }
10265
10266
0
    if (filter)
10267
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10268
0
    else
10269
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10270
10271
0
    NEXT;
10272
0
    SKIP_BLANKS;
10273
0
}
10274
10275
/**
10276
 * xmlXPathCompNodeTest:
10277
 * @ctxt:  the XPath Parser context
10278
 * @test:  pointer to a xmlXPathTestVal
10279
 * @type:  pointer to a xmlXPathTypeVal
10280
 * @prefix:  placeholder for a possible name prefix
10281
 *
10282
 * [7] NodeTest ::=   NameTest
10283
 *        | NodeType '(' ')'
10284
 *        | 'processing-instruction' '(' Literal ')'
10285
 *
10286
 * [37] NameTest ::=  '*'
10287
 *        | NCName ':' '*'
10288
 *        | QName
10289
 * [38] NodeType ::= 'comment'
10290
 *       | 'text'
10291
 *       | 'processing-instruction'
10292
 *       | 'node'
10293
 *
10294
 * Returns the name found and updates @test, @type and @prefix appropriately
10295
 */
10296
static xmlChar *
10297
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10298
               xmlXPathTypeVal *type, xmlChar **prefix,
10299
0
         xmlChar *name) {
10300
0
    int blanks;
10301
10302
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10303
0
  STRANGE;
10304
0
  return(NULL);
10305
0
    }
10306
0
    *type = (xmlXPathTypeVal) 0;
10307
0
    *test = (xmlXPathTestVal) 0;
10308
0
    *prefix = NULL;
10309
0
    SKIP_BLANKS;
10310
10311
0
    if ((name == NULL) && (CUR == '*')) {
10312
  /*
10313
   * All elements
10314
   */
10315
0
  NEXT;
10316
0
  *test = NODE_TEST_ALL;
10317
0
  return(NULL);
10318
0
    }
10319
10320
0
    if (name == NULL)
10321
0
  name = xmlXPathParseNCName(ctxt);
10322
0
    if (name == NULL) {
10323
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
10324
0
    }
10325
10326
0
    blanks = IS_BLANK_CH(CUR);
10327
0
    SKIP_BLANKS;
10328
0
    if (CUR == '(') {
10329
0
  NEXT;
10330
  /*
10331
   * NodeType or PI search
10332
   */
10333
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
10334
0
      *type = NODE_TYPE_COMMENT;
10335
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
10336
0
      *type = NODE_TYPE_NODE;
10337
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10338
0
      *type = NODE_TYPE_PI;
10339
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
10340
0
      *type = NODE_TYPE_TEXT;
10341
0
  else {
10342
0
      if (name != NULL)
10343
0
    xmlFree(name);
10344
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
10345
0
  }
10346
10347
0
  *test = NODE_TEST_TYPE;
10348
10349
0
  SKIP_BLANKS;
10350
0
  if (*type == NODE_TYPE_PI) {
10351
      /*
10352
       * Specific case: search a PI by name.
10353
       */
10354
0
      if (name != NULL)
10355
0
    xmlFree(name);
10356
0
      name = NULL;
10357
0
      if (CUR != ')') {
10358
0
    name = xmlXPathParseLiteral(ctxt);
10359
0
                if (name == NULL) {
10360
0
              XP_ERRORNULL(XPATH_EXPR_ERROR);
10361
0
                }
10362
0
    *test = NODE_TEST_PI;
10363
0
    SKIP_BLANKS;
10364
0
      }
10365
0
  }
10366
0
  if (CUR != ')') {
10367
0
      if (name != NULL)
10368
0
    xmlFree(name);
10369
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10370
0
  }
10371
0
  NEXT;
10372
0
  return(name);
10373
0
    }
10374
0
    *test = NODE_TEST_NAME;
10375
0
    if ((!blanks) && (CUR == ':')) {
10376
0
  NEXT;
10377
10378
  /*
10379
   * Since currently the parser context don't have a
10380
   * namespace list associated:
10381
   * The namespace name for this prefix can be computed
10382
   * only at evaluation time. The compilation is done
10383
   * outside of any context.
10384
   */
10385
#if 0
10386
  *prefix = xmlXPathNsLookup(ctxt->context, name);
10387
  if (name != NULL)
10388
      xmlFree(name);
10389
  if (*prefix == NULL) {
10390
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10391
  }
10392
#else
10393
0
  *prefix = name;
10394
0
#endif
10395
10396
0
  if (CUR == '*') {
10397
      /*
10398
       * All elements
10399
       */
10400
0
      NEXT;
10401
0
      *test = NODE_TEST_ALL;
10402
0
      return(NULL);
10403
0
  }
10404
10405
0
  name = xmlXPathParseNCName(ctxt);
10406
0
  if (name == NULL) {
10407
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
10408
0
  }
10409
0
    }
10410
0
    return(name);
10411
0
}
10412
10413
/**
10414
 * xmlXPathIsAxisName:
10415
 * @name:  a preparsed name token
10416
 *
10417
 * [6] AxisName ::=   'ancestor'
10418
 *                  | 'ancestor-or-self'
10419
 *                  | 'attribute'
10420
 *                  | 'child'
10421
 *                  | 'descendant'
10422
 *                  | 'descendant-or-self'
10423
 *                  | 'following'
10424
 *                  | 'following-sibling'
10425
 *                  | 'namespace'
10426
 *                  | 'parent'
10427
 *                  | 'preceding'
10428
 *                  | 'preceding-sibling'
10429
 *                  | 'self'
10430
 *
10431
 * Returns the axis or 0
10432
 */
10433
static xmlXPathAxisVal
10434
0
xmlXPathIsAxisName(const xmlChar *name) {
10435
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10436
0
    switch (name[0]) {
10437
0
  case 'a':
10438
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
10439
0
    ret = AXIS_ANCESTOR;
10440
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10441
0
    ret = AXIS_ANCESTOR_OR_SELF;
10442
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
10443
0
    ret = AXIS_ATTRIBUTE;
10444
0
      break;
10445
0
  case 'c':
10446
0
      if (xmlStrEqual(name, BAD_CAST "child"))
10447
0
    ret = AXIS_CHILD;
10448
0
      break;
10449
0
  case 'd':
10450
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
10451
0
    ret = AXIS_DESCENDANT;
10452
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10453
0
    ret = AXIS_DESCENDANT_OR_SELF;
10454
0
      break;
10455
0
  case 'f':
10456
0
      if (xmlStrEqual(name, BAD_CAST "following"))
10457
0
    ret = AXIS_FOLLOWING;
10458
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10459
0
    ret = AXIS_FOLLOWING_SIBLING;
10460
0
      break;
10461
0
  case 'n':
10462
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
10463
0
    ret = AXIS_NAMESPACE;
10464
0
      break;
10465
0
  case 'p':
10466
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
10467
0
    ret = AXIS_PARENT;
10468
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
10469
0
    ret = AXIS_PRECEDING;
10470
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10471
0
    ret = AXIS_PRECEDING_SIBLING;
10472
0
      break;
10473
0
  case 's':
10474
0
      if (xmlStrEqual(name, BAD_CAST "self"))
10475
0
    ret = AXIS_SELF;
10476
0
      break;
10477
0
    }
10478
0
    return(ret);
10479
0
}
10480
10481
/**
10482
 * xmlXPathCompStep:
10483
 * @ctxt:  the XPath Parser context
10484
 *
10485
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
10486
 *                  | AbbreviatedStep
10487
 *
10488
 * [12] AbbreviatedStep ::=   '.' | '..'
10489
 *
10490
 * [5] AxisSpecifier ::= AxisName '::'
10491
 *                  | AbbreviatedAxisSpecifier
10492
 *
10493
 * [13] AbbreviatedAxisSpecifier ::= '@'?
10494
 *
10495
 * Modified for XPtr range support as:
10496
 *
10497
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10498
 *                     | AbbreviatedStep
10499
 *                     | 'range-to' '(' Expr ')' Predicate*
10500
 *
10501
 * Compile one step in a Location Path
10502
 * A location step of . is short for self::node(). This is
10503
 * particularly useful in conjunction with //. For example, the
10504
 * location path .//para is short for
10505
 * self::node()/descendant-or-self::node()/child::para
10506
 * and so will select all para descendant elements of the context
10507
 * node.
10508
 * Similarly, a location step of .. is short for parent::node().
10509
 * For example, ../title is short for parent::node()/child::title
10510
 * and so will select the title children of the parent of the context
10511
 * node.
10512
 */
10513
static void
10514
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10515
#ifdef LIBXML_XPTR_LOCS_ENABLED
10516
    int rangeto = 0;
10517
    int op2 = -1;
10518
#endif
10519
10520
0
    SKIP_BLANKS;
10521
0
    if ((CUR == '.') && (NXT(1) == '.')) {
10522
0
  SKIP(2);
10523
0
  SKIP_BLANKS;
10524
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10525
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10526
0
    } else if (CUR == '.') {
10527
0
  NEXT;
10528
0
  SKIP_BLANKS;
10529
0
    } else {
10530
0
  xmlChar *name = NULL;
10531
0
  xmlChar *prefix = NULL;
10532
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
10533
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10534
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10535
0
  int op1;
10536
10537
  /*
10538
   * The modification needed for XPointer change to the production
10539
   */
10540
#ifdef LIBXML_XPTR_LOCS_ENABLED
10541
  if (ctxt->xptr) {
10542
      name = xmlXPathParseNCName(ctxt);
10543
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10544
                op2 = ctxt->comp->last;
10545
    xmlFree(name);
10546
    SKIP_BLANKS;
10547
    if (CUR != '(') {
10548
        XP_ERROR(XPATH_EXPR_ERROR);
10549
    }
10550
    NEXT;
10551
    SKIP_BLANKS;
10552
10553
    xmlXPathCompileExpr(ctxt, 1);
10554
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10555
    CHECK_ERROR;
10556
10557
    SKIP_BLANKS;
10558
    if (CUR != ')') {
10559
        XP_ERROR(XPATH_EXPR_ERROR);
10560
    }
10561
    NEXT;
10562
    rangeto = 1;
10563
    goto eval_predicates;
10564
      }
10565
  }
10566
#endif
10567
0
  if (CUR == '*') {
10568
0
      axis = AXIS_CHILD;
10569
0
  } else {
10570
0
      if (name == NULL)
10571
0
    name = xmlXPathParseNCName(ctxt);
10572
0
      if (name != NULL) {
10573
0
    axis = xmlXPathIsAxisName(name);
10574
0
    if (axis != 0) {
10575
0
        SKIP_BLANKS;
10576
0
        if ((CUR == ':') && (NXT(1) == ':')) {
10577
0
      SKIP(2);
10578
0
      xmlFree(name);
10579
0
      name = NULL;
10580
0
        } else {
10581
      /* an element name can conflict with an axis one :-\ */
10582
0
      axis = AXIS_CHILD;
10583
0
        }
10584
0
    } else {
10585
0
        axis = AXIS_CHILD;
10586
0
    }
10587
0
      } else if (CUR == '@') {
10588
0
    NEXT;
10589
0
    axis = AXIS_ATTRIBUTE;
10590
0
      } else {
10591
0
    axis = AXIS_CHILD;
10592
0
      }
10593
0
  }
10594
10595
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
10596
0
            xmlFree(name);
10597
0
            return;
10598
0
        }
10599
10600
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10601
0
  if (test == 0)
10602
0
      return;
10603
10604
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
10605
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
10606
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10607
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10608
0
      }
10609
0
  }
10610
10611
#ifdef LIBXML_XPTR_LOCS_ENABLED
10612
eval_predicates:
10613
#endif
10614
0
  op1 = ctxt->comp->last;
10615
0
  ctxt->comp->last = -1;
10616
10617
0
  SKIP_BLANKS;
10618
0
  while (CUR == '[') {
10619
0
      xmlXPathCompPredicate(ctxt, 0);
10620
0
  }
10621
10622
#ifdef LIBXML_XPTR_LOCS_ENABLED
10623
  if (rangeto) {
10624
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10625
  } else
10626
#endif
10627
0
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10628
0
                           test, type, (void *)prefix, (void *)name) == -1) {
10629
0
            xmlFree(prefix);
10630
0
            xmlFree(name);
10631
0
        }
10632
0
    }
10633
0
}
10634
10635
/**
10636
 * xmlXPathCompRelativeLocationPath:
10637
 * @ctxt:  the XPath Parser context
10638
 *
10639
 *  [3]   RelativeLocationPath ::=   Step
10640
 *                     | RelativeLocationPath '/' Step
10641
 *                     | AbbreviatedRelativeLocationPath
10642
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
10643
 *
10644
 * Compile a relative location path.
10645
 */
10646
static void
10647
xmlXPathCompRelativeLocationPath
10648
0
(xmlXPathParserContextPtr ctxt) {
10649
0
    SKIP_BLANKS;
10650
0
    if ((CUR == '/') && (NXT(1) == '/')) {
10651
0
  SKIP(2);
10652
0
  SKIP_BLANKS;
10653
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10654
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10655
0
    } else if (CUR == '/') {
10656
0
      NEXT;
10657
0
  SKIP_BLANKS;
10658
0
    }
10659
0
    xmlXPathCompStep(ctxt);
10660
0
    CHECK_ERROR;
10661
0
    SKIP_BLANKS;
10662
0
    while (CUR == '/') {
10663
0
  if ((CUR == '/') && (NXT(1) == '/')) {
10664
0
      SKIP(2);
10665
0
      SKIP_BLANKS;
10666
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10667
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10668
0
      xmlXPathCompStep(ctxt);
10669
0
  } else if (CUR == '/') {
10670
0
      NEXT;
10671
0
      SKIP_BLANKS;
10672
0
      xmlXPathCompStep(ctxt);
10673
0
  }
10674
0
  SKIP_BLANKS;
10675
0
    }
10676
0
}
10677
10678
/**
10679
 * xmlXPathCompLocationPath:
10680
 * @ctxt:  the XPath Parser context
10681
 *
10682
 *  [1]   LocationPath ::=   RelativeLocationPath
10683
 *                     | AbsoluteLocationPath
10684
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
10685
 *                     | AbbreviatedAbsoluteLocationPath
10686
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
10687
 *                           '//' RelativeLocationPath
10688
 *
10689
 * Compile a location path
10690
 *
10691
 * // is short for /descendant-or-self::node()/. For example,
10692
 * //para is short for /descendant-or-self::node()/child::para and
10693
 * so will select any para element in the document (even a para element
10694
 * that is a document element will be selected by //para since the
10695
 * document element node is a child of the root node); div//para is
10696
 * short for div/descendant-or-self::node()/child::para and so will
10697
 * select all para descendants of div children.
10698
 */
10699
static void
10700
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10701
0
    SKIP_BLANKS;
10702
0
    if (CUR != '/') {
10703
0
        xmlXPathCompRelativeLocationPath(ctxt);
10704
0
    } else {
10705
0
  while (CUR == '/') {
10706
0
      if ((CUR == '/') && (NXT(1) == '/')) {
10707
0
    SKIP(2);
10708
0
    SKIP_BLANKS;
10709
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10710
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10711
0
    xmlXPathCompRelativeLocationPath(ctxt);
10712
0
      } else if (CUR == '/') {
10713
0
    NEXT;
10714
0
    SKIP_BLANKS;
10715
0
    if ((CUR != 0 ) &&
10716
0
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10717
0
         (CUR == '@') || (CUR == '*')))
10718
0
        xmlXPathCompRelativeLocationPath(ctxt);
10719
0
      }
10720
0
      CHECK_ERROR;
10721
0
  }
10722
0
    }
10723
0
}
10724
10725
/************************************************************************
10726
 *                  *
10727
 *    XPath precompiled expression evaluation     *
10728
 *                  *
10729
 ************************************************************************/
10730
10731
static int
10732
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10733
10734
/**
10735
 * xmlXPathNodeSetFilter:
10736
 * @ctxt:  the XPath Parser context
10737
 * @set: the node set to filter
10738
 * @filterOpIndex: the index of the predicate/filter op
10739
 * @minPos: minimum position in the filtered set (1-based)
10740
 * @maxPos: maximum position in the filtered set (1-based)
10741
 * @hasNsNodes: true if the node set may contain namespace nodes
10742
 *
10743
 * Filter a node set, keeping only nodes for which the predicate expression
10744
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
10745
 * filtered result.
10746
 */
10747
static void
10748
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10749
          xmlNodeSetPtr set,
10750
          int filterOpIndex,
10751
                      int minPos, int maxPos,
10752
          int hasNsNodes)
10753
0
{
10754
0
    xmlXPathContextPtr xpctxt;
10755
0
    xmlNodePtr oldnode;
10756
0
    xmlDocPtr olddoc;
10757
0
    xmlXPathStepOpPtr filterOp;
10758
0
    int oldcs, oldpp;
10759
0
    int i, j, pos;
10760
10761
0
    if ((set == NULL) || (set->nodeNr == 0))
10762
0
        return;
10763
10764
    /*
10765
    * Check if the node set contains a sufficient number of nodes for
10766
    * the requested range.
10767
    */
10768
0
    if (set->nodeNr < minPos) {
10769
0
        xmlXPathNodeSetClear(set, hasNsNodes);
10770
0
        return;
10771
0
    }
10772
10773
0
    xpctxt = ctxt->context;
10774
0
    oldnode = xpctxt->node;
10775
0
    olddoc = xpctxt->doc;
10776
0
    oldcs = xpctxt->contextSize;
10777
0
    oldpp = xpctxt->proximityPosition;
10778
0
    filterOp = &ctxt->comp->steps[filterOpIndex];
10779
10780
0
    xpctxt->contextSize = set->nodeNr;
10781
10782
0
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10783
0
        xmlNodePtr node = set->nodeTab[i];
10784
0
        int res;
10785
10786
0
        xpctxt->node = node;
10787
0
        xpctxt->proximityPosition = i + 1;
10788
10789
        /*
10790
        * Also set the xpath document in case things like
10791
        * key() are evaluated in the predicate.
10792
        *
10793
        * TODO: Get real doc for namespace nodes.
10794
        */
10795
0
        if ((node->type != XML_NAMESPACE_DECL) &&
10796
0
            (node->doc != NULL))
10797
0
            xpctxt->doc = node->doc;
10798
10799
0
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10800
10801
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
10802
0
            break;
10803
0
        if (res < 0) {
10804
            /* Shouldn't happen */
10805
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10806
0
            break;
10807
0
        }
10808
10809
0
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10810
0
            if (i != j) {
10811
0
                set->nodeTab[j] = node;
10812
0
                set->nodeTab[i] = NULL;
10813
0
            }
10814
10815
0
            j += 1;
10816
0
        } else {
10817
            /* Remove the entry from the initial node set. */
10818
0
            set->nodeTab[i] = NULL;
10819
0
            if (node->type == XML_NAMESPACE_DECL)
10820
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10821
0
        }
10822
10823
0
        if (res != 0) {
10824
0
            if (pos == maxPos) {
10825
0
                i += 1;
10826
0
                break;
10827
0
            }
10828
10829
0
            pos += 1;
10830
0
        }
10831
0
    }
10832
10833
    /* Free remaining nodes. */
10834
0
    if (hasNsNodes) {
10835
0
        for (; i < set->nodeNr; i++) {
10836
0
            xmlNodePtr node = set->nodeTab[i];
10837
0
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10838
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10839
0
        }
10840
0
    }
10841
10842
0
    set->nodeNr = j;
10843
10844
    /* If too many elements were removed, shrink table to preserve memory. */
10845
0
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10846
0
        (set->nodeNr < set->nodeMax / 2)) {
10847
0
        xmlNodePtr *tmp;
10848
0
        int nodeMax = set->nodeNr;
10849
10850
0
        if (nodeMax < XML_NODESET_DEFAULT)
10851
0
            nodeMax = XML_NODESET_DEFAULT;
10852
0
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10853
0
                nodeMax * sizeof(xmlNodePtr));
10854
0
        if (tmp == NULL) {
10855
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
10856
0
        } else {
10857
0
            set->nodeTab = tmp;
10858
0
            set->nodeMax = nodeMax;
10859
0
        }
10860
0
    }
10861
10862
0
    xpctxt->node = oldnode;
10863
0
    xpctxt->doc = olddoc;
10864
0
    xpctxt->contextSize = oldcs;
10865
0
    xpctxt->proximityPosition = oldpp;
10866
0
}
10867
10868
#ifdef LIBXML_XPTR_LOCS_ENABLED
10869
/**
10870
 * xmlXPathLocationSetFilter:
10871
 * @ctxt:  the XPath Parser context
10872
 * @locset: the location set to filter
10873
 * @filterOpIndex: the index of the predicate/filter op
10874
 * @minPos: minimum position in the filtered set (1-based)
10875
 * @maxPos: maximum position in the filtered set (1-based)
10876
 *
10877
 * Filter a location set, keeping only nodes for which the predicate
10878
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
10879
 * in the filtered result.
10880
 */
10881
static void
10882
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10883
              xmlLocationSetPtr locset,
10884
              int filterOpIndex,
10885
                          int minPos, int maxPos)
10886
{
10887
    xmlXPathContextPtr xpctxt;
10888
    xmlNodePtr oldnode;
10889
    xmlDocPtr olddoc;
10890
    xmlXPathStepOpPtr filterOp;
10891
    int oldcs, oldpp;
10892
    int i, j, pos;
10893
10894
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10895
        return;
10896
10897
    xpctxt = ctxt->context;
10898
    oldnode = xpctxt->node;
10899
    olddoc = xpctxt->doc;
10900
    oldcs = xpctxt->contextSize;
10901
    oldpp = xpctxt->proximityPosition;
10902
    filterOp = &ctxt->comp->steps[filterOpIndex];
10903
10904
    xpctxt->contextSize = locset->locNr;
10905
10906
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10907
        xmlNodePtr contextNode = locset->locTab[i]->user;
10908
        int res;
10909
10910
        xpctxt->node = contextNode;
10911
        xpctxt->proximityPosition = i + 1;
10912
10913
        /*
10914
        * Also set the xpath document in case things like
10915
        * key() are evaluated in the predicate.
10916
        *
10917
        * TODO: Get real doc for namespace nodes.
10918
        */
10919
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
10920
            (contextNode->doc != NULL))
10921
            xpctxt->doc = contextNode->doc;
10922
10923
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10924
10925
        if (ctxt->error != XPATH_EXPRESSION_OK)
10926
            break;
10927
        if (res < 0) {
10928
            /* Shouldn't happen */
10929
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10930
            break;
10931
        }
10932
10933
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10934
            if (i != j) {
10935
                locset->locTab[j] = locset->locTab[i];
10936
                locset->locTab[i] = NULL;
10937
            }
10938
10939
            j += 1;
10940
        } else {
10941
            /* Remove the entry from the initial location set. */
10942
            xmlXPathFreeObject(locset->locTab[i]);
10943
            locset->locTab[i] = NULL;
10944
        }
10945
10946
        if (res != 0) {
10947
            if (pos == maxPos) {
10948
                i += 1;
10949
                break;
10950
            }
10951
10952
            pos += 1;
10953
        }
10954
    }
10955
10956
    /* Free remaining nodes. */
10957
    for (; i < locset->locNr; i++)
10958
        xmlXPathFreeObject(locset->locTab[i]);
10959
10960
    locset->locNr = j;
10961
10962
    /* If too many elements were removed, shrink table to preserve memory. */
10963
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
10964
        (locset->locNr < locset->locMax / 2)) {
10965
        xmlXPathObjectPtr *tmp;
10966
        int locMax = locset->locNr;
10967
10968
        if (locMax < XML_NODESET_DEFAULT)
10969
            locMax = XML_NODESET_DEFAULT;
10970
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10971
                locMax * sizeof(xmlXPathObjectPtr));
10972
        if (tmp == NULL) {
10973
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
10974
        } else {
10975
            locset->locTab = tmp;
10976
            locset->locMax = locMax;
10977
        }
10978
    }
10979
10980
    xpctxt->node = oldnode;
10981
    xpctxt->doc = olddoc;
10982
    xpctxt->contextSize = oldcs;
10983
    xpctxt->proximityPosition = oldpp;
10984
}
10985
#endif /* LIBXML_XPTR_LOCS_ENABLED */
10986
10987
/**
10988
 * xmlXPathCompOpEvalPredicate:
10989
 * @ctxt:  the XPath Parser context
10990
 * @op: the predicate op
10991
 * @set: the node set to filter
10992
 * @minPos: minimum position in the filtered set (1-based)
10993
 * @maxPos: maximum position in the filtered set (1-based)
10994
 * @hasNsNodes: true if the node set may contain namespace nodes
10995
 *
10996
 * Filter a node set, keeping only nodes for which the sequence of predicate
10997
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
10998
 * in the filtered result.
10999
 */
11000
static void
11001
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11002
          xmlXPathStepOpPtr op,
11003
          xmlNodeSetPtr set,
11004
                            int minPos, int maxPos,
11005
          int hasNsNodes)
11006
0
{
11007
0
    if (op->ch1 != -1) {
11008
0
  xmlXPathCompExprPtr comp = ctxt->comp;
11009
  /*
11010
  * Process inner predicates first.
11011
  */
11012
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11013
0
            xmlGenericError(xmlGenericErrorContext,
11014
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11015
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11016
0
  }
11017
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11018
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11019
0
        ctxt->context->depth += 1;
11020
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11021
0
                                    1, set->nodeNr, hasNsNodes);
11022
0
        ctxt->context->depth -= 1;
11023
0
  CHECK_ERROR;
11024
0
    }
11025
11026
0
    if (op->ch2 != -1)
11027
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11028
0
}
11029
11030
static int
11031
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11032
          xmlXPathStepOpPtr op,
11033
          int *maxPos)
11034
0
{
11035
11036
0
    xmlXPathStepOpPtr exprOp;
11037
11038
    /*
11039
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11040
    */
11041
11042
    /*
11043
    * If not -1, then ch1 will point to:
11044
    * 1) For predicates (XPATH_OP_PREDICATE):
11045
    *    - an inner predicate operator
11046
    * 2) For filters (XPATH_OP_FILTER):
11047
    *    - an inner filter operator OR
11048
    *    - an expression selecting the node set.
11049
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11050
    */
11051
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11052
0
  return(0);
11053
11054
0
    if (op->ch2 != -1) {
11055
0
  exprOp = &ctxt->comp->steps[op->ch2];
11056
0
    } else
11057
0
  return(0);
11058
11059
0
    if ((exprOp != NULL) &&
11060
0
  (exprOp->op == XPATH_OP_VALUE) &&
11061
0
  (exprOp->value4 != NULL) &&
11062
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11063
0
    {
11064
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11065
11066
  /*
11067
  * We have a "[n]" predicate here.
11068
  * TODO: Unfortunately this simplistic test here is not
11069
  * able to detect a position() predicate in compound
11070
  * expressions like "[@attr = 'a" and position() = 1],
11071
  * and even not the usage of position() in
11072
  * "[position() = 1]"; thus - obviously - a position-range,
11073
  * like it "[position() < 5]", is also not detected.
11074
  * Maybe we could rewrite the AST to ease the optimization.
11075
  */
11076
11077
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11078
0
      *maxPos = (int) floatval;
11079
0
            if (floatval == (double) *maxPos)
11080
0
                return(1);
11081
0
        }
11082
0
    }
11083
0
    return(0);
11084
0
}
11085
11086
static int
11087
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11088
                           xmlXPathStepOpPtr op,
11089
         xmlNodePtr * first, xmlNodePtr * last,
11090
         int toBool)
11091
0
{
11092
11093
0
#define XP_TEST_HIT \
11094
0
    if (hasAxisRange != 0) { \
11095
0
  if (++pos == maxPos) { \
11096
0
      if (addNode(seq, cur) < 0) \
11097
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11098
0
      goto axis_range_end; } \
11099
0
    } else { \
11100
0
  if (addNode(seq, cur) < 0) \
11101
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11102
0
  if (breakOnFirstHit) goto first_hit; }
11103
11104
0
#define XP_TEST_HIT_NS \
11105
0
    if (hasAxisRange != 0) { \
11106
0
  if (++pos == maxPos) { \
11107
0
      hasNsNodes = 1; \
11108
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11109
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11110
0
  goto axis_range_end; } \
11111
0
    } else { \
11112
0
  hasNsNodes = 1; \
11113
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11114
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11115
0
  if (breakOnFirstHit) goto first_hit; }
11116
11117
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11118
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11119
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11120
0
    const xmlChar *prefix = op->value4;
11121
0
    const xmlChar *name = op->value5;
11122
0
    const xmlChar *URI = NULL;
11123
11124
0
    int total = 0, hasNsNodes = 0;
11125
    /* The popped object holding the context nodes */
11126
0
    xmlXPathObjectPtr obj;
11127
    /* The set of context nodes for the node tests */
11128
0
    xmlNodeSetPtr contextSeq;
11129
0
    int contextIdx;
11130
0
    xmlNodePtr contextNode;
11131
    /* The final resulting node set wrt to all context nodes */
11132
0
    xmlNodeSetPtr outSeq;
11133
    /*
11134
    * The temporary resulting node set wrt 1 context node.
11135
    * Used to feed predicate evaluation.
11136
    */
11137
0
    xmlNodeSetPtr seq;
11138
0
    xmlNodePtr cur;
11139
    /* First predicate operator */
11140
0
    xmlXPathStepOpPtr predOp;
11141
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
11142
0
    int hasPredicateRange, hasAxisRange, pos;
11143
0
    int breakOnFirstHit;
11144
11145
0
    xmlXPathTraversalFunction next = NULL;
11146
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11147
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
11148
0
    xmlNodePtr oldContextNode;
11149
0
    xmlXPathContextPtr xpctxt = ctxt->context;
11150
11151
11152
0
    CHECK_TYPE0(XPATH_NODESET);
11153
0
    obj = valuePop(ctxt);
11154
    /*
11155
    * Setup namespaces.
11156
    */
11157
0
    if (prefix != NULL) {
11158
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
11159
0
        if (URI == NULL) {
11160
0
      xmlXPathReleaseObject(xpctxt, obj);
11161
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11162
0
  }
11163
0
    }
11164
    /*
11165
    * Setup axis.
11166
    *
11167
    * MAYBE FUTURE TODO: merging optimizations:
11168
    * - If the nodes to be traversed wrt to the initial nodes and
11169
    *   the current axis cannot overlap, then we could avoid searching
11170
    *   for duplicates during the merge.
11171
    *   But the question is how/when to evaluate if they cannot overlap.
11172
    *   Example: if we know that for two initial nodes, the one is
11173
    *   not in the ancestor-or-self axis of the other, then we could safely
11174
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11175
    *   the descendant-or-self axis.
11176
    */
11177
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
11178
0
    switch (axis) {
11179
0
        case AXIS_ANCESTOR:
11180
0
            first = NULL;
11181
0
            next = xmlXPathNextAncestor;
11182
0
            break;
11183
0
        case AXIS_ANCESTOR_OR_SELF:
11184
0
            first = NULL;
11185
0
            next = xmlXPathNextAncestorOrSelf;
11186
0
            break;
11187
0
        case AXIS_ATTRIBUTE:
11188
0
            first = NULL;
11189
0
      last = NULL;
11190
0
            next = xmlXPathNextAttribute;
11191
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11192
0
            break;
11193
0
        case AXIS_CHILD:
11194
0
      last = NULL;
11195
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11196
0
    (type == NODE_TYPE_NODE))
11197
0
      {
11198
    /*
11199
    * Optimization if an element node type is 'element'.
11200
    */
11201
0
    next = xmlXPathNextChildElement;
11202
0
      } else
11203
0
    next = xmlXPathNextChild;
11204
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11205
0
            break;
11206
0
        case AXIS_DESCENDANT:
11207
0
      last = NULL;
11208
0
            next = xmlXPathNextDescendant;
11209
0
            break;
11210
0
        case AXIS_DESCENDANT_OR_SELF:
11211
0
      last = NULL;
11212
0
            next = xmlXPathNextDescendantOrSelf;
11213
0
            break;
11214
0
        case AXIS_FOLLOWING:
11215
0
      last = NULL;
11216
0
            next = xmlXPathNextFollowing;
11217
0
            break;
11218
0
        case AXIS_FOLLOWING_SIBLING:
11219
0
      last = NULL;
11220
0
            next = xmlXPathNextFollowingSibling;
11221
0
            break;
11222
0
        case AXIS_NAMESPACE:
11223
0
            first = NULL;
11224
0
      last = NULL;
11225
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11226
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11227
0
            break;
11228
0
        case AXIS_PARENT:
11229
0
            first = NULL;
11230
0
            next = xmlXPathNextParent;
11231
0
            break;
11232
0
        case AXIS_PRECEDING:
11233
0
            first = NULL;
11234
0
            next = xmlXPathNextPrecedingInternal;
11235
0
            break;
11236
0
        case AXIS_PRECEDING_SIBLING:
11237
0
            first = NULL;
11238
0
            next = xmlXPathNextPrecedingSibling;
11239
0
            break;
11240
0
        case AXIS_SELF:
11241
0
            first = NULL;
11242
0
      last = NULL;
11243
0
            next = xmlXPathNextSelf;
11244
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11245
0
            break;
11246
0
    }
11247
11248
0
    if (next == NULL) {
11249
0
  xmlXPathReleaseObject(xpctxt, obj);
11250
0
        return(0);
11251
0
    }
11252
0
    contextSeq = obj->nodesetval;
11253
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
11254
0
  xmlXPathReleaseObject(xpctxt, obj);
11255
0
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
11256
0
        return(0);
11257
0
    }
11258
    /*
11259
    * Predicate optimization ---------------------------------------------
11260
    * If this step has a last predicate, which contains a position(),
11261
    * then we'll optimize (although not exactly "position()", but only
11262
    * the  short-hand form, i.e., "[n]".
11263
    *
11264
    * Example - expression "/foo[parent::bar][1]":
11265
    *
11266
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
11267
    *   ROOT                               -- op->ch1
11268
    *   PREDICATE                          -- op->ch2 (predOp)
11269
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
11270
    *       SORT
11271
    *         COLLECT  'parent' 'name' 'node' bar
11272
    *           NODE
11273
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
11274
    *
11275
    */
11276
0
    maxPos = 0;
11277
0
    predOp = NULL;
11278
0
    hasPredicateRange = 0;
11279
0
    hasAxisRange = 0;
11280
0
    if (op->ch2 != -1) {
11281
  /*
11282
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
11283
  */
11284
0
  predOp = &ctxt->comp->steps[op->ch2];
11285
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
11286
0
      if (predOp->ch1 != -1) {
11287
    /*
11288
    * Use the next inner predicate operator.
11289
    */
11290
0
    predOp = &ctxt->comp->steps[predOp->ch1];
11291
0
    hasPredicateRange = 1;
11292
0
      } else {
11293
    /*
11294
    * There's no other predicate than the [n] predicate.
11295
    */
11296
0
    predOp = NULL;
11297
0
    hasAxisRange = 1;
11298
0
      }
11299
0
  }
11300
0
    }
11301
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11302
    /*
11303
    * Axis traversal -----------------------------------------------------
11304
    */
11305
    /*
11306
     * 2.3 Node Tests
11307
     *  - For the attribute axis, the principal node type is attribute.
11308
     *  - For the namespace axis, the principal node type is namespace.
11309
     *  - For other axes, the principal node type is element.
11310
     *
11311
     * A node test * is true for any node of the
11312
     * principal node type. For example, child::* will
11313
     * select all element children of the context node
11314
     */
11315
0
    oldContextNode = xpctxt->node;
11316
0
    addNode = xmlXPathNodeSetAddUnique;
11317
0
    outSeq = NULL;
11318
0
    seq = NULL;
11319
0
    contextNode = NULL;
11320
0
    contextIdx = 0;
11321
11322
11323
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11324
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
11325
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
11326
11327
0
  if (seq == NULL) {
11328
0
      seq = xmlXPathNodeSetCreate(NULL);
11329
0
      if (seq == NULL) {
11330
                /* TODO: Propagate memory error. */
11331
0
    total = 0;
11332
0
    goto error;
11333
0
      }
11334
0
  }
11335
  /*
11336
  * Traverse the axis and test the nodes.
11337
  */
11338
0
  pos = 0;
11339
0
  cur = NULL;
11340
0
  hasNsNodes = 0;
11341
0
        do {
11342
0
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
11343
0
                goto error;
11344
11345
0
            cur = next(ctxt, cur);
11346
0
            if (cur == NULL)
11347
0
                break;
11348
11349
      /*
11350
      * QUESTION TODO: What does the "first" and "last" stuff do?
11351
      */
11352
0
            if ((first != NULL) && (*first != NULL)) {
11353
0
    if (*first == cur)
11354
0
        break;
11355
0
    if (((total % 256) == 0) &&
11356
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11357
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
11358
#else
11359
        (xmlXPathCmpNodes(*first, cur) >= 0))
11360
#endif
11361
0
    {
11362
0
        break;
11363
0
    }
11364
0
      }
11365
0
      if ((last != NULL) && (*last != NULL)) {
11366
0
    if (*last == cur)
11367
0
        break;
11368
0
    if (((total % 256) == 0) &&
11369
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11370
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
11371
#else
11372
        (xmlXPathCmpNodes(cur, *last) >= 0))
11373
#endif
11374
0
    {
11375
0
        break;
11376
0
    }
11377
0
      }
11378
11379
0
            total++;
11380
11381
0
      switch (test) {
11382
0
                case NODE_TEST_NONE:
11383
0
        total = 0;
11384
0
                    STRANGE
11385
0
        goto error;
11386
0
                case NODE_TEST_TYPE:
11387
0
        if (type == NODE_TYPE_NODE) {
11388
0
      switch (cur->type) {
11389
0
          case XML_DOCUMENT_NODE:
11390
0
          case XML_HTML_DOCUMENT_NODE:
11391
0
          case XML_ELEMENT_NODE:
11392
0
          case XML_ATTRIBUTE_NODE:
11393
0
          case XML_PI_NODE:
11394
0
          case XML_COMMENT_NODE:
11395
0
          case XML_CDATA_SECTION_NODE:
11396
0
          case XML_TEXT_NODE:
11397
0
        XP_TEST_HIT
11398
0
        break;
11399
0
          case XML_NAMESPACE_DECL: {
11400
0
        if (axis == AXIS_NAMESPACE) {
11401
0
            XP_TEST_HIT_NS
11402
0
        } else {
11403
0
                              hasNsNodes = 1;
11404
0
            XP_TEST_HIT
11405
0
        }
11406
0
        break;
11407
0
                            }
11408
0
          default:
11409
0
        break;
11410
0
      }
11411
0
        } else if (cur->type == (xmlElementType) type) {
11412
0
      if (cur->type == XML_NAMESPACE_DECL)
11413
0
          XP_TEST_HIT_NS
11414
0
      else
11415
0
          XP_TEST_HIT
11416
0
        } else if ((type == NODE_TYPE_TEXT) &&
11417
0
       (cur->type == XML_CDATA_SECTION_NODE))
11418
0
        {
11419
0
      XP_TEST_HIT
11420
0
        }
11421
0
        break;
11422
0
                case NODE_TEST_PI:
11423
0
                    if ((cur->type == XML_PI_NODE) &&
11424
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
11425
0
        {
11426
0
      XP_TEST_HIT
11427
0
                    }
11428
0
                    break;
11429
0
                case NODE_TEST_ALL:
11430
0
                    if (axis == AXIS_ATTRIBUTE) {
11431
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
11432
0
      {
11433
0
                            if (prefix == NULL)
11434
0
          {
11435
0
        XP_TEST_HIT
11436
0
                            } else if ((cur->ns != NULL) &&
11437
0
        (xmlStrEqual(URI, cur->ns->href)))
11438
0
          {
11439
0
        XP_TEST_HIT
11440
0
                            }
11441
0
                        }
11442
0
                    } else if (axis == AXIS_NAMESPACE) {
11443
0
                        if (cur->type == XML_NAMESPACE_DECL)
11444
0
      {
11445
0
          XP_TEST_HIT_NS
11446
0
                        }
11447
0
                    } else {
11448
0
                        if (cur->type == XML_ELEMENT_NODE) {
11449
0
                            if (prefix == NULL)
11450
0
          {
11451
0
        XP_TEST_HIT
11452
11453
0
                            } else if ((cur->ns != NULL) &&
11454
0
        (xmlStrEqual(URI, cur->ns->href)))
11455
0
          {
11456
0
        XP_TEST_HIT
11457
0
                            }
11458
0
                        }
11459
0
                    }
11460
0
                    break;
11461
0
                case NODE_TEST_NS:{
11462
0
                        TODO;
11463
0
                        break;
11464
0
                    }
11465
0
                case NODE_TEST_NAME:
11466
0
                    if (axis == AXIS_ATTRIBUTE) {
11467
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
11468
0
          break;
11469
0
        } else if (axis == AXIS_NAMESPACE) {
11470
0
                        if (cur->type != XML_NAMESPACE_DECL)
11471
0
          break;
11472
0
        } else {
11473
0
            if (cur->type != XML_ELEMENT_NODE)
11474
0
          break;
11475
0
        }
11476
0
                    switch (cur->type) {
11477
0
                        case XML_ELEMENT_NODE:
11478
0
                            if (xmlStrEqual(name, cur->name)) {
11479
0
                                if (prefix == NULL) {
11480
0
                                    if (cur->ns == NULL)
11481
0
            {
11482
0
          XP_TEST_HIT
11483
0
                                    }
11484
0
                                } else {
11485
0
                                    if ((cur->ns != NULL) &&
11486
0
                                        (xmlStrEqual(URI, cur->ns->href)))
11487
0
            {
11488
0
          XP_TEST_HIT
11489
0
                                    }
11490
0
                                }
11491
0
                            }
11492
0
                            break;
11493
0
                        case XML_ATTRIBUTE_NODE:{
11494
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
11495
11496
0
                                if (xmlStrEqual(name, attr->name)) {
11497
0
                                    if (prefix == NULL) {
11498
0
                                        if ((attr->ns == NULL) ||
11499
0
                                            (attr->ns->prefix == NULL))
11500
0
          {
11501
0
              XP_TEST_HIT
11502
0
                                        }
11503
0
                                    } else {
11504
0
                                        if ((attr->ns != NULL) &&
11505
0
                                            (xmlStrEqual(URI,
11506
0
                attr->ns->href)))
11507
0
          {
11508
0
              XP_TEST_HIT
11509
0
                                        }
11510
0
                                    }
11511
0
                                }
11512
0
                                break;
11513
0
                            }
11514
0
                        case XML_NAMESPACE_DECL:
11515
0
                            if (cur->type == XML_NAMESPACE_DECL) {
11516
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
11517
11518
0
                                if ((ns->prefix != NULL) && (name != NULL)
11519
0
                                    && (xmlStrEqual(ns->prefix, name)))
11520
0
        {
11521
0
            XP_TEST_HIT_NS
11522
0
                                }
11523
0
                            }
11524
0
                            break;
11525
0
                        default:
11526
0
                            break;
11527
0
                    }
11528
0
                    break;
11529
0
      } /* switch(test) */
11530
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11531
11532
0
  goto apply_predicates;
11533
11534
0
axis_range_end: /* ----------------------------------------------------- */
11535
  /*
11536
  * We have a "/foo[n]", and position() = n was reached.
11537
  * Note that we can have as well "/foo/::parent::foo[1]", so
11538
  * a duplicate-aware merge is still needed.
11539
  * Merge with the result.
11540
  */
11541
0
  if (outSeq == NULL) {
11542
0
      outSeq = seq;
11543
0
      seq = NULL;
11544
0
  } else
11545
            /* TODO: Check memory error. */
11546
0
      outSeq = mergeAndClear(outSeq, seq);
11547
  /*
11548
  * Break if only a true/false result was requested.
11549
  */
11550
0
  if (toBool)
11551
0
      break;
11552
0
  continue;
11553
11554
0
first_hit: /* ---------------------------------------------------------- */
11555
  /*
11556
  * Break if only a true/false result was requested and
11557
  * no predicates existed and a node test succeeded.
11558
  */
11559
0
  if (outSeq == NULL) {
11560
0
      outSeq = seq;
11561
0
      seq = NULL;
11562
0
  } else
11563
            /* TODO: Check memory error. */
11564
0
      outSeq = mergeAndClear(outSeq, seq);
11565
0
  break;
11566
11567
0
apply_predicates: /* --------------------------------------------------- */
11568
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
11569
0
      goto error;
11570
11571
        /*
11572
  * Apply predicates.
11573
  */
11574
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
11575
      /*
11576
      * E.g. when we have a "/foo[some expression][n]".
11577
      */
11578
      /*
11579
      * QUESTION TODO: The old predicate evaluation took into
11580
      *  account location-sets.
11581
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11582
      *  Do we expect such a set here?
11583
      *  All what I learned now from the evaluation semantics
11584
      *  does not indicate that a location-set will be processed
11585
      *  here, so this looks OK.
11586
      */
11587
      /*
11588
      * Iterate over all predicates, starting with the outermost
11589
      * predicate.
11590
      * TODO: Problem: we cannot execute the inner predicates first
11591
      *  since we cannot go back *up* the operator tree!
11592
      *  Options we have:
11593
      *  1) Use of recursive functions (like is it currently done
11594
      *     via xmlXPathCompOpEval())
11595
      *  2) Add a predicate evaluation information stack to the
11596
      *     context struct
11597
      *  3) Change the way the operators are linked; we need a
11598
      *     "parent" field on xmlXPathStepOp
11599
      *
11600
      * For the moment, I'll try to solve this with a recursive
11601
      * function: xmlXPathCompOpEvalPredicate().
11602
      */
11603
0
      if (hasPredicateRange != 0)
11604
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11605
0
              hasNsNodes);
11606
0
      else
11607
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11608
0
              hasNsNodes);
11609
11610
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
11611
0
    total = 0;
11612
0
    goto error;
11613
0
      }
11614
0
        }
11615
11616
0
        if (seq->nodeNr > 0) {
11617
      /*
11618
      * Add to result set.
11619
      */
11620
0
      if (outSeq == NULL) {
11621
0
    outSeq = seq;
11622
0
    seq = NULL;
11623
0
      } else {
11624
                /* TODO: Check memory error. */
11625
0
    outSeq = mergeAndClear(outSeq, seq);
11626
0
      }
11627
11628
0
            if (toBool)
11629
0
                break;
11630
0
  }
11631
0
    }
11632
11633
0
error:
11634
0
    if ((obj->boolval) && (obj->user != NULL)) {
11635
  /*
11636
  * QUESTION TODO: What does this do and why?
11637
  * TODO: Do we have to do this also for the "error"
11638
  * cleanup further down?
11639
  */
11640
0
  ctxt->value->boolval = 1;
11641
0
  ctxt->value->user = obj->user;
11642
0
  obj->user = NULL;
11643
0
  obj->boolval = 0;
11644
0
    }
11645
0
    xmlXPathReleaseObject(xpctxt, obj);
11646
11647
    /*
11648
    * Ensure we return at least an empty set.
11649
    */
11650
0
    if (outSeq == NULL) {
11651
0
  if ((seq != NULL) && (seq->nodeNr == 0))
11652
0
      outSeq = seq;
11653
0
  else
11654
            /* TODO: Check memory error. */
11655
0
      outSeq = xmlXPathNodeSetCreate(NULL);
11656
0
    }
11657
0
    if ((seq != NULL) && (seq != outSeq)) {
11658
0
   xmlXPathFreeNodeSet(seq);
11659
0
    }
11660
    /*
11661
    * Hand over the result. Better to push the set also in
11662
    * case of errors.
11663
    */
11664
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
11665
    /*
11666
    * Reset the context node.
11667
    */
11668
0
    xpctxt->node = oldContextNode;
11669
    /*
11670
    * When traversing the namespace axis in "toBool" mode, it's
11671
    * possible that tmpNsList wasn't freed.
11672
    */
11673
0
    if (xpctxt->tmpNsList != NULL) {
11674
0
        xmlFree(xpctxt->tmpNsList);
11675
0
        xpctxt->tmpNsList = NULL;
11676
0
    }
11677
11678
0
    return(total);
11679
0
}
11680
11681
static int
11682
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11683
            xmlXPathStepOpPtr op, xmlNodePtr * first);
11684
11685
/**
11686
 * xmlXPathCompOpEvalFirst:
11687
 * @ctxt:  the XPath parser context with the compiled expression
11688
 * @op:  an XPath compiled operation
11689
 * @first:  the first elem found so far
11690
 *
11691
 * Evaluate the Precompiled XPath operation searching only the first
11692
 * element in document order
11693
 *
11694
 * Returns the number of examined objects.
11695
 */
11696
static int
11697
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11698
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
11699
0
{
11700
0
    int total = 0, cur;
11701
0
    xmlXPathCompExprPtr comp;
11702
0
    xmlXPathObjectPtr arg1, arg2;
11703
11704
0
    CHECK_ERROR0;
11705
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11706
0
        return(0);
11707
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11708
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11709
0
    ctxt->context->depth += 1;
11710
0
    comp = ctxt->comp;
11711
0
    switch (op->op) {
11712
0
        case XPATH_OP_END:
11713
0
            break;
11714
0
        case XPATH_OP_UNION:
11715
0
            total =
11716
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11717
0
                                        first);
11718
0
      CHECK_ERROR0;
11719
0
            if ((ctxt->value != NULL)
11720
0
                && (ctxt->value->type == XPATH_NODESET)
11721
0
                && (ctxt->value->nodesetval != NULL)
11722
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
11723
                /*
11724
                 * limit tree traversing to first node in the result
11725
                 */
11726
    /*
11727
    * OPTIMIZE TODO: This implicitly sorts
11728
    *  the result, even if not needed. E.g. if the argument
11729
    *  of the count() function, no sorting is needed.
11730
    * OPTIMIZE TODO: How do we know if the node-list wasn't
11731
    *  already sorted?
11732
    */
11733
0
    if (ctxt->value->nodesetval->nodeNr > 1)
11734
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
11735
0
                *first = ctxt->value->nodesetval->nodeTab[0];
11736
0
            }
11737
0
            cur =
11738
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11739
0
                                        first);
11740
0
      CHECK_ERROR0;
11741
11742
0
            arg2 = valuePop(ctxt);
11743
0
            arg1 = valuePop(ctxt);
11744
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11745
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11746
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11747
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11748
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11749
0
            }
11750
0
            if ((ctxt->context->opLimit != 0) &&
11751
0
                (((arg1->nodesetval != NULL) &&
11752
0
                  (xmlXPathCheckOpLimit(ctxt,
11753
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11754
0
                 ((arg2->nodesetval != NULL) &&
11755
0
                  (xmlXPathCheckOpLimit(ctxt,
11756
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11757
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11758
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11759
0
                break;
11760
0
            }
11761
11762
            /* TODO: Check memory error. */
11763
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11764
0
                                                    arg2->nodesetval);
11765
0
            valuePush(ctxt, arg1);
11766
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11767
            /* optimizer */
11768
0
      if (total > cur)
11769
0
    xmlXPathCompSwap(op);
11770
0
            total += cur;
11771
0
            break;
11772
0
        case XPATH_OP_ROOT:
11773
0
            xmlXPathRoot(ctxt);
11774
0
            break;
11775
0
        case XPATH_OP_NODE:
11776
0
            if (op->ch1 != -1)
11777
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11778
0
      CHECK_ERROR0;
11779
0
            if (op->ch2 != -1)
11780
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11781
0
      CHECK_ERROR0;
11782
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11783
0
    ctxt->context->node));
11784
0
            break;
11785
0
        case XPATH_OP_COLLECT:{
11786
0
                if (op->ch1 == -1)
11787
0
                    break;
11788
11789
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11790
0
    CHECK_ERROR0;
11791
11792
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11793
0
                break;
11794
0
            }
11795
0
        case XPATH_OP_VALUE:
11796
0
            valuePush(ctxt,
11797
0
                      xmlXPathCacheObjectCopy(ctxt->context,
11798
0
      (xmlXPathObjectPtr) op->value4));
11799
0
            break;
11800
0
        case XPATH_OP_SORT:
11801
0
            if (op->ch1 != -1)
11802
0
                total +=
11803
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11804
0
                                            first);
11805
0
      CHECK_ERROR0;
11806
0
            if ((ctxt->value != NULL)
11807
0
                && (ctxt->value->type == XPATH_NODESET)
11808
0
                && (ctxt->value->nodesetval != NULL)
11809
0
    && (ctxt->value->nodesetval->nodeNr > 1))
11810
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11811
0
            break;
11812
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
11813
0
  case XPATH_OP_FILTER:
11814
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11815
0
            break;
11816
0
#endif
11817
0
        default:
11818
0
            total += xmlXPathCompOpEval(ctxt, op);
11819
0
            break;
11820
0
    }
11821
11822
0
    ctxt->context->depth -= 1;
11823
0
    return(total);
11824
0
}
11825
11826
/**
11827
 * xmlXPathCompOpEvalLast:
11828
 * @ctxt:  the XPath parser context with the compiled expression
11829
 * @op:  an XPath compiled operation
11830
 * @last:  the last elem found so far
11831
 *
11832
 * Evaluate the Precompiled XPath operation searching only the last
11833
 * element in document order
11834
 *
11835
 * Returns the number of nodes traversed
11836
 */
11837
static int
11838
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11839
                       xmlNodePtr * last)
11840
0
{
11841
0
    int total = 0, cur;
11842
0
    xmlXPathCompExprPtr comp;
11843
0
    xmlXPathObjectPtr arg1, arg2;
11844
11845
0
    CHECK_ERROR0;
11846
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11847
0
        return(0);
11848
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11849
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11850
0
    ctxt->context->depth += 1;
11851
0
    comp = ctxt->comp;
11852
0
    switch (op->op) {
11853
0
        case XPATH_OP_END:
11854
0
            break;
11855
0
        case XPATH_OP_UNION:
11856
0
            total =
11857
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11858
0
      CHECK_ERROR0;
11859
0
            if ((ctxt->value != NULL)
11860
0
                && (ctxt->value->type == XPATH_NODESET)
11861
0
                && (ctxt->value->nodesetval != NULL)
11862
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
11863
                /*
11864
                 * limit tree traversing to first node in the result
11865
                 */
11866
0
    if (ctxt->value->nodesetval->nodeNr > 1)
11867
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
11868
0
                *last =
11869
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
11870
0
                                                     nodesetval->nodeNr -
11871
0
                                                     1];
11872
0
            }
11873
0
            cur =
11874
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11875
0
      CHECK_ERROR0;
11876
0
            if ((ctxt->value != NULL)
11877
0
                && (ctxt->value->type == XPATH_NODESET)
11878
0
                && (ctxt->value->nodesetval != NULL)
11879
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11880
0
            }
11881
11882
0
            arg2 = valuePop(ctxt);
11883
0
            arg1 = valuePop(ctxt);
11884
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11885
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11886
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11887
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11888
0
                XP_ERROR0(XPATH_INVALID_TYPE);
11889
0
            }
11890
0
            if ((ctxt->context->opLimit != 0) &&
11891
0
                (((arg1->nodesetval != NULL) &&
11892
0
                  (xmlXPathCheckOpLimit(ctxt,
11893
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
11894
0
                 ((arg2->nodesetval != NULL) &&
11895
0
                  (xmlXPathCheckOpLimit(ctxt,
11896
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
11897
0
          xmlXPathReleaseObject(ctxt->context, arg1);
11898
0
          xmlXPathReleaseObject(ctxt->context, arg2);
11899
0
                break;
11900
0
            }
11901
11902
            /* TODO: Check memory error. */
11903
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11904
0
                                                    arg2->nodesetval);
11905
0
            valuePush(ctxt, arg1);
11906
0
      xmlXPathReleaseObject(ctxt->context, arg2);
11907
            /* optimizer */
11908
0
      if (total > cur)
11909
0
    xmlXPathCompSwap(op);
11910
0
            total += cur;
11911
0
            break;
11912
0
        case XPATH_OP_ROOT:
11913
0
            xmlXPathRoot(ctxt);
11914
0
            break;
11915
0
        case XPATH_OP_NODE:
11916
0
            if (op->ch1 != -1)
11917
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11918
0
      CHECK_ERROR0;
11919
0
            if (op->ch2 != -1)
11920
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11921
0
      CHECK_ERROR0;
11922
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11923
0
    ctxt->context->node));
11924
0
            break;
11925
0
        case XPATH_OP_COLLECT:{
11926
0
                if (op->ch1 == -1)
11927
0
                    break;
11928
11929
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11930
0
    CHECK_ERROR0;
11931
11932
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11933
0
                break;
11934
0
            }
11935
0
        case XPATH_OP_VALUE:
11936
0
            valuePush(ctxt,
11937
0
                      xmlXPathCacheObjectCopy(ctxt->context,
11938
0
      (xmlXPathObjectPtr) op->value4));
11939
0
            break;
11940
0
        case XPATH_OP_SORT:
11941
0
            if (op->ch1 != -1)
11942
0
                total +=
11943
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11944
0
                                           last);
11945
0
      CHECK_ERROR0;
11946
0
            if ((ctxt->value != NULL)
11947
0
                && (ctxt->value->type == XPATH_NODESET)
11948
0
                && (ctxt->value->nodesetval != NULL)
11949
0
    && (ctxt->value->nodesetval->nodeNr > 1))
11950
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11951
0
            break;
11952
0
        default:
11953
0
            total += xmlXPathCompOpEval(ctxt, op);
11954
0
            break;
11955
0
    }
11956
11957
0
    ctxt->context->depth -= 1;
11958
0
    return (total);
11959
0
}
11960
11961
#ifdef XP_OPTIMIZED_FILTER_FIRST
11962
static int
11963
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11964
            xmlXPathStepOpPtr op, xmlNodePtr * first)
11965
0
{
11966
0
    int total = 0;
11967
0
    xmlXPathCompExprPtr comp;
11968
0
    xmlXPathObjectPtr obj;
11969
0
    xmlNodeSetPtr set;
11970
11971
0
    CHECK_ERROR0;
11972
0
    comp = ctxt->comp;
11973
    /*
11974
    * Optimization for ()[last()] selection i.e. the last elem
11975
    */
11976
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
11977
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11978
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11979
0
  int f = comp->steps[op->ch2].ch1;
11980
11981
0
  if ((f != -1) &&
11982
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11983
0
      (comp->steps[f].value5 == NULL) &&
11984
0
      (comp->steps[f].value == 0) &&
11985
0
      (comp->steps[f].value4 != NULL) &&
11986
0
      (xmlStrEqual
11987
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
11988
0
      xmlNodePtr last = NULL;
11989
11990
0
      total +=
11991
0
    xmlXPathCompOpEvalLast(ctxt,
11992
0
        &comp->steps[op->ch1],
11993
0
        &last);
11994
0
      CHECK_ERROR0;
11995
      /*
11996
      * The nodeset should be in document order,
11997
      * Keep only the last value
11998
      */
11999
0
      if ((ctxt->value != NULL) &&
12000
0
    (ctxt->value->type == XPATH_NODESET) &&
12001
0
    (ctxt->value->nodesetval != NULL) &&
12002
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12003
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
12004
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12005
0
    *first = *(ctxt->value->nodesetval->nodeTab);
12006
0
      }
12007
0
      return (total);
12008
0
  }
12009
0
    }
12010
12011
0
    if (op->ch1 != -1)
12012
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12013
0
    CHECK_ERROR0;
12014
0
    if (op->ch2 == -1)
12015
0
  return (total);
12016
0
    if (ctxt->value == NULL)
12017
0
  return (total);
12018
12019
#ifdef LIBXML_XPTR_LOCS_ENABLED
12020
    /*
12021
    * Hum are we filtering the result of an XPointer expression
12022
    */
12023
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12024
        xmlLocationSetPtr locset = ctxt->value->user;
12025
12026
        if (locset != NULL) {
12027
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12028
            if (locset->locNr > 0)
12029
                *first = (xmlNodePtr) locset->locTab[0]->user;
12030
        }
12031
12032
  return (total);
12033
    }
12034
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12035
12036
    /*
12037
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12038
     * the stack. We have to temporarily remove the nodeset object from the
12039
     * stack to avoid freeing it prematurely.
12040
     */
12041
0
    CHECK_TYPE0(XPATH_NODESET);
12042
0
    obj = valuePop(ctxt);
12043
0
    set = obj->nodesetval;
12044
0
    if (set != NULL) {
12045
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12046
0
        if (set->nodeNr > 0)
12047
0
            *first = set->nodeTab[0];
12048
0
    }
12049
0
    valuePush(ctxt, obj);
12050
12051
0
    return (total);
12052
0
}
12053
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12054
12055
/**
12056
 * xmlXPathCompOpEval:
12057
 * @ctxt:  the XPath parser context with the compiled expression
12058
 * @op:  an XPath compiled operation
12059
 *
12060
 * Evaluate the Precompiled XPath operation
12061
 * Returns the number of nodes traversed
12062
 */
12063
static int
12064
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12065
0
{
12066
0
    int total = 0;
12067
0
    int equal, ret;
12068
0
    xmlXPathCompExprPtr comp;
12069
0
    xmlXPathObjectPtr arg1, arg2;
12070
12071
0
    CHECK_ERROR0;
12072
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12073
0
        return(0);
12074
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12075
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12076
0
    ctxt->context->depth += 1;
12077
0
    comp = ctxt->comp;
12078
0
    switch (op->op) {
12079
0
        case XPATH_OP_END:
12080
0
            break;
12081
0
        case XPATH_OP_AND:
12082
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12083
0
      CHECK_ERROR0;
12084
0
            xmlXPathBooleanFunction(ctxt, 1);
12085
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12086
0
                break;
12087
0
            arg2 = valuePop(ctxt);
12088
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12089
0
      if (ctxt->error) {
12090
0
    xmlXPathFreeObject(arg2);
12091
0
    break;
12092
0
      }
12093
0
            xmlXPathBooleanFunction(ctxt, 1);
12094
0
            if (ctxt->value != NULL)
12095
0
                ctxt->value->boolval &= arg2->boolval;
12096
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12097
0
            break;
12098
0
        case XPATH_OP_OR:
12099
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12100
0
      CHECK_ERROR0;
12101
0
            xmlXPathBooleanFunction(ctxt, 1);
12102
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12103
0
                break;
12104
0
            arg2 = valuePop(ctxt);
12105
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12106
0
      if (ctxt->error) {
12107
0
    xmlXPathFreeObject(arg2);
12108
0
    break;
12109
0
      }
12110
0
            xmlXPathBooleanFunction(ctxt, 1);
12111
0
            if (ctxt->value != NULL)
12112
0
                ctxt->value->boolval |= arg2->boolval;
12113
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12114
0
            break;
12115
0
        case XPATH_OP_EQUAL:
12116
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12117
0
      CHECK_ERROR0;
12118
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12119
0
      CHECK_ERROR0;
12120
0
      if (op->value)
12121
0
    equal = xmlXPathEqualValues(ctxt);
12122
0
      else
12123
0
    equal = xmlXPathNotEqualValues(ctxt);
12124
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12125
0
            break;
12126
0
        case XPATH_OP_CMP:
12127
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12128
0
      CHECK_ERROR0;
12129
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12130
0
      CHECK_ERROR0;
12131
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
12132
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
12133
0
            break;
12134
0
        case XPATH_OP_PLUS:
12135
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12136
0
      CHECK_ERROR0;
12137
0
            if (op->ch2 != -1) {
12138
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12139
0
      }
12140
0
      CHECK_ERROR0;
12141
0
            if (op->value == 0)
12142
0
                xmlXPathSubValues(ctxt);
12143
0
            else if (op->value == 1)
12144
0
                xmlXPathAddValues(ctxt);
12145
0
            else if (op->value == 2)
12146
0
                xmlXPathValueFlipSign(ctxt);
12147
0
            else if (op->value == 3) {
12148
0
                CAST_TO_NUMBER;
12149
0
                CHECK_TYPE0(XPATH_NUMBER);
12150
0
            }
12151
0
            break;
12152
0
        case XPATH_OP_MULT:
12153
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12154
0
      CHECK_ERROR0;
12155
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12156
0
      CHECK_ERROR0;
12157
0
            if (op->value == 0)
12158
0
                xmlXPathMultValues(ctxt);
12159
0
            else if (op->value == 1)
12160
0
                xmlXPathDivValues(ctxt);
12161
0
            else if (op->value == 2)
12162
0
                xmlXPathModValues(ctxt);
12163
0
            break;
12164
0
        case XPATH_OP_UNION:
12165
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12166
0
      CHECK_ERROR0;
12167
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12168
0
      CHECK_ERROR0;
12169
12170
0
            arg2 = valuePop(ctxt);
12171
0
            arg1 = valuePop(ctxt);
12172
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12173
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12174
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12175
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12176
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12177
0
            }
12178
0
            if ((ctxt->context->opLimit != 0) &&
12179
0
                (((arg1->nodesetval != NULL) &&
12180
0
                  (xmlXPathCheckOpLimit(ctxt,
12181
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12182
0
                 ((arg2->nodesetval != NULL) &&
12183
0
                  (xmlXPathCheckOpLimit(ctxt,
12184
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12185
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12186
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12187
0
                break;
12188
0
            }
12189
12190
0
      if ((arg1->nodesetval == NULL) ||
12191
0
    ((arg2->nodesetval != NULL) &&
12192
0
     (arg2->nodesetval->nodeNr != 0)))
12193
0
      {
12194
                /* TODO: Check memory error. */
12195
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12196
0
              arg2->nodesetval);
12197
0
      }
12198
12199
0
            valuePush(ctxt, arg1);
12200
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12201
0
            break;
12202
0
        case XPATH_OP_ROOT:
12203
0
            xmlXPathRoot(ctxt);
12204
0
            break;
12205
0
        case XPATH_OP_NODE:
12206
0
            if (op->ch1 != -1)
12207
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12208
0
      CHECK_ERROR0;
12209
0
            if (op->ch2 != -1)
12210
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12211
0
      CHECK_ERROR0;
12212
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12213
0
    ctxt->context->node));
12214
0
            break;
12215
0
        case XPATH_OP_COLLECT:{
12216
0
                if (op->ch1 == -1)
12217
0
                    break;
12218
12219
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12220
0
    CHECK_ERROR0;
12221
12222
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
12223
0
                break;
12224
0
            }
12225
0
        case XPATH_OP_VALUE:
12226
0
            valuePush(ctxt,
12227
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12228
0
      (xmlXPathObjectPtr) op->value4));
12229
0
            break;
12230
0
        case XPATH_OP_VARIABLE:{
12231
0
    xmlXPathObjectPtr val;
12232
12233
0
                if (op->ch1 != -1)
12234
0
                    total +=
12235
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12236
0
                if (op->value5 == NULL) {
12237
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
12238
0
        if (val == NULL)
12239
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
12240
0
                    valuePush(ctxt, val);
12241
0
    } else {
12242
0
                    const xmlChar *URI;
12243
12244
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
12245
0
                    if (URI == NULL) {
12246
0
                        xmlGenericError(xmlGenericErrorContext,
12247
0
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
12248
0
                                    (char *) op->value4, (char *)op->value5);
12249
0
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
12250
0
                        break;
12251
0
                    }
12252
0
        val = xmlXPathVariableLookupNS(ctxt->context,
12253
0
                                                       op->value4, URI);
12254
0
        if (val == NULL)
12255
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
12256
0
                    valuePush(ctxt, val);
12257
0
                }
12258
0
                break;
12259
0
            }
12260
0
        case XPATH_OP_FUNCTION:{
12261
0
                xmlXPathFunction func;
12262
0
                const xmlChar *oldFunc, *oldFuncURI;
12263
0
    int i;
12264
0
                int frame;
12265
12266
0
                frame = ctxt->valueNr;
12267
0
                if (op->ch1 != -1) {
12268
0
                    total +=
12269
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12270
0
                    if (ctxt->error != XPATH_EXPRESSION_OK)
12271
0
                        break;
12272
0
                }
12273
0
    if (ctxt->valueNr < frame + op->value) {
12274
0
        xmlGenericError(xmlGenericErrorContext,
12275
0
          "xmlXPathCompOpEval: parameter error\n");
12276
0
        ctxt->error = XPATH_INVALID_OPERAND;
12277
0
        break;
12278
0
    }
12279
0
    for (i = 0; i < op->value; i++) {
12280
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
12281
0
      xmlGenericError(xmlGenericErrorContext,
12282
0
        "xmlXPathCompOpEval: parameter error\n");
12283
0
      ctxt->error = XPATH_INVALID_OPERAND;
12284
0
      break;
12285
0
        }
12286
0
                }
12287
0
                if (op->cache != NULL)
12288
0
                    func = op->cache;
12289
0
                else {
12290
0
                    const xmlChar *URI = NULL;
12291
12292
0
                    if (op->value5 == NULL)
12293
0
                        func =
12294
0
                            xmlXPathFunctionLookup(ctxt->context,
12295
0
                                                   op->value4);
12296
0
                    else {
12297
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
12298
0
                        if (URI == NULL) {
12299
0
                            xmlGenericError(xmlGenericErrorContext,
12300
0
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
12301
0
                                    (char *)op->value4, (char *)op->value5);
12302
0
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
12303
0
                            break;
12304
0
                        }
12305
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
12306
0
                                                        op->value4, URI);
12307
0
                    }
12308
0
                    if (func == NULL) {
12309
0
                        xmlGenericError(xmlGenericErrorContext,
12310
0
                                "xmlXPathCompOpEval: function %s not found\n",
12311
0
                                        (char *)op->value4);
12312
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12313
0
                    }
12314
0
                    op->cache = func;
12315
0
                    op->cacheURI = (void *) URI;
12316
0
                }
12317
0
                oldFunc = ctxt->context->function;
12318
0
                oldFuncURI = ctxt->context->functionURI;
12319
0
                ctxt->context->function = op->value4;
12320
0
                ctxt->context->functionURI = op->cacheURI;
12321
0
                func(ctxt, op->value);
12322
0
                ctxt->context->function = oldFunc;
12323
0
                ctxt->context->functionURI = oldFuncURI;
12324
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12325
0
                    (ctxt->valueNr != frame + 1))
12326
0
                    XP_ERROR0(XPATH_STACK_ERROR);
12327
0
                break;
12328
0
            }
12329
0
        case XPATH_OP_ARG:
12330
0
            if (op->ch1 != -1) {
12331
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12332
0
          CHECK_ERROR0;
12333
0
            }
12334
0
            if (op->ch2 != -1) {
12335
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12336
0
          CHECK_ERROR0;
12337
0
      }
12338
0
            break;
12339
0
        case XPATH_OP_PREDICATE:
12340
0
        case XPATH_OP_FILTER:{
12341
0
                xmlXPathObjectPtr obj;
12342
0
                xmlNodeSetPtr set;
12343
12344
                /*
12345
                 * Optimization for ()[1] selection i.e. the first elem
12346
                 */
12347
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
12348
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12349
        /*
12350
        * FILTER TODO: Can we assume that the inner processing
12351
        *  will result in an ordered list if we have an
12352
        *  XPATH_OP_FILTER?
12353
        *  What about an additional field or flag on
12354
        *  xmlXPathObject like @sorted ? This way we wouldn't need
12355
        *  to assume anything, so it would be more robust and
12356
        *  easier to optimize.
12357
        */
12358
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12359
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12360
#else
12361
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12362
#endif
12363
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12364
0
                    xmlXPathObjectPtr val;
12365
12366
0
                    val = comp->steps[op->ch2].value4;
12367
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12368
0
                        (val->floatval == 1.0)) {
12369
0
                        xmlNodePtr first = NULL;
12370
12371
0
                        total +=
12372
0
                            xmlXPathCompOpEvalFirst(ctxt,
12373
0
                                                    &comp->steps[op->ch1],
12374
0
                                                    &first);
12375
0
      CHECK_ERROR0;
12376
                        /*
12377
                         * The nodeset should be in document order,
12378
                         * Keep only the first value
12379
                         */
12380
0
                        if ((ctxt->value != NULL) &&
12381
0
                            (ctxt->value->type == XPATH_NODESET) &&
12382
0
                            (ctxt->value->nodesetval != NULL) &&
12383
0
                            (ctxt->value->nodesetval->nodeNr > 1))
12384
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12385
0
                                                        1, 1);
12386
0
                        break;
12387
0
                    }
12388
0
                }
12389
                /*
12390
                 * Optimization for ()[last()] selection i.e. the last elem
12391
                 */
12392
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
12393
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12394
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12395
0
                    int f = comp->steps[op->ch2].ch1;
12396
12397
0
                    if ((f != -1) &&
12398
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12399
0
                        (comp->steps[f].value5 == NULL) &&
12400
0
                        (comp->steps[f].value == 0) &&
12401
0
                        (comp->steps[f].value4 != NULL) &&
12402
0
                        (xmlStrEqual
12403
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
12404
0
                        xmlNodePtr last = NULL;
12405
12406
0
                        total +=
12407
0
                            xmlXPathCompOpEvalLast(ctxt,
12408
0
                                                   &comp->steps[op->ch1],
12409
0
                                                   &last);
12410
0
      CHECK_ERROR0;
12411
                        /*
12412
                         * The nodeset should be in document order,
12413
                         * Keep only the last value
12414
                         */
12415
0
                        if ((ctxt->value != NULL) &&
12416
0
                            (ctxt->value->type == XPATH_NODESET) &&
12417
0
                            (ctxt->value->nodesetval != NULL) &&
12418
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
12419
0
                            (ctxt->value->nodesetval->nodeNr > 1))
12420
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12421
0
                        break;
12422
0
                    }
12423
0
                }
12424
    /*
12425
    * Process inner predicates first.
12426
    * Example "index[parent::book][1]":
12427
    * ...
12428
    *   PREDICATE   <-- we are here "[1]"
12429
    *     PREDICATE <-- process "[parent::book]" first
12430
    *       SORT
12431
    *         COLLECT  'parent' 'name' 'node' book
12432
    *           NODE
12433
    *     ELEM Object is a number : 1
12434
    */
12435
0
                if (op->ch1 != -1)
12436
0
                    total +=
12437
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12438
0
    CHECK_ERROR0;
12439
0
                if (op->ch2 == -1)
12440
0
                    break;
12441
0
                if (ctxt->value == NULL)
12442
0
                    break;
12443
12444
#ifdef LIBXML_XPTR_LOCS_ENABLED
12445
                /*
12446
                 * Hum are we filtering the result of an XPointer expression
12447
                 */
12448
                if (ctxt->value->type == XPATH_LOCATIONSET) {
12449
                    xmlLocationSetPtr locset = ctxt->value->user;
12450
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12451
                                              1, locset->locNr);
12452
                    break;
12453
                }
12454
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12455
12456
                /*
12457
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
12458
                 * nodes from the stack. We have to temporarily remove the
12459
                 * nodeset object from the stack to avoid freeing it
12460
                 * prematurely.
12461
                 */
12462
0
                CHECK_TYPE0(XPATH_NODESET);
12463
0
                obj = valuePop(ctxt);
12464
0
                set = obj->nodesetval;
12465
0
                if (set != NULL)
12466
0
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12467
0
                                          1, set->nodeNr, 1);
12468
0
                valuePush(ctxt, obj);
12469
0
                break;
12470
0
            }
12471
0
        case XPATH_OP_SORT:
12472
0
            if (op->ch1 != -1)
12473
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12474
0
      CHECK_ERROR0;
12475
0
            if ((ctxt->value != NULL) &&
12476
0
                (ctxt->value->type == XPATH_NODESET) &&
12477
0
                (ctxt->value->nodesetval != NULL) &&
12478
0
    (ctxt->value->nodesetval->nodeNr > 1))
12479
0
      {
12480
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12481
0
      }
12482
0
            break;
12483
#ifdef LIBXML_XPTR_LOCS_ENABLED
12484
        case XPATH_OP_RANGETO:{
12485
                xmlXPathObjectPtr range;
12486
                xmlXPathObjectPtr res, obj;
12487
                xmlXPathObjectPtr tmp;
12488
                xmlLocationSetPtr newlocset = NULL;
12489
        xmlLocationSetPtr oldlocset;
12490
                xmlNodeSetPtr oldset;
12491
                xmlNodePtr oldnode = ctxt->context->node;
12492
                int oldcs = ctxt->context->contextSize;
12493
                int oldpp = ctxt->context->proximityPosition;
12494
                int i, j;
12495
12496
                if (op->ch1 != -1) {
12497
                    total +=
12498
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12499
                    CHECK_ERROR0;
12500
                }
12501
                if (ctxt->value == NULL) {
12502
                    XP_ERROR0(XPATH_INVALID_OPERAND);
12503
                }
12504
                if (op->ch2 == -1)
12505
                    break;
12506
12507
                if (ctxt->value->type == XPATH_LOCATIONSET) {
12508
                    /*
12509
                     * Extract the old locset, and then evaluate the result of the
12510
                     * expression for all the element in the locset. use it to grow
12511
                     * up a new locset.
12512
                     */
12513
                    CHECK_TYPE0(XPATH_LOCATIONSET);
12514
12515
                    if ((ctxt->value->user == NULL) ||
12516
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12517
                        break;
12518
12519
                    obj = valuePop(ctxt);
12520
                    oldlocset = obj->user;
12521
12522
                    newlocset = xmlXPtrLocationSetCreate(NULL);
12523
12524
                    for (i = 0; i < oldlocset->locNr; i++) {
12525
                        /*
12526
                         * Run the evaluation with a node list made of a
12527
                         * single item in the nodelocset.
12528
                         */
12529
                        ctxt->context->node = oldlocset->locTab[i]->user;
12530
                        ctxt->context->contextSize = oldlocset->locNr;
12531
                        ctxt->context->proximityPosition = i + 1;
12532
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12533
          ctxt->context->node);
12534
                        valuePush(ctxt, tmp);
12535
12536
                        if (op->ch2 != -1)
12537
                            total +=
12538
                                xmlXPathCompOpEval(ctxt,
12539
                                                   &comp->steps[op->ch2]);
12540
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12541
                            xmlXPtrFreeLocationSet(newlocset);
12542
                            goto rangeto_error;
12543
      }
12544
12545
                        res = valuePop(ctxt);
12546
      if (res->type == XPATH_LOCATIONSET) {
12547
          xmlLocationSetPtr rloc =
12548
              (xmlLocationSetPtr)res->user;
12549
          for (j=0; j<rloc->locNr; j++) {
12550
              range = xmlXPtrNewRange(
12551
          oldlocset->locTab[i]->user,
12552
          oldlocset->locTab[i]->index,
12553
          rloc->locTab[j]->user2,
12554
          rloc->locTab[j]->index2);
12555
        if (range != NULL) {
12556
            xmlXPtrLocationSetAdd(newlocset, range);
12557
        }
12558
          }
12559
      } else {
12560
          range = xmlXPtrNewRangeNodeObject(
12561
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
12562
                            if (range != NULL) {
12563
                                xmlXPtrLocationSetAdd(newlocset,range);
12564
          }
12565
                        }
12566
12567
                        /*
12568
                         * Cleanup
12569
                         */
12570
                        if (res != NULL) {
12571
          xmlXPathReleaseObject(ctxt->context, res);
12572
      }
12573
                        if (ctxt->value == tmp) {
12574
                            res = valuePop(ctxt);
12575
          xmlXPathReleaseObject(ctxt->context, res);
12576
                        }
12577
                    }
12578
    } else {  /* Not a location set */
12579
                    CHECK_TYPE0(XPATH_NODESET);
12580
                    obj = valuePop(ctxt);
12581
                    oldset = obj->nodesetval;
12582
12583
                    newlocset = xmlXPtrLocationSetCreate(NULL);
12584
12585
                    if (oldset != NULL) {
12586
                        for (i = 0; i < oldset->nodeNr; i++) {
12587
                            /*
12588
                             * Run the evaluation with a node list made of a single item
12589
                             * in the nodeset.
12590
                             */
12591
                            ctxt->context->node = oldset->nodeTab[i];
12592
          /*
12593
          * OPTIMIZE TODO: Avoid recreation for every iteration.
12594
          */
12595
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12596
        ctxt->context->node);
12597
                            valuePush(ctxt, tmp);
12598
12599
                            if (op->ch2 != -1)
12600
                                total +=
12601
                                    xmlXPathCompOpEval(ctxt,
12602
                                                   &comp->steps[op->ch2]);
12603
          if (ctxt->error != XPATH_EXPRESSION_OK) {
12604
                                xmlXPtrFreeLocationSet(newlocset);
12605
                                goto rangeto_error;
12606
          }
12607
12608
                            res = valuePop(ctxt);
12609
                            range =
12610
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12611
                                                      res);
12612
                            if (range != NULL) {
12613
                                xmlXPtrLocationSetAdd(newlocset, range);
12614
                            }
12615
12616
                            /*
12617
                             * Cleanup
12618
                             */
12619
                            if (res != NULL) {
12620
        xmlXPathReleaseObject(ctxt->context, res);
12621
          }
12622
                            if (ctxt->value == tmp) {
12623
                                res = valuePop(ctxt);
12624
        xmlXPathReleaseObject(ctxt->context, res);
12625
                            }
12626
                        }
12627
                    }
12628
                }
12629
12630
                /*
12631
                 * The result is used as the new evaluation set.
12632
                 */
12633
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12634
rangeto_error:
12635
    xmlXPathReleaseObject(ctxt->context, obj);
12636
                ctxt->context->node = oldnode;
12637
                ctxt->context->contextSize = oldcs;
12638
                ctxt->context->proximityPosition = oldpp;
12639
                break;
12640
            }
12641
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12642
0
        default:
12643
0
            xmlGenericError(xmlGenericErrorContext,
12644
0
                            "XPath: unknown precompiled operation %d\n", op->op);
12645
0
            ctxt->error = XPATH_INVALID_OPERAND;
12646
0
            break;
12647
0
    }
12648
12649
0
    ctxt->context->depth -= 1;
12650
0
    return (total);
12651
0
}
12652
12653
/**
12654
 * xmlXPathCompOpEvalToBoolean:
12655
 * @ctxt:  the XPath parser context
12656
 *
12657
 * Evaluates if the expression evaluates to true.
12658
 *
12659
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
12660
 */
12661
static int
12662
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12663
          xmlXPathStepOpPtr op,
12664
          int isPredicate)
12665
0
{
12666
0
    xmlXPathObjectPtr resObj = NULL;
12667
12668
0
start:
12669
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12670
0
        return(0);
12671
    /* comp = ctxt->comp; */
12672
0
    switch (op->op) {
12673
0
        case XPATH_OP_END:
12674
0
            return (0);
12675
0
  case XPATH_OP_VALUE:
12676
0
      resObj = (xmlXPathObjectPtr) op->value4;
12677
0
      if (isPredicate)
12678
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12679
0
      return(xmlXPathCastToBoolean(resObj));
12680
0
  case XPATH_OP_SORT:
12681
      /*
12682
      * We don't need sorting for boolean results. Skip this one.
12683
      */
12684
0
            if (op->ch1 != -1) {
12685
0
    op = &ctxt->comp->steps[op->ch1];
12686
0
    goto start;
12687
0
      }
12688
0
      return(0);
12689
0
  case XPATH_OP_COLLECT:
12690
0
      if (op->ch1 == -1)
12691
0
    return(0);
12692
12693
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12694
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12695
0
    return(-1);
12696
12697
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12698
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12699
0
    return(-1);
12700
12701
0
      resObj = valuePop(ctxt);
12702
0
      if (resObj == NULL)
12703
0
    return(-1);
12704
0
      break;
12705
0
  default:
12706
      /*
12707
      * Fallback to call xmlXPathCompOpEval().
12708
      */
12709
0
      xmlXPathCompOpEval(ctxt, op);
12710
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
12711
0
    return(-1);
12712
12713
0
      resObj = valuePop(ctxt);
12714
0
      if (resObj == NULL)
12715
0
    return(-1);
12716
0
      break;
12717
0
    }
12718
12719
0
    if (resObj) {
12720
0
  int res;
12721
12722
0
  if (resObj->type == XPATH_BOOLEAN) {
12723
0
      res = resObj->boolval;
12724
0
  } else if (isPredicate) {
12725
      /*
12726
      * For predicates a result of type "number" is handled
12727
      * differently:
12728
      * SPEC XPath 1.0:
12729
      * "If the result is a number, the result will be converted
12730
      *  to true if the number is equal to the context position
12731
      *  and will be converted to false otherwise;"
12732
      */
12733
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12734
0
  } else {
12735
0
      res = xmlXPathCastToBoolean(resObj);
12736
0
  }
12737
0
  xmlXPathReleaseObject(ctxt->context, resObj);
12738
0
  return(res);
12739
0
    }
12740
12741
0
    return(0);
12742
0
}
12743
12744
#ifdef XPATH_STREAMING
12745
/**
12746
 * xmlXPathRunStreamEval:
12747
 * @ctxt:  the XPath parser context with the compiled expression
12748
 *
12749
 * Evaluate the Precompiled Streamable XPath expression in the given context.
12750
 */
12751
static int
12752
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
12753
          xmlXPathObjectPtr *resultSeq, int toBool)
12754
0
{
12755
0
    int max_depth, min_depth;
12756
0
    int from_root;
12757
0
    int ret, depth;
12758
0
    int eval_all_nodes;
12759
0
    xmlNodePtr cur = NULL, limit = NULL;
12760
0
    xmlStreamCtxtPtr patstream = NULL;
12761
12762
0
    if ((ctxt == NULL) || (comp == NULL))
12763
0
        return(-1);
12764
0
    max_depth = xmlPatternMaxDepth(comp);
12765
0
    if (max_depth == -1)
12766
0
        return(-1);
12767
0
    if (max_depth == -2)
12768
0
        max_depth = 10000;
12769
0
    min_depth = xmlPatternMinDepth(comp);
12770
0
    if (min_depth == -1)
12771
0
        return(-1);
12772
0
    from_root = xmlPatternFromRoot(comp);
12773
0
    if (from_root < 0)
12774
0
        return(-1);
12775
#if 0
12776
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12777
#endif
12778
12779
0
    if (! toBool) {
12780
0
  if (resultSeq == NULL)
12781
0
      return(-1);
12782
0
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
12783
0
  if (*resultSeq == NULL)
12784
0
      return(-1);
12785
0
    }
12786
12787
    /*
12788
     * handle the special cases of "/" amd "." being matched
12789
     */
12790
0
    if (min_depth == 0) {
12791
0
  if (from_root) {
12792
      /* Select "/" */
12793
0
      if (toBool)
12794
0
    return(1);
12795
            /* TODO: Check memory error. */
12796
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12797
0
                         (xmlNodePtr) ctxt->doc);
12798
0
  } else {
12799
      /* Select "self::node()" */
12800
0
      if (toBool)
12801
0
    return(1);
12802
            /* TODO: Check memory error. */
12803
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
12804
0
  }
12805
0
    }
12806
0
    if (max_depth == 0) {
12807
0
  return(0);
12808
0
    }
12809
12810
0
    if (from_root) {
12811
0
        cur = (xmlNodePtr)ctxt->doc;
12812
0
    } else if (ctxt->node != NULL) {
12813
0
        switch (ctxt->node->type) {
12814
0
            case XML_ELEMENT_NODE:
12815
0
            case XML_DOCUMENT_NODE:
12816
0
            case XML_DOCUMENT_FRAG_NODE:
12817
0
            case XML_HTML_DOCUMENT_NODE:
12818
0
          cur = ctxt->node;
12819
0
    break;
12820
0
            case XML_ATTRIBUTE_NODE:
12821
0
            case XML_TEXT_NODE:
12822
0
            case XML_CDATA_SECTION_NODE:
12823
0
            case XML_ENTITY_REF_NODE:
12824
0
            case XML_ENTITY_NODE:
12825
0
            case XML_PI_NODE:
12826
0
            case XML_COMMENT_NODE:
12827
0
            case XML_NOTATION_NODE:
12828
0
            case XML_DTD_NODE:
12829
0
            case XML_DOCUMENT_TYPE_NODE:
12830
0
            case XML_ELEMENT_DECL:
12831
0
            case XML_ATTRIBUTE_DECL:
12832
0
            case XML_ENTITY_DECL:
12833
0
            case XML_NAMESPACE_DECL:
12834
0
            case XML_XINCLUDE_START:
12835
0
            case XML_XINCLUDE_END:
12836
0
    break;
12837
0
  }
12838
0
  limit = cur;
12839
0
    }
12840
0
    if (cur == NULL) {
12841
0
        return(0);
12842
0
    }
12843
12844
0
    patstream = xmlPatternGetStreamCtxt(comp);
12845
0
    if (patstream == NULL) {
12846
  /*
12847
  * QUESTION TODO: Is this an error?
12848
  */
12849
0
  return(0);
12850
0
    }
12851
12852
0
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12853
12854
0
    if (from_root) {
12855
0
  ret = xmlStreamPush(patstream, NULL, NULL);
12856
0
  if (ret < 0) {
12857
0
  } else if (ret == 1) {
12858
0
      if (toBool)
12859
0
    goto return_1;
12860
            /* TODO: Check memory error. */
12861
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
12862
0
  }
12863
0
    }
12864
0
    depth = 0;
12865
0
    goto scan_children;
12866
0
next_node:
12867
0
    do {
12868
0
        if (ctxt->opLimit != 0) {
12869
0
            if (ctxt->opCount >= ctxt->opLimit) {
12870
0
                xmlGenericError(xmlGenericErrorContext,
12871
0
                        "XPath operation limit exceeded\n");
12872
0
                xmlFreeStreamCtxt(patstream);
12873
0
                return(-1);
12874
0
            }
12875
0
            ctxt->opCount++;
12876
0
        }
12877
12878
0
  switch (cur->type) {
12879
0
      case XML_ELEMENT_NODE:
12880
0
      case XML_TEXT_NODE:
12881
0
      case XML_CDATA_SECTION_NODE:
12882
0
      case XML_COMMENT_NODE:
12883
0
      case XML_PI_NODE:
12884
0
    if (cur->type == XML_ELEMENT_NODE) {
12885
0
        ret = xmlStreamPush(patstream, cur->name,
12886
0
        (cur->ns ? cur->ns->href : NULL));
12887
0
    } else if (eval_all_nodes)
12888
0
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12889
0
    else
12890
0
        break;
12891
12892
0
    if (ret < 0) {
12893
        /* NOP. */
12894
0
    } else if (ret == 1) {
12895
0
        if (toBool)
12896
0
      goto return_1;
12897
0
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
12898
0
            < 0) {
12899
0
      ctxt->lastError.domain = XML_FROM_XPATH;
12900
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
12901
0
        }
12902
0
    }
12903
0
    if ((cur->children == NULL) || (depth >= max_depth)) {
12904
0
        ret = xmlStreamPop(patstream);
12905
0
        while (cur->next != NULL) {
12906
0
      cur = cur->next;
12907
0
      if ((cur->type != XML_ENTITY_DECL) &&
12908
0
          (cur->type != XML_DTD_NODE))
12909
0
          goto next_node;
12910
0
        }
12911
0
    }
12912
0
      default:
12913
0
    break;
12914
0
  }
12915
12916
0
scan_children:
12917
0
  if (cur->type == XML_NAMESPACE_DECL) break;
12918
0
  if ((cur->children != NULL) && (depth < max_depth)) {
12919
      /*
12920
       * Do not descend on entities declarations
12921
       */
12922
0
      if (cur->children->type != XML_ENTITY_DECL) {
12923
0
    cur = cur->children;
12924
0
    depth++;
12925
    /*
12926
     * Skip DTDs
12927
     */
12928
0
    if (cur->type != XML_DTD_NODE)
12929
0
        continue;
12930
0
      }
12931
0
  }
12932
12933
0
  if (cur == limit)
12934
0
      break;
12935
12936
0
  while (cur->next != NULL) {
12937
0
      cur = cur->next;
12938
0
      if ((cur->type != XML_ENTITY_DECL) &&
12939
0
    (cur->type != XML_DTD_NODE))
12940
0
    goto next_node;
12941
0
  }
12942
12943
0
  do {
12944
0
      cur = cur->parent;
12945
0
      depth--;
12946
0
      if ((cur == NULL) || (cur == limit) ||
12947
0
                (cur->type == XML_DOCUMENT_NODE))
12948
0
          goto done;
12949
0
      if (cur->type == XML_ELEMENT_NODE) {
12950
0
    ret = xmlStreamPop(patstream);
12951
0
      } else if ((eval_all_nodes) &&
12952
0
    ((cur->type == XML_TEXT_NODE) ||
12953
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
12954
0
     (cur->type == XML_COMMENT_NODE) ||
12955
0
     (cur->type == XML_PI_NODE)))
12956
0
      {
12957
0
    ret = xmlStreamPop(patstream);
12958
0
      }
12959
0
      if (cur->next != NULL) {
12960
0
    cur = cur->next;
12961
0
    break;
12962
0
      }
12963
0
  } while (cur != NULL);
12964
12965
0
    } while ((cur != NULL) && (depth >= 0));
12966
12967
0
done:
12968
12969
0
    if (patstream)
12970
0
  xmlFreeStreamCtxt(patstream);
12971
0
    return(0);
12972
12973
0
return_1:
12974
0
    if (patstream)
12975
0
  xmlFreeStreamCtxt(patstream);
12976
0
    return(1);
12977
0
}
12978
#endif /* XPATH_STREAMING */
12979
12980
/**
12981
 * xmlXPathRunEval:
12982
 * @ctxt:  the XPath parser context with the compiled expression
12983
 * @toBool:  evaluate to a boolean result
12984
 *
12985
 * Evaluate the Precompiled XPath expression in the given context.
12986
 */
12987
static int
12988
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12989
0
{
12990
0
    xmlXPathCompExprPtr comp;
12991
0
    int oldDepth;
12992
12993
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
12994
0
  return(-1);
12995
12996
0
    if (ctxt->valueTab == NULL) {
12997
  /* Allocate the value stack */
12998
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
12999
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13000
0
  if (ctxt->valueTab == NULL) {
13001
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13002
0
      return(-1);
13003
0
  }
13004
0
  ctxt->valueNr = 0;
13005
0
  ctxt->valueMax = 10;
13006
0
  ctxt->value = NULL;
13007
0
    }
13008
0
#ifdef XPATH_STREAMING
13009
0
    if (ctxt->comp->stream) {
13010
0
  int res;
13011
13012
0
  if (toBool) {
13013
      /*
13014
      * Evaluation to boolean result.
13015
      */
13016
0
      res = xmlXPathRunStreamEval(ctxt->context,
13017
0
    ctxt->comp->stream, NULL, 1);
13018
0
      if (res != -1)
13019
0
    return(res);
13020
0
  } else {
13021
0
      xmlXPathObjectPtr resObj = NULL;
13022
13023
      /*
13024
      * Evaluation to a sequence.
13025
      */
13026
0
      res = xmlXPathRunStreamEval(ctxt->context,
13027
0
    ctxt->comp->stream, &resObj, 0);
13028
13029
0
      if ((res != -1) && (resObj != NULL)) {
13030
0
    valuePush(ctxt, resObj);
13031
0
    return(0);
13032
0
      }
13033
0
      if (resObj != NULL)
13034
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13035
0
  }
13036
  /*
13037
  * QUESTION TODO: This falls back to normal XPath evaluation
13038
  * if res == -1. Is this intended?
13039
  */
13040
0
    }
13041
0
#endif
13042
0
    comp = ctxt->comp;
13043
0
    if (comp->last < 0) {
13044
0
  xmlGenericError(xmlGenericErrorContext,
13045
0
      "xmlXPathRunEval: last is less than zero\n");
13046
0
  return(-1);
13047
0
    }
13048
0
    oldDepth = ctxt->context->depth;
13049
0
    if (toBool)
13050
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13051
0
      &comp->steps[comp->last], 0));
13052
0
    else
13053
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13054
0
    ctxt->context->depth = oldDepth;
13055
13056
0
    return(0);
13057
0
}
13058
13059
/************************************************************************
13060
 *                  *
13061
 *      Public interfaces       *
13062
 *                  *
13063
 ************************************************************************/
13064
13065
/**
13066
 * xmlXPathEvalPredicate:
13067
 * @ctxt:  the XPath context
13068
 * @res:  the Predicate Expression evaluation result
13069
 *
13070
 * Evaluate a predicate result for the current node.
13071
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13072
 * the result to a boolean. If the result is a number, the result will
13073
 * be converted to true if the number is equal to the position of the
13074
 * context node in the context node list (as returned by the position
13075
 * function) and will be converted to false otherwise; if the result
13076
 * is not a number, then the result will be converted as if by a call
13077
 * to the boolean function.
13078
 *
13079
 * Returns 1 if predicate is true, 0 otherwise
13080
 */
13081
int
13082
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13083
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13084
0
    switch (res->type) {
13085
0
        case XPATH_BOOLEAN:
13086
0
      return(res->boolval);
13087
0
        case XPATH_NUMBER:
13088
0
      return(res->floatval == ctxt->proximityPosition);
13089
0
        case XPATH_NODESET:
13090
0
        case XPATH_XSLT_TREE:
13091
0
      if (res->nodesetval == NULL)
13092
0
    return(0);
13093
0
      return(res->nodesetval->nodeNr != 0);
13094
0
        case XPATH_STRING:
13095
0
      return((res->stringval != NULL) &&
13096
0
             (xmlStrlen(res->stringval) != 0));
13097
0
        default:
13098
0
      STRANGE
13099
0
    }
13100
0
    return(0);
13101
0
}
13102
13103
/**
13104
 * xmlXPathEvaluatePredicateResult:
13105
 * @ctxt:  the XPath Parser context
13106
 * @res:  the Predicate Expression evaluation result
13107
 *
13108
 * Evaluate a predicate result for the current node.
13109
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13110
 * the result to a boolean. If the result is a number, the result will
13111
 * be converted to true if the number is equal to the position of the
13112
 * context node in the context node list (as returned by the position
13113
 * function) and will be converted to false otherwise; if the result
13114
 * is not a number, then the result will be converted as if by a call
13115
 * to the boolean function.
13116
 *
13117
 * Returns 1 if predicate is true, 0 otherwise
13118
 */
13119
int
13120
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13121
0
                                xmlXPathObjectPtr res) {
13122
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13123
0
    switch (res->type) {
13124
0
        case XPATH_BOOLEAN:
13125
0
      return(res->boolval);
13126
0
        case XPATH_NUMBER:
13127
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
13128
      return((res->floatval == ctxt->context->proximityPosition) &&
13129
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
13130
#else
13131
0
      return(res->floatval == ctxt->context->proximityPosition);
13132
0
#endif
13133
0
        case XPATH_NODESET:
13134
0
        case XPATH_XSLT_TREE:
13135
0
      if (res->nodesetval == NULL)
13136
0
    return(0);
13137
0
      return(res->nodesetval->nodeNr != 0);
13138
0
        case XPATH_STRING:
13139
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
13140
#ifdef LIBXML_XPTR_LOCS_ENABLED
13141
  case XPATH_LOCATIONSET:{
13142
      xmlLocationSetPtr ptr = res->user;
13143
      if (ptr == NULL)
13144
          return(0);
13145
      return (ptr->locNr != 0);
13146
      }
13147
#endif
13148
0
        default:
13149
0
      STRANGE
13150
0
    }
13151
0
    return(0);
13152
0
}
13153
13154
#ifdef XPATH_STREAMING
13155
/**
13156
 * xmlXPathTryStreamCompile:
13157
 * @ctxt: an XPath context
13158
 * @str:  the XPath expression
13159
 *
13160
 * Try to compile the XPath expression as a streamable subset.
13161
 *
13162
 * Returns the compiled expression or NULL if failed to compile.
13163
 */
13164
static xmlXPathCompExprPtr
13165
0
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13166
    /*
13167
     * Optimization: use streaming patterns when the XPath expression can
13168
     * be compiled to a stream lookup
13169
     */
13170
0
    xmlPatternPtr stream;
13171
0
    xmlXPathCompExprPtr comp;
13172
0
    xmlDictPtr dict = NULL;
13173
0
    const xmlChar **namespaces = NULL;
13174
0
    xmlNsPtr ns;
13175
0
    int i, j;
13176
13177
0
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13178
0
        (!xmlStrchr(str, '@'))) {
13179
0
  const xmlChar *tmp;
13180
13181
  /*
13182
   * We don't try to handle expressions using the verbose axis
13183
   * specifiers ("::"), just the simplified form at this point.
13184
   * Additionally, if there is no list of namespaces available and
13185
   *  there's a ":" in the expression, indicating a prefixed QName,
13186
   *  then we won't try to compile either. xmlPatterncompile() needs
13187
   *  to have a list of namespaces at compilation time in order to
13188
   *  compile prefixed name tests.
13189
   */
13190
0
  tmp = xmlStrchr(str, ':');
13191
0
  if ((tmp != NULL) &&
13192
0
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13193
0
      return(NULL);
13194
13195
0
  if (ctxt != NULL) {
13196
0
      dict = ctxt->dict;
13197
0
      if (ctxt->nsNr > 0) {
13198
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
13199
0
    if (namespaces == NULL) {
13200
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
13201
0
        return(NULL);
13202
0
    }
13203
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
13204
0
        ns = ctxt->namespaces[j];
13205
0
        namespaces[i++] = ns->href;
13206
0
        namespaces[i++] = ns->prefix;
13207
0
    }
13208
0
    namespaces[i++] = NULL;
13209
0
    namespaces[i] = NULL;
13210
0
      }
13211
0
  }
13212
13213
0
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
13214
0
  if (namespaces != NULL) {
13215
0
      xmlFree((xmlChar **)namespaces);
13216
0
  }
13217
0
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
13218
0
      comp = xmlXPathNewCompExpr();
13219
0
      if (comp == NULL) {
13220
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
13221
0
          xmlFreePattern(stream);
13222
0
    return(NULL);
13223
0
      }
13224
0
      comp->stream = stream;
13225
0
      comp->dict = dict;
13226
0
      if (comp->dict)
13227
0
    xmlDictReference(comp->dict);
13228
0
      return(comp);
13229
0
  }
13230
0
  xmlFreePattern(stream);
13231
0
    }
13232
0
    return(NULL);
13233
0
}
13234
#endif /* XPATH_STREAMING */
13235
13236
static void
13237
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
13238
                           xmlXPathStepOpPtr op)
13239
0
{
13240
0
    xmlXPathCompExprPtr comp = pctxt->comp;
13241
0
    xmlXPathContextPtr ctxt;
13242
13243
    /*
13244
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
13245
    * internal representation.
13246
    */
13247
13248
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
13249
0
        (op->ch1 != -1) &&
13250
0
        (op->ch2 == -1 /* no predicate */))
13251
0
    {
13252
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
13253
13254
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
13255
0
            ((xmlXPathAxisVal) prevop->value ==
13256
0
                AXIS_DESCENDANT_OR_SELF) &&
13257
0
            (prevop->ch2 == -1) &&
13258
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
13259
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
13260
0
        {
13261
            /*
13262
            * This is a "descendant-or-self::node()" without predicates.
13263
            * Try to eliminate it.
13264
            */
13265
13266
0
            switch ((xmlXPathAxisVal) op->value) {
13267
0
                case AXIS_CHILD:
13268
0
                case AXIS_DESCENDANT:
13269
                    /*
13270
                    * Convert "descendant-or-self::node()/child::" or
13271
                    * "descendant-or-self::node()/descendant::" to
13272
                    * "descendant::"
13273
                    */
13274
0
                    op->ch1   = prevop->ch1;
13275
0
                    op->value = AXIS_DESCENDANT;
13276
0
                    break;
13277
0
                case AXIS_SELF:
13278
0
                case AXIS_DESCENDANT_OR_SELF:
13279
                    /*
13280
                    * Convert "descendant-or-self::node()/self::" or
13281
                    * "descendant-or-self::node()/descendant-or-self::" to
13282
                    * to "descendant-or-self::"
13283
                    */
13284
0
                    op->ch1   = prevop->ch1;
13285
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
13286
0
                    break;
13287
0
                default:
13288
0
                    break;
13289
0
            }
13290
0
  }
13291
0
    }
13292
13293
    /* OP_VALUE has invalid ch1. */
13294
0
    if (op->op == XPATH_OP_VALUE)
13295
0
        return;
13296
13297
    /* Recurse */
13298
0
    ctxt = pctxt->context;
13299
0
    if (ctxt != NULL) {
13300
0
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
13301
0
            return;
13302
0
        ctxt->depth += 1;
13303
0
    }
13304
0
    if (op->ch1 != -1)
13305
0
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
13306
0
    if (op->ch2 != -1)
13307
0
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
13308
0
    if (ctxt != NULL)
13309
0
        ctxt->depth -= 1;
13310
0
}
13311
13312
/**
13313
 * xmlXPathCtxtCompile:
13314
 * @ctxt: an XPath context
13315
 * @str:  the XPath expression
13316
 *
13317
 * Compile an XPath expression
13318
 *
13319
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13320
 *         the caller has to free the object.
13321
 */
13322
xmlXPathCompExprPtr
13323
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13324
0
    xmlXPathParserContextPtr pctxt;
13325
0
    xmlXPathCompExprPtr comp;
13326
0
    int oldDepth = 0;
13327
13328
0
#ifdef XPATH_STREAMING
13329
0
    comp = xmlXPathTryStreamCompile(ctxt, str);
13330
0
    if (comp != NULL)
13331
0
        return(comp);
13332
0
#endif
13333
13334
0
    xmlInitParser();
13335
13336
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
13337
0
    if (pctxt == NULL)
13338
0
        return NULL;
13339
0
    if (ctxt != NULL)
13340
0
        oldDepth = ctxt->depth;
13341
0
    xmlXPathCompileExpr(pctxt, 1);
13342
0
    if (ctxt != NULL)
13343
0
        ctxt->depth = oldDepth;
13344
13345
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
13346
0
    {
13347
0
        xmlXPathFreeParserContext(pctxt);
13348
0
        return(NULL);
13349
0
    }
13350
13351
0
    if (*pctxt->cur != 0) {
13352
  /*
13353
   * aleksey: in some cases this line prints *second* error message
13354
   * (see bug #78858) and probably this should be fixed.
13355
   * However, we are not sure that all error messages are printed
13356
   * out in other places. It's not critical so we leave it as-is for now
13357
   */
13358
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13359
0
  comp = NULL;
13360
0
    } else {
13361
0
  comp = pctxt->comp;
13362
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
13363
0
            if (ctxt != NULL)
13364
0
                oldDepth = ctxt->depth;
13365
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13366
0
            if (ctxt != NULL)
13367
0
                ctxt->depth = oldDepth;
13368
0
  }
13369
0
  pctxt->comp = NULL;
13370
0
    }
13371
0
    xmlXPathFreeParserContext(pctxt);
13372
13373
0
    if (comp != NULL) {
13374
0
  comp->expr = xmlStrdup(str);
13375
0
    }
13376
0
    return(comp);
13377
0
}
13378
13379
/**
13380
 * xmlXPathCompile:
13381
 * @str:  the XPath expression
13382
 *
13383
 * Compile an XPath expression
13384
 *
13385
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13386
 *         the caller has to free the object.
13387
 */
13388
xmlXPathCompExprPtr
13389
0
xmlXPathCompile(const xmlChar *str) {
13390
0
    return(xmlXPathCtxtCompile(NULL, str));
13391
0
}
13392
13393
/**
13394
 * xmlXPathCompiledEvalInternal:
13395
 * @comp:  the compiled XPath expression
13396
 * @ctxt:  the XPath context
13397
 * @resObj: the resulting XPath object or NULL
13398
 * @toBool: 1 if only a boolean result is requested
13399
 *
13400
 * Evaluate the Precompiled XPath expression in the given context.
13401
 * The caller has to free @resObj.
13402
 *
13403
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13404
 *         the caller has to free the object.
13405
 */
13406
static int
13407
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13408
           xmlXPathContextPtr ctxt,
13409
           xmlXPathObjectPtr *resObjPtr,
13410
           int toBool)
13411
0
{
13412
0
    xmlXPathParserContextPtr pctxt;
13413
0
    xmlXPathObjectPtr resObj;
13414
#ifndef LIBXML_THREAD_ENABLED
13415
    static int reentance = 0;
13416
#endif
13417
0
    int res;
13418
13419
0
    CHECK_CTXT_NEG(ctxt)
13420
13421
0
    if (comp == NULL)
13422
0
  return(-1);
13423
0
    xmlInitParser();
13424
13425
#ifndef LIBXML_THREAD_ENABLED
13426
    reentance++;
13427
    if (reentance > 1)
13428
  xmlXPathDisableOptimizer = 1;
13429
#endif
13430
13431
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
13432
0
    if (pctxt == NULL)
13433
0
        return(-1);
13434
0
    res = xmlXPathRunEval(pctxt, toBool);
13435
13436
0
    if (pctxt->error != XPATH_EXPRESSION_OK) {
13437
0
        resObj = NULL;
13438
0
    } else {
13439
0
        resObj = valuePop(pctxt);
13440
0
        if (resObj == NULL) {
13441
0
            if (!toBool)
13442
0
                xmlGenericError(xmlGenericErrorContext,
13443
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
13444
0
        } else if (pctxt->valueNr > 0) {
13445
0
            xmlGenericError(xmlGenericErrorContext,
13446
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
13447
0
                pctxt->valueNr);
13448
0
        }
13449
0
    }
13450
13451
0
    if (resObjPtr)
13452
0
        *resObjPtr = resObj;
13453
0
    else
13454
0
        xmlXPathReleaseObject(ctxt, resObj);
13455
13456
0
    pctxt->comp = NULL;
13457
0
    xmlXPathFreeParserContext(pctxt);
13458
#ifndef LIBXML_THREAD_ENABLED
13459
    reentance--;
13460
#endif
13461
13462
0
    return(res);
13463
0
}
13464
13465
/**
13466
 * xmlXPathCompiledEval:
13467
 * @comp:  the compiled XPath expression
13468
 * @ctx:  the XPath context
13469
 *
13470
 * Evaluate the Precompiled XPath expression in the given context.
13471
 *
13472
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13473
 *         the caller has to free the object.
13474
 */
13475
xmlXPathObjectPtr
13476
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13477
0
{
13478
0
    xmlXPathObjectPtr res = NULL;
13479
13480
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13481
0
    return(res);
13482
0
}
13483
13484
/**
13485
 * xmlXPathCompiledEvalToBoolean:
13486
 * @comp:  the compiled XPath expression
13487
 * @ctxt:  the XPath context
13488
 *
13489
 * Applies the XPath boolean() function on the result of the given
13490
 * compiled expression.
13491
 *
13492
 * Returns 1 if the expression evaluated to true, 0 if to false and
13493
 *         -1 in API and internal errors.
13494
 */
13495
int
13496
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13497
            xmlXPathContextPtr ctxt)
13498
0
{
13499
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13500
0
}
13501
13502
/**
13503
 * xmlXPathEvalExpr:
13504
 * @ctxt:  the XPath Parser context
13505
 *
13506
 * Parse and evaluate an XPath expression in the given context,
13507
 * then push the result on the context stack
13508
 */
13509
void
13510
0
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13511
0
#ifdef XPATH_STREAMING
13512
0
    xmlXPathCompExprPtr comp;
13513
0
#endif
13514
0
    int oldDepth = 0;
13515
13516
0
    if (ctxt == NULL) return;
13517
13518
0
#ifdef XPATH_STREAMING
13519
0
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13520
0
    if (comp != NULL) {
13521
0
        if (ctxt->comp != NULL)
13522
0
      xmlXPathFreeCompExpr(ctxt->comp);
13523
0
        ctxt->comp = comp;
13524
0
    } else
13525
0
#endif
13526
0
    {
13527
0
        if (ctxt->context != NULL)
13528
0
            oldDepth = ctxt->context->depth;
13529
0
  xmlXPathCompileExpr(ctxt, 1);
13530
0
        if (ctxt->context != NULL)
13531
0
            ctxt->context->depth = oldDepth;
13532
0
        CHECK_ERROR;
13533
13534
        /* Check for trailing characters. */
13535
0
        if (*ctxt->cur != 0)
13536
0
            XP_ERROR(XPATH_EXPR_ERROR);
13537
13538
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13539
0
            if (ctxt->context != NULL)
13540
0
                oldDepth = ctxt->context->depth;
13541
0
      xmlXPathOptimizeExpression(ctxt,
13542
0
    &ctxt->comp->steps[ctxt->comp->last]);
13543
0
            if (ctxt->context != NULL)
13544
0
                ctxt->context->depth = oldDepth;
13545
0
        }
13546
0
    }
13547
13548
0
    xmlXPathRunEval(ctxt, 0);
13549
0
}
13550
13551
/**
13552
 * xmlXPathEval:
13553
 * @str:  the XPath expression
13554
 * @ctx:  the XPath context
13555
 *
13556
 * Evaluate the XPath Location Path in the given context.
13557
 *
13558
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13559
 *         the caller has to free the object.
13560
 */
13561
xmlXPathObjectPtr
13562
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13563
0
    xmlXPathParserContextPtr ctxt;
13564
0
    xmlXPathObjectPtr res;
13565
13566
0
    CHECK_CTXT(ctx)
13567
13568
0
    xmlInitParser();
13569
13570
0
    ctxt = xmlXPathNewParserContext(str, ctx);
13571
0
    if (ctxt == NULL)
13572
0
        return NULL;
13573
0
    xmlXPathEvalExpr(ctxt);
13574
13575
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
13576
0
  res = NULL;
13577
0
    } else {
13578
0
  res = valuePop(ctxt);
13579
0
        if (res == NULL) {
13580
0
            xmlGenericError(xmlGenericErrorContext,
13581
0
                "xmlXPathCompiledEval: No result on the stack.\n");
13582
0
        } else if (ctxt->valueNr > 0) {
13583
0
            xmlGenericError(xmlGenericErrorContext,
13584
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
13585
0
                ctxt->valueNr);
13586
0
        }
13587
0
    }
13588
13589
0
    xmlXPathFreeParserContext(ctxt);
13590
0
    return(res);
13591
0
}
13592
13593
/**
13594
 * xmlXPathSetContextNode:
13595
 * @node: the node to to use as the context node
13596
 * @ctx:  the XPath context
13597
 *
13598
 * Sets 'node' as the context node. The node must be in the same
13599
 * document as that associated with the context.
13600
 *
13601
 * Returns -1 in case of error or 0 if successful
13602
 */
13603
int
13604
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13605
0
    if ((node == NULL) || (ctx == NULL))
13606
0
        return(-1);
13607
13608
0
    if (node->doc == ctx->doc) {
13609
0
        ctx->node = node;
13610
0
  return(0);
13611
0
    }
13612
0
    return(-1);
13613
0
}
13614
13615
/**
13616
 * xmlXPathNodeEval:
13617
 * @node: the node to to use as the context node
13618
 * @str:  the XPath expression
13619
 * @ctx:  the XPath context
13620
 *
13621
 * Evaluate the XPath Location Path in the given context. The node 'node'
13622
 * is set as the context node. The context node is not restored.
13623
 *
13624
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13625
 *         the caller has to free the object.
13626
 */
13627
xmlXPathObjectPtr
13628
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13629
0
    if (str == NULL)
13630
0
        return(NULL);
13631
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
13632
0
        return(NULL);
13633
0
    return(xmlXPathEval(str, ctx));
13634
0
}
13635
13636
/**
13637
 * xmlXPathEvalExpression:
13638
 * @str:  the XPath expression
13639
 * @ctxt:  the XPath context
13640
 *
13641
 * Alias for xmlXPathEval().
13642
 *
13643
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13644
 *         the caller has to free the object.
13645
 */
13646
xmlXPathObjectPtr
13647
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13648
0
    return(xmlXPathEval(str, ctxt));
13649
0
}
13650
13651
/************************************************************************
13652
 *                  *
13653
 *  Extra functions not pertaining to the XPath spec    *
13654
 *                  *
13655
 ************************************************************************/
13656
/**
13657
 * xmlXPathEscapeUriFunction:
13658
 * @ctxt:  the XPath Parser context
13659
 * @nargs:  the number of arguments
13660
 *
13661
 * Implement the escape-uri() XPath function
13662
 *    string escape-uri(string $str, bool $escape-reserved)
13663
 *
13664
 * This function applies the URI escaping rules defined in section 2 of [RFC
13665
 * 2396] to the string supplied as $uri-part, which typically represents all
13666
 * or part of a URI. The effect of the function is to replace any special
13667
 * character in the string by an escape sequence of the form %xx%yy...,
13668
 * where xxyy... is the hexadecimal representation of the octets used to
13669
 * represent the character in UTF-8.
13670
 *
13671
 * The set of characters that are escaped depends on the setting of the
13672
 * boolean argument $escape-reserved.
13673
 *
13674
 * If $escape-reserved is true, all characters are escaped other than lower
13675
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13676
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13677
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13678
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13679
 * A-F).
13680
 *
13681
 * If $escape-reserved is false, the behavior differs in that characters
13682
 * referred to in [RFC 2396] as reserved characters are not escaped. These
13683
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13684
 *
13685
 * [RFC 2396] does not define whether escaped URIs should use lower case or
13686
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
13687
 * compared using string comparison functions, this function must always use
13688
 * the upper-case letters A-F.
13689
 *
13690
 * Generally, $escape-reserved should be set to true when escaping a string
13691
 * that is to form a single part of a URI, and to false when escaping an
13692
 * entire URI or URI reference.
13693
 *
13694
 * In the case of non-ascii characters, the string is encoded according to
13695
 * utf-8 and then converted according to RFC 2396.
13696
 *
13697
 * Examples
13698
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13699
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13700
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13701
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13702
 *
13703
 */
13704
static void
13705
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13706
0
    xmlXPathObjectPtr str;
13707
0
    int escape_reserved;
13708
0
    xmlBufPtr target;
13709
0
    xmlChar *cptr;
13710
0
    xmlChar escape[4];
13711
13712
0
    CHECK_ARITY(2);
13713
13714
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
13715
13716
0
    CAST_TO_STRING;
13717
0
    str = valuePop(ctxt);
13718
13719
0
    target = xmlBufCreate();
13720
13721
0
    escape[0] = '%';
13722
0
    escape[3] = 0;
13723
13724
0
    if (target) {
13725
0
  for (cptr = str->stringval; *cptr; cptr++) {
13726
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
13727
0
    (*cptr >= 'a' && *cptr <= 'z') ||
13728
0
    (*cptr >= '0' && *cptr <= '9') ||
13729
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
13730
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
13731
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13732
0
    (*cptr == '%' &&
13733
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13734
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
13735
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
13736
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13737
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
13738
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
13739
0
    (!escape_reserved &&
13740
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13741
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
13742
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
13743
0
      *cptr == ','))) {
13744
0
    xmlBufAdd(target, cptr, 1);
13745
0
      } else {
13746
0
    if ((*cptr >> 4) < 10)
13747
0
        escape[1] = '0' + (*cptr >> 4);
13748
0
    else
13749
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
13750
0
    if ((*cptr & 0xF) < 10)
13751
0
        escape[2] = '0' + (*cptr & 0xF);
13752
0
    else
13753
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
13754
13755
0
    xmlBufAdd(target, &escape[0], 3);
13756
0
      }
13757
0
  }
13758
0
    }
13759
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
13760
0
  xmlBufContent(target)));
13761
0
    xmlBufFree(target);
13762
0
    xmlXPathReleaseObject(ctxt->context, str);
13763
0
}
13764
13765
/**
13766
 * xmlXPathRegisterAllFunctions:
13767
 * @ctxt:  the XPath context
13768
 *
13769
 * Registers all default XPath functions in this context
13770
 */
13771
void
13772
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13773
0
{
13774
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13775
0
                         xmlXPathBooleanFunction);
13776
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13777
0
                         xmlXPathCeilingFunction);
13778
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13779
0
                         xmlXPathCountFunction);
13780
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13781
0
                         xmlXPathConcatFunction);
13782
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13783
0
                         xmlXPathContainsFunction);
13784
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13785
0
                         xmlXPathIdFunction);
13786
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13787
0
                         xmlXPathFalseFunction);
13788
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13789
0
                         xmlXPathFloorFunction);
13790
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13791
0
                         xmlXPathLastFunction);
13792
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13793
0
                         xmlXPathLangFunction);
13794
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13795
0
                         xmlXPathLocalNameFunction);
13796
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13797
0
                         xmlXPathNotFunction);
13798
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13799
0
                         xmlXPathNameFunction);
13800
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13801
0
                         xmlXPathNamespaceURIFunction);
13802
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13803
0
                         xmlXPathNormalizeFunction);
13804
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13805
0
                         xmlXPathNumberFunction);
13806
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13807
0
                         xmlXPathPositionFunction);
13808
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13809
0
                         xmlXPathRoundFunction);
13810
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13811
0
                         xmlXPathStringFunction);
13812
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13813
0
                         xmlXPathStringLengthFunction);
13814
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13815
0
                         xmlXPathStartsWithFunction);
13816
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13817
0
                         xmlXPathSubstringFunction);
13818
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13819
0
                         xmlXPathSubstringBeforeFunction);
13820
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13821
0
                         xmlXPathSubstringAfterFunction);
13822
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13823
0
                         xmlXPathSumFunction);
13824
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13825
0
                         xmlXPathTrueFunction);
13826
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13827
0
                         xmlXPathTranslateFunction);
13828
13829
0
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13830
0
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13831
0
                         xmlXPathEscapeUriFunction);
13832
0
}
13833
13834
#endif /* LIBXML_XPATH_ENABLED */