Coverage Report

Created: 2023-09-25 06:03

/src/libxml2-2.11.5/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/valid.h>
35
#include <libxml/xpath.h>
36
#include <libxml/xpathInternals.h>
37
#include <libxml/parserInternals.h>
38
#include <libxml/hash.h>
39
#ifdef LIBXML_XPTR_LOCS_ENABLED
40
#include <libxml/xpointer.h>
41
#endif
42
#ifdef LIBXML_DEBUG_ENABLED
43
#include <libxml/debugXML.h>
44
#endif
45
#include <libxml/xmlerror.h>
46
#include <libxml/threads.h>
47
#include <libxml/globals.h>
48
#ifdef LIBXML_PATTERN_ENABLED
49
#include <libxml/pattern.h>
50
#endif
51
52
#include "private/buf.h"
53
#include "private/error.h"
54
#include "private/xpath.h"
55
56
#ifdef LIBXML_PATTERN_ENABLED
57
#define XPATH_STREAMING
58
#endif
59
60
#define TODO                \
61
0
    xmlGenericError(xmlGenericErrorContext,       \
62
0
      "Unimplemented block at %s:%d\n",       \
63
0
            __FILE__, __LINE__);
64
65
/**
66
 * WITH_TIM_SORT:
67
 *
68
 * Use the Timsort algorithm provided in timsort.h to sort
69
 * nodeset as this is a great improvement over the old Shell sort
70
 * used in xmlXPathNodeSetSort()
71
 */
72
#define WITH_TIM_SORT
73
74
/*
75
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
76
* If defined, this will use xmlXPathCmpNodesExt() instead of
77
* xmlXPathCmpNodes(). The new function is optimized comparison of
78
* non-element nodes; actually it will speed up comparison only if
79
* xmlXPathOrderDocElems() was called in order to index the elements of
80
* a tree in document order; Libxslt does such an indexing, thus it will
81
* benefit from this optimization.
82
*/
83
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
84
85
/*
86
* XP_OPTIMIZED_FILTER_FIRST:
87
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
88
* in a way, that it stop evaluation at the first node.
89
*/
90
#define XP_OPTIMIZED_FILTER_FIRST
91
92
/*
93
* XP_DEBUG_OBJ_USAGE:
94
* Internal flag to enable tracking of how much XPath objects have been
95
* created.
96
*/
97
/* #define XP_DEBUG_OBJ_USAGE */
98
99
/*
100
 * XPATH_MAX_STEPS:
101
 * when compiling an XPath expression we arbitrary limit the maximum
102
 * number of step operation in the compiled expression. 1000000 is
103
 * an insanely large value which should never be reached under normal
104
 * circumstances
105
 */
106
0
#define XPATH_MAX_STEPS 1000000
107
108
/*
109
 * XPATH_MAX_STACK_DEPTH:
110
 * when evaluating an XPath expression we arbitrary limit the maximum
111
 * number of object allowed to be pushed on the stack. 1000000 is
112
 * an insanely large value which should never be reached under normal
113
 * circumstances
114
 */
115
0
#define XPATH_MAX_STACK_DEPTH 1000000
116
117
/*
118
 * XPATH_MAX_NODESET_LENGTH:
119
 * when evaluating an XPath expression nodesets are created and we
120
 * arbitrary limit the maximum length of those node set. 10000000 is
121
 * an insanely large value which should never be reached under normal
122
 * circumstances, one would first need to construct an in memory tree
123
 * with more than 10 millions nodes.
124
 */
125
0
#define XPATH_MAX_NODESET_LENGTH 10000000
126
127
/*
128
 * XPATH_MAX_RECRUSION_DEPTH:
129
 * Maximum amount of nested functions calls when parsing or evaluating
130
 * expressions
131
 */
132
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
133
0
#define XPATH_MAX_RECURSION_DEPTH 500
134
#elif defined(_WIN32)
135
/* Windows typically limits stack size to 1MB. */
136
#define XPATH_MAX_RECURSION_DEPTH 1000
137
#else
138
#define XPATH_MAX_RECURSION_DEPTH 5000
139
#endif
140
141
/*
142
 * TODO:
143
 * There are a few spots where some tests are done which depend upon ascii
144
 * data.  These should be enhanced for full UTF8 support (see particularly
145
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
146
 */
147
148
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
149
150
/************************************************************************
151
 *                  *
152
 *      Floating point stuff        *
153
 *                  *
154
 ************************************************************************/
155
156
double xmlXPathNAN = 0.0;
157
double xmlXPathPINF = 0.0;
158
double xmlXPathNINF = 0.0;
159
160
/**
161
 * xmlXPathInit:
162
 *
163
 * DEPRECATED: Alias for xmlInitParser.
164
 */
165
void
166
0
xmlXPathInit(void) {
167
0
    xmlInitParser();
168
0
}
169
170
/**
171
 * xmlInitXPathInternal:
172
 *
173
 * Initialize the XPath environment
174
 */
175
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
176
void
177
1
xmlInitXPathInternal(void) {
178
1
#if defined(NAN) && defined(INFINITY)
179
1
    xmlXPathNAN = NAN;
180
1
    xmlXPathPINF = INFINITY;
181
1
    xmlXPathNINF = -INFINITY;
182
#else
183
    /* MSVC doesn't allow division by zero in constant expressions. */
184
    double zero = 0.0;
185
    xmlXPathNAN = 0.0 / zero;
186
    xmlXPathPINF = 1.0 / zero;
187
    xmlXPathNINF = -xmlXPathPINF;
188
#endif
189
1
}
190
191
/**
192
 * xmlXPathIsNaN:
193
 * @val:  a double value
194
 *
195
 * Returns 1 if the value is a NaN, 0 otherwise
196
 */
197
int
198
0
xmlXPathIsNaN(double val) {
199
0
#ifdef isnan
200
0
    return isnan(val);
201
#else
202
    return !(val == val);
203
#endif
204
0
}
205
206
/**
207
 * xmlXPathIsInf:
208
 * @val:  a double value
209
 *
210
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
211
 */
212
int
213
0
xmlXPathIsInf(double val) {
214
0
#ifdef isinf
215
0
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
216
#else
217
    if (val >= xmlXPathPINF)
218
        return 1;
219
    if (val <= -xmlXPathPINF)
220
        return -1;
221
    return 0;
222
#endif
223
0
}
224
225
#endif /* SCHEMAS or XPATH */
226
227
#ifdef LIBXML_XPATH_ENABLED
228
229
/*
230
 * TODO: when compatibility allows remove all "fake node libxslt" strings
231
 *       the test should just be name[0] = ' '
232
 */
233
#ifdef DEBUG_XPATH_EXPRESSION
234
#define DEBUG_STEP
235
#define DEBUG_EXPR
236
#define DEBUG_EVAL_COUNTS
237
#endif
238
239
static xmlNs xmlXPathXMLNamespaceStruct = {
240
    NULL,
241
    XML_NAMESPACE_DECL,
242
    XML_XML_NAMESPACE,
243
    BAD_CAST "xml",
244
    NULL,
245
    NULL
246
};
247
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
248
#ifndef LIBXML_THREAD_ENABLED
249
/*
250
 * Optimizer is disabled only when threaded apps are detected while
251
 * the library ain't compiled for thread safety.
252
 */
253
static int xmlXPathDisableOptimizer = 0;
254
#endif
255
256
static void
257
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
258
259
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
260
/**
261
 * xmlXPathCmpNodesExt:
262
 * @node1:  the first node
263
 * @node2:  the second node
264
 *
265
 * Compare two nodes w.r.t document order.
266
 * This one is optimized for handling of non-element nodes.
267
 *
268
 * Returns -2 in case of error 1 if first point < second point, 0 if
269
 *         it's the same node, -1 otherwise
270
 */
271
static int
272
0
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
273
0
    int depth1, depth2;
274
0
    int misc = 0, precedence1 = 0, precedence2 = 0;
275
0
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
276
0
    xmlNodePtr cur, root;
277
0
    ptrdiff_t l1, l2;
278
279
0
    if ((node1 == NULL) || (node2 == NULL))
280
0
  return(-2);
281
282
0
    if (node1 == node2)
283
0
  return(0);
284
285
    /*
286
     * a couple of optimizations which will avoid computations in most cases
287
     */
288
0
    switch (node1->type) {
289
0
  case XML_ELEMENT_NODE:
290
0
      if (node2->type == XML_ELEMENT_NODE) {
291
0
    if ((0 > (ptrdiff_t) node1->content) &&
292
0
        (0 > (ptrdiff_t) node2->content) &&
293
0
        (node1->doc == node2->doc))
294
0
    {
295
0
        l1 = -((ptrdiff_t) node1->content);
296
0
        l2 = -((ptrdiff_t) node2->content);
297
0
        if (l1 < l2)
298
0
      return(1);
299
0
        if (l1 > l2)
300
0
      return(-1);
301
0
    } else
302
0
        goto turtle_comparison;
303
0
      }
304
0
      break;
305
0
  case XML_ATTRIBUTE_NODE:
306
0
      precedence1 = 1; /* element is owner */
307
0
      miscNode1 = node1;
308
0
      node1 = node1->parent;
309
0
      misc = 1;
310
0
      break;
311
0
  case XML_TEXT_NODE:
312
0
  case XML_CDATA_SECTION_NODE:
313
0
  case XML_COMMENT_NODE:
314
0
  case XML_PI_NODE: {
315
0
      miscNode1 = node1;
316
      /*
317
      * Find nearest element node.
318
      */
319
0
      if (node1->prev != NULL) {
320
0
    do {
321
0
        node1 = node1->prev;
322
0
        if (node1->type == XML_ELEMENT_NODE) {
323
0
      precedence1 = 3; /* element in prev-sibl axis */
324
0
      break;
325
0
        }
326
0
        if (node1->prev == NULL) {
327
0
      precedence1 = 2; /* element is parent */
328
      /*
329
      * URGENT TODO: Are there any cases, where the
330
      * parent of such a node is not an element node?
331
      */
332
0
      node1 = node1->parent;
333
0
      break;
334
0
        }
335
0
    } while (1);
336
0
      } else {
337
0
    precedence1 = 2; /* element is parent */
338
0
    node1 = node1->parent;
339
0
      }
340
0
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
341
0
    (0 <= (ptrdiff_t) node1->content)) {
342
    /*
343
    * Fallback for whatever case.
344
    */
345
0
    node1 = miscNode1;
346
0
    precedence1 = 0;
347
0
      } else
348
0
    misc = 1;
349
0
  }
350
0
      break;
351
0
  case XML_NAMESPACE_DECL:
352
      /*
353
      * TODO: why do we return 1 for namespace nodes?
354
      */
355
0
      return(1);
356
0
  default:
357
0
      break;
358
0
    }
359
0
    switch (node2->type) {
360
0
  case XML_ELEMENT_NODE:
361
0
      break;
362
0
  case XML_ATTRIBUTE_NODE:
363
0
      precedence2 = 1; /* element is owner */
364
0
      miscNode2 = node2;
365
0
      node2 = node2->parent;
366
0
      misc = 1;
367
0
      break;
368
0
  case XML_TEXT_NODE:
369
0
  case XML_CDATA_SECTION_NODE:
370
0
  case XML_COMMENT_NODE:
371
0
  case XML_PI_NODE: {
372
0
      miscNode2 = node2;
373
0
      if (node2->prev != NULL) {
374
0
    do {
375
0
        node2 = node2->prev;
376
0
        if (node2->type == XML_ELEMENT_NODE) {
377
0
      precedence2 = 3; /* element in prev-sibl axis */
378
0
      break;
379
0
        }
380
0
        if (node2->prev == NULL) {
381
0
      precedence2 = 2; /* element is parent */
382
0
      node2 = node2->parent;
383
0
      break;
384
0
        }
385
0
    } while (1);
386
0
      } else {
387
0
    precedence2 = 2; /* element is parent */
388
0
    node2 = node2->parent;
389
0
      }
390
0
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
391
0
    (0 <= (ptrdiff_t) node2->content))
392
0
      {
393
0
    node2 = miscNode2;
394
0
    precedence2 = 0;
395
0
      } else
396
0
    misc = 1;
397
0
  }
398
0
      break;
399
0
  case XML_NAMESPACE_DECL:
400
0
      return(1);
401
0
  default:
402
0
      break;
403
0
    }
404
0
    if (misc) {
405
0
  if (node1 == node2) {
406
0
      if (precedence1 == precedence2) {
407
    /*
408
    * The ugly case; but normally there aren't many
409
    * adjacent non-element nodes around.
410
    */
411
0
    cur = miscNode2->prev;
412
0
    while (cur != NULL) {
413
0
        if (cur == miscNode1)
414
0
      return(1);
415
0
        if (cur->type == XML_ELEMENT_NODE)
416
0
      return(-1);
417
0
        cur = cur->prev;
418
0
    }
419
0
    return (-1);
420
0
      } else {
421
    /*
422
    * Evaluate based on higher precedence wrt to the element.
423
    * TODO: This assumes attributes are sorted before content.
424
    *   Is this 100% correct?
425
    */
426
0
    if (precedence1 < precedence2)
427
0
        return(1);
428
0
    else
429
0
        return(-1);
430
0
      }
431
0
  }
432
  /*
433
  * Special case: One of the helper-elements is contained by the other.
434
  * <foo>
435
  *   <node2>
436
  *     <node1>Text-1(precedence1 == 2)</node1>
437
  *   </node2>
438
  *   Text-6(precedence2 == 3)
439
  * </foo>
440
  */
441
0
  if ((precedence2 == 3) && (precedence1 > 1)) {
442
0
      cur = node1->parent;
443
0
      while (cur) {
444
0
    if (cur == node2)
445
0
        return(1);
446
0
    cur = cur->parent;
447
0
      }
448
0
  }
449
0
  if ((precedence1 == 3) && (precedence2 > 1)) {
450
0
      cur = node2->parent;
451
0
      while (cur) {
452
0
    if (cur == node1)
453
0
        return(-1);
454
0
    cur = cur->parent;
455
0
      }
456
0
  }
457
0
    }
458
459
    /*
460
     * Speedup using document order if available.
461
     */
462
0
    if ((node1->type == XML_ELEMENT_NODE) &&
463
0
  (node2->type == XML_ELEMENT_NODE) &&
464
0
  (0 > (ptrdiff_t) node1->content) &&
465
0
  (0 > (ptrdiff_t) node2->content) &&
466
0
  (node1->doc == node2->doc)) {
467
468
0
  l1 = -((ptrdiff_t) node1->content);
469
0
  l2 = -((ptrdiff_t) node2->content);
470
0
  if (l1 < l2)
471
0
      return(1);
472
0
  if (l1 > l2)
473
0
      return(-1);
474
0
    }
475
476
0
turtle_comparison:
477
478
0
    if (node1 == node2->prev)
479
0
  return(1);
480
0
    if (node1 == node2->next)
481
0
  return(-1);
482
    /*
483
     * compute depth to root
484
     */
485
0
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
486
0
  if (cur->parent == node1)
487
0
      return(1);
488
0
  depth2++;
489
0
    }
490
0
    root = cur;
491
0
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
492
0
  if (cur->parent == node2)
493
0
      return(-1);
494
0
  depth1++;
495
0
    }
496
    /*
497
     * Distinct document (or distinct entities :-( ) case.
498
     */
499
0
    if (root != cur) {
500
0
  return(-2);
501
0
    }
502
    /*
503
     * get the nearest common ancestor.
504
     */
505
0
    while (depth1 > depth2) {
506
0
  depth1--;
507
0
  node1 = node1->parent;
508
0
    }
509
0
    while (depth2 > depth1) {
510
0
  depth2--;
511
0
  node2 = node2->parent;
512
0
    }
513
0
    while (node1->parent != node2->parent) {
514
0
  node1 = node1->parent;
515
0
  node2 = node2->parent;
516
  /* should not happen but just in case ... */
517
0
  if ((node1 == NULL) || (node2 == NULL))
518
0
      return(-2);
519
0
    }
520
    /*
521
     * Find who's first.
522
     */
523
0
    if (node1 == node2->prev)
524
0
  return(1);
525
0
    if (node1 == node2->next)
526
0
  return(-1);
527
    /*
528
     * Speedup using document order if available.
529
     */
530
0
    if ((node1->type == XML_ELEMENT_NODE) &&
531
0
  (node2->type == XML_ELEMENT_NODE) &&
532
0
  (0 > (ptrdiff_t) node1->content) &&
533
0
  (0 > (ptrdiff_t) node2->content) &&
534
0
  (node1->doc == node2->doc)) {
535
536
0
  l1 = -((ptrdiff_t) node1->content);
537
0
  l2 = -((ptrdiff_t) node2->content);
538
0
  if (l1 < l2)
539
0
      return(1);
540
0
  if (l1 > l2)
541
0
      return(-1);
542
0
    }
543
544
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
545
0
  if (cur == node2)
546
0
      return(1);
547
0
    return(-1); /* assume there is no sibling list corruption */
548
0
}
549
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
550
551
/*
552
 * Wrapper for the Timsort algorithm from timsort.h
553
 */
554
#ifdef WITH_TIM_SORT
555
#define SORT_NAME libxml_domnode
556
0
#define SORT_TYPE xmlNodePtr
557
/**
558
 * wrap_cmp:
559
 * @x: a node
560
 * @y: another node
561
 *
562
 * Comparison function for the Timsort implementation
563
 *
564
 * Returns -2 in case of error -1 if first point < second point, 0 if
565
 *         it's the same node, +1 otherwise
566
 */
567
static
568
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
569
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
570
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
571
0
    {
572
0
        int res = xmlXPathCmpNodesExt(x, y);
573
0
        return res == -2 ? res : -res;
574
0
    }
575
#else
576
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
577
    {
578
        int res = xmlXPathCmpNodes(x, y);
579
        return res == -2 ? res : -res;
580
    }
581
#endif
582
0
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
583
#include "timsort.h"
584
#endif /* WITH_TIM_SORT */
585
586
/************************************************************************
587
 *                  *
588
 *      Error handling routines       *
589
 *                  *
590
 ************************************************************************/
591
592
/**
593
 * XP_ERRORNULL:
594
 * @X:  the error code
595
 *
596
 * Macro to raise an XPath error and return NULL.
597
 */
598
#define XP_ERRORNULL(X)             \
599
0
    { xmlXPathErr(ctxt, X); return(NULL); }
600
601
/*
602
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603
 */
604
static const char* const xmlXPathErrorMessages[] = {
605
    "Ok\n",
606
    "Number encoding\n",
607
    "Unfinished literal\n",
608
    "Start of literal\n",
609
    "Expected $ for variable reference\n",
610
    "Undefined variable\n",
611
    "Invalid predicate\n",
612
    "Invalid expression\n",
613
    "Missing closing curly brace\n",
614
    "Unregistered function\n",
615
    "Invalid operand\n",
616
    "Invalid type\n",
617
    "Invalid number of arguments\n",
618
    "Invalid context size\n",
619
    "Invalid context position\n",
620
    "Memory allocation error\n",
621
    "Syntax error\n",
622
    "Resource error\n",
623
    "Sub resource error\n",
624
    "Undefined namespace prefix\n",
625
    "Encoding error\n",
626
    "Char out of XML range\n",
627
    "Invalid or incomplete context\n",
628
    "Stack usage error\n",
629
    "Forbidden variable\n",
630
    "Operation limit exceeded\n",
631
    "Recursion limit exceeded\n",
632
    "?? Unknown error ??\n" /* Must be last in the list! */
633
};
634
0
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
635
0
       sizeof(xmlXPathErrorMessages[0])) - 1)
636
/**
637
 * xmlXPathErrMemory:
638
 * @ctxt:  an XPath context
639
 * @extra:  extra information
640
 *
641
 * Handle a redefinition of attribute error
642
 */
643
static void
644
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
645
0
{
646
0
    if (ctxt != NULL) {
647
0
        xmlResetError(&ctxt->lastError);
648
0
        if (extra) {
649
0
            xmlChar buf[200];
650
651
0
            xmlStrPrintf(buf, 200,
652
0
                         "Memory allocation failed : %s\n",
653
0
                         extra);
654
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
655
0
        } else {
656
0
            ctxt->lastError.message = (char *)
657
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
658
0
        }
659
0
        ctxt->lastError.domain = XML_FROM_XPATH;
660
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
661
0
  if (ctxt->error != NULL)
662
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
663
0
    } else {
664
0
        if (extra)
665
0
            __xmlRaiseError(NULL, NULL, NULL,
666
0
                            NULL, NULL, XML_FROM_XPATH,
667
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
668
0
                            extra, NULL, NULL, 0, 0,
669
0
                            "Memory allocation failed : %s\n", extra);
670
0
        else
671
0
            __xmlRaiseError(NULL, NULL, NULL,
672
0
                            NULL, NULL, XML_FROM_XPATH,
673
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
674
0
                            NULL, NULL, NULL, 0, 0,
675
0
                            "Memory allocation failed\n");
676
0
    }
677
0
}
678
679
/**
680
 * xmlXPathPErrMemory:
681
 * @ctxt:  an XPath parser context
682
 * @extra:  extra information
683
 *
684
 * Handle a redefinition of attribute error
685
 */
686
static void
687
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
688
0
{
689
0
    if (ctxt == NULL)
690
0
  xmlXPathErrMemory(NULL, extra);
691
0
    else {
692
0
  ctxt->error = XPATH_MEMORY_ERROR;
693
0
  xmlXPathErrMemory(ctxt->context, extra);
694
0
    }
695
0
}
696
697
/**
698
 * xmlXPathErr:
699
 * @ctxt:  a XPath parser context
700
 * @error:  the error code
701
 *
702
 * Handle an XPath error
703
 */
704
void
705
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
706
0
{
707
0
    if ((error < 0) || (error > MAXERRNO))
708
0
  error = MAXERRNO;
709
0
    if (ctxt == NULL) {
710
0
  __xmlRaiseError(NULL, NULL, NULL,
711
0
      NULL, NULL, XML_FROM_XPATH,
712
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
713
0
      XML_ERR_ERROR, NULL, 0,
714
0
      NULL, NULL, NULL, 0, 0,
715
0
      "%s", xmlXPathErrorMessages[error]);
716
0
  return;
717
0
    }
718
    /* Only report the first error */
719
0
    if (ctxt->error != 0)
720
0
        return;
721
0
    ctxt->error = error;
722
0
    if (ctxt->context == NULL) {
723
0
  __xmlRaiseError(NULL, NULL, NULL,
724
0
      NULL, NULL, XML_FROM_XPATH,
725
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726
0
      XML_ERR_ERROR, NULL, 0,
727
0
      (const char *) ctxt->base, NULL, NULL,
728
0
      ctxt->cur - ctxt->base, 0,
729
0
      "%s", xmlXPathErrorMessages[error]);
730
0
  return;
731
0
    }
732
733
    /* cleanup current last error */
734
0
    xmlResetError(&ctxt->context->lastError);
735
736
0
    ctxt->context->lastError.domain = XML_FROM_XPATH;
737
0
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
738
0
                           XPATH_EXPRESSION_OK;
739
0
    ctxt->context->lastError.level = XML_ERR_ERROR;
740
0
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
741
0
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
742
0
    ctxt->context->lastError.node = ctxt->context->debugNode;
743
0
    if (ctxt->context->error != NULL) {
744
0
  ctxt->context->error(ctxt->context->userData,
745
0
                       &ctxt->context->lastError);
746
0
    } else {
747
0
  __xmlRaiseError(NULL, NULL, NULL,
748
0
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
749
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
750
0
      XML_ERR_ERROR, NULL, 0,
751
0
      (const char *) ctxt->base, NULL, NULL,
752
0
      ctxt->cur - ctxt->base, 0,
753
0
      "%s", xmlXPathErrorMessages[error]);
754
0
    }
755
756
0
}
757
758
/**
759
 * xmlXPatherror:
760
 * @ctxt:  the XPath Parser context
761
 * @file:  the file name
762
 * @line:  the line number
763
 * @no:  the error number
764
 *
765
 * Formats an error message.
766
 */
767
void
768
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
769
0
              int line ATTRIBUTE_UNUSED, int no) {
770
0
    xmlXPathErr(ctxt, no);
771
0
}
772
773
/**
774
 * xmlXPathCheckOpLimit:
775
 * @ctxt:  the XPath Parser context
776
 * @opCount:  the number of operations to be added
777
 *
778
 * Adds opCount to the running total of operations and returns -1 if the
779
 * operation limit is exceeded. Returns 0 otherwise.
780
 */
781
static int
782
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
783
0
    xmlXPathContextPtr xpctxt = ctxt->context;
784
785
0
    if ((opCount > xpctxt->opLimit) ||
786
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
787
0
        xpctxt->opCount = xpctxt->opLimit;
788
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
789
0
        return(-1);
790
0
    }
791
792
0
    xpctxt->opCount += opCount;
793
0
    return(0);
794
0
}
795
796
#define OP_LIMIT_EXCEEDED(ctxt, n) \
797
0
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
798
799
/************************************************************************
800
 *                  *
801
 *      Utilities         *
802
 *                  *
803
 ************************************************************************/
804
805
/**
806
 * xsltPointerList:
807
 *
808
 * Pointer-list for various purposes.
809
 */
810
typedef struct _xmlPointerList xmlPointerList;
811
typedef xmlPointerList *xmlPointerListPtr;
812
struct _xmlPointerList {
813
    void **items;
814
    int number;
815
    int size;
816
};
817
/*
818
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
819
* and here, we should make the functions public.
820
*/
821
static int
822
xmlPointerListAddSize(xmlPointerListPtr list,
823
           void *item,
824
           int initialSize)
825
0
{
826
0
    if (list->size <= list->number) {
827
0
        void **tmp;
828
0
        size_t newSize;
829
830
0
        if (list->size == 0) {
831
0
            if (initialSize <= 0)
832
0
                initialSize = 1;
833
0
            newSize = initialSize;
834
0
        } else {
835
0
            if (list->size > 50000000) {
836
0
                xmlXPathErrMemory(NULL,
837
0
                    "xmlPointerListAddSize: re-allocating item\n");
838
0
                return(-1);
839
0
            }
840
0
      newSize = list->size * 2;
841
0
        }
842
0
  tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
843
0
  if (tmp == NULL) {
844
0
      xmlXPathErrMemory(NULL,
845
0
    "xmlPointerListAddSize: re-allocating item\n");
846
0
      return(-1);
847
0
  }
848
0
        list->items = tmp;
849
0
        list->size = newSize;
850
0
    }
851
0
    list->items[list->number++] = item;
852
0
    return(0);
853
0
}
854
855
/**
856
 * xsltPointerListCreate:
857
 *
858
 * Creates an xsltPointerList structure.
859
 *
860
 * Returns a xsltPointerList structure or NULL in case of an error.
861
 */
862
static xmlPointerListPtr
863
xmlPointerListCreate(int initialSize)
864
0
{
865
0
    xmlPointerListPtr ret;
866
867
0
    ret = xmlMalloc(sizeof(xmlPointerList));
868
0
    if (ret == NULL) {
869
0
  xmlXPathErrMemory(NULL,
870
0
      "xmlPointerListCreate: allocating item\n");
871
0
  return (NULL);
872
0
    }
873
0
    memset(ret, 0, sizeof(xmlPointerList));
874
0
    if (initialSize > 0) {
875
0
  xmlPointerListAddSize(ret, NULL, initialSize);
876
0
  ret->number = 0;
877
0
    }
878
0
    return (ret);
879
0
}
880
881
/**
882
 * xsltPointerListFree:
883
 *
884
 * Frees the xsltPointerList structure. This does not free
885
 * the content of the list.
886
 */
887
static void
888
xmlPointerListFree(xmlPointerListPtr list)
889
0
{
890
0
    if (list == NULL)
891
0
  return;
892
0
    if (list->items != NULL)
893
0
  xmlFree(list->items);
894
0
    xmlFree(list);
895
0
}
896
897
/************************************************************************
898
 *                  *
899
 *      Parser Types          *
900
 *                  *
901
 ************************************************************************/
902
903
/*
904
 * Types are private:
905
 */
906
907
typedef enum {
908
    XPATH_OP_END=0,
909
    XPATH_OP_AND,
910
    XPATH_OP_OR,
911
    XPATH_OP_EQUAL,
912
    XPATH_OP_CMP,
913
    XPATH_OP_PLUS,
914
    XPATH_OP_MULT,
915
    XPATH_OP_UNION,
916
    XPATH_OP_ROOT,
917
    XPATH_OP_NODE,
918
    XPATH_OP_COLLECT,
919
    XPATH_OP_VALUE, /* 11 */
920
    XPATH_OP_VARIABLE,
921
    XPATH_OP_FUNCTION,
922
    XPATH_OP_ARG,
923
    XPATH_OP_PREDICATE,
924
    XPATH_OP_FILTER, /* 16 */
925
    XPATH_OP_SORT /* 17 */
926
#ifdef LIBXML_XPTR_LOCS_ENABLED
927
    ,XPATH_OP_RANGETO
928
#endif
929
} xmlXPathOp;
930
931
typedef enum {
932
    AXIS_ANCESTOR = 1,
933
    AXIS_ANCESTOR_OR_SELF,
934
    AXIS_ATTRIBUTE,
935
    AXIS_CHILD,
936
    AXIS_DESCENDANT,
937
    AXIS_DESCENDANT_OR_SELF,
938
    AXIS_FOLLOWING,
939
    AXIS_FOLLOWING_SIBLING,
940
    AXIS_NAMESPACE,
941
    AXIS_PARENT,
942
    AXIS_PRECEDING,
943
    AXIS_PRECEDING_SIBLING,
944
    AXIS_SELF
945
} xmlXPathAxisVal;
946
947
typedef enum {
948
    NODE_TEST_NONE = 0,
949
    NODE_TEST_TYPE = 1,
950
    NODE_TEST_PI = 2,
951
    NODE_TEST_ALL = 3,
952
    NODE_TEST_NS = 4,
953
    NODE_TEST_NAME = 5
954
} xmlXPathTestVal;
955
956
typedef enum {
957
    NODE_TYPE_NODE = 0,
958
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
959
    NODE_TYPE_TEXT = XML_TEXT_NODE,
960
    NODE_TYPE_PI = XML_PI_NODE
961
} xmlXPathTypeVal;
962
963
typedef struct _xmlXPathStepOp xmlXPathStepOp;
964
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
965
struct _xmlXPathStepOp {
966
    xmlXPathOp op;    /* The identifier of the operation */
967
    int ch1;      /* First child */
968
    int ch2;      /* Second child */
969
    int value;
970
    int value2;
971
    int value3;
972
    void *value4;
973
    void *value5;
974
    xmlXPathFunction cache;
975
    void *cacheURI;
976
};
977
978
struct _xmlXPathCompExpr {
979
    int nbStep;     /* Number of steps in this expression */
980
    int maxStep;    /* Maximum number of steps allocated */
981
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
982
    int last;     /* index of last step in expression */
983
    xmlChar *expr;    /* the expression being computed */
984
    xmlDictPtr dict;    /* the dictionary to use if any */
985
#ifdef DEBUG_EVAL_COUNTS
986
    int nb;
987
    xmlChar *string;
988
#endif
989
#ifdef XPATH_STREAMING
990
    xmlPatternPtr stream;
991
#endif
992
};
993
994
/************************************************************************
995
 *                  *
996
 *      Forward declarations        *
997
 *                  *
998
 ************************************************************************/
999
static void
1000
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
1001
static void
1002
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
1003
static int
1004
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
1005
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
1006
static int
1007
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
1008
          xmlXPathStepOpPtr op,
1009
          int isPredicate);
1010
static void
1011
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
1012
1013
/************************************************************************
1014
 *                  *
1015
 *      Parser Type functions       *
1016
 *                  *
1017
 ************************************************************************/
1018
1019
/**
1020
 * xmlXPathNewCompExpr:
1021
 *
1022
 * Create a new Xpath component
1023
 *
1024
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1025
 */
1026
static xmlXPathCompExprPtr
1027
0
xmlXPathNewCompExpr(void) {
1028
0
    xmlXPathCompExprPtr cur;
1029
1030
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1031
0
    if (cur == NULL) {
1032
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1033
0
  return(NULL);
1034
0
    }
1035
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1036
0
    cur->maxStep = 10;
1037
0
    cur->nbStep = 0;
1038
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1039
0
                                     sizeof(xmlXPathStepOp));
1040
0
    if (cur->steps == NULL) {
1041
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1042
0
  xmlFree(cur);
1043
0
  return(NULL);
1044
0
    }
1045
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1046
0
    cur->last = -1;
1047
#ifdef DEBUG_EVAL_COUNTS
1048
    cur->nb = 0;
1049
#endif
1050
0
    return(cur);
1051
0
}
1052
1053
/**
1054
 * xmlXPathFreeCompExpr:
1055
 * @comp:  an XPATH comp
1056
 *
1057
 * Free up the memory allocated by @comp
1058
 */
1059
void
1060
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1061
0
{
1062
0
    xmlXPathStepOpPtr op;
1063
0
    int i;
1064
1065
0
    if (comp == NULL)
1066
0
        return;
1067
0
    if (comp->dict == NULL) {
1068
0
  for (i = 0; i < comp->nbStep; i++) {
1069
0
      op = &comp->steps[i];
1070
0
      if (op->value4 != NULL) {
1071
0
    if (op->op == XPATH_OP_VALUE)
1072
0
        xmlXPathFreeObject(op->value4);
1073
0
    else
1074
0
        xmlFree(op->value4);
1075
0
      }
1076
0
      if (op->value5 != NULL)
1077
0
    xmlFree(op->value5);
1078
0
  }
1079
0
    } else {
1080
0
  for (i = 0; i < comp->nbStep; i++) {
1081
0
      op = &comp->steps[i];
1082
0
      if (op->value4 != NULL) {
1083
0
    if (op->op == XPATH_OP_VALUE)
1084
0
        xmlXPathFreeObject(op->value4);
1085
0
      }
1086
0
  }
1087
0
        xmlDictFree(comp->dict);
1088
0
    }
1089
0
    if (comp->steps != NULL) {
1090
0
        xmlFree(comp->steps);
1091
0
    }
1092
#ifdef DEBUG_EVAL_COUNTS
1093
    if (comp->string != NULL) {
1094
        xmlFree(comp->string);
1095
    }
1096
#endif
1097
0
#ifdef XPATH_STREAMING
1098
0
    if (comp->stream != NULL) {
1099
0
        xmlFreePatternList(comp->stream);
1100
0
    }
1101
0
#endif
1102
0
    if (comp->expr != NULL) {
1103
0
        xmlFree(comp->expr);
1104
0
    }
1105
1106
0
    xmlFree(comp);
1107
0
}
1108
1109
/**
1110
 * xmlXPathCompExprAdd:
1111
 * @comp:  the compiled expression
1112
 * @ch1: first child index
1113
 * @ch2: second child index
1114
 * @op:  an op
1115
 * @value:  the first int value
1116
 * @value2:  the second int value
1117
 * @value3:  the third int value
1118
 * @value4:  the first string value
1119
 * @value5:  the second string value
1120
 *
1121
 * Add a step to an XPath Compiled Expression
1122
 *
1123
 * Returns -1 in case of failure, the index otherwise
1124
 */
1125
static int
1126
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1127
   xmlXPathOp op, int value,
1128
0
   int value2, int value3, void *value4, void *value5) {
1129
0
    xmlXPathCompExprPtr comp = ctxt->comp;
1130
0
    if (comp->nbStep >= comp->maxStep) {
1131
0
  xmlXPathStepOp *real;
1132
1133
0
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1134
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1135
0
      return(-1);
1136
0
        }
1137
0
  comp->maxStep *= 2;
1138
0
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1139
0
                          comp->maxStep * sizeof(xmlXPathStepOp));
1140
0
  if (real == NULL) {
1141
0
      comp->maxStep /= 2;
1142
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1143
0
      return(-1);
1144
0
  }
1145
0
  comp->steps = real;
1146
0
    }
1147
0
    comp->last = comp->nbStep;
1148
0
    comp->steps[comp->nbStep].ch1 = ch1;
1149
0
    comp->steps[comp->nbStep].ch2 = ch2;
1150
0
    comp->steps[comp->nbStep].op = op;
1151
0
    comp->steps[comp->nbStep].value = value;
1152
0
    comp->steps[comp->nbStep].value2 = value2;
1153
0
    comp->steps[comp->nbStep].value3 = value3;
1154
0
    if ((comp->dict != NULL) &&
1155
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1156
0
   (op == XPATH_OP_COLLECT))) {
1157
0
        if (value4 != NULL) {
1158
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1159
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1160
0
      xmlFree(value4);
1161
0
  } else
1162
0
      comp->steps[comp->nbStep].value4 = NULL;
1163
0
        if (value5 != NULL) {
1164
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1165
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1166
0
      xmlFree(value5);
1167
0
  } else
1168
0
      comp->steps[comp->nbStep].value5 = NULL;
1169
0
    } else {
1170
0
  comp->steps[comp->nbStep].value4 = value4;
1171
0
  comp->steps[comp->nbStep].value5 = value5;
1172
0
    }
1173
0
    comp->steps[comp->nbStep].cache = NULL;
1174
0
    return(comp->nbStep++);
1175
0
}
1176
1177
/**
1178
 * xmlXPathCompSwap:
1179
 * @comp:  the compiled expression
1180
 * @op: operation index
1181
 *
1182
 * Swaps 2 operations in the compiled expression
1183
 */
1184
static void
1185
0
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1186
0
    int tmp;
1187
1188
#ifndef LIBXML_THREAD_ENABLED
1189
    /*
1190
     * Since this manipulates possibly shared variables, this is
1191
     * disabled if one detects that the library is used in a multithreaded
1192
     * application
1193
     */
1194
    if (xmlXPathDisableOptimizer)
1195
  return;
1196
#endif
1197
1198
0
    tmp = op->ch1;
1199
0
    op->ch1 = op->ch2;
1200
0
    op->ch2 = tmp;
1201
0
}
1202
1203
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1204
0
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1205
0
                  (op), (val), (val2), (val3), (val4), (val5))
1206
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1207
0
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1208
0
                  (op), (val), (val2), (val3), (val4), (val5))
1209
1210
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1211
0
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1212
1213
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1214
0
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1215
1216
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1217
0
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1218
0
      (val), (val2), 0 ,NULL ,NULL)
1219
1220
/************************************************************************
1221
 *                  *
1222
 *    XPath object cache structures       *
1223
 *                  *
1224
 ************************************************************************/
1225
1226
/* #define XP_DEFAULT_CACHE_ON */
1227
1228
0
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1229
1230
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1231
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1232
struct _xmlXPathContextCache {
1233
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1234
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1235
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1236
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1237
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1238
    int maxNodeset;
1239
    int maxString;
1240
    int maxBoolean;
1241
    int maxNumber;
1242
    int maxMisc;
1243
#ifdef XP_DEBUG_OBJ_USAGE
1244
    int dbgCachedAll;
1245
    int dbgCachedNodeset;
1246
    int dbgCachedString;
1247
    int dbgCachedBool;
1248
    int dbgCachedNumber;
1249
    int dbgCachedPoint;
1250
    int dbgCachedRange;
1251
    int dbgCachedLocset;
1252
    int dbgCachedUsers;
1253
    int dbgCachedXSLTTree;
1254
    int dbgCachedUndefined;
1255
1256
1257
    int dbgReusedAll;
1258
    int dbgReusedNodeset;
1259
    int dbgReusedString;
1260
    int dbgReusedBool;
1261
    int dbgReusedNumber;
1262
    int dbgReusedPoint;
1263
    int dbgReusedRange;
1264
    int dbgReusedLocset;
1265
    int dbgReusedUsers;
1266
    int dbgReusedXSLTTree;
1267
    int dbgReusedUndefined;
1268
1269
#endif
1270
};
1271
1272
/************************************************************************
1273
 *                  *
1274
 *    Debugging related functions       *
1275
 *                  *
1276
 ************************************************************************/
1277
1278
#define STRANGE             \
1279
0
    xmlGenericError(xmlGenericErrorContext,       \
1280
0
      "Internal error at %s:%d\n",        \
1281
0
            __FILE__, __LINE__);
1282
1283
#ifdef LIBXML_DEBUG_ENABLED
1284
static void
1285
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1286
0
    int i;
1287
0
    char shift[100];
1288
1289
0
    for (i = 0;((i < depth) && (i < 25));i++)
1290
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1291
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1292
0
    if (cur == NULL) {
1293
0
  fprintf(output, "%s", shift);
1294
0
  fprintf(output, "Node is NULL !\n");
1295
0
  return;
1296
1297
0
    }
1298
1299
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1300
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1301
0
  fprintf(output, "%s", shift);
1302
0
  fprintf(output, " /\n");
1303
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1304
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1305
0
    else
1306
0
  xmlDebugDumpOneNode(output, cur, depth);
1307
0
}
1308
static void
1309
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1310
0
    xmlNodePtr tmp;
1311
0
    int i;
1312
0
    char shift[100];
1313
1314
0
    for (i = 0;((i < depth) && (i < 25));i++)
1315
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1316
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1317
0
    if (cur == NULL) {
1318
0
  fprintf(output, "%s", shift);
1319
0
  fprintf(output, "Node is NULL !\n");
1320
0
  return;
1321
1322
0
    }
1323
1324
0
    while (cur != NULL) {
1325
0
  tmp = cur;
1326
0
  cur = cur->next;
1327
0
  xmlDebugDumpOneNode(output, tmp, depth);
1328
0
    }
1329
0
}
1330
1331
static void
1332
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1333
0
    int i;
1334
0
    char shift[100];
1335
1336
0
    for (i = 0;((i < depth) && (i < 25));i++)
1337
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1338
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1339
1340
0
    if (cur == NULL) {
1341
0
  fprintf(output, "%s", shift);
1342
0
  fprintf(output, "NodeSet is NULL !\n");
1343
0
  return;
1344
1345
0
    }
1346
1347
0
    if (cur != NULL) {
1348
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1349
0
  for (i = 0;i < cur->nodeNr;i++) {
1350
0
      fprintf(output, "%s", shift);
1351
0
      fprintf(output, "%d", i + 1);
1352
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1353
0
  }
1354
0
    }
1355
0
}
1356
1357
static void
1358
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1359
0
    int i;
1360
0
    char shift[100];
1361
1362
0
    for (i = 0;((i < depth) && (i < 25));i++)
1363
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1364
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1365
1366
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1367
0
  fprintf(output, "%s", shift);
1368
0
  fprintf(output, "Value Tree is NULL !\n");
1369
0
  return;
1370
1371
0
    }
1372
1373
0
    fprintf(output, "%s", shift);
1374
0
    fprintf(output, "%d", i + 1);
1375
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1376
0
}
1377
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1378
static void
1379
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1380
    int i;
1381
    char shift[100];
1382
1383
    for (i = 0;((i < depth) && (i < 25));i++)
1384
        shift[2 * i] = shift[2 * i + 1] = ' ';
1385
    shift[2 * i] = shift[2 * i + 1] = 0;
1386
1387
    if (cur == NULL) {
1388
  fprintf(output, "%s", shift);
1389
  fprintf(output, "LocationSet is NULL !\n");
1390
  return;
1391
1392
    }
1393
1394
    for (i = 0;i < cur->locNr;i++) {
1395
  fprintf(output, "%s", shift);
1396
        fprintf(output, "%d : ", i + 1);
1397
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1398
    }
1399
}
1400
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1401
1402
/**
1403
 * xmlXPathDebugDumpObject:
1404
 * @output:  the FILE * to dump the output
1405
 * @cur:  the object to inspect
1406
 * @depth:  indentation level
1407
 *
1408
 * Dump the content of the object for debugging purposes
1409
 */
1410
void
1411
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1412
0
    int i;
1413
0
    char shift[100];
1414
1415
0
    if (output == NULL) return;
1416
1417
0
    for (i = 0;((i < depth) && (i < 25));i++)
1418
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1419
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1420
1421
1422
0
    fprintf(output, "%s", shift);
1423
1424
0
    if (cur == NULL) {
1425
0
        fprintf(output, "Object is empty (NULL)\n");
1426
0
  return;
1427
0
    }
1428
0
    switch(cur->type) {
1429
0
        case XPATH_UNDEFINED:
1430
0
      fprintf(output, "Object is uninitialized\n");
1431
0
      break;
1432
0
        case XPATH_NODESET:
1433
0
      fprintf(output, "Object is a Node Set :\n");
1434
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1435
0
      break;
1436
0
  case XPATH_XSLT_TREE:
1437
0
      fprintf(output, "Object is an XSLT value tree :\n");
1438
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1439
0
      break;
1440
0
        case XPATH_BOOLEAN:
1441
0
      fprintf(output, "Object is a Boolean : ");
1442
0
      if (cur->boolval) fprintf(output, "true\n");
1443
0
      else fprintf(output, "false\n");
1444
0
      break;
1445
0
        case XPATH_NUMBER:
1446
0
      switch (xmlXPathIsInf(cur->floatval)) {
1447
0
      case 1:
1448
0
    fprintf(output, "Object is a number : Infinity\n");
1449
0
    break;
1450
0
      case -1:
1451
0
    fprintf(output, "Object is a number : -Infinity\n");
1452
0
    break;
1453
0
      default:
1454
0
    if (xmlXPathIsNaN(cur->floatval)) {
1455
0
        fprintf(output, "Object is a number : NaN\n");
1456
0
    } else if (cur->floatval == 0) {
1457
                    /* Omit sign for negative zero. */
1458
0
        fprintf(output, "Object is a number : 0\n");
1459
0
    } else {
1460
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1461
0
    }
1462
0
      }
1463
0
      break;
1464
0
        case XPATH_STRING:
1465
0
      fprintf(output, "Object is a string : ");
1466
0
      xmlDebugDumpString(output, cur->stringval);
1467
0
      fprintf(output, "\n");
1468
0
      break;
1469
#ifdef LIBXML_XPTR_LOCS_ENABLED
1470
  case XPATH_POINT:
1471
      fprintf(output, "Object is a point : index %d in node", cur->index);
1472
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1473
      fprintf(output, "\n");
1474
      break;
1475
  case XPATH_RANGE:
1476
      if ((cur->user2 == NULL) ||
1477
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1478
    fprintf(output, "Object is a collapsed range :\n");
1479
    fprintf(output, "%s", shift);
1480
    if (cur->index >= 0)
1481
        fprintf(output, "index %d in ", cur->index);
1482
    fprintf(output, "node\n");
1483
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1484
                    depth + 1);
1485
      } else  {
1486
    fprintf(output, "Object is a range :\n");
1487
    fprintf(output, "%s", shift);
1488
    fprintf(output, "From ");
1489
    if (cur->index >= 0)
1490
        fprintf(output, "index %d in ", cur->index);
1491
    fprintf(output, "node\n");
1492
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1493
                    depth + 1);
1494
    fprintf(output, "%s", shift);
1495
    fprintf(output, "To ");
1496
    if (cur->index2 >= 0)
1497
        fprintf(output, "index %d in ", cur->index2);
1498
    fprintf(output, "node\n");
1499
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1500
                    depth + 1);
1501
    fprintf(output, "\n");
1502
      }
1503
      break;
1504
  case XPATH_LOCATIONSET:
1505
      fprintf(output, "Object is a Location Set:\n");
1506
      xmlXPathDebugDumpLocationSet(output,
1507
        (xmlLocationSetPtr) cur->user, depth);
1508
      break;
1509
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1510
0
  case XPATH_USERS:
1511
0
      fprintf(output, "Object is user defined\n");
1512
0
      break;
1513
0
    }
1514
0
}
1515
1516
static void
1517
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1518
0
                       xmlXPathStepOpPtr op, int depth) {
1519
0
    int i;
1520
0
    char shift[100];
1521
1522
0
    for (i = 0;((i < depth) && (i < 25));i++)
1523
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1524
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1525
1526
0
    fprintf(output, "%s", shift);
1527
0
    if (op == NULL) {
1528
0
  fprintf(output, "Step is NULL\n");
1529
0
  return;
1530
0
    }
1531
0
    switch (op->op) {
1532
0
        case XPATH_OP_END:
1533
0
      fprintf(output, "END"); break;
1534
0
        case XPATH_OP_AND:
1535
0
      fprintf(output, "AND"); break;
1536
0
        case XPATH_OP_OR:
1537
0
      fprintf(output, "OR"); break;
1538
0
        case XPATH_OP_EQUAL:
1539
0
       if (op->value)
1540
0
     fprintf(output, "EQUAL =");
1541
0
       else
1542
0
     fprintf(output, "EQUAL !=");
1543
0
       break;
1544
0
        case XPATH_OP_CMP:
1545
0
       if (op->value)
1546
0
     fprintf(output, "CMP <");
1547
0
       else
1548
0
     fprintf(output, "CMP >");
1549
0
       if (!op->value2)
1550
0
     fprintf(output, "=");
1551
0
       break;
1552
0
        case XPATH_OP_PLUS:
1553
0
       if (op->value == 0)
1554
0
     fprintf(output, "PLUS -");
1555
0
       else if (op->value == 1)
1556
0
     fprintf(output, "PLUS +");
1557
0
       else if (op->value == 2)
1558
0
     fprintf(output, "PLUS unary -");
1559
0
       else if (op->value == 3)
1560
0
     fprintf(output, "PLUS unary - -");
1561
0
       break;
1562
0
        case XPATH_OP_MULT:
1563
0
       if (op->value == 0)
1564
0
     fprintf(output, "MULT *");
1565
0
       else if (op->value == 1)
1566
0
     fprintf(output, "MULT div");
1567
0
       else
1568
0
     fprintf(output, "MULT mod");
1569
0
       break;
1570
0
        case XPATH_OP_UNION:
1571
0
       fprintf(output, "UNION"); break;
1572
0
        case XPATH_OP_ROOT:
1573
0
       fprintf(output, "ROOT"); break;
1574
0
        case XPATH_OP_NODE:
1575
0
       fprintf(output, "NODE"); break;
1576
0
        case XPATH_OP_SORT:
1577
0
       fprintf(output, "SORT"); break;
1578
0
        case XPATH_OP_COLLECT: {
1579
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1580
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1581
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1582
0
      const xmlChar *prefix = op->value4;
1583
0
      const xmlChar *name = op->value5;
1584
1585
0
      fprintf(output, "COLLECT ");
1586
0
      switch (axis) {
1587
0
    case AXIS_ANCESTOR:
1588
0
        fprintf(output, " 'ancestors' "); break;
1589
0
    case AXIS_ANCESTOR_OR_SELF:
1590
0
        fprintf(output, " 'ancestors-or-self' "); break;
1591
0
    case AXIS_ATTRIBUTE:
1592
0
        fprintf(output, " 'attributes' "); break;
1593
0
    case AXIS_CHILD:
1594
0
        fprintf(output, " 'child' "); break;
1595
0
    case AXIS_DESCENDANT:
1596
0
        fprintf(output, " 'descendant' "); break;
1597
0
    case AXIS_DESCENDANT_OR_SELF:
1598
0
        fprintf(output, " 'descendant-or-self' "); break;
1599
0
    case AXIS_FOLLOWING:
1600
0
        fprintf(output, " 'following' "); break;
1601
0
    case AXIS_FOLLOWING_SIBLING:
1602
0
        fprintf(output, " 'following-siblings' "); break;
1603
0
    case AXIS_NAMESPACE:
1604
0
        fprintf(output, " 'namespace' "); break;
1605
0
    case AXIS_PARENT:
1606
0
        fprintf(output, " 'parent' "); break;
1607
0
    case AXIS_PRECEDING:
1608
0
        fprintf(output, " 'preceding' "); break;
1609
0
    case AXIS_PRECEDING_SIBLING:
1610
0
        fprintf(output, " 'preceding-sibling' "); break;
1611
0
    case AXIS_SELF:
1612
0
        fprintf(output, " 'self' "); break;
1613
0
      }
1614
0
      switch (test) {
1615
0
                case NODE_TEST_NONE:
1616
0
        fprintf(output, "'none' "); break;
1617
0
                case NODE_TEST_TYPE:
1618
0
        fprintf(output, "'type' "); break;
1619
0
                case NODE_TEST_PI:
1620
0
        fprintf(output, "'PI' "); break;
1621
0
                case NODE_TEST_ALL:
1622
0
        fprintf(output, "'all' "); break;
1623
0
                case NODE_TEST_NS:
1624
0
        fprintf(output, "'namespace' "); break;
1625
0
                case NODE_TEST_NAME:
1626
0
        fprintf(output, "'name' "); break;
1627
0
      }
1628
0
      switch (type) {
1629
0
                case NODE_TYPE_NODE:
1630
0
        fprintf(output, "'node' "); break;
1631
0
                case NODE_TYPE_COMMENT:
1632
0
        fprintf(output, "'comment' "); break;
1633
0
                case NODE_TYPE_TEXT:
1634
0
        fprintf(output, "'text' "); break;
1635
0
                case NODE_TYPE_PI:
1636
0
        fprintf(output, "'PI' "); break;
1637
0
      }
1638
0
      if (prefix != NULL)
1639
0
    fprintf(output, "%s:", prefix);
1640
0
      if (name != NULL)
1641
0
    fprintf(output, "%s", (const char *) name);
1642
0
      break;
1643
1644
0
        }
1645
0
  case XPATH_OP_VALUE: {
1646
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1647
1648
0
      fprintf(output, "ELEM ");
1649
0
      xmlXPathDebugDumpObject(output, object, 0);
1650
0
      goto finish;
1651
0
  }
1652
0
  case XPATH_OP_VARIABLE: {
1653
0
      const xmlChar *prefix = op->value5;
1654
0
      const xmlChar *name = op->value4;
1655
1656
0
      if (prefix != NULL)
1657
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1658
0
      else
1659
0
    fprintf(output, "VARIABLE %s", name);
1660
0
      break;
1661
0
  }
1662
0
  case XPATH_OP_FUNCTION: {
1663
0
      int nbargs = op->value;
1664
0
      const xmlChar *prefix = op->value5;
1665
0
      const xmlChar *name = op->value4;
1666
1667
0
      if (prefix != NULL)
1668
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1669
0
      prefix, name, nbargs);
1670
0
      else
1671
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1672
0
      break;
1673
0
  }
1674
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1675
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1676
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1677
#ifdef LIBXML_XPTR_LOCS_ENABLED
1678
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1679
#endif
1680
0
  default:
1681
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1682
0
    }
1683
0
    fprintf(output, "\n");
1684
0
finish:
1685
0
    if (op->ch1 >= 0)
1686
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1687
0
    if (op->ch2 >= 0)
1688
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1689
0
}
1690
1691
/**
1692
 * xmlXPathDebugDumpCompExpr:
1693
 * @output:  the FILE * for the output
1694
 * @comp:  the precompiled XPath expression
1695
 * @depth:  the indentation level.
1696
 *
1697
 * Dumps the tree of the compiled XPath expression.
1698
 */
1699
void
1700
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1701
0
                    int depth) {
1702
0
    int i;
1703
0
    char shift[100];
1704
1705
0
    if ((output == NULL) || (comp == NULL)) return;
1706
1707
0
    for (i = 0;((i < depth) && (i < 25));i++)
1708
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1709
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1710
1711
0
    fprintf(output, "%s", shift);
1712
1713
0
#ifdef XPATH_STREAMING
1714
0
    if (comp->stream) {
1715
0
        fprintf(output, "Streaming Expression\n");
1716
0
    } else
1717
0
#endif
1718
0
    {
1719
0
        fprintf(output, "Compiled Expression : %d elements\n",
1720
0
                comp->nbStep);
1721
0
        i = comp->last;
1722
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1723
0
    }
1724
0
}
1725
1726
#ifdef XP_DEBUG_OBJ_USAGE
1727
1728
/*
1729
* XPath object usage related debugging variables.
1730
*/
1731
static int xmlXPathDebugObjCounterUndefined = 0;
1732
static int xmlXPathDebugObjCounterNodeset = 0;
1733
static int xmlXPathDebugObjCounterBool = 0;
1734
static int xmlXPathDebugObjCounterNumber = 0;
1735
static int xmlXPathDebugObjCounterString = 0;
1736
static int xmlXPathDebugObjCounterPoint = 0;
1737
static int xmlXPathDebugObjCounterRange = 0;
1738
static int xmlXPathDebugObjCounterLocset = 0;
1739
static int xmlXPathDebugObjCounterUsers = 0;
1740
static int xmlXPathDebugObjCounterXSLTTree = 0;
1741
static int xmlXPathDebugObjCounterAll = 0;
1742
1743
static int xmlXPathDebugObjTotalUndefined = 0;
1744
static int xmlXPathDebugObjTotalNodeset = 0;
1745
static int xmlXPathDebugObjTotalBool = 0;
1746
static int xmlXPathDebugObjTotalNumber = 0;
1747
static int xmlXPathDebugObjTotalString = 0;
1748
static int xmlXPathDebugObjTotalPoint = 0;
1749
static int xmlXPathDebugObjTotalRange = 0;
1750
static int xmlXPathDebugObjTotalLocset = 0;
1751
static int xmlXPathDebugObjTotalUsers = 0;
1752
static int xmlXPathDebugObjTotalXSLTTree = 0;
1753
static int xmlXPathDebugObjTotalAll = 0;
1754
1755
static int xmlXPathDebugObjMaxUndefined = 0;
1756
static int xmlXPathDebugObjMaxNodeset = 0;
1757
static int xmlXPathDebugObjMaxBool = 0;
1758
static int xmlXPathDebugObjMaxNumber = 0;
1759
static int xmlXPathDebugObjMaxString = 0;
1760
static int xmlXPathDebugObjMaxPoint = 0;
1761
static int xmlXPathDebugObjMaxRange = 0;
1762
static int xmlXPathDebugObjMaxLocset = 0;
1763
static int xmlXPathDebugObjMaxUsers = 0;
1764
static int xmlXPathDebugObjMaxXSLTTree = 0;
1765
static int xmlXPathDebugObjMaxAll = 0;
1766
1767
static void
1768
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1769
{
1770
    if (ctxt != NULL) {
1771
  if (ctxt->cache != NULL) {
1772
      xmlXPathContextCachePtr cache =
1773
    (xmlXPathContextCachePtr) ctxt->cache;
1774
1775
      cache->dbgCachedAll = 0;
1776
      cache->dbgCachedNodeset = 0;
1777
      cache->dbgCachedString = 0;
1778
      cache->dbgCachedBool = 0;
1779
      cache->dbgCachedNumber = 0;
1780
      cache->dbgCachedPoint = 0;
1781
      cache->dbgCachedRange = 0;
1782
      cache->dbgCachedLocset = 0;
1783
      cache->dbgCachedUsers = 0;
1784
      cache->dbgCachedXSLTTree = 0;
1785
      cache->dbgCachedUndefined = 0;
1786
1787
      cache->dbgReusedAll = 0;
1788
      cache->dbgReusedNodeset = 0;
1789
      cache->dbgReusedString = 0;
1790
      cache->dbgReusedBool = 0;
1791
      cache->dbgReusedNumber = 0;
1792
      cache->dbgReusedPoint = 0;
1793
      cache->dbgReusedRange = 0;
1794
      cache->dbgReusedLocset = 0;
1795
      cache->dbgReusedUsers = 0;
1796
      cache->dbgReusedXSLTTree = 0;
1797
      cache->dbgReusedUndefined = 0;
1798
  }
1799
    }
1800
1801
    xmlXPathDebugObjCounterUndefined = 0;
1802
    xmlXPathDebugObjCounterNodeset = 0;
1803
    xmlXPathDebugObjCounterBool = 0;
1804
    xmlXPathDebugObjCounterNumber = 0;
1805
    xmlXPathDebugObjCounterString = 0;
1806
    xmlXPathDebugObjCounterPoint = 0;
1807
    xmlXPathDebugObjCounterRange = 0;
1808
    xmlXPathDebugObjCounterLocset = 0;
1809
    xmlXPathDebugObjCounterUsers = 0;
1810
    xmlXPathDebugObjCounterXSLTTree = 0;
1811
    xmlXPathDebugObjCounterAll = 0;
1812
1813
    xmlXPathDebugObjTotalUndefined = 0;
1814
    xmlXPathDebugObjTotalNodeset = 0;
1815
    xmlXPathDebugObjTotalBool = 0;
1816
    xmlXPathDebugObjTotalNumber = 0;
1817
    xmlXPathDebugObjTotalString = 0;
1818
    xmlXPathDebugObjTotalPoint = 0;
1819
    xmlXPathDebugObjTotalRange = 0;
1820
    xmlXPathDebugObjTotalLocset = 0;
1821
    xmlXPathDebugObjTotalUsers = 0;
1822
    xmlXPathDebugObjTotalXSLTTree = 0;
1823
    xmlXPathDebugObjTotalAll = 0;
1824
1825
    xmlXPathDebugObjMaxUndefined = 0;
1826
    xmlXPathDebugObjMaxNodeset = 0;
1827
    xmlXPathDebugObjMaxBool = 0;
1828
    xmlXPathDebugObjMaxNumber = 0;
1829
    xmlXPathDebugObjMaxString = 0;
1830
    xmlXPathDebugObjMaxPoint = 0;
1831
    xmlXPathDebugObjMaxRange = 0;
1832
    xmlXPathDebugObjMaxLocset = 0;
1833
    xmlXPathDebugObjMaxUsers = 0;
1834
    xmlXPathDebugObjMaxXSLTTree = 0;
1835
    xmlXPathDebugObjMaxAll = 0;
1836
1837
}
1838
1839
static void
1840
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1841
            xmlXPathObjectType objType)
1842
{
1843
    int isCached = 0;
1844
1845
    if (ctxt != NULL) {
1846
  if (ctxt->cache != NULL) {
1847
      xmlXPathContextCachePtr cache =
1848
    (xmlXPathContextCachePtr) ctxt->cache;
1849
1850
      isCached = 1;
1851
1852
      cache->dbgReusedAll++;
1853
      switch (objType) {
1854
    case XPATH_UNDEFINED:
1855
        cache->dbgReusedUndefined++;
1856
        break;
1857
    case XPATH_NODESET:
1858
        cache->dbgReusedNodeset++;
1859
        break;
1860
    case XPATH_BOOLEAN:
1861
        cache->dbgReusedBool++;
1862
        break;
1863
    case XPATH_NUMBER:
1864
        cache->dbgReusedNumber++;
1865
        break;
1866
    case XPATH_STRING:
1867
        cache->dbgReusedString++;
1868
        break;
1869
#ifdef LIBXML_XPTR_LOCS_ENABLED
1870
    case XPATH_POINT:
1871
        cache->dbgReusedPoint++;
1872
        break;
1873
    case XPATH_RANGE:
1874
        cache->dbgReusedRange++;
1875
        break;
1876
    case XPATH_LOCATIONSET:
1877
        cache->dbgReusedLocset++;
1878
        break;
1879
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1880
    case XPATH_USERS:
1881
        cache->dbgReusedUsers++;
1882
        break;
1883
    case XPATH_XSLT_TREE:
1884
        cache->dbgReusedXSLTTree++;
1885
        break;
1886
    default:
1887
        break;
1888
      }
1889
  }
1890
    }
1891
1892
    switch (objType) {
1893
  case XPATH_UNDEFINED:
1894
      if (! isCached)
1895
    xmlXPathDebugObjTotalUndefined++;
1896
      xmlXPathDebugObjCounterUndefined++;
1897
      if (xmlXPathDebugObjCounterUndefined >
1898
    xmlXPathDebugObjMaxUndefined)
1899
    xmlXPathDebugObjMaxUndefined =
1900
        xmlXPathDebugObjCounterUndefined;
1901
      break;
1902
  case XPATH_NODESET:
1903
      if (! isCached)
1904
    xmlXPathDebugObjTotalNodeset++;
1905
      xmlXPathDebugObjCounterNodeset++;
1906
      if (xmlXPathDebugObjCounterNodeset >
1907
    xmlXPathDebugObjMaxNodeset)
1908
    xmlXPathDebugObjMaxNodeset =
1909
        xmlXPathDebugObjCounterNodeset;
1910
      break;
1911
  case XPATH_BOOLEAN:
1912
      if (! isCached)
1913
    xmlXPathDebugObjTotalBool++;
1914
      xmlXPathDebugObjCounterBool++;
1915
      if (xmlXPathDebugObjCounterBool >
1916
    xmlXPathDebugObjMaxBool)
1917
    xmlXPathDebugObjMaxBool =
1918
        xmlXPathDebugObjCounterBool;
1919
      break;
1920
  case XPATH_NUMBER:
1921
      if (! isCached)
1922
    xmlXPathDebugObjTotalNumber++;
1923
      xmlXPathDebugObjCounterNumber++;
1924
      if (xmlXPathDebugObjCounterNumber >
1925
    xmlXPathDebugObjMaxNumber)
1926
    xmlXPathDebugObjMaxNumber =
1927
        xmlXPathDebugObjCounterNumber;
1928
      break;
1929
  case XPATH_STRING:
1930
      if (! isCached)
1931
    xmlXPathDebugObjTotalString++;
1932
      xmlXPathDebugObjCounterString++;
1933
      if (xmlXPathDebugObjCounterString >
1934
    xmlXPathDebugObjMaxString)
1935
    xmlXPathDebugObjMaxString =
1936
        xmlXPathDebugObjCounterString;
1937
      break;
1938
#ifdef LIBXML_XPTR_LOCS_ENABLED
1939
  case XPATH_POINT:
1940
      if (! isCached)
1941
    xmlXPathDebugObjTotalPoint++;
1942
      xmlXPathDebugObjCounterPoint++;
1943
      if (xmlXPathDebugObjCounterPoint >
1944
    xmlXPathDebugObjMaxPoint)
1945
    xmlXPathDebugObjMaxPoint =
1946
        xmlXPathDebugObjCounterPoint;
1947
      break;
1948
  case XPATH_RANGE:
1949
      if (! isCached)
1950
    xmlXPathDebugObjTotalRange++;
1951
      xmlXPathDebugObjCounterRange++;
1952
      if (xmlXPathDebugObjCounterRange >
1953
    xmlXPathDebugObjMaxRange)
1954
    xmlXPathDebugObjMaxRange =
1955
        xmlXPathDebugObjCounterRange;
1956
      break;
1957
  case XPATH_LOCATIONSET:
1958
      if (! isCached)
1959
    xmlXPathDebugObjTotalLocset++;
1960
      xmlXPathDebugObjCounterLocset++;
1961
      if (xmlXPathDebugObjCounterLocset >
1962
    xmlXPathDebugObjMaxLocset)
1963
    xmlXPathDebugObjMaxLocset =
1964
        xmlXPathDebugObjCounterLocset;
1965
      break;
1966
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1967
  case XPATH_USERS:
1968
      if (! isCached)
1969
    xmlXPathDebugObjTotalUsers++;
1970
      xmlXPathDebugObjCounterUsers++;
1971
      if (xmlXPathDebugObjCounterUsers >
1972
    xmlXPathDebugObjMaxUsers)
1973
    xmlXPathDebugObjMaxUsers =
1974
        xmlXPathDebugObjCounterUsers;
1975
      break;
1976
  case XPATH_XSLT_TREE:
1977
      if (! isCached)
1978
    xmlXPathDebugObjTotalXSLTTree++;
1979
      xmlXPathDebugObjCounterXSLTTree++;
1980
      if (xmlXPathDebugObjCounterXSLTTree >
1981
    xmlXPathDebugObjMaxXSLTTree)
1982
    xmlXPathDebugObjMaxXSLTTree =
1983
        xmlXPathDebugObjCounterXSLTTree;
1984
      break;
1985
  default:
1986
      break;
1987
    }
1988
    if (! isCached)
1989
  xmlXPathDebugObjTotalAll++;
1990
    xmlXPathDebugObjCounterAll++;
1991
    if (xmlXPathDebugObjCounterAll >
1992
  xmlXPathDebugObjMaxAll)
1993
  xmlXPathDebugObjMaxAll =
1994
      xmlXPathDebugObjCounterAll;
1995
}
1996
1997
static void
1998
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1999
            xmlXPathObjectType objType)
2000
{
2001
    int isCached = 0;
2002
2003
    if (ctxt != NULL) {
2004
  if (ctxt->cache != NULL) {
2005
      xmlXPathContextCachePtr cache =
2006
    (xmlXPathContextCachePtr) ctxt->cache;
2007
2008
      isCached = 1;
2009
2010
      cache->dbgCachedAll++;
2011
      switch (objType) {
2012
    case XPATH_UNDEFINED:
2013
        cache->dbgCachedUndefined++;
2014
        break;
2015
    case XPATH_NODESET:
2016
        cache->dbgCachedNodeset++;
2017
        break;
2018
    case XPATH_BOOLEAN:
2019
        cache->dbgCachedBool++;
2020
        break;
2021
    case XPATH_NUMBER:
2022
        cache->dbgCachedNumber++;
2023
        break;
2024
    case XPATH_STRING:
2025
        cache->dbgCachedString++;
2026
        break;
2027
#ifdef LIBXML_XPTR_LOCS_ENABLED
2028
    case XPATH_POINT:
2029
        cache->dbgCachedPoint++;
2030
        break;
2031
    case XPATH_RANGE:
2032
        cache->dbgCachedRange++;
2033
        break;
2034
    case XPATH_LOCATIONSET:
2035
        cache->dbgCachedLocset++;
2036
        break;
2037
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2038
    case XPATH_USERS:
2039
        cache->dbgCachedUsers++;
2040
        break;
2041
    case XPATH_XSLT_TREE:
2042
        cache->dbgCachedXSLTTree++;
2043
        break;
2044
    default:
2045
        break;
2046
      }
2047
2048
  }
2049
    }
2050
    switch (objType) {
2051
  case XPATH_UNDEFINED:
2052
      xmlXPathDebugObjCounterUndefined--;
2053
      break;
2054
  case XPATH_NODESET:
2055
      xmlXPathDebugObjCounterNodeset--;
2056
      break;
2057
  case XPATH_BOOLEAN:
2058
      xmlXPathDebugObjCounterBool--;
2059
      break;
2060
  case XPATH_NUMBER:
2061
      xmlXPathDebugObjCounterNumber--;
2062
      break;
2063
  case XPATH_STRING:
2064
      xmlXPathDebugObjCounterString--;
2065
      break;
2066
#ifdef LIBXML_XPTR_LOCS_ENABLED
2067
  case XPATH_POINT:
2068
      xmlXPathDebugObjCounterPoint--;
2069
      break;
2070
  case XPATH_RANGE:
2071
      xmlXPathDebugObjCounterRange--;
2072
      break;
2073
  case XPATH_LOCATIONSET:
2074
      xmlXPathDebugObjCounterLocset--;
2075
      break;
2076
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2077
  case XPATH_USERS:
2078
      xmlXPathDebugObjCounterUsers--;
2079
      break;
2080
  case XPATH_XSLT_TREE:
2081
      xmlXPathDebugObjCounterXSLTTree--;
2082
      break;
2083
  default:
2084
      break;
2085
    }
2086
    xmlXPathDebugObjCounterAll--;
2087
}
2088
2089
static void
2090
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2091
{
2092
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2093
  reqXSLTTree, reqUndefined;
2094
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2095
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2096
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2097
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2098
    int leftObjs = xmlXPathDebugObjCounterAll;
2099
2100
    reqAll = xmlXPathDebugObjTotalAll;
2101
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2102
    reqString = xmlXPathDebugObjTotalString;
2103
    reqBool = xmlXPathDebugObjTotalBool;
2104
    reqNumber = xmlXPathDebugObjTotalNumber;
2105
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2106
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2107
2108
    printf("# XPath object usage:\n");
2109
2110
    if (ctxt != NULL) {
2111
  if (ctxt->cache != NULL) {
2112
      xmlXPathContextCachePtr cache =
2113
    (xmlXPathContextCachePtr) ctxt->cache;
2114
2115
      reAll = cache->dbgReusedAll;
2116
      reqAll += reAll;
2117
      reNodeset = cache->dbgReusedNodeset;
2118
      reqNodeset += reNodeset;
2119
      reString = cache->dbgReusedString;
2120
      reqString += reString;
2121
      reBool = cache->dbgReusedBool;
2122
      reqBool += reBool;
2123
      reNumber = cache->dbgReusedNumber;
2124
      reqNumber += reNumber;
2125
      reXSLTTree = cache->dbgReusedXSLTTree;
2126
      reqXSLTTree += reXSLTTree;
2127
      reUndefined = cache->dbgReusedUndefined;
2128
      reqUndefined += reUndefined;
2129
2130
      caAll = cache->dbgCachedAll;
2131
      caBool = cache->dbgCachedBool;
2132
      caNodeset = cache->dbgCachedNodeset;
2133
      caString = cache->dbgCachedString;
2134
      caNumber = cache->dbgCachedNumber;
2135
      caXSLTTree = cache->dbgCachedXSLTTree;
2136
      caUndefined = cache->dbgCachedUndefined;
2137
2138
      if (cache->nodesetObjs)
2139
    leftObjs -= cache->nodesetObjs->number;
2140
      if (cache->stringObjs)
2141
    leftObjs -= cache->stringObjs->number;
2142
      if (cache->booleanObjs)
2143
    leftObjs -= cache->booleanObjs->number;
2144
      if (cache->numberObjs)
2145
    leftObjs -= cache->numberObjs->number;
2146
      if (cache->miscObjs)
2147
    leftObjs -= cache->miscObjs->number;
2148
  }
2149
    }
2150
2151
    printf("# all\n");
2152
    printf("#   total  : %d\n", reqAll);
2153
    printf("#   left  : %d\n", leftObjs);
2154
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2155
    printf("#   reused : %d\n", reAll);
2156
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2157
2158
    printf("# node-sets\n");
2159
    printf("#   total  : %d\n", reqNodeset);
2160
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2161
    printf("#   reused : %d\n", reNodeset);
2162
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2163
2164
    printf("# strings\n");
2165
    printf("#   total  : %d\n", reqString);
2166
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2167
    printf("#   reused : %d\n", reString);
2168
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2169
2170
    printf("# booleans\n");
2171
    printf("#   total  : %d\n", reqBool);
2172
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2173
    printf("#   reused : %d\n", reBool);
2174
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2175
2176
    printf("# numbers\n");
2177
    printf("#   total  : %d\n", reqNumber);
2178
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2179
    printf("#   reused : %d\n", reNumber);
2180
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2181
2182
    printf("# XSLT result tree fragments\n");
2183
    printf("#   total  : %d\n", reqXSLTTree);
2184
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2185
    printf("#   reused : %d\n", reXSLTTree);
2186
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2187
2188
    printf("# undefined\n");
2189
    printf("#   total  : %d\n", reqUndefined);
2190
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2191
    printf("#   reused : %d\n", reUndefined);
2192
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2193
2194
}
2195
2196
#endif /* XP_DEBUG_OBJ_USAGE */
2197
2198
#endif /* LIBXML_DEBUG_ENABLED */
2199
2200
/************************************************************************
2201
 *                  *
2202
 *      XPath object caching        *
2203
 *                  *
2204
 ************************************************************************/
2205
2206
/**
2207
 * xmlXPathNewCache:
2208
 *
2209
 * Create a new object cache
2210
 *
2211
 * Returns the xmlXPathCache just allocated.
2212
 */
2213
static xmlXPathContextCachePtr
2214
xmlXPathNewCache(void)
2215
0
{
2216
0
    xmlXPathContextCachePtr ret;
2217
2218
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2219
0
    if (ret == NULL) {
2220
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2221
0
  return(NULL);
2222
0
    }
2223
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
2224
0
    ret->maxNodeset = 100;
2225
0
    ret->maxString = 100;
2226
0
    ret->maxBoolean = 100;
2227
0
    ret->maxNumber = 100;
2228
0
    ret->maxMisc = 100;
2229
0
    return(ret);
2230
0
}
2231
2232
static void
2233
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2234
0
{
2235
0
    int i;
2236
0
    xmlXPathObjectPtr obj;
2237
2238
0
    if (list == NULL)
2239
0
  return;
2240
2241
0
    for (i = 0; i < list->number; i++) {
2242
0
  obj = list->items[i];
2243
  /*
2244
  * Note that it is already assured that we don't need to
2245
  * look out for namespace nodes in the node-set.
2246
  */
2247
0
  if (obj->nodesetval != NULL) {
2248
0
      if (obj->nodesetval->nodeTab != NULL)
2249
0
    xmlFree(obj->nodesetval->nodeTab);
2250
0
      xmlFree(obj->nodesetval);
2251
0
  }
2252
0
  xmlFree(obj);
2253
#ifdef XP_DEBUG_OBJ_USAGE
2254
  xmlXPathDebugObjCounterAll--;
2255
#endif
2256
0
    }
2257
0
    xmlPointerListFree(list);
2258
0
}
2259
2260
static void
2261
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2262
0
{
2263
0
    if (cache == NULL)
2264
0
  return;
2265
0
    if (cache->nodesetObjs)
2266
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2267
0
    if (cache->stringObjs)
2268
0
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2269
0
    if (cache->booleanObjs)
2270
0
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2271
0
    if (cache->numberObjs)
2272
0
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2273
0
    if (cache->miscObjs)
2274
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2275
0
    xmlFree(cache);
2276
0
}
2277
2278
/**
2279
 * xmlXPathContextSetCache:
2280
 *
2281
 * @ctxt:  the XPath context
2282
 * @active: enables/disables (creates/frees) the cache
2283
 * @value: a value with semantics dependent on @options
2284
 * @options: options (currently only the value 0 is used)
2285
 *
2286
 * Creates/frees an object cache on the XPath context.
2287
 * If activates XPath objects (xmlXPathObject) will be cached internally
2288
 * to be reused.
2289
 * @options:
2290
 *   0: This will set the XPath object caching:
2291
 *      @value:
2292
 *        This will set the maximum number of XPath objects
2293
 *        to be cached per slot
2294
 *        There are 5 slots for: node-set, string, number, boolean, and
2295
 *        misc objects. Use <0 for the default number (100).
2296
 *   Other values for @options have currently no effect.
2297
 *
2298
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2299
 */
2300
int
2301
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2302
      int active,
2303
      int value,
2304
      int options)
2305
0
{
2306
0
    if (ctxt == NULL)
2307
0
  return(-1);
2308
0
    if (active) {
2309
0
  xmlXPathContextCachePtr cache;
2310
2311
0
  if (ctxt->cache == NULL) {
2312
0
      ctxt->cache = xmlXPathNewCache();
2313
0
      if (ctxt->cache == NULL)
2314
0
    return(-1);
2315
0
  }
2316
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2317
0
  if (options == 0) {
2318
0
      if (value < 0)
2319
0
    value = 100;
2320
0
      cache->maxNodeset = value;
2321
0
      cache->maxString = value;
2322
0
      cache->maxNumber = value;
2323
0
      cache->maxBoolean = value;
2324
0
      cache->maxMisc = value;
2325
0
  }
2326
0
    } else if (ctxt->cache != NULL) {
2327
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2328
0
  ctxt->cache = NULL;
2329
0
    }
2330
0
    return(0);
2331
0
}
2332
2333
/**
2334
 * xmlXPathCacheWrapNodeSet:
2335
 * @ctxt: the XPath context
2336
 * @val:  the NodePtr value
2337
 *
2338
 * This is the cached version of xmlXPathWrapNodeSet().
2339
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2340
 *
2341
 * Returns the created or reused object.
2342
 *
2343
 * In case of error the node set is destroyed and NULL is returned.
2344
 */
2345
static xmlXPathObjectPtr
2346
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2347
0
{
2348
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2349
0
  xmlXPathContextCachePtr cache =
2350
0
      (xmlXPathContextCachePtr) ctxt->cache;
2351
2352
0
  if ((cache->miscObjs != NULL) &&
2353
0
      (cache->miscObjs->number != 0))
2354
0
  {
2355
0
      xmlXPathObjectPtr ret;
2356
2357
0
      ret = (xmlXPathObjectPtr)
2358
0
    cache->miscObjs->items[--cache->miscObjs->number];
2359
0
      ret->type = XPATH_NODESET;
2360
0
      ret->nodesetval = val;
2361
#ifdef XP_DEBUG_OBJ_USAGE
2362
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2363
#endif
2364
0
      return(ret);
2365
0
  }
2366
0
    }
2367
2368
0
    return(xmlXPathWrapNodeSet(val));
2369
2370
0
}
2371
2372
/**
2373
 * xmlXPathCacheWrapString:
2374
 * @ctxt: the XPath context
2375
 * @val:  the xmlChar * value
2376
 *
2377
 * This is the cached version of xmlXPathWrapString().
2378
 * Wraps the @val string into an XPath object.
2379
 *
2380
 * Returns the created or reused object.
2381
 */
2382
static xmlXPathObjectPtr
2383
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2384
0
{
2385
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2386
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2387
2388
0
  if ((cache->stringObjs != NULL) &&
2389
0
      (cache->stringObjs->number != 0))
2390
0
  {
2391
2392
0
      xmlXPathObjectPtr ret;
2393
2394
0
      ret = (xmlXPathObjectPtr)
2395
0
    cache->stringObjs->items[--cache->stringObjs->number];
2396
0
      ret->type = XPATH_STRING;
2397
0
      ret->stringval = val;
2398
#ifdef XP_DEBUG_OBJ_USAGE
2399
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2400
#endif
2401
0
      return(ret);
2402
0
  } else if ((cache->miscObjs != NULL) &&
2403
0
      (cache->miscObjs->number != 0))
2404
0
  {
2405
0
      xmlXPathObjectPtr ret;
2406
      /*
2407
      * Fallback to misc-cache.
2408
      */
2409
0
      ret = (xmlXPathObjectPtr)
2410
0
    cache->miscObjs->items[--cache->miscObjs->number];
2411
2412
0
      ret->type = XPATH_STRING;
2413
0
      ret->stringval = val;
2414
#ifdef XP_DEBUG_OBJ_USAGE
2415
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2416
#endif
2417
0
      return(ret);
2418
0
  }
2419
0
    }
2420
0
    return(xmlXPathWrapString(val));
2421
0
}
2422
2423
/**
2424
 * xmlXPathCacheNewNodeSet:
2425
 * @ctxt: the XPath context
2426
 * @val:  the NodePtr value
2427
 *
2428
 * This is the cached version of xmlXPathNewNodeSet().
2429
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2430
 * it with the single Node @val
2431
 *
2432
 * Returns the created or reused object.
2433
 */
2434
static xmlXPathObjectPtr
2435
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2436
0
{
2437
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2438
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2439
2440
0
  if ((cache->nodesetObjs != NULL) &&
2441
0
      (cache->nodesetObjs->number != 0))
2442
0
  {
2443
0
      xmlXPathObjectPtr ret;
2444
      /*
2445
      * Use the nodeset-cache.
2446
      */
2447
0
      ret = (xmlXPathObjectPtr)
2448
0
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2449
0
      ret->type = XPATH_NODESET;
2450
0
      ret->boolval = 0;
2451
0
      if (val) {
2452
0
    if ((ret->nodesetval->nodeMax == 0) ||
2453
0
        (val->type == XML_NAMESPACE_DECL))
2454
0
    {
2455
                    /* TODO: Check memory error. */
2456
0
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2457
0
    } else {
2458
0
        ret->nodesetval->nodeTab[0] = val;
2459
0
        ret->nodesetval->nodeNr = 1;
2460
0
    }
2461
0
      }
2462
#ifdef XP_DEBUG_OBJ_USAGE
2463
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2464
#endif
2465
0
      return(ret);
2466
0
  } else if ((cache->miscObjs != NULL) &&
2467
0
      (cache->miscObjs->number != 0))
2468
0
  {
2469
0
      xmlXPathObjectPtr ret;
2470
0
            xmlNodeSetPtr set;
2471
      /*
2472
      * Fallback to misc-cache.
2473
      */
2474
2475
0
      set = xmlXPathNodeSetCreate(val);
2476
0
      if (set == NULL) {
2477
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2478
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2479
0
    return(NULL);
2480
0
      }
2481
2482
0
      ret = (xmlXPathObjectPtr)
2483
0
    cache->miscObjs->items[--cache->miscObjs->number];
2484
2485
0
      ret->type = XPATH_NODESET;
2486
0
      ret->boolval = 0;
2487
0
      ret->nodesetval = set;
2488
#ifdef XP_DEBUG_OBJ_USAGE
2489
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2490
#endif
2491
0
      return(ret);
2492
0
  }
2493
0
    }
2494
0
    return(xmlXPathNewNodeSet(val));
2495
0
}
2496
2497
/**
2498
 * xmlXPathCacheNewString:
2499
 * @ctxt: the XPath context
2500
 * @val:  the xmlChar * value
2501
 *
2502
 * This is the cached version of xmlXPathNewString().
2503
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2504
 *
2505
 * Returns the created or reused object.
2506
 */
2507
static xmlXPathObjectPtr
2508
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2509
0
{
2510
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2511
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2512
2513
0
  if ((cache->stringObjs != NULL) &&
2514
0
      (cache->stringObjs->number != 0))
2515
0
  {
2516
0
      xmlXPathObjectPtr ret;
2517
0
            xmlChar *copy;
2518
2519
0
            if (val == NULL)
2520
0
                val = BAD_CAST "";
2521
0
            copy = xmlStrdup(val);
2522
0
            if (copy == NULL) {
2523
0
                xmlXPathErrMemory(ctxt, NULL);
2524
0
                return(NULL);
2525
0
            }
2526
2527
0
      ret = (xmlXPathObjectPtr)
2528
0
    cache->stringObjs->items[--cache->stringObjs->number];
2529
0
      ret->type = XPATH_STRING;
2530
0
            ret->stringval = copy;
2531
#ifdef XP_DEBUG_OBJ_USAGE
2532
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2533
#endif
2534
0
      return(ret);
2535
0
  } else if ((cache->miscObjs != NULL) &&
2536
0
      (cache->miscObjs->number != 0))
2537
0
  {
2538
0
      xmlXPathObjectPtr ret;
2539
0
            xmlChar *copy;
2540
2541
0
            if (val == NULL)
2542
0
                val = BAD_CAST "";
2543
0
            copy = xmlStrdup(val);
2544
0
            if (copy == NULL) {
2545
0
                xmlXPathErrMemory(ctxt, NULL);
2546
0
                return(NULL);
2547
0
            }
2548
2549
0
      ret = (xmlXPathObjectPtr)
2550
0
    cache->miscObjs->items[--cache->miscObjs->number];
2551
2552
0
      ret->type = XPATH_STRING;
2553
0
            ret->stringval = copy;
2554
#ifdef XP_DEBUG_OBJ_USAGE
2555
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2556
#endif
2557
0
      return(ret);
2558
0
  }
2559
0
    }
2560
0
    return(xmlXPathNewString(val));
2561
0
}
2562
2563
/**
2564
 * xmlXPathCacheNewCString:
2565
 * @ctxt: the XPath context
2566
 * @val:  the char * value
2567
 *
2568
 * This is the cached version of xmlXPathNewCString().
2569
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2570
 *
2571
 * Returns the created or reused object.
2572
 */
2573
static xmlXPathObjectPtr
2574
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2575
0
{
2576
0
    return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2577
0
}
2578
2579
/**
2580
 * xmlXPathCacheNewBoolean:
2581
 * @ctxt: the XPath context
2582
 * @val:  the boolean value
2583
 *
2584
 * This is the cached version of xmlXPathNewBoolean().
2585
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2586
 *
2587
 * Returns the created or reused object.
2588
 */
2589
static xmlXPathObjectPtr
2590
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2591
0
{
2592
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2593
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2594
2595
0
  if ((cache->booleanObjs != NULL) &&
2596
0
      (cache->booleanObjs->number != 0))
2597
0
  {
2598
0
      xmlXPathObjectPtr ret;
2599
2600
0
      ret = (xmlXPathObjectPtr)
2601
0
    cache->booleanObjs->items[--cache->booleanObjs->number];
2602
0
      ret->type = XPATH_BOOLEAN;
2603
0
      ret->boolval = (val != 0);
2604
#ifdef XP_DEBUG_OBJ_USAGE
2605
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2606
#endif
2607
0
      return(ret);
2608
0
  } else if ((cache->miscObjs != NULL) &&
2609
0
      (cache->miscObjs->number != 0))
2610
0
  {
2611
0
      xmlXPathObjectPtr ret;
2612
2613
0
      ret = (xmlXPathObjectPtr)
2614
0
    cache->miscObjs->items[--cache->miscObjs->number];
2615
2616
0
      ret->type = XPATH_BOOLEAN;
2617
0
      ret->boolval = (val != 0);
2618
#ifdef XP_DEBUG_OBJ_USAGE
2619
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2620
#endif
2621
0
      return(ret);
2622
0
  }
2623
0
    }
2624
0
    return(xmlXPathNewBoolean(val));
2625
0
}
2626
2627
/**
2628
 * xmlXPathCacheNewFloat:
2629
 * @ctxt: the XPath context
2630
 * @val:  the double value
2631
 *
2632
 * This is the cached version of xmlXPathNewFloat().
2633
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2634
 *
2635
 * Returns the created or reused object.
2636
 */
2637
static xmlXPathObjectPtr
2638
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2639
0
{
2640
0
     if ((ctxt != NULL) && (ctxt->cache)) {
2641
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2642
2643
0
  if ((cache->numberObjs != NULL) &&
2644
0
      (cache->numberObjs->number != 0))
2645
0
  {
2646
0
      xmlXPathObjectPtr ret;
2647
2648
0
      ret = (xmlXPathObjectPtr)
2649
0
    cache->numberObjs->items[--cache->numberObjs->number];
2650
0
      ret->type = XPATH_NUMBER;
2651
0
      ret->floatval = val;
2652
#ifdef XP_DEBUG_OBJ_USAGE
2653
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2654
#endif
2655
0
      return(ret);
2656
0
  } else if ((cache->miscObjs != NULL) &&
2657
0
      (cache->miscObjs->number != 0))
2658
0
  {
2659
0
      xmlXPathObjectPtr ret;
2660
2661
0
      ret = (xmlXPathObjectPtr)
2662
0
    cache->miscObjs->items[--cache->miscObjs->number];
2663
2664
0
      ret->type = XPATH_NUMBER;
2665
0
      ret->floatval = val;
2666
#ifdef XP_DEBUG_OBJ_USAGE
2667
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2668
#endif
2669
0
      return(ret);
2670
0
  }
2671
0
    }
2672
0
    return(xmlXPathNewFloat(val));
2673
0
}
2674
2675
/**
2676
 * xmlXPathCacheConvertString:
2677
 * @ctxt: the XPath context
2678
 * @val:  an XPath object
2679
 *
2680
 * This is the cached version of xmlXPathConvertString().
2681
 * Converts an existing object to its string() equivalent
2682
 *
2683
 * Returns a created or reused object, the old one is freed (cached)
2684
 *         (or the operation is done directly on @val)
2685
 */
2686
2687
static xmlXPathObjectPtr
2688
0
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2689
0
    xmlChar *res = NULL;
2690
2691
0
    if (val == NULL)
2692
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2693
2694
0
    switch (val->type) {
2695
0
    case XPATH_UNDEFINED:
2696
#ifdef DEBUG_EXPR
2697
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2698
#endif
2699
0
  break;
2700
0
    case XPATH_NODESET:
2701
0
    case XPATH_XSLT_TREE:
2702
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2703
0
  break;
2704
0
    case XPATH_STRING:
2705
0
  return(val);
2706
0
    case XPATH_BOOLEAN:
2707
0
  res = xmlXPathCastBooleanToString(val->boolval);
2708
0
  break;
2709
0
    case XPATH_NUMBER:
2710
0
  res = xmlXPathCastNumberToString(val->floatval);
2711
0
  break;
2712
0
    case XPATH_USERS:
2713
#ifdef LIBXML_XPTR_LOCS_ENABLED
2714
    case XPATH_POINT:
2715
    case XPATH_RANGE:
2716
    case XPATH_LOCATIONSET:
2717
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2718
0
  TODO;
2719
0
  break;
2720
0
    }
2721
0
    xmlXPathReleaseObject(ctxt, val);
2722
0
    if (res == NULL)
2723
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2724
0
    return(xmlXPathCacheWrapString(ctxt, res));
2725
0
}
2726
2727
/**
2728
 * xmlXPathCacheObjectCopy:
2729
 * @ctxt: the XPath context
2730
 * @val:  the original object
2731
 *
2732
 * This is the cached version of xmlXPathObjectCopy().
2733
 * Acquire a copy of a given object
2734
 *
2735
 * Returns a created or reused created object.
2736
 */
2737
static xmlXPathObjectPtr
2738
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2739
0
{
2740
0
    if (val == NULL)
2741
0
  return(NULL);
2742
2743
0
    if (XP_HAS_CACHE(ctxt)) {
2744
0
  switch (val->type) {
2745
0
      case XPATH_NODESET:
2746
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2747
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2748
0
      case XPATH_STRING:
2749
0
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2750
0
      case XPATH_BOOLEAN:
2751
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2752
0
      case XPATH_NUMBER:
2753
0
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2754
0
      default:
2755
0
    break;
2756
0
  }
2757
0
    }
2758
0
    return(xmlXPathObjectCopy(val));
2759
0
}
2760
2761
/**
2762
 * xmlXPathCacheConvertBoolean:
2763
 * @ctxt: the XPath context
2764
 * @val:  an XPath object
2765
 *
2766
 * This is the cached version of xmlXPathConvertBoolean().
2767
 * Converts an existing object to its boolean() equivalent
2768
 *
2769
 * Returns a created or reused object, the old one is freed (or the operation
2770
 *         is done directly on @val)
2771
 */
2772
static xmlXPathObjectPtr
2773
0
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774
0
    xmlXPathObjectPtr ret;
2775
2776
0
    if (val == NULL)
2777
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2778
0
    if (val->type == XPATH_BOOLEAN)
2779
0
  return(val);
2780
0
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2781
0
    xmlXPathReleaseObject(ctxt, val);
2782
0
    return(ret);
2783
0
}
2784
2785
/**
2786
 * xmlXPathCacheConvertNumber:
2787
 * @ctxt: the XPath context
2788
 * @val:  an XPath object
2789
 *
2790
 * This is the cached version of xmlXPathConvertNumber().
2791
 * Converts an existing object to its number() equivalent
2792
 *
2793
 * Returns a created or reused object, the old one is freed (or the operation
2794
 *         is done directly on @val)
2795
 */
2796
static xmlXPathObjectPtr
2797
0
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2798
0
    xmlXPathObjectPtr ret;
2799
2800
0
    if (val == NULL)
2801
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2802
0
    if (val->type == XPATH_NUMBER)
2803
0
  return(val);
2804
0
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2805
0
    xmlXPathReleaseObject(ctxt, val);
2806
0
    return(ret);
2807
0
}
2808
2809
/************************************************************************
2810
 *                  *
2811
 *    Parser stacks related functions and macros    *
2812
 *                  *
2813
 ************************************************************************/
2814
2815
/**
2816
 * valuePop:
2817
 * @ctxt: an XPath evaluation context
2818
 *
2819
 * Pops the top XPath object from the value stack
2820
 *
2821
 * Returns the XPath object just removed
2822
 */
2823
xmlXPathObjectPtr
2824
valuePop(xmlXPathParserContextPtr ctxt)
2825
0
{
2826
0
    xmlXPathObjectPtr ret;
2827
2828
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2829
0
        return (NULL);
2830
2831
0
    ctxt->valueNr--;
2832
0
    if (ctxt->valueNr > 0)
2833
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2834
0
    else
2835
0
        ctxt->value = NULL;
2836
0
    ret = ctxt->valueTab[ctxt->valueNr];
2837
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
2838
0
    return (ret);
2839
0
}
2840
/**
2841
 * valuePush:
2842
 * @ctxt:  an XPath evaluation context
2843
 * @value:  the XPath object
2844
 *
2845
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2846
 * a memory error is recorded in the parser context.
2847
 *
2848
 * Returns the number of items on the value stack, or -1 in case of error.
2849
 *
2850
 * The object is destroyed in case of error.
2851
 */
2852
int
2853
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2854
0
{
2855
0
    if (ctxt == NULL) return(-1);
2856
0
    if (value == NULL) {
2857
        /*
2858
         * A NULL value typically indicates that a memory allocation failed,
2859
         * so we set ctxt->error here to propagate the error.
2860
         */
2861
0
  ctxt->error = XPATH_MEMORY_ERROR;
2862
0
        return(-1);
2863
0
    }
2864
0
    if (ctxt->valueNr >= ctxt->valueMax) {
2865
0
        xmlXPathObjectPtr *tmp;
2866
2867
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2868
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2869
0
            xmlXPathFreeObject(value);
2870
0
            return (-1);
2871
0
        }
2872
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2873
0
                                             2 * ctxt->valueMax *
2874
0
                                             sizeof(ctxt->valueTab[0]));
2875
0
        if (tmp == NULL) {
2876
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2877
0
            xmlXPathFreeObject(value);
2878
0
            return (-1);
2879
0
        }
2880
0
        ctxt->valueMax *= 2;
2881
0
  ctxt->valueTab = tmp;
2882
0
    }
2883
0
    ctxt->valueTab[ctxt->valueNr] = value;
2884
0
    ctxt->value = value;
2885
0
    return (ctxt->valueNr++);
2886
0
}
2887
2888
/**
2889
 * xmlXPathPopBoolean:
2890
 * @ctxt:  an XPath parser context
2891
 *
2892
 * Pops a boolean from the stack, handling conversion if needed.
2893
 * Check error with #xmlXPathCheckError.
2894
 *
2895
 * Returns the boolean
2896
 */
2897
int
2898
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2899
0
    xmlXPathObjectPtr obj;
2900
0
    int ret;
2901
2902
0
    obj = valuePop(ctxt);
2903
0
    if (obj == NULL) {
2904
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905
0
  return(0);
2906
0
    }
2907
0
    if (obj->type != XPATH_BOOLEAN)
2908
0
  ret = xmlXPathCastToBoolean(obj);
2909
0
    else
2910
0
        ret = obj->boolval;
2911
0
    xmlXPathReleaseObject(ctxt->context, obj);
2912
0
    return(ret);
2913
0
}
2914
2915
/**
2916
 * xmlXPathPopNumber:
2917
 * @ctxt:  an XPath parser context
2918
 *
2919
 * Pops a number from the stack, handling conversion if needed.
2920
 * Check error with #xmlXPathCheckError.
2921
 *
2922
 * Returns the number
2923
 */
2924
double
2925
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2926
0
    xmlXPathObjectPtr obj;
2927
0
    double ret;
2928
2929
0
    obj = valuePop(ctxt);
2930
0
    if (obj == NULL) {
2931
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932
0
  return(0);
2933
0
    }
2934
0
    if (obj->type != XPATH_NUMBER)
2935
0
  ret = xmlXPathCastToNumber(obj);
2936
0
    else
2937
0
        ret = obj->floatval;
2938
0
    xmlXPathReleaseObject(ctxt->context, obj);
2939
0
    return(ret);
2940
0
}
2941
2942
/**
2943
 * xmlXPathPopString:
2944
 * @ctxt:  an XPath parser context
2945
 *
2946
 * Pops a string from the stack, handling conversion if needed.
2947
 * Check error with #xmlXPathCheckError.
2948
 *
2949
 * Returns the string
2950
 */
2951
xmlChar *
2952
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2953
0
    xmlXPathObjectPtr obj;
2954
0
    xmlChar * ret;
2955
2956
0
    obj = valuePop(ctxt);
2957
0
    if (obj == NULL) {
2958
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959
0
  return(NULL);
2960
0
    }
2961
0
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2962
    /* TODO: needs refactoring somewhere else */
2963
0
    if (obj->stringval == ret)
2964
0
  obj->stringval = NULL;
2965
0
    xmlXPathReleaseObject(ctxt->context, obj);
2966
0
    return(ret);
2967
0
}
2968
2969
/**
2970
 * xmlXPathPopNodeSet:
2971
 * @ctxt:  an XPath parser context
2972
 *
2973
 * Pops a node-set from the stack, handling conversion if needed.
2974
 * Check error with #xmlXPathCheckError.
2975
 *
2976
 * Returns the node-set
2977
 */
2978
xmlNodeSetPtr
2979
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2980
0
    xmlXPathObjectPtr obj;
2981
0
    xmlNodeSetPtr ret;
2982
2983
0
    if (ctxt == NULL) return(NULL);
2984
0
    if (ctxt->value == NULL) {
2985
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986
0
  return(NULL);
2987
0
    }
2988
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2989
0
  xmlXPathSetTypeError(ctxt);
2990
0
  return(NULL);
2991
0
    }
2992
0
    obj = valuePop(ctxt);
2993
0
    ret = obj->nodesetval;
2994
#if 0
2995
    /* to fix memory leak of not clearing obj->user */
2996
    if (obj->boolval && obj->user != NULL)
2997
        xmlFreeNodeList((xmlNodePtr) obj->user);
2998
#endif
2999
0
    obj->nodesetval = NULL;
3000
0
    xmlXPathReleaseObject(ctxt->context, obj);
3001
0
    return(ret);
3002
0
}
3003
3004
/**
3005
 * xmlXPathPopExternal:
3006
 * @ctxt:  an XPath parser context
3007
 *
3008
 * Pops an external object from the stack, handling conversion if needed.
3009
 * Check error with #xmlXPathCheckError.
3010
 *
3011
 * Returns the object
3012
 */
3013
void *
3014
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3015
0
    xmlXPathObjectPtr obj;
3016
0
    void * ret;
3017
3018
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3019
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3020
0
  return(NULL);
3021
0
    }
3022
0
    if (ctxt->value->type != XPATH_USERS) {
3023
0
  xmlXPathSetTypeError(ctxt);
3024
0
  return(NULL);
3025
0
    }
3026
0
    obj = valuePop(ctxt);
3027
0
    ret = obj->user;
3028
0
    obj->user = NULL;
3029
0
    xmlXPathReleaseObject(ctxt->context, obj);
3030
0
    return(ret);
3031
0
}
3032
3033
/*
3034
 * Macros for accessing the content. Those should be used only by the parser,
3035
 * and not exported.
3036
 *
3037
 * Dirty macros, i.e. one need to make assumption on the context to use them
3038
 *
3039
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3040
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3041
 *           in ISO-Latin or UTF-8.
3042
 *           This should be used internally by the parser
3043
 *           only to compare to ASCII values otherwise it would break when
3044
 *           running with UTF-8 encoding.
3045
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3046
 *           to compare on ASCII based substring.
3047
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3048
 *           strings within the parser.
3049
 *   CURRENT Returns the current char value, with the full decoding of
3050
 *           UTF-8 if we are using this mode. It returns an int.
3051
 *   NEXT    Skip to the next character, this does the proper decoding
3052
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3053
 *           It returns the pointer to the current xmlChar.
3054
 */
3055
3056
0
#define CUR (*ctxt->cur)
3057
0
#define SKIP(val) ctxt->cur += (val)
3058
0
#define NXT(val) ctxt->cur[(val)]
3059
0
#define CUR_PTR ctxt->cur
3060
0
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3061
3062
#define COPY_BUF(l,b,i,v)                                              \
3063
0
    if (l == 1) b[i++] = v;                                            \
3064
0
    else i += xmlCopyChar(l,&b[i],v)
3065
3066
0
#define NEXTL(l)  ctxt->cur += l
3067
3068
#define SKIP_BLANKS             \
3069
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3070
3071
#define CURRENT (*ctxt->cur)
3072
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3073
3074
3075
#ifndef DBL_DIG
3076
#define DBL_DIG 16
3077
#endif
3078
#ifndef DBL_EPSILON
3079
#define DBL_EPSILON 1E-9
3080
#endif
3081
3082
0
#define UPPER_DOUBLE 1E9
3083
0
#define LOWER_DOUBLE 1E-5
3084
#define LOWER_DOUBLE_EXP 5
3085
3086
#define INTEGER_DIGITS DBL_DIG
3087
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3088
0
#define EXPONENT_DIGITS (3 + 2)
3089
3090
/**
3091
 * xmlXPathFormatNumber:
3092
 * @number:     number to format
3093
 * @buffer:     output buffer
3094
 * @buffersize: size of output buffer
3095
 *
3096
 * Convert the number into a string representation.
3097
 */
3098
static void
3099
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3100
0
{
3101
0
    switch (xmlXPathIsInf(number)) {
3102
0
    case 1:
3103
0
  if (buffersize > (int)sizeof("Infinity"))
3104
0
      snprintf(buffer, buffersize, "Infinity");
3105
0
  break;
3106
0
    case -1:
3107
0
  if (buffersize > (int)sizeof("-Infinity"))
3108
0
      snprintf(buffer, buffersize, "-Infinity");
3109
0
  break;
3110
0
    default:
3111
0
  if (xmlXPathIsNaN(number)) {
3112
0
      if (buffersize > (int)sizeof("NaN"))
3113
0
    snprintf(buffer, buffersize, "NaN");
3114
0
  } else if (number == 0) {
3115
            /* Omit sign for negative zero. */
3116
0
      snprintf(buffer, buffersize, "0");
3117
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3118
0
                   (number == (int) number)) {
3119
0
      char work[30];
3120
0
      char *ptr, *cur;
3121
0
      int value = (int) number;
3122
3123
0
            ptr = &buffer[0];
3124
0
      if (value == 0) {
3125
0
    *ptr++ = '0';
3126
0
      } else {
3127
0
    snprintf(work, 29, "%d", value);
3128
0
    cur = &work[0];
3129
0
    while ((*cur) && (ptr - buffer < buffersize)) {
3130
0
        *ptr++ = *cur++;
3131
0
    }
3132
0
      }
3133
0
      if (ptr - buffer < buffersize) {
3134
0
    *ptr = 0;
3135
0
      } else if (buffersize > 0) {
3136
0
    ptr--;
3137
0
    *ptr = 0;
3138
0
      }
3139
0
  } else {
3140
      /*
3141
        For the dimension of work,
3142
            DBL_DIG is number of significant digits
3143
      EXPONENT is only needed for "scientific notation"
3144
            3 is sign, decimal point, and terminating zero
3145
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3146
        Note that this dimension is slightly (a few characters)
3147
        larger than actually necessary.
3148
      */
3149
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3150
0
      int integer_place, fraction_place;
3151
0
      char *ptr;
3152
0
      char *after_fraction;
3153
0
      double absolute_value;
3154
0
      int size;
3155
3156
0
      absolute_value = fabs(number);
3157
3158
      /*
3159
       * First choose format - scientific or regular floating point.
3160
       * In either case, result is in work, and after_fraction points
3161
       * just past the fractional part.
3162
      */
3163
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
3164
0
      (absolute_value < LOWER_DOUBLE)) &&
3165
0
     (absolute_value != 0.0) ) {
3166
    /* Use scientific notation */
3167
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3168
0
    fraction_place = DBL_DIG - 1;
3169
0
    size = snprintf(work, sizeof(work),"%*.*e",
3170
0
       integer_place, fraction_place, number);
3171
0
    while ((size > 0) && (work[size] != 'e')) size--;
3172
3173
0
      }
3174
0
      else {
3175
    /* Use regular notation */
3176
0
    if (absolute_value > 0.0) {
3177
0
        integer_place = (int)log10(absolute_value);
3178
0
        if (integer_place > 0)
3179
0
            fraction_place = DBL_DIG - integer_place - 1;
3180
0
        else
3181
0
            fraction_place = DBL_DIG - integer_place;
3182
0
    } else {
3183
0
        fraction_place = 1;
3184
0
    }
3185
0
    size = snprintf(work, sizeof(work), "%0.*f",
3186
0
        fraction_place, number);
3187
0
      }
3188
3189
      /* Remove leading spaces sometimes inserted by snprintf */
3190
0
      while (work[0] == ' ') {
3191
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3192
0
    size--;
3193
0
      }
3194
3195
      /* Remove fractional trailing zeroes */
3196
0
      after_fraction = work + size;
3197
0
      ptr = after_fraction;
3198
0
      while (*(--ptr) == '0')
3199
0
    ;
3200
0
      if (*ptr != '.')
3201
0
          ptr++;
3202
0
      while ((*ptr++ = *after_fraction++) != 0);
3203
3204
      /* Finally copy result back to caller */
3205
0
      size = strlen(work) + 1;
3206
0
      if (size > buffersize) {
3207
0
    work[buffersize - 1] = 0;
3208
0
    size = buffersize;
3209
0
      }
3210
0
      memmove(buffer, work, size);
3211
0
  }
3212
0
  break;
3213
0
    }
3214
0
}
3215
3216
3217
/************************************************************************
3218
 *                  *
3219
 *      Routines to handle NodeSets     *
3220
 *                  *
3221
 ************************************************************************/
3222
3223
/**
3224
 * xmlXPathOrderDocElems:
3225
 * @doc:  an input document
3226
 *
3227
 * Call this routine to speed up XPath computation on static documents.
3228
 * This stamps all the element nodes with the document order
3229
 * Like for line information, the order is kept in the element->content
3230
 * field, the value stored is actually - the node number (starting at -1)
3231
 * to be able to differentiate from line numbers.
3232
 *
3233
 * Returns the number of elements found in the document or -1 in case
3234
 *    of error.
3235
 */
3236
long
3237
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
3238
0
    ptrdiff_t count = 0;
3239
0
    xmlNodePtr cur;
3240
3241
0
    if (doc == NULL)
3242
0
  return(-1);
3243
0
    cur = doc->children;
3244
0
    while (cur != NULL) {
3245
0
  if (cur->type == XML_ELEMENT_NODE) {
3246
0
      cur->content = (void *) (-(++count));
3247
0
      if (cur->children != NULL) {
3248
0
    cur = cur->children;
3249
0
    continue;
3250
0
      }
3251
0
  }
3252
0
  if (cur->next != NULL) {
3253
0
      cur = cur->next;
3254
0
      continue;
3255
0
  }
3256
0
  do {
3257
0
      cur = cur->parent;
3258
0
      if (cur == NULL)
3259
0
    break;
3260
0
      if (cur == (xmlNodePtr) doc) {
3261
0
    cur = NULL;
3262
0
    break;
3263
0
      }
3264
0
      if (cur->next != NULL) {
3265
0
    cur = cur->next;
3266
0
    break;
3267
0
      }
3268
0
  } while (cur != NULL);
3269
0
    }
3270
0
    return(count);
3271
0
}
3272
3273
/**
3274
 * xmlXPathCmpNodes:
3275
 * @node1:  the first node
3276
 * @node2:  the second node
3277
 *
3278
 * Compare two nodes w.r.t document order
3279
 *
3280
 * Returns -2 in case of error 1 if first point < second point, 0 if
3281
 *         it's the same node, -1 otherwise
3282
 */
3283
int
3284
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3285
0
    int depth1, depth2;
3286
0
    int attr1 = 0, attr2 = 0;
3287
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3288
0
    xmlNodePtr cur, root;
3289
3290
0
    if ((node1 == NULL) || (node2 == NULL))
3291
0
  return(-2);
3292
    /*
3293
     * a couple of optimizations which will avoid computations in most cases
3294
     */
3295
0
    if (node1 == node2)   /* trivial case */
3296
0
  return(0);
3297
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
3298
0
  attr1 = 1;
3299
0
  attrNode1 = node1;
3300
0
  node1 = node1->parent;
3301
0
    }
3302
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
3303
0
  attr2 = 1;
3304
0
  attrNode2 = node2;
3305
0
  node2 = node2->parent;
3306
0
    }
3307
0
    if (node1 == node2) {
3308
0
  if (attr1 == attr2) {
3309
      /* not required, but we keep attributes in order */
3310
0
      if (attr1 != 0) {
3311
0
          cur = attrNode2->prev;
3312
0
    while (cur != NULL) {
3313
0
        if (cur == attrNode1)
3314
0
            return (1);
3315
0
        cur = cur->prev;
3316
0
    }
3317
0
    return (-1);
3318
0
      }
3319
0
      return(0);
3320
0
  }
3321
0
  if (attr2 == 1)
3322
0
      return(1);
3323
0
  return(-1);
3324
0
    }
3325
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
3326
0
        (node2->type == XML_NAMESPACE_DECL))
3327
0
  return(1);
3328
0
    if (node1 == node2->prev)
3329
0
  return(1);
3330
0
    if (node1 == node2->next)
3331
0
  return(-1);
3332
3333
    /*
3334
     * Speedup using document order if available.
3335
     */
3336
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3337
0
  (node2->type == XML_ELEMENT_NODE) &&
3338
0
  (0 > (ptrdiff_t) node1->content) &&
3339
0
  (0 > (ptrdiff_t) node2->content) &&
3340
0
  (node1->doc == node2->doc)) {
3341
0
  ptrdiff_t l1, l2;
3342
3343
0
  l1 = -((ptrdiff_t) node1->content);
3344
0
  l2 = -((ptrdiff_t) node2->content);
3345
0
  if (l1 < l2)
3346
0
      return(1);
3347
0
  if (l1 > l2)
3348
0
      return(-1);
3349
0
    }
3350
3351
    /*
3352
     * compute depth to root
3353
     */
3354
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3355
0
  if (cur->parent == node1)
3356
0
      return(1);
3357
0
  depth2++;
3358
0
    }
3359
0
    root = cur;
3360
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3361
0
  if (cur->parent == node2)
3362
0
      return(-1);
3363
0
  depth1++;
3364
0
    }
3365
    /*
3366
     * Distinct document (or distinct entities :-( ) case.
3367
     */
3368
0
    if (root != cur) {
3369
0
  return(-2);
3370
0
    }
3371
    /*
3372
     * get the nearest common ancestor.
3373
     */
3374
0
    while (depth1 > depth2) {
3375
0
  depth1--;
3376
0
  node1 = node1->parent;
3377
0
    }
3378
0
    while (depth2 > depth1) {
3379
0
  depth2--;
3380
0
  node2 = node2->parent;
3381
0
    }
3382
0
    while (node1->parent != node2->parent) {
3383
0
  node1 = node1->parent;
3384
0
  node2 = node2->parent;
3385
  /* should not happen but just in case ... */
3386
0
  if ((node1 == NULL) || (node2 == NULL))
3387
0
      return(-2);
3388
0
    }
3389
    /*
3390
     * Find who's first.
3391
     */
3392
0
    if (node1 == node2->prev)
3393
0
  return(1);
3394
0
    if (node1 == node2->next)
3395
0
  return(-1);
3396
    /*
3397
     * Speedup using document order if available.
3398
     */
3399
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3400
0
  (node2->type == XML_ELEMENT_NODE) &&
3401
0
  (0 > (ptrdiff_t) node1->content) &&
3402
0
  (0 > (ptrdiff_t) node2->content) &&
3403
0
  (node1->doc == node2->doc)) {
3404
0
  ptrdiff_t l1, l2;
3405
3406
0
  l1 = -((ptrdiff_t) node1->content);
3407
0
  l2 = -((ptrdiff_t) node2->content);
3408
0
  if (l1 < l2)
3409
0
      return(1);
3410
0
  if (l1 > l2)
3411
0
      return(-1);
3412
0
    }
3413
3414
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
3415
0
  if (cur == node2)
3416
0
      return(1);
3417
0
    return(-1); /* assume there is no sibling list corruption */
3418
0
}
3419
3420
/**
3421
 * xmlXPathNodeSetSort:
3422
 * @set:  the node set
3423
 *
3424
 * Sort the node set in document order
3425
 */
3426
void
3427
0
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3428
#ifndef WITH_TIM_SORT
3429
    int i, j, incr, len;
3430
    xmlNodePtr tmp;
3431
#endif
3432
3433
0
    if (set == NULL)
3434
0
  return;
3435
3436
#ifndef WITH_TIM_SORT
3437
    /*
3438
     * Use the old Shell's sort implementation to sort the node-set
3439
     * Timsort ought to be quite faster
3440
     */
3441
    len = set->nodeNr;
3442
    for (incr = len / 2; incr > 0; incr /= 2) {
3443
  for (i = incr; i < len; i++) {
3444
      j = i - incr;
3445
      while (j >= 0) {
3446
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3447
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3448
      set->nodeTab[j + incr]) == -1)
3449
#else
3450
    if (xmlXPathCmpNodes(set->nodeTab[j],
3451
      set->nodeTab[j + incr]) == -1)
3452
#endif
3453
    {
3454
        tmp = set->nodeTab[j];
3455
        set->nodeTab[j] = set->nodeTab[j + incr];
3456
        set->nodeTab[j + incr] = tmp;
3457
        j -= incr;
3458
    } else
3459
        break;
3460
      }
3461
  }
3462
    }
3463
#else /* WITH_TIM_SORT */
3464
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3465
0
#endif /* WITH_TIM_SORT */
3466
0
}
3467
3468
0
#define XML_NODESET_DEFAULT 10
3469
/**
3470
 * xmlXPathNodeSetDupNs:
3471
 * @node:  the parent node of the namespace XPath node
3472
 * @ns:  the libxml namespace declaration node.
3473
 *
3474
 * Namespace node in libxml don't match the XPath semantic. In a node set
3475
 * the namespace nodes are duplicated and the next pointer is set to the
3476
 * parent node in the XPath semantic.
3477
 *
3478
 * Returns the newly created object.
3479
 */
3480
static xmlNodePtr
3481
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3482
0
    xmlNsPtr cur;
3483
3484
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3485
0
  return(NULL);
3486
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3487
0
  return((xmlNodePtr) ns);
3488
3489
    /*
3490
     * Allocate a new Namespace and fill the fields.
3491
     */
3492
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3493
0
    if (cur == NULL) {
3494
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3495
0
  return(NULL);
3496
0
    }
3497
0
    memset(cur, 0, sizeof(xmlNs));
3498
0
    cur->type = XML_NAMESPACE_DECL;
3499
0
    if (ns->href != NULL)
3500
0
  cur->href = xmlStrdup(ns->href);
3501
0
    if (ns->prefix != NULL)
3502
0
  cur->prefix = xmlStrdup(ns->prefix);
3503
0
    cur->next = (xmlNsPtr) node;
3504
0
    return((xmlNodePtr) cur);
3505
0
}
3506
3507
/**
3508
 * xmlXPathNodeSetFreeNs:
3509
 * @ns:  the XPath namespace node found in a nodeset.
3510
 *
3511
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3512
 * the namespace nodes are duplicated and the next pointer is set to the
3513
 * parent node in the XPath semantic. Check if such a node needs to be freed
3514
 */
3515
void
3516
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3517
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3518
0
  return;
3519
3520
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3521
0
  if (ns->href != NULL)
3522
0
      xmlFree((xmlChar *)ns->href);
3523
0
  if (ns->prefix != NULL)
3524
0
      xmlFree((xmlChar *)ns->prefix);
3525
0
  xmlFree(ns);
3526
0
    }
3527
0
}
3528
3529
/**
3530
 * xmlXPathNodeSetCreate:
3531
 * @val:  an initial xmlNodePtr, or NULL
3532
 *
3533
 * Create a new xmlNodeSetPtr of type double and of value @val
3534
 *
3535
 * Returns the newly created object.
3536
 */
3537
xmlNodeSetPtr
3538
0
xmlXPathNodeSetCreate(xmlNodePtr val) {
3539
0
    xmlNodeSetPtr ret;
3540
3541
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3542
0
    if (ret == NULL) {
3543
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3544
0
  return(NULL);
3545
0
    }
3546
0
    memset(ret, 0 , sizeof(xmlNodeSet));
3547
0
    if (val != NULL) {
3548
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3549
0
               sizeof(xmlNodePtr));
3550
0
  if (ret->nodeTab == NULL) {
3551
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3552
0
      xmlFree(ret);
3553
0
      return(NULL);
3554
0
  }
3555
0
  memset(ret->nodeTab, 0 ,
3556
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3557
0
        ret->nodeMax = XML_NODESET_DEFAULT;
3558
0
  if (val->type == XML_NAMESPACE_DECL) {
3559
0
      xmlNsPtr ns = (xmlNsPtr) val;
3560
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3561
3562
0
            if (nsNode == NULL) {
3563
0
                xmlXPathFreeNodeSet(ret);
3564
0
                return(NULL);
3565
0
            }
3566
0
      ret->nodeTab[ret->nodeNr++] = nsNode;
3567
0
  } else
3568
0
      ret->nodeTab[ret->nodeNr++] = val;
3569
0
    }
3570
0
    return(ret);
3571
0
}
3572
3573
/**
3574
 * xmlXPathNodeSetContains:
3575
 * @cur:  the node-set
3576
 * @val:  the node
3577
 *
3578
 * checks whether @cur contains @val
3579
 *
3580
 * Returns true (1) if @cur contains @val, false (0) otherwise
3581
 */
3582
int
3583
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3584
0
    int i;
3585
3586
0
    if ((cur == NULL) || (val == NULL)) return(0);
3587
0
    if (val->type == XML_NAMESPACE_DECL) {
3588
0
  for (i = 0; i < cur->nodeNr; i++) {
3589
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3590
0
    xmlNsPtr ns1, ns2;
3591
3592
0
    ns1 = (xmlNsPtr) val;
3593
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3594
0
    if (ns1 == ns2)
3595
0
        return(1);
3596
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3597
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3598
0
        return(1);
3599
0
      }
3600
0
  }
3601
0
    } else {
3602
0
  for (i = 0; i < cur->nodeNr; i++) {
3603
0
      if (cur->nodeTab[i] == val)
3604
0
    return(1);
3605
0
  }
3606
0
    }
3607
0
    return(0);
3608
0
}
3609
3610
/**
3611
 * xmlXPathNodeSetAddNs:
3612
 * @cur:  the initial node set
3613
 * @node:  the hosting node
3614
 * @ns:  a the namespace node
3615
 *
3616
 * add a new namespace node to an existing NodeSet
3617
 *
3618
 * Returns 0 in case of success and -1 in case of error
3619
 */
3620
int
3621
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3622
0
    int i;
3623
0
    xmlNodePtr nsNode;
3624
3625
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3626
0
        (ns->type != XML_NAMESPACE_DECL) ||
3627
0
  (node->type != XML_ELEMENT_NODE))
3628
0
  return(-1);
3629
3630
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3631
    /*
3632
     * prevent duplicates
3633
     */
3634
0
    for (i = 0;i < cur->nodeNr;i++) {
3635
0
        if ((cur->nodeTab[i] != NULL) &&
3636
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3637
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3638
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3639
0
      return(0);
3640
0
    }
3641
3642
    /*
3643
     * grow the nodeTab if needed
3644
     */
3645
0
    if (cur->nodeMax == 0) {
3646
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3647
0
               sizeof(xmlNodePtr));
3648
0
  if (cur->nodeTab == NULL) {
3649
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3650
0
      return(-1);
3651
0
  }
3652
0
  memset(cur->nodeTab, 0 ,
3653
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3654
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3655
0
    } else if (cur->nodeNr == cur->nodeMax) {
3656
0
        xmlNodePtr *temp;
3657
3658
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3659
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3660
0
            return(-1);
3661
0
        }
3662
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3663
0
              sizeof(xmlNodePtr));
3664
0
  if (temp == NULL) {
3665
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3666
0
      return(-1);
3667
0
  }
3668
0
        cur->nodeMax *= 2;
3669
0
  cur->nodeTab = temp;
3670
0
    }
3671
0
    nsNode = xmlXPathNodeSetDupNs(node, ns);
3672
0
    if(nsNode == NULL)
3673
0
        return(-1);
3674
0
    cur->nodeTab[cur->nodeNr++] = nsNode;
3675
0
    return(0);
3676
0
}
3677
3678
/**
3679
 * xmlXPathNodeSetAdd:
3680
 * @cur:  the initial node set
3681
 * @val:  a new xmlNodePtr
3682
 *
3683
 * add a new xmlNodePtr to an existing NodeSet
3684
 *
3685
 * Returns 0 in case of success, and -1 in case of error
3686
 */
3687
int
3688
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3689
0
    int i;
3690
3691
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3692
3693
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3694
    /*
3695
     * prevent duplicates
3696
     */
3697
0
    for (i = 0;i < cur->nodeNr;i++)
3698
0
        if (cur->nodeTab[i] == val) return(0);
3699
3700
    /*
3701
     * grow the nodeTab if needed
3702
     */
3703
0
    if (cur->nodeMax == 0) {
3704
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3705
0
               sizeof(xmlNodePtr));
3706
0
  if (cur->nodeTab == NULL) {
3707
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3708
0
      return(-1);
3709
0
  }
3710
0
  memset(cur->nodeTab, 0 ,
3711
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3712
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3713
0
    } else if (cur->nodeNr == cur->nodeMax) {
3714
0
        xmlNodePtr *temp;
3715
3716
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3717
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3718
0
            return(-1);
3719
0
        }
3720
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3721
0
              sizeof(xmlNodePtr));
3722
0
  if (temp == NULL) {
3723
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3724
0
      return(-1);
3725
0
  }
3726
0
        cur->nodeMax *= 2;
3727
0
  cur->nodeTab = temp;
3728
0
    }
3729
0
    if (val->type == XML_NAMESPACE_DECL) {
3730
0
  xmlNsPtr ns = (xmlNsPtr) val;
3731
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3732
3733
0
        if (nsNode == NULL)
3734
0
            return(-1);
3735
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
3736
0
    } else
3737
0
  cur->nodeTab[cur->nodeNr++] = val;
3738
0
    return(0);
3739
0
}
3740
3741
/**
3742
 * xmlXPathNodeSetAddUnique:
3743
 * @cur:  the initial node set
3744
 * @val:  a new xmlNodePtr
3745
 *
3746
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3747
 * when we are sure the node is not already in the set.
3748
 *
3749
 * Returns 0 in case of success and -1 in case of failure
3750
 */
3751
int
3752
0
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3753
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3754
3755
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3756
    /*
3757
     * grow the nodeTab if needed
3758
     */
3759
0
    if (cur->nodeMax == 0) {
3760
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3761
0
               sizeof(xmlNodePtr));
3762
0
  if (cur->nodeTab == NULL) {
3763
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3764
0
      return(-1);
3765
0
  }
3766
0
  memset(cur->nodeTab, 0 ,
3767
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3768
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3769
0
    } else if (cur->nodeNr == cur->nodeMax) {
3770
0
        xmlNodePtr *temp;
3771
3772
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3773
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3774
0
            return(-1);
3775
0
        }
3776
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3777
0
              sizeof(xmlNodePtr));
3778
0
  if (temp == NULL) {
3779
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3780
0
      return(-1);
3781
0
  }
3782
0
  cur->nodeTab = temp;
3783
0
        cur->nodeMax *= 2;
3784
0
    }
3785
0
    if (val->type == XML_NAMESPACE_DECL) {
3786
0
  xmlNsPtr ns = (xmlNsPtr) val;
3787
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3788
3789
0
        if (nsNode == NULL)
3790
0
            return(-1);
3791
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
3792
0
    } else
3793
0
  cur->nodeTab[cur->nodeNr++] = val;
3794
0
    return(0);
3795
0
}
3796
3797
/**
3798
 * xmlXPathNodeSetMerge:
3799
 * @val1:  the first NodeSet or NULL
3800
 * @val2:  the second NodeSet
3801
 *
3802
 * Merges two nodesets, all nodes from @val2 are added to @val1
3803
 * if @val1 is NULL, a new set is created and copied from @val2
3804
 *
3805
 * Returns @val1 once extended or NULL in case of error.
3806
 *
3807
 * Frees @val1 in case of error.
3808
 */
3809
xmlNodeSetPtr
3810
0
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3811
0
    int i, j, initNr, skip;
3812
0
    xmlNodePtr n1, n2;
3813
3814
0
    if (val2 == NULL) return(val1);
3815
0
    if (val1 == NULL) {
3816
0
  val1 = xmlXPathNodeSetCreate(NULL);
3817
0
        if (val1 == NULL)
3818
0
            return (NULL);
3819
0
    }
3820
3821
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822
0
    initNr = val1->nodeNr;
3823
3824
0
    for (i = 0;i < val2->nodeNr;i++) {
3825
0
  n2 = val2->nodeTab[i];
3826
  /*
3827
   * check against duplicates
3828
   */
3829
0
  skip = 0;
3830
0
  for (j = 0; j < initNr; j++) {
3831
0
      n1 = val1->nodeTab[j];
3832
0
      if (n1 == n2) {
3833
0
    skip = 1;
3834
0
    break;
3835
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3836
0
           (n2->type == XML_NAMESPACE_DECL)) {
3837
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3838
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3839
0
      ((xmlNsPtr) n2)->prefix)))
3840
0
    {
3841
0
        skip = 1;
3842
0
        break;
3843
0
    }
3844
0
      }
3845
0
  }
3846
0
  if (skip)
3847
0
      continue;
3848
3849
  /*
3850
   * grow the nodeTab if needed
3851
   */
3852
0
  if (val1->nodeMax == 0) {
3853
0
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3854
0
                sizeof(xmlNodePtr));
3855
0
      if (val1->nodeTab == NULL) {
3856
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3857
0
    goto error;
3858
0
      }
3859
0
      memset(val1->nodeTab, 0 ,
3860
0
       XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3861
0
      val1->nodeMax = XML_NODESET_DEFAULT;
3862
0
  } else if (val1->nodeNr == val1->nodeMax) {
3863
0
      xmlNodePtr *temp;
3864
3865
0
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3866
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3867
0
                goto error;
3868
0
            }
3869
0
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3870
0
               sizeof(xmlNodePtr));
3871
0
      if (temp == NULL) {
3872
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3873
0
    goto error;
3874
0
      }
3875
0
      val1->nodeTab = temp;
3876
0
      val1->nodeMax *= 2;
3877
0
  }
3878
0
  if (n2->type == XML_NAMESPACE_DECL) {
3879
0
      xmlNsPtr ns = (xmlNsPtr) n2;
3880
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3881
3882
0
            if (nsNode == NULL)
3883
0
                goto error;
3884
0
      val1->nodeTab[val1->nodeNr++] = nsNode;
3885
0
  } else
3886
0
      val1->nodeTab[val1->nodeNr++] = n2;
3887
0
    }
3888
3889
0
    return(val1);
3890
3891
0
error:
3892
0
    xmlXPathFreeNodeSet(val1);
3893
0
    return(NULL);
3894
0
}
3895
3896
3897
/**
3898
 * xmlXPathNodeSetMergeAndClear:
3899
 * @set1:  the first NodeSet or NULL
3900
 * @set2:  the second NodeSet
3901
 *
3902
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3903
 * Checks for duplicate nodes. Clears set2.
3904
 *
3905
 * Returns @set1 once extended or NULL in case of error.
3906
 *
3907
 * Frees @set1 in case of error.
3908
 */
3909
static xmlNodeSetPtr
3910
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3911
0
{
3912
0
    {
3913
0
  int i, j, initNbSet1;
3914
0
  xmlNodePtr n1, n2;
3915
3916
0
  initNbSet1 = set1->nodeNr;
3917
0
  for (i = 0;i < set2->nodeNr;i++) {
3918
0
      n2 = set2->nodeTab[i];
3919
      /*
3920
      * Skip duplicates.
3921
      */
3922
0
      for (j = 0; j < initNbSet1; j++) {
3923
0
    n1 = set1->nodeTab[j];
3924
0
    if (n1 == n2) {
3925
0
        goto skip_node;
3926
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3927
0
        (n2->type == XML_NAMESPACE_DECL))
3928
0
    {
3929
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3930
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3931
0
      ((xmlNsPtr) n2)->prefix)))
3932
0
        {
3933
      /*
3934
      * Free the namespace node.
3935
      */
3936
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3937
0
      goto skip_node;
3938
0
        }
3939
0
    }
3940
0
      }
3941
      /*
3942
      * grow the nodeTab if needed
3943
      */
3944
0
      if (set1->nodeMax == 0) {
3945
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3946
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3947
0
    if (set1->nodeTab == NULL) {
3948
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3949
0
        goto error;
3950
0
    }
3951
0
    memset(set1->nodeTab, 0,
3952
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3953
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3954
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3955
0
    xmlNodePtr *temp;
3956
3957
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3958
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3959
0
                    goto error;
3960
0
                }
3961
0
    temp = (xmlNodePtr *) xmlRealloc(
3962
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3963
0
    if (temp == NULL) {
3964
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3965
0
        goto error;
3966
0
    }
3967
0
    set1->nodeTab = temp;
3968
0
    set1->nodeMax *= 2;
3969
0
      }
3970
0
      set1->nodeTab[set1->nodeNr++] = n2;
3971
0
skip_node:
3972
0
            set2->nodeTab[i] = NULL;
3973
0
  }
3974
0
    }
3975
0
    set2->nodeNr = 0;
3976
0
    return(set1);
3977
3978
0
error:
3979
0
    xmlXPathFreeNodeSet(set1);
3980
0
    xmlXPathNodeSetClear(set2, 1);
3981
0
    return(NULL);
3982
0
}
3983
3984
/**
3985
 * xmlXPathNodeSetMergeAndClearNoDupls:
3986
 * @set1:  the first NodeSet or NULL
3987
 * @set2:  the second NodeSet
3988
 *
3989
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3990
 * Doesn't check for duplicate nodes. Clears set2.
3991
 *
3992
 * Returns @set1 once extended or NULL in case of error.
3993
 *
3994
 * Frees @set1 in case of error.
3995
 */
3996
static xmlNodeSetPtr
3997
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3998
0
{
3999
0
    {
4000
0
  int i;
4001
0
  xmlNodePtr n2;
4002
4003
0
  for (i = 0;i < set2->nodeNr;i++) {
4004
0
      n2 = set2->nodeTab[i];
4005
0
      if (set1->nodeMax == 0) {
4006
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008
0
    if (set1->nodeTab == NULL) {
4009
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4010
0
        goto error;
4011
0
    }
4012
0
    memset(set1->nodeTab, 0,
4013
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4014
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4015
0
      } else if (set1->nodeNr >= set1->nodeMax) {
4016
0
    xmlNodePtr *temp;
4017
4018
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4020
0
                    goto error;
4021
0
                }
4022
0
    temp = (xmlNodePtr *) xmlRealloc(
4023
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4024
0
    if (temp == NULL) {
4025
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4026
0
        goto error;
4027
0
    }
4028
0
    set1->nodeTab = temp;
4029
0
    set1->nodeMax *= 2;
4030
0
      }
4031
0
      set1->nodeTab[set1->nodeNr++] = n2;
4032
0
            set2->nodeTab[i] = NULL;
4033
0
  }
4034
0
    }
4035
0
    set2->nodeNr = 0;
4036
0
    return(set1);
4037
4038
0
error:
4039
0
    xmlXPathFreeNodeSet(set1);
4040
0
    xmlXPathNodeSetClear(set2, 1);
4041
0
    return(NULL);
4042
0
}
4043
4044
/**
4045
 * xmlXPathNodeSetDel:
4046
 * @cur:  the initial node set
4047
 * @val:  an xmlNodePtr
4048
 *
4049
 * Removes an xmlNodePtr from an existing NodeSet
4050
 */
4051
void
4052
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4053
0
    int i;
4054
4055
0
    if (cur == NULL) return;
4056
0
    if (val == NULL) return;
4057
4058
    /*
4059
     * find node in nodeTab
4060
     */
4061
0
    for (i = 0;i < cur->nodeNr;i++)
4062
0
        if (cur->nodeTab[i] == val) break;
4063
4064
0
    if (i >= cur->nodeNr) { /* not found */
4065
#ifdef DEBUG
4066
        xmlGenericError(xmlGenericErrorContext,
4067
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4068
    val->name);
4069
#endif
4070
0
        return;
4071
0
    }
4072
0
    if ((cur->nodeTab[i] != NULL) &&
4073
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4074
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4075
0
    cur->nodeNr--;
4076
0
    for (;i < cur->nodeNr;i++)
4077
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4078
0
    cur->nodeTab[cur->nodeNr] = NULL;
4079
0
}
4080
4081
/**
4082
 * xmlXPathNodeSetRemove:
4083
 * @cur:  the initial node set
4084
 * @val:  the index to remove
4085
 *
4086
 * Removes an entry from an existing NodeSet list.
4087
 */
4088
void
4089
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4090
0
    if (cur == NULL) return;
4091
0
    if (val >= cur->nodeNr) return;
4092
0
    if ((cur->nodeTab[val] != NULL) &&
4093
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4094
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4095
0
    cur->nodeNr--;
4096
0
    for (;val < cur->nodeNr;val++)
4097
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4098
0
    cur->nodeTab[cur->nodeNr] = NULL;
4099
0
}
4100
4101
/**
4102
 * xmlXPathFreeNodeSet:
4103
 * @obj:  the xmlNodeSetPtr to free
4104
 *
4105
 * Free the NodeSet compound (not the actual nodes !).
4106
 */
4107
void
4108
0
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4109
0
    if (obj == NULL) return;
4110
0
    if (obj->nodeTab != NULL) {
4111
0
  int i;
4112
4113
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114
0
  for (i = 0;i < obj->nodeNr;i++)
4115
0
      if ((obj->nodeTab[i] != NULL) &&
4116
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4117
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4118
0
  xmlFree(obj->nodeTab);
4119
0
    }
4120
0
    xmlFree(obj);
4121
0
}
4122
4123
/**
4124
 * xmlXPathNodeSetClearFromPos:
4125
 * @set: the node set to be cleared
4126
 * @pos: the start position to clear from
4127
 *
4128
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4129
 * are feed) starting with the entry at @pos, but does *not* free the list
4130
 * itself. Sets the length of the list to @pos.
4131
 */
4132
static void
4133
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4134
0
{
4135
0
    if ((set == NULL) || (pos >= set->nodeNr))
4136
0
  return;
4137
0
    else if ((hasNsNodes)) {
4138
0
  int i;
4139
0
  xmlNodePtr node;
4140
4141
0
  for (i = pos; i < set->nodeNr; i++) {
4142
0
      node = set->nodeTab[i];
4143
0
      if ((node != NULL) &&
4144
0
    (node->type == XML_NAMESPACE_DECL))
4145
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4146
0
  }
4147
0
    }
4148
0
    set->nodeNr = pos;
4149
0
}
4150
4151
/**
4152
 * xmlXPathNodeSetClear:
4153
 * @set:  the node set to clear
4154
 *
4155
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4156
 * are feed), but does *not* free the list itself. Sets the length of the
4157
 * list to 0.
4158
 */
4159
static void
4160
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4161
0
{
4162
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4163
0
}
4164
4165
/**
4166
 * xmlXPathNodeSetKeepLast:
4167
 * @set: the node set to be cleared
4168
 *
4169
 * Move the last node to the first position and clear temporary XPath objects
4170
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4171
 * to 1.
4172
 */
4173
static void
4174
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4175
0
{
4176
0
    int i;
4177
0
    xmlNodePtr node;
4178
4179
0
    if ((set == NULL) || (set->nodeNr <= 1))
4180
0
  return;
4181
0
    for (i = 0; i < set->nodeNr - 1; i++) {
4182
0
        node = set->nodeTab[i];
4183
0
        if ((node != NULL) &&
4184
0
            (node->type == XML_NAMESPACE_DECL))
4185
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4186
0
    }
4187
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4188
0
    set->nodeNr = 1;
4189
0
}
4190
4191
/**
4192
 * xmlXPathFreeValueTree:
4193
 * @obj:  the xmlNodeSetPtr to free
4194
 *
4195
 * Free the NodeSet compound and the actual tree, this is different
4196
 * from xmlXPathFreeNodeSet()
4197
 */
4198
static void
4199
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4200
0
    int i;
4201
4202
0
    if (obj == NULL) return;
4203
4204
0
    if (obj->nodeTab != NULL) {
4205
0
  for (i = 0;i < obj->nodeNr;i++) {
4206
0
      if (obj->nodeTab[i] != NULL) {
4207
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4208
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4209
0
    } else {
4210
0
        xmlFreeNodeList(obj->nodeTab[i]);
4211
0
    }
4212
0
      }
4213
0
  }
4214
0
  xmlFree(obj->nodeTab);
4215
0
    }
4216
0
    xmlFree(obj);
4217
0
}
4218
4219
#if defined(DEBUG) || defined(DEBUG_STEP)
4220
/**
4221
 * xmlGenericErrorContextNodeSet:
4222
 * @output:  a FILE * for the output
4223
 * @obj:  the xmlNodeSetPtr to display
4224
 *
4225
 * Quick display of a NodeSet
4226
 */
4227
void
4228
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4229
    int i;
4230
4231
    if (output == NULL) output = xmlGenericErrorContext;
4232
    if (obj == NULL)  {
4233
        fprintf(output, "NodeSet == NULL !\n");
4234
  return;
4235
    }
4236
    if (obj->nodeNr == 0) {
4237
        fprintf(output, "NodeSet is empty\n");
4238
  return;
4239
    }
4240
    if (obj->nodeTab == NULL) {
4241
  fprintf(output, " nodeTab == NULL !\n");
4242
  return;
4243
    }
4244
    for (i = 0; i < obj->nodeNr; i++) {
4245
        if (obj->nodeTab[i] == NULL) {
4246
      fprintf(output, " NULL !\n");
4247
      return;
4248
        }
4249
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4250
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4251
      fprintf(output, " /");
4252
  else if (obj->nodeTab[i]->name == NULL)
4253
      fprintf(output, " noname!");
4254
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4255
    }
4256
    fprintf(output, "\n");
4257
}
4258
#endif
4259
4260
/**
4261
 * xmlXPathNewNodeSet:
4262
 * @val:  the NodePtr value
4263
 *
4264
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4265
 * it with the single Node @val
4266
 *
4267
 * Returns the newly created object.
4268
 */
4269
xmlXPathObjectPtr
4270
0
xmlXPathNewNodeSet(xmlNodePtr val) {
4271
0
    xmlXPathObjectPtr ret;
4272
4273
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4274
0
    if (ret == NULL) {
4275
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4276
0
  return(NULL);
4277
0
    }
4278
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4279
0
    ret->type = XPATH_NODESET;
4280
0
    ret->boolval = 0;
4281
    /* TODO: Check memory error. */
4282
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4283
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4284
#ifdef XP_DEBUG_OBJ_USAGE
4285
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4286
#endif
4287
0
    return(ret);
4288
0
}
4289
4290
/**
4291
 * xmlXPathNewValueTree:
4292
 * @val:  the NodePtr value
4293
 *
4294
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4295
 * it with the tree root @val
4296
 *
4297
 * Returns the newly created object.
4298
 */
4299
xmlXPathObjectPtr
4300
0
xmlXPathNewValueTree(xmlNodePtr val) {
4301
0
    xmlXPathObjectPtr ret;
4302
4303
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304
0
    if (ret == NULL) {
4305
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4306
0
  return(NULL);
4307
0
    }
4308
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4309
0
    ret->type = XPATH_XSLT_TREE;
4310
0
    ret->boolval = 1;
4311
0
    ret->user = (void *) val;
4312
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4313
#ifdef XP_DEBUG_OBJ_USAGE
4314
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4315
#endif
4316
0
    return(ret);
4317
0
}
4318
4319
/**
4320
 * xmlXPathNewNodeSetList:
4321
 * @val:  an existing NodeSet
4322
 *
4323
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4324
 * it with the Nodeset @val
4325
 *
4326
 * Returns the newly created object.
4327
 */
4328
xmlXPathObjectPtr
4329
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4330
0
{
4331
0
    xmlXPathObjectPtr ret;
4332
0
    int i;
4333
4334
0
    if (val == NULL)
4335
0
        ret = NULL;
4336
0
    else if (val->nodeTab == NULL)
4337
0
        ret = xmlXPathNewNodeSet(NULL);
4338
0
    else {
4339
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4340
0
        if (ret) {
4341
0
            for (i = 1; i < val->nodeNr; ++i) {
4342
                /* TODO: Propagate memory error. */
4343
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4344
0
        < 0) break;
4345
0
      }
4346
0
  }
4347
0
    }
4348
4349
0
    return (ret);
4350
0
}
4351
4352
/**
4353
 * xmlXPathWrapNodeSet:
4354
 * @val:  the NodePtr value
4355
 *
4356
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4357
 *
4358
 * Returns the newly created object.
4359
 *
4360
 * In case of error the node set is destroyed and NULL is returned.
4361
 */
4362
xmlXPathObjectPtr
4363
0
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4364
0
    xmlXPathObjectPtr ret;
4365
4366
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4367
0
    if (ret == NULL) {
4368
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4369
0
        xmlXPathFreeNodeSet(val);
4370
0
  return(NULL);
4371
0
    }
4372
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4373
0
    ret->type = XPATH_NODESET;
4374
0
    ret->nodesetval = val;
4375
#ifdef XP_DEBUG_OBJ_USAGE
4376
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4377
#endif
4378
0
    return(ret);
4379
0
}
4380
4381
/**
4382
 * xmlXPathFreeNodeSetList:
4383
 * @obj:  an existing NodeSetList object
4384
 *
4385
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4386
 * the list contrary to xmlXPathFreeObject().
4387
 */
4388
void
4389
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4390
0
    if (obj == NULL) return;
4391
#ifdef XP_DEBUG_OBJ_USAGE
4392
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4393
#endif
4394
0
    xmlFree(obj);
4395
0
}
4396
4397
/**
4398
 * xmlXPathDifference:
4399
 * @nodes1:  a node-set
4400
 * @nodes2:  a node-set
4401
 *
4402
 * Implements the EXSLT - Sets difference() function:
4403
 *    node-set set:difference (node-set, node-set)
4404
 *
4405
 * Returns the difference between the two node sets, or nodes1 if
4406
 *         nodes2 is empty
4407
 */
4408
xmlNodeSetPtr
4409
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4410
0
    xmlNodeSetPtr ret;
4411
0
    int i, l1;
4412
0
    xmlNodePtr cur;
4413
4414
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4415
0
  return(nodes1);
4416
4417
    /* TODO: Check memory error. */
4418
0
    ret = xmlXPathNodeSetCreate(NULL);
4419
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4420
0
  return(ret);
4421
4422
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4423
4424
0
    for (i = 0; i < l1; i++) {
4425
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4426
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4427
            /* TODO: Propagate memory error. */
4428
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4429
0
          break;
4430
0
  }
4431
0
    }
4432
0
    return(ret);
4433
0
}
4434
4435
/**
4436
 * xmlXPathIntersection:
4437
 * @nodes1:  a node-set
4438
 * @nodes2:  a node-set
4439
 *
4440
 * Implements the EXSLT - Sets intersection() function:
4441
 *    node-set set:intersection (node-set, node-set)
4442
 *
4443
 * Returns a node set comprising the nodes that are within both the
4444
 *         node sets passed as arguments
4445
 */
4446
xmlNodeSetPtr
4447
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4448
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4449
0
    int i, l1;
4450
0
    xmlNodePtr cur;
4451
4452
0
    if (ret == NULL)
4453
0
        return(ret);
4454
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4455
0
  return(ret);
4456
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4457
0
  return(ret);
4458
4459
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4460
4461
0
    for (i = 0; i < l1; i++) {
4462
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4463
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4464
            /* TODO: Propagate memory error. */
4465
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4466
0
          break;
4467
0
  }
4468
0
    }
4469
0
    return(ret);
4470
0
}
4471
4472
/**
4473
 * xmlXPathDistinctSorted:
4474
 * @nodes:  a node-set, sorted by document order
4475
 *
4476
 * Implements the EXSLT - Sets distinct() function:
4477
 *    node-set set:distinct (node-set)
4478
 *
4479
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4480
 *         it is empty
4481
 */
4482
xmlNodeSetPtr
4483
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4484
0
    xmlNodeSetPtr ret;
4485
0
    xmlHashTablePtr hash;
4486
0
    int i, l;
4487
0
    xmlChar * strval;
4488
0
    xmlNodePtr cur;
4489
4490
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4491
0
  return(nodes);
4492
4493
0
    ret = xmlXPathNodeSetCreate(NULL);
4494
0
    if (ret == NULL)
4495
0
        return(ret);
4496
0
    l = xmlXPathNodeSetGetLength(nodes);
4497
0
    hash = xmlHashCreate (l);
4498
0
    for (i = 0; i < l; i++) {
4499
0
  cur = xmlXPathNodeSetItem(nodes, i);
4500
0
  strval = xmlXPathCastNodeToString(cur);
4501
0
  if (xmlHashLookup(hash, strval) == NULL) {
4502
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
4503
0
                xmlFree(strval);
4504
0
                goto error;
4505
0
            }
4506
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4507
0
          goto error;
4508
0
  } else {
4509
0
      xmlFree(strval);
4510
0
  }
4511
0
    }
4512
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4513
0
    return(ret);
4514
4515
0
error:
4516
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4517
0
    xmlXPathFreeNodeSet(ret);
4518
0
    return(NULL);
4519
0
}
4520
4521
/**
4522
 * xmlXPathDistinct:
4523
 * @nodes:  a node-set
4524
 *
4525
 * Implements the EXSLT - Sets distinct() function:
4526
 *    node-set set:distinct (node-set)
4527
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4528
 * is called with the sorted node-set
4529
 *
4530
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4531
 *         it is empty
4532
 */
4533
xmlNodeSetPtr
4534
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4535
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4536
0
  return(nodes);
4537
4538
0
    xmlXPathNodeSetSort(nodes);
4539
0
    return(xmlXPathDistinctSorted(nodes));
4540
0
}
4541
4542
/**
4543
 * xmlXPathHasSameNodes:
4544
 * @nodes1:  a node-set
4545
 * @nodes2:  a node-set
4546
 *
4547
 * Implements the EXSLT - Sets has-same-nodes function:
4548
 *    boolean set:has-same-node(node-set, node-set)
4549
 *
4550
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4551
 *         otherwise
4552
 */
4553
int
4554
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4555
0
    int i, l;
4556
0
    xmlNodePtr cur;
4557
4558
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4559
0
  xmlXPathNodeSetIsEmpty(nodes2))
4560
0
  return(0);
4561
4562
0
    l = xmlXPathNodeSetGetLength(nodes1);
4563
0
    for (i = 0; i < l; i++) {
4564
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4565
0
  if (xmlXPathNodeSetContains(nodes2, cur))
4566
0
      return(1);
4567
0
    }
4568
0
    return(0);
4569
0
}
4570
4571
/**
4572
 * xmlXPathNodeLeadingSorted:
4573
 * @nodes: a node-set, sorted by document order
4574
 * @node: a node
4575
 *
4576
 * Implements the EXSLT - Sets leading() function:
4577
 *    node-set set:leading (node-set, node-set)
4578
 *
4579
 * Returns the nodes in @nodes that precede @node in document order,
4580
 *         @nodes if @node is NULL or an empty node-set if @nodes
4581
 *         doesn't contain @node
4582
 */
4583
xmlNodeSetPtr
4584
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4585
0
    int i, l;
4586
0
    xmlNodePtr cur;
4587
0
    xmlNodeSetPtr ret;
4588
4589
0
    if (node == NULL)
4590
0
  return(nodes);
4591
4592
0
    ret = xmlXPathNodeSetCreate(NULL);
4593
0
    if (ret == NULL)
4594
0
        return(ret);
4595
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4596
0
  (!xmlXPathNodeSetContains(nodes, node)))
4597
0
  return(ret);
4598
4599
0
    l = xmlXPathNodeSetGetLength(nodes);
4600
0
    for (i = 0; i < l; i++) {
4601
0
  cur = xmlXPathNodeSetItem(nodes, i);
4602
0
  if (cur == node)
4603
0
      break;
4604
        /* TODO: Propagate memory error. */
4605
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4606
0
      break;
4607
0
    }
4608
0
    return(ret);
4609
0
}
4610
4611
/**
4612
 * xmlXPathNodeLeading:
4613
 * @nodes:  a node-set
4614
 * @node:  a node
4615
 *
4616
 * Implements the EXSLT - Sets leading() function:
4617
 *    node-set set:leading (node-set, node-set)
4618
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4619
 * is called.
4620
 *
4621
 * Returns the nodes in @nodes that precede @node in document order,
4622
 *         @nodes if @node is NULL or an empty node-set if @nodes
4623
 *         doesn't contain @node
4624
 */
4625
xmlNodeSetPtr
4626
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627
0
    xmlXPathNodeSetSort(nodes);
4628
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4629
0
}
4630
4631
/**
4632
 * xmlXPathLeadingSorted:
4633
 * @nodes1:  a node-set, sorted by document order
4634
 * @nodes2:  a node-set, sorted by document order
4635
 *
4636
 * Implements the EXSLT - Sets leading() function:
4637
 *    node-set set:leading (node-set, node-set)
4638
 *
4639
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4640
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4641
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4642
 */
4643
xmlNodeSetPtr
4644
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4646
0
  return(nodes1);
4647
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4648
0
             xmlXPathNodeSetItem(nodes2, 1)));
4649
0
}
4650
4651
/**
4652
 * xmlXPathLeading:
4653
 * @nodes1:  a node-set
4654
 * @nodes2:  a node-set
4655
 *
4656
 * Implements the EXSLT - Sets leading() function:
4657
 *    node-set set:leading (node-set, node-set)
4658
 * @nodes1 and @nodes2 are sorted by document order, then
4659
 * #exslSetsLeadingSorted is called.
4660
 *
4661
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4662
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4663
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4664
 */
4665
xmlNodeSetPtr
4666
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4668
0
  return(nodes1);
4669
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4670
0
  return(xmlXPathNodeSetCreate(NULL));
4671
0
    xmlXPathNodeSetSort(nodes1);
4672
0
    xmlXPathNodeSetSort(nodes2);
4673
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4674
0
             xmlXPathNodeSetItem(nodes2, 1)));
4675
0
}
4676
4677
/**
4678
 * xmlXPathNodeTrailingSorted:
4679
 * @nodes: a node-set, sorted by document order
4680
 * @node: a node
4681
 *
4682
 * Implements the EXSLT - Sets trailing() function:
4683
 *    node-set set:trailing (node-set, node-set)
4684
 *
4685
 * Returns the nodes in @nodes that follow @node in document order,
4686
 *         @nodes if @node is NULL or an empty node-set if @nodes
4687
 *         doesn't contain @node
4688
 */
4689
xmlNodeSetPtr
4690
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4691
0
    int i, l;
4692
0
    xmlNodePtr cur;
4693
0
    xmlNodeSetPtr ret;
4694
4695
0
    if (node == NULL)
4696
0
  return(nodes);
4697
4698
0
    ret = xmlXPathNodeSetCreate(NULL);
4699
0
    if (ret == NULL)
4700
0
        return(ret);
4701
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4702
0
  (!xmlXPathNodeSetContains(nodes, node)))
4703
0
  return(ret);
4704
4705
0
    l = xmlXPathNodeSetGetLength(nodes);
4706
0
    for (i = l - 1; i >= 0; i--) {
4707
0
  cur = xmlXPathNodeSetItem(nodes, i);
4708
0
  if (cur == node)
4709
0
      break;
4710
        /* TODO: Propagate memory error. */
4711
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4712
0
      break;
4713
0
    }
4714
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4715
0
    return(ret);
4716
0
}
4717
4718
/**
4719
 * xmlXPathNodeTrailing:
4720
 * @nodes:  a node-set
4721
 * @node:  a node
4722
 *
4723
 * Implements the EXSLT - Sets trailing() function:
4724
 *    node-set set:trailing (node-set, node-set)
4725
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4726
 * is called.
4727
 *
4728
 * Returns the nodes in @nodes that follow @node in document order,
4729
 *         @nodes if @node is NULL or an empty node-set if @nodes
4730
 *         doesn't contain @node
4731
 */
4732
xmlNodeSetPtr
4733
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4734
0
    xmlXPathNodeSetSort(nodes);
4735
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4736
0
}
4737
4738
/**
4739
 * xmlXPathTrailingSorted:
4740
 * @nodes1:  a node-set, sorted by document order
4741
 * @nodes2:  a node-set, sorted by document order
4742
 *
4743
 * Implements the EXSLT - Sets trailing() function:
4744
 *    node-set set:trailing (node-set, node-set)
4745
 *
4746
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4747
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4748
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4749
 */
4750
xmlNodeSetPtr
4751
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4752
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4753
0
  return(nodes1);
4754
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4755
0
              xmlXPathNodeSetItem(nodes2, 0)));
4756
0
}
4757
4758
/**
4759
 * xmlXPathTrailing:
4760
 * @nodes1:  a node-set
4761
 * @nodes2:  a node-set
4762
 *
4763
 * Implements the EXSLT - Sets trailing() function:
4764
 *    node-set set:trailing (node-set, node-set)
4765
 * @nodes1 and @nodes2 are sorted by document order, then
4766
 * #xmlXPathTrailingSorted is called.
4767
 *
4768
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4769
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4770
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4771
 */
4772
xmlNodeSetPtr
4773
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4774
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4775
0
  return(nodes1);
4776
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4777
0
  return(xmlXPathNodeSetCreate(NULL));
4778
0
    xmlXPathNodeSetSort(nodes1);
4779
0
    xmlXPathNodeSetSort(nodes2);
4780
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4781
0
              xmlXPathNodeSetItem(nodes2, 0)));
4782
0
}
4783
4784
/************************************************************************
4785
 *                  *
4786
 *    Routines to handle extra functions      *
4787
 *                  *
4788
 ************************************************************************/
4789
4790
/**
4791
 * xmlXPathRegisterFunc:
4792
 * @ctxt:  the XPath context
4793
 * @name:  the function name
4794
 * @f:  the function implementation or NULL
4795
 *
4796
 * Register a new function. If @f is NULL it unregisters the function
4797
 *
4798
 * Returns 0 in case of success, -1 in case of error
4799
 */
4800
int
4801
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4802
0
         xmlXPathFunction f) {
4803
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4804
0
}
4805
4806
/**
4807
 * xmlXPathRegisterFuncNS:
4808
 * @ctxt:  the XPath context
4809
 * @name:  the function name
4810
 * @ns_uri:  the function namespace URI
4811
 * @f:  the function implementation or NULL
4812
 *
4813
 * Register a new function. If @f is NULL it unregisters the function
4814
 *
4815
 * Returns 0 in case of success, -1 in case of error
4816
 */
4817
int
4818
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4819
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
4820
0
    if (ctxt == NULL)
4821
0
  return(-1);
4822
0
    if (name == NULL)
4823
0
  return(-1);
4824
4825
0
    if (ctxt->funcHash == NULL)
4826
0
  ctxt->funcHash = xmlHashCreate(0);
4827
0
    if (ctxt->funcHash == NULL)
4828
0
  return(-1);
4829
0
    if (f == NULL)
4830
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4831
0
XML_IGNORE_FPTR_CAST_WARNINGS
4832
0
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4833
0
XML_POP_WARNINGS
4834
0
}
4835
4836
/**
4837
 * xmlXPathRegisterFuncLookup:
4838
 * @ctxt:  the XPath context
4839
 * @f:  the lookup function
4840
 * @funcCtxt:  the lookup data
4841
 *
4842
 * Registers an external mechanism to do function lookup.
4843
 */
4844
void
4845
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4846
          xmlXPathFuncLookupFunc f,
4847
0
          void *funcCtxt) {
4848
0
    if (ctxt == NULL)
4849
0
  return;
4850
0
    ctxt->funcLookupFunc = f;
4851
0
    ctxt->funcLookupData = funcCtxt;
4852
0
}
4853
4854
/**
4855
 * xmlXPathFunctionLookup:
4856
 * @ctxt:  the XPath context
4857
 * @name:  the function name
4858
 *
4859
 * Search in the Function array of the context for the given
4860
 * function.
4861
 *
4862
 * Returns the xmlXPathFunction or NULL if not found
4863
 */
4864
xmlXPathFunction
4865
0
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4866
0
    if (ctxt == NULL)
4867
0
  return (NULL);
4868
4869
0
    if (ctxt->funcLookupFunc != NULL) {
4870
0
  xmlXPathFunction ret;
4871
0
  xmlXPathFuncLookupFunc f;
4872
4873
0
  f = ctxt->funcLookupFunc;
4874
0
  ret = f(ctxt->funcLookupData, name, NULL);
4875
0
  if (ret != NULL)
4876
0
      return(ret);
4877
0
    }
4878
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4879
0
}
4880
4881
/**
4882
 * xmlXPathFunctionLookupNS:
4883
 * @ctxt:  the XPath context
4884
 * @name:  the function name
4885
 * @ns_uri:  the function namespace URI
4886
 *
4887
 * Search in the Function array of the context for the given
4888
 * function.
4889
 *
4890
 * Returns the xmlXPathFunction or NULL if not found
4891
 */
4892
xmlXPathFunction
4893
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4894
0
       const xmlChar *ns_uri) {
4895
0
    xmlXPathFunction ret;
4896
4897
0
    if (ctxt == NULL)
4898
0
  return(NULL);
4899
0
    if (name == NULL)
4900
0
  return(NULL);
4901
4902
0
    if (ctxt->funcLookupFunc != NULL) {
4903
0
  xmlXPathFuncLookupFunc f;
4904
4905
0
  f = ctxt->funcLookupFunc;
4906
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
4907
0
  if (ret != NULL)
4908
0
      return(ret);
4909
0
    }
4910
4911
0
    if (ctxt->funcHash == NULL)
4912
0
  return(NULL);
4913
4914
0
XML_IGNORE_FPTR_CAST_WARNINGS
4915
0
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4916
0
XML_POP_WARNINGS
4917
0
    return(ret);
4918
0
}
4919
4920
/**
4921
 * xmlXPathRegisteredFuncsCleanup:
4922
 * @ctxt:  the XPath context
4923
 *
4924
 * Cleanup the XPath context data associated to registered functions
4925
 */
4926
void
4927
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4928
0
    if (ctxt == NULL)
4929
0
  return;
4930
4931
0
    xmlHashFree(ctxt->funcHash, NULL);
4932
0
    ctxt->funcHash = NULL;
4933
0
}
4934
4935
/************************************************************************
4936
 *                  *
4937
 *      Routines to handle Variables      *
4938
 *                  *
4939
 ************************************************************************/
4940
4941
/**
4942
 * xmlXPathRegisterVariable:
4943
 * @ctxt:  the XPath context
4944
 * @name:  the variable name
4945
 * @value:  the variable value or NULL
4946
 *
4947
 * Register a new variable value. If @value is NULL it unregisters
4948
 * the variable
4949
 *
4950
 * Returns 0 in case of success, -1 in case of error
4951
 */
4952
int
4953
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4954
0
       xmlXPathObjectPtr value) {
4955
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4956
0
}
4957
4958
/**
4959
 * xmlXPathRegisterVariableNS:
4960
 * @ctxt:  the XPath context
4961
 * @name:  the variable name
4962
 * @ns_uri:  the variable namespace URI
4963
 * @value:  the variable value or NULL
4964
 *
4965
 * Register a new variable value. If @value is NULL it unregisters
4966
 * the variable
4967
 *
4968
 * Returns 0 in case of success, -1 in case of error
4969
 */
4970
int
4971
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4972
         const xmlChar *ns_uri,
4973
0
         xmlXPathObjectPtr value) {
4974
0
    if (ctxt == NULL)
4975
0
  return(-1);
4976
0
    if (name == NULL)
4977
0
  return(-1);
4978
4979
0
    if (ctxt->varHash == NULL)
4980
0
  ctxt->varHash = xmlHashCreate(0);
4981
0
    if (ctxt->varHash == NULL)
4982
0
  return(-1);
4983
0
    if (value == NULL)
4984
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4985
0
                             xmlXPathFreeObjectEntry));
4986
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4987
0
             (void *) value, xmlXPathFreeObjectEntry));
4988
0
}
4989
4990
/**
4991
 * xmlXPathRegisterVariableLookup:
4992
 * @ctxt:  the XPath context
4993
 * @f:  the lookup function
4994
 * @data:  the lookup data
4995
 *
4996
 * register an external mechanism to do variable lookup
4997
 */
4998
void
4999
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5000
0
   xmlXPathVariableLookupFunc f, void *data) {
5001
0
    if (ctxt == NULL)
5002
0
  return;
5003
0
    ctxt->varLookupFunc = f;
5004
0
    ctxt->varLookupData = data;
5005
0
}
5006
5007
/**
5008
 * xmlXPathVariableLookup:
5009
 * @ctxt:  the XPath context
5010
 * @name:  the variable name
5011
 *
5012
 * Search in the Variable array of the context for the given
5013
 * variable value.
5014
 *
5015
 * Returns a copy of the value or NULL if not found
5016
 */
5017
xmlXPathObjectPtr
5018
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5019
0
    if (ctxt == NULL)
5020
0
  return(NULL);
5021
5022
0
    if (ctxt->varLookupFunc != NULL) {
5023
0
  xmlXPathObjectPtr ret;
5024
5025
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5026
0
          (ctxt->varLookupData, name, NULL);
5027
0
  return(ret);
5028
0
    }
5029
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5030
0
}
5031
5032
/**
5033
 * xmlXPathVariableLookupNS:
5034
 * @ctxt:  the XPath context
5035
 * @name:  the variable name
5036
 * @ns_uri:  the variable namespace URI
5037
 *
5038
 * Search in the Variable array of the context for the given
5039
 * variable value.
5040
 *
5041
 * Returns the a copy of the value or NULL if not found
5042
 */
5043
xmlXPathObjectPtr
5044
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5045
0
       const xmlChar *ns_uri) {
5046
0
    if (ctxt == NULL)
5047
0
  return(NULL);
5048
5049
0
    if (ctxt->varLookupFunc != NULL) {
5050
0
  xmlXPathObjectPtr ret;
5051
5052
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5053
0
          (ctxt->varLookupData, name, ns_uri);
5054
0
  if (ret != NULL) return(ret);
5055
0
    }
5056
5057
0
    if (ctxt->varHash == NULL)
5058
0
  return(NULL);
5059
0
    if (name == NULL)
5060
0
  return(NULL);
5061
5062
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5063
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5064
0
}
5065
5066
/**
5067
 * xmlXPathRegisteredVariablesCleanup:
5068
 * @ctxt:  the XPath context
5069
 *
5070
 * Cleanup the XPath context data associated to registered variables
5071
 */
5072
void
5073
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5074
0
    if (ctxt == NULL)
5075
0
  return;
5076
5077
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5078
0
    ctxt->varHash = NULL;
5079
0
}
5080
5081
/**
5082
 * xmlXPathRegisterNs:
5083
 * @ctxt:  the XPath context
5084
 * @prefix:  the namespace prefix cannot be NULL or empty string
5085
 * @ns_uri:  the namespace name
5086
 *
5087
 * Register a new namespace. If @ns_uri is NULL it unregisters
5088
 * the namespace
5089
 *
5090
 * Returns 0 in case of success, -1 in case of error
5091
 */
5092
int
5093
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5094
0
         const xmlChar *ns_uri) {
5095
0
    xmlChar *copy;
5096
5097
0
    if (ctxt == NULL)
5098
0
  return(-1);
5099
0
    if (prefix == NULL)
5100
0
  return(-1);
5101
0
    if (prefix[0] == 0)
5102
0
  return(-1);
5103
5104
0
    if (ctxt->nsHash == NULL)
5105
0
  ctxt->nsHash = xmlHashCreate(10);
5106
0
    if (ctxt->nsHash == NULL)
5107
0
  return(-1);
5108
0
    if (ns_uri == NULL)
5109
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5110
0
                            xmlHashDefaultDeallocator));
5111
5112
0
    copy = xmlStrdup(ns_uri);
5113
0
    if (copy == NULL)
5114
0
        return(-1);
5115
0
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
5116
0
                           xmlHashDefaultDeallocator) < 0) {
5117
0
        xmlFree(copy);
5118
0
        return(-1);
5119
0
    }
5120
5121
0
    return(0);
5122
0
}
5123
5124
/**
5125
 * xmlXPathNsLookup:
5126
 * @ctxt:  the XPath context
5127
 * @prefix:  the namespace prefix value
5128
 *
5129
 * Search in the namespace declaration array of the context for the given
5130
 * namespace name associated to the given prefix
5131
 *
5132
 * Returns the value or NULL if not found
5133
 */
5134
const xmlChar *
5135
0
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5136
0
    if (ctxt == NULL)
5137
0
  return(NULL);
5138
0
    if (prefix == NULL)
5139
0
  return(NULL);
5140
5141
0
#ifdef XML_XML_NAMESPACE
5142
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5143
0
  return(XML_XML_NAMESPACE);
5144
0
#endif
5145
5146
0
    if (ctxt->namespaces != NULL) {
5147
0
  int i;
5148
5149
0
  for (i = 0;i < ctxt->nsNr;i++) {
5150
0
      if ((ctxt->namespaces[i] != NULL) &&
5151
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5152
0
    return(ctxt->namespaces[i]->href);
5153
0
  }
5154
0
    }
5155
5156
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5157
0
}
5158
5159
/**
5160
 * xmlXPathRegisteredNsCleanup:
5161
 * @ctxt:  the XPath context
5162
 *
5163
 * Cleanup the XPath context data associated to registered variables
5164
 */
5165
void
5166
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5167
0
    if (ctxt == NULL)
5168
0
  return;
5169
5170
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5171
0
    ctxt->nsHash = NULL;
5172
0
}
5173
5174
/************************************************************************
5175
 *                  *
5176
 *      Routines to handle Values     *
5177
 *                  *
5178
 ************************************************************************/
5179
5180
/* Allocations are terrible, one needs to optimize all this !!! */
5181
5182
/**
5183
 * xmlXPathNewFloat:
5184
 * @val:  the double value
5185
 *
5186
 * Create a new xmlXPathObjectPtr of type double and of value @val
5187
 *
5188
 * Returns the newly created object.
5189
 */
5190
xmlXPathObjectPtr
5191
0
xmlXPathNewFloat(double val) {
5192
0
    xmlXPathObjectPtr ret;
5193
5194
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5195
0
    if (ret == NULL) {
5196
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5197
0
  return(NULL);
5198
0
    }
5199
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5200
0
    ret->type = XPATH_NUMBER;
5201
0
    ret->floatval = val;
5202
#ifdef XP_DEBUG_OBJ_USAGE
5203
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5204
#endif
5205
0
    return(ret);
5206
0
}
5207
5208
/**
5209
 * xmlXPathNewBoolean:
5210
 * @val:  the boolean value
5211
 *
5212
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5213
 *
5214
 * Returns the newly created object.
5215
 */
5216
xmlXPathObjectPtr
5217
0
xmlXPathNewBoolean(int val) {
5218
0
    xmlXPathObjectPtr ret;
5219
5220
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5221
0
    if (ret == NULL) {
5222
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5223
0
  return(NULL);
5224
0
    }
5225
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5226
0
    ret->type = XPATH_BOOLEAN;
5227
0
    ret->boolval = (val != 0);
5228
#ifdef XP_DEBUG_OBJ_USAGE
5229
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5230
#endif
5231
0
    return(ret);
5232
0
}
5233
5234
/**
5235
 * xmlXPathNewString:
5236
 * @val:  the xmlChar * value
5237
 *
5238
 * Create a new xmlXPathObjectPtr of type string and of value @val
5239
 *
5240
 * Returns the newly created object.
5241
 */
5242
xmlXPathObjectPtr
5243
0
xmlXPathNewString(const xmlChar *val) {
5244
0
    xmlXPathObjectPtr ret;
5245
5246
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247
0
    if (ret == NULL) {
5248
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5249
0
  return(NULL);
5250
0
    }
5251
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5252
0
    ret->type = XPATH_STRING;
5253
0
    if (val == NULL)
5254
0
        val = BAD_CAST "";
5255
0
    ret->stringval = xmlStrdup(val);
5256
0
    if (ret->stringval == NULL) {
5257
0
        xmlFree(ret);
5258
0
        return(NULL);
5259
0
    }
5260
#ifdef XP_DEBUG_OBJ_USAGE
5261
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5262
#endif
5263
0
    return(ret);
5264
0
}
5265
5266
/**
5267
 * xmlXPathWrapString:
5268
 * @val:  the xmlChar * value
5269
 *
5270
 * Wraps the @val string into an XPath object.
5271
 *
5272
 * Returns the newly created object.
5273
 *
5274
 * Frees @val in case of error.
5275
 */
5276
xmlXPathObjectPtr
5277
0
xmlXPathWrapString (xmlChar *val) {
5278
0
    xmlXPathObjectPtr ret;
5279
5280
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5281
0
    if (ret == NULL) {
5282
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5283
0
        xmlFree(val);
5284
0
  return(NULL);
5285
0
    }
5286
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5287
0
    ret->type = XPATH_STRING;
5288
0
    ret->stringval = val;
5289
#ifdef XP_DEBUG_OBJ_USAGE
5290
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5291
#endif
5292
0
    return(ret);
5293
0
}
5294
5295
/**
5296
 * xmlXPathNewCString:
5297
 * @val:  the char * value
5298
 *
5299
 * Create a new xmlXPathObjectPtr of type string and of value @val
5300
 *
5301
 * Returns the newly created object.
5302
 */
5303
xmlXPathObjectPtr
5304
0
xmlXPathNewCString(const char *val) {
5305
0
    return(xmlXPathNewString(BAD_CAST val));
5306
0
}
5307
5308
/**
5309
 * xmlXPathWrapCString:
5310
 * @val:  the char * value
5311
 *
5312
 * Wraps a string into an XPath object.
5313
 *
5314
 * Returns the newly created object.
5315
 */
5316
xmlXPathObjectPtr
5317
0
xmlXPathWrapCString (char * val) {
5318
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5319
0
}
5320
5321
/**
5322
 * xmlXPathWrapExternal:
5323
 * @val:  the user data
5324
 *
5325
 * Wraps the @val data into an XPath object.
5326
 *
5327
 * Returns the newly created object.
5328
 */
5329
xmlXPathObjectPtr
5330
0
xmlXPathWrapExternal (void *val) {
5331
0
    xmlXPathObjectPtr ret;
5332
5333
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5334
0
    if (ret == NULL) {
5335
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5336
0
  return(NULL);
5337
0
    }
5338
0
    memset(ret, 0 , sizeof(xmlXPathObject));
5339
0
    ret->type = XPATH_USERS;
5340
0
    ret->user = val;
5341
#ifdef XP_DEBUG_OBJ_USAGE
5342
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5343
#endif
5344
0
    return(ret);
5345
0
}
5346
5347
/**
5348
 * xmlXPathObjectCopy:
5349
 * @val:  the original object
5350
 *
5351
 * allocate a new copy of a given object
5352
 *
5353
 * Returns the newly created object.
5354
 */
5355
xmlXPathObjectPtr
5356
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5357
0
    xmlXPathObjectPtr ret;
5358
5359
0
    if (val == NULL)
5360
0
  return(NULL);
5361
5362
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5363
0
    if (ret == NULL) {
5364
0
        xmlXPathErrMemory(NULL, "copying object\n");
5365
0
  return(NULL);
5366
0
    }
5367
0
    memcpy(ret, val , sizeof(xmlXPathObject));
5368
#ifdef XP_DEBUG_OBJ_USAGE
5369
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5370
#endif
5371
0
    switch (val->type) {
5372
0
  case XPATH_BOOLEAN:
5373
0
  case XPATH_NUMBER:
5374
#ifdef LIBXML_XPTR_LOCS_ENABLED
5375
  case XPATH_POINT:
5376
  case XPATH_RANGE:
5377
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5378
0
      break;
5379
0
  case XPATH_STRING:
5380
0
      ret->stringval = xmlStrdup(val->stringval);
5381
0
            if (ret->stringval == NULL) {
5382
0
                xmlFree(ret);
5383
0
                return(NULL);
5384
0
            }
5385
0
      break;
5386
0
  case XPATH_XSLT_TREE:
5387
#if 0
5388
/*
5389
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5390
  this previous handling is no longer correct, and can cause some serious
5391
  problems (ref. bug 145547)
5392
*/
5393
      if ((val->nodesetval != NULL) &&
5394
    (val->nodesetval->nodeTab != NULL)) {
5395
    xmlNodePtr cur, tmp;
5396
    xmlDocPtr top;
5397
5398
    ret->boolval = 1;
5399
    top =  xmlNewDoc(NULL);
5400
    top->name = (char *)
5401
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5402
    ret->user = top;
5403
    if (top != NULL) {
5404
        top->doc = top;
5405
        cur = val->nodesetval->nodeTab[0]->children;
5406
        while (cur != NULL) {
5407
      tmp = xmlDocCopyNode(cur, top, 1);
5408
      xmlAddChild((xmlNodePtr) top, tmp);
5409
      cur = cur->next;
5410
        }
5411
    }
5412
5413
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5414
      } else
5415
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5416
      /* Deallocate the copied tree value */
5417
      break;
5418
#endif
5419
0
  case XPATH_NODESET:
5420
            /* TODO: Check memory error. */
5421
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5422
      /* Do not deallocate the copied tree value */
5423
0
      ret->boolval = 0;
5424
0
      break;
5425
#ifdef LIBXML_XPTR_LOCS_ENABLED
5426
  case XPATH_LOCATIONSET:
5427
  {
5428
      xmlLocationSetPtr loc = val->user;
5429
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5430
      break;
5431
  }
5432
#endif
5433
0
        case XPATH_USERS:
5434
0
      ret->user = val->user;
5435
0
      break;
5436
0
        case XPATH_UNDEFINED:
5437
0
      xmlGenericError(xmlGenericErrorContext,
5438
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5439
0
        val->type);
5440
0
      break;
5441
0
    }
5442
0
    return(ret);
5443
0
}
5444
5445
/**
5446
 * xmlXPathFreeObject:
5447
 * @obj:  the object to free
5448
 *
5449
 * Free up an xmlXPathObjectPtr object.
5450
 */
5451
void
5452
0
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5453
0
    if (obj == NULL) return;
5454
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5455
0
  if (obj->boolval) {
5456
#if 0
5457
      if (obj->user != NULL) {
5458
                xmlXPathFreeNodeSet(obj->nodesetval);
5459
    xmlFreeNodeList((xmlNodePtr) obj->user);
5460
      } else
5461
#endif
5462
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5463
0
      if (obj->nodesetval != NULL)
5464
0
    xmlXPathFreeValueTree(obj->nodesetval);
5465
0
  } else {
5466
0
      if (obj->nodesetval != NULL)
5467
0
    xmlXPathFreeNodeSet(obj->nodesetval);
5468
0
  }
5469
#ifdef LIBXML_XPTR_LOCS_ENABLED
5470
    } else if (obj->type == XPATH_LOCATIONSET) {
5471
  if (obj->user != NULL)
5472
      xmlXPtrFreeLocationSet(obj->user);
5473
#endif
5474
0
    } else if (obj->type == XPATH_STRING) {
5475
0
  if (obj->stringval != NULL)
5476
0
      xmlFree(obj->stringval);
5477
0
    }
5478
#ifdef XP_DEBUG_OBJ_USAGE
5479
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5480
#endif
5481
0
    xmlFree(obj);
5482
0
}
5483
5484
static void
5485
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5486
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5487
0
}
5488
5489
/**
5490
 * xmlXPathReleaseObject:
5491
 * @obj:  the xmlXPathObjectPtr to free or to cache
5492
 *
5493
 * Depending on the state of the cache this frees the given
5494
 * XPath object or stores it in the cache.
5495
 */
5496
static void
5497
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5498
0
{
5499
0
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500
0
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501
0
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5502
5503
0
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5504
5505
0
    if (obj == NULL)
5506
0
  return;
5507
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5508
0
   xmlXPathFreeObject(obj);
5509
0
    } else {
5510
0
  xmlXPathContextCachePtr cache =
5511
0
      (xmlXPathContextCachePtr) ctxt->cache;
5512
5513
0
  switch (obj->type) {
5514
0
      case XPATH_NODESET:
5515
0
      case XPATH_XSLT_TREE:
5516
0
    if (obj->nodesetval != NULL) {
5517
0
        if (obj->boolval) {
5518
      /*
5519
      * It looks like the @boolval is used for
5520
      * evaluation if this an XSLT Result Tree Fragment.
5521
      * TODO: Check if this assumption is correct.
5522
      */
5523
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5524
0
      xmlXPathFreeValueTree(obj->nodesetval);
5525
0
      obj->nodesetval = NULL;
5526
0
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5527
0
      (XP_CACHE_WANTS(cache->nodesetObjs,
5528
0
          cache->maxNodeset)))
5529
0
        {
5530
0
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5531
0
      goto obj_cached;
5532
0
        } else {
5533
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5534
0
      obj->nodesetval = NULL;
5535
0
        }
5536
0
    }
5537
0
    break;
5538
0
      case XPATH_STRING:
5539
0
    if (obj->stringval != NULL)
5540
0
        xmlFree(obj->stringval);
5541
5542
0
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5543
0
        XP_CACHE_ADD(cache->stringObjs, obj);
5544
0
        goto obj_cached;
5545
0
    }
5546
0
    break;
5547
0
      case XPATH_BOOLEAN:
5548
0
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5549
0
        XP_CACHE_ADD(cache->booleanObjs, obj);
5550
0
        goto obj_cached;
5551
0
    }
5552
0
    break;
5553
0
      case XPATH_NUMBER:
5554
0
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5555
0
        XP_CACHE_ADD(cache->numberObjs, obj);
5556
0
        goto obj_cached;
5557
0
    }
5558
0
    break;
5559
#ifdef LIBXML_XPTR_LOCS_ENABLED
5560
      case XPATH_LOCATIONSET:
5561
    if (obj->user != NULL) {
5562
        xmlXPtrFreeLocationSet(obj->user);
5563
    }
5564
    goto free_obj;
5565
#endif
5566
0
      default:
5567
0
    goto free_obj;
5568
0
  }
5569
5570
  /*
5571
  * Fallback to adding to the misc-objects slot.
5572
  */
5573
0
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5574
0
      XP_CACHE_ADD(cache->miscObjs, obj);
5575
0
  } else
5576
0
      goto free_obj;
5577
5578
0
obj_cached:
5579
5580
#ifdef XP_DEBUG_OBJ_USAGE
5581
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5582
#endif
5583
5584
0
  if (obj->nodesetval != NULL) {
5585
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
5586
5587
      /*
5588
      * TODO: Due to those nasty ns-nodes, we need to traverse
5589
      *  the list and free the ns-nodes.
5590
      * URGENT TODO: Check if it's actually slowing things down.
5591
      *  Maybe we shouldn't try to preserve the list.
5592
      */
5593
0
      if (tmpset->nodeNr > 1) {
5594
0
    int i;
5595
0
    xmlNodePtr node;
5596
5597
0
    for (i = 0; i < tmpset->nodeNr; i++) {
5598
0
        node = tmpset->nodeTab[i];
5599
0
        if ((node != NULL) &&
5600
0
      (node->type == XML_NAMESPACE_DECL))
5601
0
        {
5602
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5603
0
        }
5604
0
    }
5605
0
      } else if (tmpset->nodeNr == 1) {
5606
0
    if ((tmpset->nodeTab[0] != NULL) &&
5607
0
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5608
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5609
0
      }
5610
0
      tmpset->nodeNr = 0;
5611
0
      memset(obj, 0, sizeof(xmlXPathObject));
5612
0
      obj->nodesetval = tmpset;
5613
0
  } else
5614
0
      memset(obj, 0, sizeof(xmlXPathObject));
5615
5616
0
  return;
5617
5618
0
free_obj:
5619
  /*
5620
  * Cache is full; free the object.
5621
  */
5622
0
  if (obj->nodesetval != NULL)
5623
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5624
#ifdef XP_DEBUG_OBJ_USAGE
5625
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5626
#endif
5627
0
  xmlFree(obj);
5628
0
    }
5629
0
    return;
5630
0
}
5631
5632
5633
/************************************************************************
5634
 *                  *
5635
 *      Type Casting Routines       *
5636
 *                  *
5637
 ************************************************************************/
5638
5639
/**
5640
 * xmlXPathCastBooleanToString:
5641
 * @val:  a boolean
5642
 *
5643
 * Converts a boolean to its string value.
5644
 *
5645
 * Returns a newly allocated string.
5646
 */
5647
xmlChar *
5648
0
xmlXPathCastBooleanToString (int val) {
5649
0
    xmlChar *ret;
5650
0
    if (val)
5651
0
  ret = xmlStrdup((const xmlChar *) "true");
5652
0
    else
5653
0
  ret = xmlStrdup((const xmlChar *) "false");
5654
0
    return(ret);
5655
0
}
5656
5657
/**
5658
 * xmlXPathCastNumberToString:
5659
 * @val:  a number
5660
 *
5661
 * Converts a number to its string value.
5662
 *
5663
 * Returns a newly allocated string.
5664
 */
5665
xmlChar *
5666
0
xmlXPathCastNumberToString (double val) {
5667
0
    xmlChar *ret;
5668
0
    switch (xmlXPathIsInf(val)) {
5669
0
    case 1:
5670
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
5671
0
  break;
5672
0
    case -1:
5673
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5674
0
  break;
5675
0
    default:
5676
0
  if (xmlXPathIsNaN(val)) {
5677
0
      ret = xmlStrdup((const xmlChar *) "NaN");
5678
0
  } else if (val == 0) {
5679
            /* Omit sign for negative zero. */
5680
0
      ret = xmlStrdup((const xmlChar *) "0");
5681
0
  } else {
5682
      /* could be improved */
5683
0
      char buf[100];
5684
0
      xmlXPathFormatNumber(val, buf, 99);
5685
0
      buf[99] = 0;
5686
0
      ret = xmlStrdup((const xmlChar *) buf);
5687
0
  }
5688
0
    }
5689
0
    return(ret);
5690
0
}
5691
5692
/**
5693
 * xmlXPathCastNodeToString:
5694
 * @node:  a node
5695
 *
5696
 * Converts a node to its string value.
5697
 *
5698
 * Returns a newly allocated string.
5699
 */
5700
xmlChar *
5701
0
xmlXPathCastNodeToString (xmlNodePtr node) {
5702
0
xmlChar *ret;
5703
0
    if ((ret = xmlNodeGetContent(node)) == NULL)
5704
0
  ret = xmlStrdup((const xmlChar *) "");
5705
0
    return(ret);
5706
0
}
5707
5708
/**
5709
 * xmlXPathCastNodeSetToString:
5710
 * @ns:  a node-set
5711
 *
5712
 * Converts a node-set to its string value.
5713
 *
5714
 * Returns a newly allocated string.
5715
 */
5716
xmlChar *
5717
0
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5718
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5719
0
  return(xmlStrdup((const xmlChar *) ""));
5720
5721
0
    if (ns->nodeNr > 1)
5722
0
  xmlXPathNodeSetSort(ns);
5723
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5724
0
}
5725
5726
/**
5727
 * xmlXPathCastToString:
5728
 * @val:  an XPath object
5729
 *
5730
 * Converts an existing object to its string() equivalent
5731
 *
5732
 * Returns the allocated string value of the object, NULL in case of error.
5733
 *         It's up to the caller to free the string memory with xmlFree().
5734
 */
5735
xmlChar *
5736
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
5737
0
    xmlChar *ret = NULL;
5738
5739
0
    if (val == NULL)
5740
0
  return(xmlStrdup((const xmlChar *) ""));
5741
0
    switch (val->type) {
5742
0
  case XPATH_UNDEFINED:
5743
#ifdef DEBUG_EXPR
5744
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5745
#endif
5746
0
      ret = xmlStrdup((const xmlChar *) "");
5747
0
      break;
5748
0
        case XPATH_NODESET:
5749
0
        case XPATH_XSLT_TREE:
5750
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5751
0
      break;
5752
0
  case XPATH_STRING:
5753
0
      return(xmlStrdup(val->stringval));
5754
0
        case XPATH_BOOLEAN:
5755
0
      ret = xmlXPathCastBooleanToString(val->boolval);
5756
0
      break;
5757
0
  case XPATH_NUMBER: {
5758
0
      ret = xmlXPathCastNumberToString(val->floatval);
5759
0
      break;
5760
0
  }
5761
0
  case XPATH_USERS:
5762
#ifdef LIBXML_XPTR_LOCS_ENABLED
5763
  case XPATH_POINT:
5764
  case XPATH_RANGE:
5765
  case XPATH_LOCATIONSET:
5766
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5767
0
      TODO
5768
0
      ret = xmlStrdup((const xmlChar *) "");
5769
0
      break;
5770
0
    }
5771
0
    return(ret);
5772
0
}
5773
5774
/**
5775
 * xmlXPathConvertString:
5776
 * @val:  an XPath object
5777
 *
5778
 * Converts an existing object to its string() equivalent
5779
 *
5780
 * Returns the new object, the old one is freed (or the operation
5781
 *         is done directly on @val)
5782
 */
5783
xmlXPathObjectPtr
5784
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
5785
0
    xmlChar *res = NULL;
5786
5787
0
    if (val == NULL)
5788
0
  return(xmlXPathNewCString(""));
5789
5790
0
    switch (val->type) {
5791
0
    case XPATH_UNDEFINED:
5792
#ifdef DEBUG_EXPR
5793
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5794
#endif
5795
0
  break;
5796
0
    case XPATH_NODESET:
5797
0
    case XPATH_XSLT_TREE:
5798
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5799
0
  break;
5800
0
    case XPATH_STRING:
5801
0
  return(val);
5802
0
    case XPATH_BOOLEAN:
5803
0
  res = xmlXPathCastBooleanToString(val->boolval);
5804
0
  break;
5805
0
    case XPATH_NUMBER:
5806
0
  res = xmlXPathCastNumberToString(val->floatval);
5807
0
  break;
5808
0
    case XPATH_USERS:
5809
#ifdef LIBXML_XPTR_LOCS_ENABLED
5810
    case XPATH_POINT:
5811
    case XPATH_RANGE:
5812
    case XPATH_LOCATIONSET:
5813
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5814
0
  TODO;
5815
0
  break;
5816
0
    }
5817
0
    xmlXPathFreeObject(val);
5818
0
    if (res == NULL)
5819
0
  return(xmlXPathNewCString(""));
5820
0
    return(xmlXPathWrapString(res));
5821
0
}
5822
5823
/**
5824
 * xmlXPathCastBooleanToNumber:
5825
 * @val:  a boolean
5826
 *
5827
 * Converts a boolean to its number value
5828
 *
5829
 * Returns the number value
5830
 */
5831
double
5832
0
xmlXPathCastBooleanToNumber(int val) {
5833
0
    if (val)
5834
0
  return(1.0);
5835
0
    return(0.0);
5836
0
}
5837
5838
/**
5839
 * xmlXPathCastStringToNumber:
5840
 * @val:  a string
5841
 *
5842
 * Converts a string to its number value
5843
 *
5844
 * Returns the number value
5845
 */
5846
double
5847
0
xmlXPathCastStringToNumber(const xmlChar * val) {
5848
0
    return(xmlXPathStringEvalNumber(val));
5849
0
}
5850
5851
/**
5852
 * xmlXPathCastNodeToNumber:
5853
 * @node:  a node
5854
 *
5855
 * Converts a node to its number value
5856
 *
5857
 * Returns the number value
5858
 */
5859
double
5860
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5861
0
    xmlChar *strval;
5862
0
    double ret;
5863
5864
0
    if (node == NULL)
5865
0
  return(xmlXPathNAN);
5866
0
    strval = xmlXPathCastNodeToString(node);
5867
0
    if (strval == NULL)
5868
0
  return(xmlXPathNAN);
5869
0
    ret = xmlXPathCastStringToNumber(strval);
5870
0
    xmlFree(strval);
5871
5872
0
    return(ret);
5873
0
}
5874
5875
/**
5876
 * xmlXPathCastNodeSetToNumber:
5877
 * @ns:  a node-set
5878
 *
5879
 * Converts a node-set to its number value
5880
 *
5881
 * Returns the number value
5882
 */
5883
double
5884
0
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5885
0
    xmlChar *str;
5886
0
    double ret;
5887
5888
0
    if (ns == NULL)
5889
0
  return(xmlXPathNAN);
5890
0
    str = xmlXPathCastNodeSetToString(ns);
5891
0
    ret = xmlXPathCastStringToNumber(str);
5892
0
    xmlFree(str);
5893
0
    return(ret);
5894
0
}
5895
5896
/**
5897
 * xmlXPathCastToNumber:
5898
 * @val:  an XPath object
5899
 *
5900
 * Converts an XPath object to its number value
5901
 *
5902
 * Returns the number value
5903
 */
5904
double
5905
0
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5906
0
    double ret = 0.0;
5907
5908
0
    if (val == NULL)
5909
0
  return(xmlXPathNAN);
5910
0
    switch (val->type) {
5911
0
    case XPATH_UNDEFINED:
5912
#ifdef DEBUG_EXPR
5913
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5914
#endif
5915
0
  ret = xmlXPathNAN;
5916
0
  break;
5917
0
    case XPATH_NODESET:
5918
0
    case XPATH_XSLT_TREE:
5919
0
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5920
0
  break;
5921
0
    case XPATH_STRING:
5922
0
  ret = xmlXPathCastStringToNumber(val->stringval);
5923
0
  break;
5924
0
    case XPATH_NUMBER:
5925
0
  ret = val->floatval;
5926
0
  break;
5927
0
    case XPATH_BOOLEAN:
5928
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5929
0
  break;
5930
0
    case XPATH_USERS:
5931
#ifdef LIBXML_XPTR_LOCS_ENABLED
5932
    case XPATH_POINT:
5933
    case XPATH_RANGE:
5934
    case XPATH_LOCATIONSET:
5935
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5936
0
  TODO;
5937
0
  ret = xmlXPathNAN;
5938
0
  break;
5939
0
    }
5940
0
    return(ret);
5941
0
}
5942
5943
/**
5944
 * xmlXPathConvertNumber:
5945
 * @val:  an XPath object
5946
 *
5947
 * Converts an existing object to its number() equivalent
5948
 *
5949
 * Returns the new object, the old one is freed (or the operation
5950
 *         is done directly on @val)
5951
 */
5952
xmlXPathObjectPtr
5953
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5954
0
    xmlXPathObjectPtr ret;
5955
5956
0
    if (val == NULL)
5957
0
  return(xmlXPathNewFloat(0.0));
5958
0
    if (val->type == XPATH_NUMBER)
5959
0
  return(val);
5960
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5961
0
    xmlXPathFreeObject(val);
5962
0
    return(ret);
5963
0
}
5964
5965
/**
5966
 * xmlXPathCastNumberToBoolean:
5967
 * @val:  a number
5968
 *
5969
 * Converts a number to its boolean value
5970
 *
5971
 * Returns the boolean value
5972
 */
5973
int
5974
0
xmlXPathCastNumberToBoolean (double val) {
5975
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
5976
0
   return(0);
5977
0
     return(1);
5978
0
}
5979
5980
/**
5981
 * xmlXPathCastStringToBoolean:
5982
 * @val:  a string
5983
 *
5984
 * Converts a string to its boolean value
5985
 *
5986
 * Returns the boolean value
5987
 */
5988
int
5989
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
5990
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
5991
0
  return(0);
5992
0
    return(1);
5993
0
}
5994
5995
/**
5996
 * xmlXPathCastNodeSetToBoolean:
5997
 * @ns:  a node-set
5998
 *
5999
 * Converts a node-set to its boolean value
6000
 *
6001
 * Returns the boolean value
6002
 */
6003
int
6004
0
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6005
0
    if ((ns == NULL) || (ns->nodeNr == 0))
6006
0
  return(0);
6007
0
    return(1);
6008
0
}
6009
6010
/**
6011
 * xmlXPathCastToBoolean:
6012
 * @val:  an XPath object
6013
 *
6014
 * Converts an XPath object to its boolean value
6015
 *
6016
 * Returns the boolean value
6017
 */
6018
int
6019
0
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6020
0
    int ret = 0;
6021
6022
0
    if (val == NULL)
6023
0
  return(0);
6024
0
    switch (val->type) {
6025
0
    case XPATH_UNDEFINED:
6026
#ifdef DEBUG_EXPR
6027
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6028
#endif
6029
0
  ret = 0;
6030
0
  break;
6031
0
    case XPATH_NODESET:
6032
0
    case XPATH_XSLT_TREE:
6033
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6034
0
  break;
6035
0
    case XPATH_STRING:
6036
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
6037
0
  break;
6038
0
    case XPATH_NUMBER:
6039
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6040
0
  break;
6041
0
    case XPATH_BOOLEAN:
6042
0
  ret = val->boolval;
6043
0
  break;
6044
0
    case XPATH_USERS:
6045
#ifdef LIBXML_XPTR_LOCS_ENABLED
6046
    case XPATH_POINT:
6047
    case XPATH_RANGE:
6048
    case XPATH_LOCATIONSET:
6049
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6050
0
  TODO;
6051
0
  ret = 0;
6052
0
  break;
6053
0
    }
6054
0
    return(ret);
6055
0
}
6056
6057
6058
/**
6059
 * xmlXPathConvertBoolean:
6060
 * @val:  an XPath object
6061
 *
6062
 * Converts an existing object to its boolean() equivalent
6063
 *
6064
 * Returns the new object, the old one is freed (or the operation
6065
 *         is done directly on @val)
6066
 */
6067
xmlXPathObjectPtr
6068
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6069
0
    xmlXPathObjectPtr ret;
6070
6071
0
    if (val == NULL)
6072
0
  return(xmlXPathNewBoolean(0));
6073
0
    if (val->type == XPATH_BOOLEAN)
6074
0
  return(val);
6075
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6076
0
    xmlXPathFreeObject(val);
6077
0
    return(ret);
6078
0
}
6079
6080
/************************************************************************
6081
 *                  *
6082
 *    Routines to handle XPath contexts     *
6083
 *                  *
6084
 ************************************************************************/
6085
6086
/**
6087
 * xmlXPathNewContext:
6088
 * @doc:  the XML document
6089
 *
6090
 * Create a new xmlXPathContext
6091
 *
6092
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6093
 */
6094
xmlXPathContextPtr
6095
0
xmlXPathNewContext(xmlDocPtr doc) {
6096
0
    xmlXPathContextPtr ret;
6097
6098
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6099
0
    if (ret == NULL) {
6100
0
        xmlXPathErrMemory(NULL, "creating context\n");
6101
0
  return(NULL);
6102
0
    }
6103
0
    memset(ret, 0 , sizeof(xmlXPathContext));
6104
0
    ret->doc = doc;
6105
0
    ret->node = NULL;
6106
6107
0
    ret->varHash = NULL;
6108
6109
0
    ret->nb_types = 0;
6110
0
    ret->max_types = 0;
6111
0
    ret->types = NULL;
6112
6113
0
    ret->funcHash = xmlHashCreate(0);
6114
6115
0
    ret->nb_axis = 0;
6116
0
    ret->max_axis = 0;
6117
0
    ret->axis = NULL;
6118
6119
0
    ret->nsHash = NULL;
6120
0
    ret->user = NULL;
6121
6122
0
    ret->contextSize = -1;
6123
0
    ret->proximityPosition = -1;
6124
6125
#ifdef XP_DEFAULT_CACHE_ON
6126
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6127
  xmlXPathFreeContext(ret);
6128
  return(NULL);
6129
    }
6130
#endif
6131
6132
0
    xmlXPathRegisterAllFunctions(ret);
6133
6134
0
    return(ret);
6135
0
}
6136
6137
/**
6138
 * xmlXPathFreeContext:
6139
 * @ctxt:  the context to free
6140
 *
6141
 * Free up an xmlXPathContext
6142
 */
6143
void
6144
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6145
0
    if (ctxt == NULL) return;
6146
6147
0
    if (ctxt->cache != NULL)
6148
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6149
0
    xmlXPathRegisteredNsCleanup(ctxt);
6150
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
6151
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
6152
0
    xmlResetError(&ctxt->lastError);
6153
0
    xmlFree(ctxt);
6154
0
}
6155
6156
/************************************************************************
6157
 *                  *
6158
 *    Routines to handle XPath parser contexts    *
6159
 *                  *
6160
 ************************************************************************/
6161
6162
#define CHECK_CTXT(ctxt)            \
6163
0
    if (ctxt == NULL) {           \
6164
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6165
0
    NULL, NULL, XML_FROM_XPATH,       \
6166
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6167
0
    __FILE__, __LINE__,         \
6168
0
    NULL, NULL, NULL, 0, 0,         \
6169
0
    "NULL context pointer\n");        \
6170
0
  return(NULL);             \
6171
0
    }                  \
6172
6173
#define CHECK_CTXT_NEG(ctxt)            \
6174
0
    if (ctxt == NULL) {           \
6175
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6176
0
    NULL, NULL, XML_FROM_XPATH,       \
6177
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6178
0
    __FILE__, __LINE__,         \
6179
0
    NULL, NULL, NULL, 0, 0,         \
6180
0
    "NULL context pointer\n");        \
6181
0
  return(-1);             \
6182
0
    }                  \
6183
6184
6185
#define CHECK_CONTEXT(ctxt)           \
6186
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6187
        (ctxt->doc->children == NULL)) {        \
6188
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6189
  return(NULL);             \
6190
    }
6191
6192
6193
/**
6194
 * xmlXPathNewParserContext:
6195
 * @str:  the XPath expression
6196
 * @ctxt:  the XPath context
6197
 *
6198
 * Create a new xmlXPathParserContext
6199
 *
6200
 * Returns the xmlXPathParserContext just allocated.
6201
 */
6202
xmlXPathParserContextPtr
6203
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6204
0
    xmlXPathParserContextPtr ret;
6205
6206
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6207
0
    if (ret == NULL) {
6208
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6209
0
  return(NULL);
6210
0
    }
6211
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6212
0
    ret->cur = ret->base = str;
6213
0
    ret->context = ctxt;
6214
6215
0
    ret->comp = xmlXPathNewCompExpr();
6216
0
    if (ret->comp == NULL) {
6217
0
  xmlFree(ret->valueTab);
6218
0
  xmlFree(ret);
6219
0
  return(NULL);
6220
0
    }
6221
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6222
0
        ret->comp->dict = ctxt->dict;
6223
0
  xmlDictReference(ret->comp->dict);
6224
0
    }
6225
6226
0
    return(ret);
6227
0
}
6228
6229
/**
6230
 * xmlXPathCompParserContext:
6231
 * @comp:  the XPath compiled expression
6232
 * @ctxt:  the XPath context
6233
 *
6234
 * Create a new xmlXPathParserContext when processing a compiled expression
6235
 *
6236
 * Returns the xmlXPathParserContext just allocated.
6237
 */
6238
static xmlXPathParserContextPtr
6239
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6240
0
    xmlXPathParserContextPtr ret;
6241
6242
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6243
0
    if (ret == NULL) {
6244
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6245
0
  return(NULL);
6246
0
    }
6247
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
6248
6249
    /* Allocate the value stack */
6250
0
    ret->valueTab = (xmlXPathObjectPtr *)
6251
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6252
0
    if (ret->valueTab == NULL) {
6253
0
  xmlFree(ret);
6254
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6255
0
  return(NULL);
6256
0
    }
6257
0
    ret->valueNr = 0;
6258
0
    ret->valueMax = 10;
6259
0
    ret->value = NULL;
6260
6261
0
    ret->context = ctxt;
6262
0
    ret->comp = comp;
6263
6264
0
    return(ret);
6265
0
}
6266
6267
/**
6268
 * xmlXPathFreeParserContext:
6269
 * @ctxt:  the context to free
6270
 *
6271
 * Free up an xmlXPathParserContext
6272
 */
6273
void
6274
0
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6275
0
    int i;
6276
6277
0
    if (ctxt->valueTab != NULL) {
6278
0
        for (i = 0; i < ctxt->valueNr; i++) {
6279
0
            if (ctxt->context)
6280
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6281
0
            else
6282
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6283
0
        }
6284
0
        xmlFree(ctxt->valueTab);
6285
0
    }
6286
0
    if (ctxt->comp != NULL) {
6287
0
#ifdef XPATH_STREAMING
6288
0
  if (ctxt->comp->stream != NULL) {
6289
0
      xmlFreePatternList(ctxt->comp->stream);
6290
0
      ctxt->comp->stream = NULL;
6291
0
  }
6292
0
#endif
6293
0
  xmlXPathFreeCompExpr(ctxt->comp);
6294
0
    }
6295
0
    xmlFree(ctxt);
6296
0
}
6297
6298
/************************************************************************
6299
 *                  *
6300
 *    The implicit core function library      *
6301
 *                  *
6302
 ************************************************************************/
6303
6304
/**
6305
 * xmlXPathNodeValHash:
6306
 * @node:  a node pointer
6307
 *
6308
 * Function computing the beginning of the string value of the node,
6309
 * used to speed up comparisons
6310
 *
6311
 * Returns an int usable as a hash
6312
 */
6313
static unsigned int
6314
0
xmlXPathNodeValHash(xmlNodePtr node) {
6315
0
    int len = 2;
6316
0
    const xmlChar * string = NULL;
6317
0
    xmlNodePtr tmp = NULL;
6318
0
    unsigned int ret = 0;
6319
6320
0
    if (node == NULL)
6321
0
  return(0);
6322
6323
0
    if (node->type == XML_DOCUMENT_NODE) {
6324
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6325
0
  if (tmp == NULL)
6326
0
      node = node->children;
6327
0
  else
6328
0
      node = tmp;
6329
6330
0
  if (node == NULL)
6331
0
      return(0);
6332
0
    }
6333
6334
0
    switch (node->type) {
6335
0
  case XML_COMMENT_NODE:
6336
0
  case XML_PI_NODE:
6337
0
  case XML_CDATA_SECTION_NODE:
6338
0
  case XML_TEXT_NODE:
6339
0
      string = node->content;
6340
0
      if (string == NULL)
6341
0
    return(0);
6342
0
      if (string[0] == 0)
6343
0
    return(0);
6344
0
      return(string[0] + (string[1] << 8));
6345
0
  case XML_NAMESPACE_DECL:
6346
0
      string = ((xmlNsPtr)node)->href;
6347
0
      if (string == NULL)
6348
0
    return(0);
6349
0
      if (string[0] == 0)
6350
0
    return(0);
6351
0
      return(string[0] + (string[1] << 8));
6352
0
  case XML_ATTRIBUTE_NODE:
6353
0
      tmp = ((xmlAttrPtr) node)->children;
6354
0
      break;
6355
0
  case XML_ELEMENT_NODE:
6356
0
      tmp = node->children;
6357
0
      break;
6358
0
  default:
6359
0
      return(0);
6360
0
    }
6361
0
    while (tmp != NULL) {
6362
0
  switch (tmp->type) {
6363
0
      case XML_CDATA_SECTION_NODE:
6364
0
      case XML_TEXT_NODE:
6365
0
    string = tmp->content;
6366
0
    break;
6367
0
      default:
6368
0
                string = NULL;
6369
0
    break;
6370
0
  }
6371
0
  if ((string != NULL) && (string[0] != 0)) {
6372
0
      if (len == 1) {
6373
0
    return(ret + (string[0] << 8));
6374
0
      }
6375
0
      if (string[1] == 0) {
6376
0
    len = 1;
6377
0
    ret = string[0];
6378
0
      } else {
6379
0
    return(string[0] + (string[1] << 8));
6380
0
      }
6381
0
  }
6382
  /*
6383
   * Skip to next node
6384
   */
6385
0
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6386
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6387
0
    tmp = tmp->children;
6388
0
    continue;
6389
0
      }
6390
0
  }
6391
0
  if (tmp == node)
6392
0
      break;
6393
6394
0
  if (tmp->next != NULL) {
6395
0
      tmp = tmp->next;
6396
0
      continue;
6397
0
  }
6398
6399
0
  do {
6400
0
      tmp = tmp->parent;
6401
0
      if (tmp == NULL)
6402
0
    break;
6403
0
      if (tmp == node) {
6404
0
    tmp = NULL;
6405
0
    break;
6406
0
      }
6407
0
      if (tmp->next != NULL) {
6408
0
    tmp = tmp->next;
6409
0
    break;
6410
0
      }
6411
0
  } while (tmp != NULL);
6412
0
    }
6413
0
    return(ret);
6414
0
}
6415
6416
/**
6417
 * xmlXPathStringHash:
6418
 * @string:  a string
6419
 *
6420
 * Function computing the beginning of the string value of the node,
6421
 * used to speed up comparisons
6422
 *
6423
 * Returns an int usable as a hash
6424
 */
6425
static unsigned int
6426
0
xmlXPathStringHash(const xmlChar * string) {
6427
0
    if (string == NULL)
6428
0
  return(0);
6429
0
    if (string[0] == 0)
6430
0
  return(0);
6431
0
    return(string[0] + (string[1] << 8));
6432
0
}
6433
6434
/**
6435
 * xmlXPathCompareNodeSetFloat:
6436
 * @ctxt:  the XPath Parser context
6437
 * @inf:  less than (1) or greater than (0)
6438
 * @strict:  is the comparison strict
6439
 * @arg:  the node set
6440
 * @f:  the value
6441
 *
6442
 * Implement the compare operation between a nodeset and a number
6443
 *     @ns < @val    (1, 1, ...
6444
 *     @ns <= @val   (1, 0, ...
6445
 *     @ns > @val    (0, 1, ...
6446
 *     @ns >= @val   (0, 0, ...
6447
 *
6448
 * If one object to be compared is a node-set and the other is a number,
6449
 * then the comparison will be true if and only if there is a node in the
6450
 * node-set such that the result of performing the comparison on the number
6451
 * to be compared and on the result of converting the string-value of that
6452
 * node to a number using the number function is true.
6453
 *
6454
 * Returns 0 or 1 depending on the results of the test.
6455
 */
6456
static int
6457
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6458
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6459
0
    int i, ret = 0;
6460
0
    xmlNodeSetPtr ns;
6461
0
    xmlChar *str2;
6462
6463
0
    if ((f == NULL) || (arg == NULL) ||
6464
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6465
0
  xmlXPathReleaseObject(ctxt->context, arg);
6466
0
  xmlXPathReleaseObject(ctxt->context, f);
6467
0
        return(0);
6468
0
    }
6469
0
    ns = arg->nodesetval;
6470
0
    if (ns != NULL) {
6471
0
  for (i = 0;i < ns->nodeNr;i++) {
6472
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6473
0
       if (str2 != NULL) {
6474
0
     valuePush(ctxt,
6475
0
         xmlXPathCacheNewString(ctxt->context, str2));
6476
0
     xmlFree(str2);
6477
0
     xmlXPathNumberFunction(ctxt, 1);
6478
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6479
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6480
0
     if (ret)
6481
0
         break;
6482
0
       }
6483
0
  }
6484
0
    }
6485
0
    xmlXPathReleaseObject(ctxt->context, arg);
6486
0
    xmlXPathReleaseObject(ctxt->context, f);
6487
0
    return(ret);
6488
0
}
6489
6490
/**
6491
 * xmlXPathCompareNodeSetString:
6492
 * @ctxt:  the XPath Parser context
6493
 * @inf:  less than (1) or greater than (0)
6494
 * @strict:  is the comparison strict
6495
 * @arg:  the node set
6496
 * @s:  the value
6497
 *
6498
 * Implement the compare operation between a nodeset and a string
6499
 *     @ns < @val    (1, 1, ...
6500
 *     @ns <= @val   (1, 0, ...
6501
 *     @ns > @val    (0, 1, ...
6502
 *     @ns >= @val   (0, 0, ...
6503
 *
6504
 * If one object to be compared is a node-set and the other is a string,
6505
 * then the comparison will be true if and only if there is a node in
6506
 * the node-set such that the result of performing the comparison on the
6507
 * string-value of the node and the other string is true.
6508
 *
6509
 * Returns 0 or 1 depending on the results of the test.
6510
 */
6511
static int
6512
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6513
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6514
0
    int i, ret = 0;
6515
0
    xmlNodeSetPtr ns;
6516
0
    xmlChar *str2;
6517
6518
0
    if ((s == NULL) || (arg == NULL) ||
6519
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6520
0
  xmlXPathReleaseObject(ctxt->context, arg);
6521
0
  xmlXPathReleaseObject(ctxt->context, s);
6522
0
        return(0);
6523
0
    }
6524
0
    ns = arg->nodesetval;
6525
0
    if (ns != NULL) {
6526
0
  for (i = 0;i < ns->nodeNr;i++) {
6527
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6528
0
       if (str2 != NULL) {
6529
0
     valuePush(ctxt,
6530
0
         xmlXPathCacheNewString(ctxt->context, str2));
6531
0
     xmlFree(str2);
6532
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6533
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6534
0
     if (ret)
6535
0
         break;
6536
0
       }
6537
0
  }
6538
0
    }
6539
0
    xmlXPathReleaseObject(ctxt->context, arg);
6540
0
    xmlXPathReleaseObject(ctxt->context, s);
6541
0
    return(ret);
6542
0
}
6543
6544
/**
6545
 * xmlXPathCompareNodeSets:
6546
 * @inf:  less than (1) or greater than (0)
6547
 * @strict:  is the comparison strict
6548
 * @arg1:  the first node set object
6549
 * @arg2:  the second node set object
6550
 *
6551
 * Implement the compare operation on nodesets:
6552
 *
6553
 * If both objects to be compared are node-sets, then the comparison
6554
 * will be true if and only if there is a node in the first node-set
6555
 * and a node in the second node-set such that the result of performing
6556
 * the comparison on the string-values of the two nodes is true.
6557
 * ....
6558
 * When neither object to be compared is a node-set and the operator
6559
 * is <=, <, >= or >, then the objects are compared by converting both
6560
 * objects to numbers and comparing the numbers according to IEEE 754.
6561
 * ....
6562
 * The number function converts its argument to a number as follows:
6563
 *  - a string that consists of optional whitespace followed by an
6564
 *    optional minus sign followed by a Number followed by whitespace
6565
 *    is converted to the IEEE 754 number that is nearest (according
6566
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6567
 *    represented by the string; any other string is converted to NaN
6568
 *
6569
 * Conclusion all nodes need to be converted first to their string value
6570
 * and then the comparison must be done when possible
6571
 */
6572
static int
6573
xmlXPathCompareNodeSets(int inf, int strict,
6574
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6575
0
    int i, j, init = 0;
6576
0
    double val1;
6577
0
    double *values2;
6578
0
    int ret = 0;
6579
0
    xmlNodeSetPtr ns1;
6580
0
    xmlNodeSetPtr ns2;
6581
6582
0
    if ((arg1 == NULL) ||
6583
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6584
0
  xmlXPathFreeObject(arg2);
6585
0
        return(0);
6586
0
    }
6587
0
    if ((arg2 == NULL) ||
6588
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6589
0
  xmlXPathFreeObject(arg1);
6590
0
  xmlXPathFreeObject(arg2);
6591
0
        return(0);
6592
0
    }
6593
6594
0
    ns1 = arg1->nodesetval;
6595
0
    ns2 = arg2->nodesetval;
6596
6597
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6598
0
  xmlXPathFreeObject(arg1);
6599
0
  xmlXPathFreeObject(arg2);
6600
0
  return(0);
6601
0
    }
6602
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6603
0
  xmlXPathFreeObject(arg1);
6604
0
  xmlXPathFreeObject(arg2);
6605
0
  return(0);
6606
0
    }
6607
6608
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6609
0
    if (values2 == NULL) {
6610
        /* TODO: Propagate memory error. */
6611
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6612
0
  xmlXPathFreeObject(arg1);
6613
0
  xmlXPathFreeObject(arg2);
6614
0
  return(0);
6615
0
    }
6616
0
    for (i = 0;i < ns1->nodeNr;i++) {
6617
0
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6618
0
  if (xmlXPathIsNaN(val1))
6619
0
      continue;
6620
0
  for (j = 0;j < ns2->nodeNr;j++) {
6621
0
      if (init == 0) {
6622
0
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6623
0
      }
6624
0
      if (xmlXPathIsNaN(values2[j]))
6625
0
    continue;
6626
0
      if (inf && strict)
6627
0
    ret = (val1 < values2[j]);
6628
0
      else if (inf && !strict)
6629
0
    ret = (val1 <= values2[j]);
6630
0
      else if (!inf && strict)
6631
0
    ret = (val1 > values2[j]);
6632
0
      else if (!inf && !strict)
6633
0
    ret = (val1 >= values2[j]);
6634
0
      if (ret)
6635
0
    break;
6636
0
  }
6637
0
  if (ret)
6638
0
      break;
6639
0
  init = 1;
6640
0
    }
6641
0
    xmlFree(values2);
6642
0
    xmlXPathFreeObject(arg1);
6643
0
    xmlXPathFreeObject(arg2);
6644
0
    return(ret);
6645
0
}
6646
6647
/**
6648
 * xmlXPathCompareNodeSetValue:
6649
 * @ctxt:  the XPath Parser context
6650
 * @inf:  less than (1) or greater than (0)
6651
 * @strict:  is the comparison strict
6652
 * @arg:  the node set
6653
 * @val:  the value
6654
 *
6655
 * Implement the compare operation between a nodeset and a value
6656
 *     @ns < @val    (1, 1, ...
6657
 *     @ns <= @val   (1, 0, ...
6658
 *     @ns > @val    (0, 1, ...
6659
 *     @ns >= @val   (0, 0, ...
6660
 *
6661
 * If one object to be compared is a node-set and the other is a boolean,
6662
 * then the comparison will be true if and only if the result of performing
6663
 * the comparison on the boolean and on the result of converting
6664
 * the node-set to a boolean using the boolean function is true.
6665
 *
6666
 * Returns 0 or 1 depending on the results of the test.
6667
 */
6668
static int
6669
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6670
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6671
0
    if ((val == NULL) || (arg == NULL) ||
6672
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6673
0
        return(0);
6674
6675
0
    switch(val->type) {
6676
0
        case XPATH_NUMBER:
6677
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6678
0
        case XPATH_NODESET:
6679
0
        case XPATH_XSLT_TREE:
6680
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6681
0
        case XPATH_STRING:
6682
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6683
0
        case XPATH_BOOLEAN:
6684
0
      valuePush(ctxt, arg);
6685
0
      xmlXPathBooleanFunction(ctxt, 1);
6686
0
      valuePush(ctxt, val);
6687
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
6688
0
  default:
6689
0
            xmlGenericError(xmlGenericErrorContext,
6690
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6691
0
                    "and object of type %d\n",
6692
0
                    val->type);
6693
0
            xmlXPathReleaseObject(ctxt->context, arg);
6694
0
            xmlXPathReleaseObject(ctxt->context, val);
6695
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6696
0
    }
6697
0
    return(0);
6698
0
}
6699
6700
/**
6701
 * xmlXPathEqualNodeSetString:
6702
 * @arg:  the nodeset object argument
6703
 * @str:  the string to compare to.
6704
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6705
 *
6706
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6707
 * If one object to be compared is a node-set and the other is a string,
6708
 * then the comparison will be true if and only if there is a node in
6709
 * the node-set such that the result of performing the comparison on the
6710
 * string-value of the node and the other string is true.
6711
 *
6712
 * Returns 0 or 1 depending on the results of the test.
6713
 */
6714
static int
6715
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6716
0
{
6717
0
    int i;
6718
0
    xmlNodeSetPtr ns;
6719
0
    xmlChar *str2;
6720
0
    unsigned int hash;
6721
6722
0
    if ((str == NULL) || (arg == NULL) ||
6723
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6724
0
        return (0);
6725
0
    ns = arg->nodesetval;
6726
    /*
6727
     * A NULL nodeset compared with a string is always false
6728
     * (since there is no node equal, and no node not equal)
6729
     */
6730
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6731
0
        return (0);
6732
0
    hash = xmlXPathStringHash(str);
6733
0
    for (i = 0; i < ns->nodeNr; i++) {
6734
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6735
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6736
0
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6737
0
                xmlFree(str2);
6738
0
    if (neq)
6739
0
        continue;
6740
0
                return (1);
6741
0
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6742
0
    if (neq)
6743
0
        continue;
6744
0
                return (1);
6745
0
            } else if (neq) {
6746
0
    if (str2 != NULL)
6747
0
        xmlFree(str2);
6748
0
    return (1);
6749
0
      }
6750
0
            if (str2 != NULL)
6751
0
                xmlFree(str2);
6752
0
        } else if (neq)
6753
0
      return (1);
6754
0
    }
6755
0
    return (0);
6756
0
}
6757
6758
/**
6759
 * xmlXPathEqualNodeSetFloat:
6760
 * @arg:  the nodeset object argument
6761
 * @f:  the float to compare to
6762
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6763
 *
6764
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6765
 * If one object to be compared is a node-set and the other is a number,
6766
 * then the comparison will be true if and only if there is a node in
6767
 * the node-set such that the result of performing the comparison on the
6768
 * number to be compared and on the result of converting the string-value
6769
 * of that node to a number using the number function is true.
6770
 *
6771
 * Returns 0 or 1 depending on the results of the test.
6772
 */
6773
static int
6774
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6775
0
    xmlXPathObjectPtr arg, double f, int neq) {
6776
0
  int i, ret=0;
6777
0
  xmlNodeSetPtr ns;
6778
0
  xmlChar *str2;
6779
0
  xmlXPathObjectPtr val;
6780
0
  double v;
6781
6782
0
    if ((arg == NULL) ||
6783
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6784
0
        return(0);
6785
6786
0
    ns = arg->nodesetval;
6787
0
    if (ns != NULL) {
6788
0
  for (i=0;i<ns->nodeNr;i++) {
6789
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6790
0
      if (str2 != NULL) {
6791
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6792
0
    xmlFree(str2);
6793
0
    xmlXPathNumberFunction(ctxt, 1);
6794
0
                CHECK_ERROR0;
6795
0
    val = valuePop(ctxt);
6796
0
    v = val->floatval;
6797
0
    xmlXPathReleaseObject(ctxt->context, val);
6798
0
    if (!xmlXPathIsNaN(v)) {
6799
0
        if ((!neq) && (v==f)) {
6800
0
      ret = 1;
6801
0
      break;
6802
0
        } else if ((neq) && (v!=f)) {
6803
0
      ret = 1;
6804
0
      break;
6805
0
        }
6806
0
    } else { /* NaN is unequal to any value */
6807
0
        if (neq)
6808
0
      ret = 1;
6809
0
    }
6810
0
      }
6811
0
  }
6812
0
    }
6813
6814
0
    return(ret);
6815
0
}
6816
6817
6818
/**
6819
 * xmlXPathEqualNodeSets:
6820
 * @arg1:  first nodeset object argument
6821
 * @arg2:  second nodeset object argument
6822
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6823
 *
6824
 * Implement the equal / not equal operation on XPath nodesets:
6825
 * @arg1 == @arg2  or  @arg1 != @arg2
6826
 * If both objects to be compared are node-sets, then the comparison
6827
 * will be true if and only if there is a node in the first node-set and
6828
 * a node in the second node-set such that the result of performing the
6829
 * comparison on the string-values of the two nodes is true.
6830
 *
6831
 * (needless to say, this is a costly operation)
6832
 *
6833
 * Returns 0 or 1 depending on the results of the test.
6834
 */
6835
static int
6836
0
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6837
0
    int i, j;
6838
0
    unsigned int *hashs1;
6839
0
    unsigned int *hashs2;
6840
0
    xmlChar **values1;
6841
0
    xmlChar **values2;
6842
0
    int ret = 0;
6843
0
    xmlNodeSetPtr ns1;
6844
0
    xmlNodeSetPtr ns2;
6845
6846
0
    if ((arg1 == NULL) ||
6847
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6848
0
        return(0);
6849
0
    if ((arg2 == NULL) ||
6850
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6851
0
        return(0);
6852
6853
0
    ns1 = arg1->nodesetval;
6854
0
    ns2 = arg2->nodesetval;
6855
6856
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6857
0
  return(0);
6858
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6859
0
  return(0);
6860
6861
    /*
6862
     * for equal, check if there is a node pertaining to both sets
6863
     */
6864
0
    if (neq == 0)
6865
0
  for (i = 0;i < ns1->nodeNr;i++)
6866
0
      for (j = 0;j < ns2->nodeNr;j++)
6867
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6868
0
        return(1);
6869
6870
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6871
0
    if (values1 == NULL) {
6872
        /* TODO: Propagate memory error. */
6873
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6874
0
  return(0);
6875
0
    }
6876
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6877
0
    if (hashs1 == NULL) {
6878
        /* TODO: Propagate memory error. */
6879
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6880
0
  xmlFree(values1);
6881
0
  return(0);
6882
0
    }
6883
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6884
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6885
0
    if (values2 == NULL) {
6886
        /* TODO: Propagate memory error. */
6887
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6888
0
  xmlFree(hashs1);
6889
0
  xmlFree(values1);
6890
0
  return(0);
6891
0
    }
6892
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6893
0
    if (hashs2 == NULL) {
6894
        /* TODO: Propagate memory error. */
6895
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896
0
  xmlFree(hashs1);
6897
0
  xmlFree(values1);
6898
0
  xmlFree(values2);
6899
0
  return(0);
6900
0
    }
6901
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6902
0
    for (i = 0;i < ns1->nodeNr;i++) {
6903
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6904
0
  for (j = 0;j < ns2->nodeNr;j++) {
6905
0
      if (i == 0)
6906
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6907
0
      if (hashs1[i] != hashs2[j]) {
6908
0
    if (neq) {
6909
0
        ret = 1;
6910
0
        break;
6911
0
    }
6912
0
      }
6913
0
      else {
6914
0
    if (values1[i] == NULL)
6915
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6916
0
    if (values2[j] == NULL)
6917
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6918
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6919
0
    if (ret)
6920
0
        break;
6921
0
      }
6922
0
  }
6923
0
  if (ret)
6924
0
      break;
6925
0
    }
6926
0
    for (i = 0;i < ns1->nodeNr;i++)
6927
0
  if (values1[i] != NULL)
6928
0
      xmlFree(values1[i]);
6929
0
    for (j = 0;j < ns2->nodeNr;j++)
6930
0
  if (values2[j] != NULL)
6931
0
      xmlFree(values2[j]);
6932
0
    xmlFree(values1);
6933
0
    xmlFree(values2);
6934
0
    xmlFree(hashs1);
6935
0
    xmlFree(hashs2);
6936
0
    return(ret);
6937
0
}
6938
6939
static int
6940
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6941
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6942
0
    int ret = 0;
6943
    /*
6944
     *At this point we are assured neither arg1 nor arg2
6945
     *is a nodeset, so we can just pick the appropriate routine.
6946
     */
6947
0
    switch (arg1->type) {
6948
0
        case XPATH_UNDEFINED:
6949
#ifdef DEBUG_EXPR
6950
      xmlGenericError(xmlGenericErrorContext,
6951
        "Equal: undefined\n");
6952
#endif
6953
0
      break;
6954
0
        case XPATH_BOOLEAN:
6955
0
      switch (arg2->type) {
6956
0
          case XPATH_UNDEFINED:
6957
#ifdef DEBUG_EXPR
6958
        xmlGenericError(xmlGenericErrorContext,
6959
          "Equal: undefined\n");
6960
#endif
6961
0
        break;
6962
0
    case XPATH_BOOLEAN:
6963
#ifdef DEBUG_EXPR
6964
        xmlGenericError(xmlGenericErrorContext,
6965
          "Equal: %d boolean %d \n",
6966
          arg1->boolval, arg2->boolval);
6967
#endif
6968
0
        ret = (arg1->boolval == arg2->boolval);
6969
0
        break;
6970
0
    case XPATH_NUMBER:
6971
0
        ret = (arg1->boolval ==
6972
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
6973
0
        break;
6974
0
    case XPATH_STRING:
6975
0
        if ((arg2->stringval == NULL) ||
6976
0
      (arg2->stringval[0] == 0)) ret = 0;
6977
0
        else
6978
0
      ret = 1;
6979
0
        ret = (arg1->boolval == ret);
6980
0
        break;
6981
0
    case XPATH_USERS:
6982
#ifdef LIBXML_XPTR_LOCS_ENABLED
6983
    case XPATH_POINT:
6984
    case XPATH_RANGE:
6985
    case XPATH_LOCATIONSET:
6986
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6987
0
        TODO
6988
0
        break;
6989
0
    case XPATH_NODESET:
6990
0
    case XPATH_XSLT_TREE:
6991
0
        break;
6992
0
      }
6993
0
      break;
6994
0
        case XPATH_NUMBER:
6995
0
      switch (arg2->type) {
6996
0
          case XPATH_UNDEFINED:
6997
#ifdef DEBUG_EXPR
6998
        xmlGenericError(xmlGenericErrorContext,
6999
          "Equal: undefined\n");
7000
#endif
7001
0
        break;
7002
0
    case XPATH_BOOLEAN:
7003
0
        ret = (arg2->boolval==
7004
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
7005
0
        break;
7006
0
    case XPATH_STRING:
7007
0
        valuePush(ctxt, arg2);
7008
0
        xmlXPathNumberFunction(ctxt, 1);
7009
0
        arg2 = valuePop(ctxt);
7010
0
                    if (ctxt->error)
7011
0
                        break;
7012
                    /* Falls through. */
7013
0
    case XPATH_NUMBER:
7014
        /* Hand check NaN and Infinity equalities */
7015
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7016
0
          xmlXPathIsNaN(arg2->floatval)) {
7017
0
            ret = 0;
7018
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7019
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
7020
0
          ret = 1;
7021
0
      else
7022
0
          ret = 0;
7023
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7024
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7025
0
          ret = 1;
7026
0
      else
7027
0
          ret = 0;
7028
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7029
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7030
0
          ret = 1;
7031
0
      else
7032
0
          ret = 0;
7033
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7034
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7035
0
          ret = 1;
7036
0
      else
7037
0
          ret = 0;
7038
0
        } else {
7039
0
            ret = (arg1->floatval == arg2->floatval);
7040
0
        }
7041
0
        break;
7042
0
    case XPATH_USERS:
7043
#ifdef LIBXML_XPTR_LOCS_ENABLED
7044
    case XPATH_POINT:
7045
    case XPATH_RANGE:
7046
    case XPATH_LOCATIONSET:
7047
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7048
0
        TODO
7049
0
        break;
7050
0
    case XPATH_NODESET:
7051
0
    case XPATH_XSLT_TREE:
7052
0
        break;
7053
0
      }
7054
0
      break;
7055
0
        case XPATH_STRING:
7056
0
      switch (arg2->type) {
7057
0
          case XPATH_UNDEFINED:
7058
#ifdef DEBUG_EXPR
7059
        xmlGenericError(xmlGenericErrorContext,
7060
          "Equal: undefined\n");
7061
#endif
7062
0
        break;
7063
0
    case XPATH_BOOLEAN:
7064
0
        if ((arg1->stringval == NULL) ||
7065
0
      (arg1->stringval[0] == 0)) ret = 0;
7066
0
        else
7067
0
      ret = 1;
7068
0
        ret = (arg2->boolval == ret);
7069
0
        break;
7070
0
    case XPATH_STRING:
7071
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7072
0
        break;
7073
0
    case XPATH_NUMBER:
7074
0
        valuePush(ctxt, arg1);
7075
0
        xmlXPathNumberFunction(ctxt, 1);
7076
0
        arg1 = valuePop(ctxt);
7077
0
                    if (ctxt->error)
7078
0
                        break;
7079
        /* Hand check NaN and Infinity equalities */
7080
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7081
0
          xmlXPathIsNaN(arg2->floatval)) {
7082
0
            ret = 0;
7083
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7084
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7085
0
          ret = 1;
7086
0
      else
7087
0
          ret = 0;
7088
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7089
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7090
0
          ret = 1;
7091
0
      else
7092
0
          ret = 0;
7093
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7094
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7095
0
          ret = 1;
7096
0
      else
7097
0
          ret = 0;
7098
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7099
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7100
0
          ret = 1;
7101
0
      else
7102
0
          ret = 0;
7103
0
        } else {
7104
0
            ret = (arg1->floatval == arg2->floatval);
7105
0
        }
7106
0
        break;
7107
0
    case XPATH_USERS:
7108
#ifdef LIBXML_XPTR_LOCS_ENABLED
7109
    case XPATH_POINT:
7110
    case XPATH_RANGE:
7111
    case XPATH_LOCATIONSET:
7112
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7113
0
        TODO
7114
0
        break;
7115
0
    case XPATH_NODESET:
7116
0
    case XPATH_XSLT_TREE:
7117
0
        break;
7118
0
      }
7119
0
      break;
7120
0
        case XPATH_USERS:
7121
#ifdef LIBXML_XPTR_LOCS_ENABLED
7122
  case XPATH_POINT:
7123
  case XPATH_RANGE:
7124
  case XPATH_LOCATIONSET:
7125
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7126
0
      TODO
7127
0
      break;
7128
0
  case XPATH_NODESET:
7129
0
  case XPATH_XSLT_TREE:
7130
0
      break;
7131
0
    }
7132
0
    xmlXPathReleaseObject(ctxt->context, arg1);
7133
0
    xmlXPathReleaseObject(ctxt->context, arg2);
7134
0
    return(ret);
7135
0
}
7136
7137
/**
7138
 * xmlXPathEqualValues:
7139
 * @ctxt:  the XPath Parser context
7140
 *
7141
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7142
 *
7143
 * Returns 0 or 1 depending on the results of the test.
7144
 */
7145
int
7146
0
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7147
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
7148
0
    int ret = 0;
7149
7150
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7151
0
    arg2 = valuePop(ctxt);
7152
0
    arg1 = valuePop(ctxt);
7153
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7154
0
  if (arg1 != NULL)
7155
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7156
0
  else
7157
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7158
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7159
0
    }
7160
7161
0
    if (arg1 == arg2) {
7162
#ifdef DEBUG_EXPR
7163
        xmlGenericError(xmlGenericErrorContext,
7164
    "Equal: by pointer\n");
7165
#endif
7166
0
  xmlXPathFreeObject(arg1);
7167
0
        return(1);
7168
0
    }
7169
7170
    /*
7171
     *If either argument is a nodeset, it's a 'special case'
7172
     */
7173
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7174
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7175
  /*
7176
   *Hack it to assure arg1 is the nodeset
7177
   */
7178
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7179
0
    argtmp = arg2;
7180
0
    arg2 = arg1;
7181
0
    arg1 = argtmp;
7182
0
  }
7183
0
  switch (arg2->type) {
7184
0
      case XPATH_UNDEFINED:
7185
#ifdef DEBUG_EXPR
7186
    xmlGenericError(xmlGenericErrorContext,
7187
      "Equal: undefined\n");
7188
#endif
7189
0
    break;
7190
0
      case XPATH_NODESET:
7191
0
      case XPATH_XSLT_TREE:
7192
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7193
0
    break;
7194
0
      case XPATH_BOOLEAN:
7195
0
    if ((arg1->nodesetval == NULL) ||
7196
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7197
0
    else
7198
0
        ret = 1;
7199
0
    ret = (ret == arg2->boolval);
7200
0
    break;
7201
0
      case XPATH_NUMBER:
7202
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7203
0
    break;
7204
0
      case XPATH_STRING:
7205
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7206
0
    break;
7207
0
      case XPATH_USERS:
7208
#ifdef LIBXML_XPTR_LOCS_ENABLED
7209
      case XPATH_POINT:
7210
      case XPATH_RANGE:
7211
      case XPATH_LOCATIONSET:
7212
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7213
0
    TODO
7214
0
    break;
7215
0
  }
7216
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7217
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7218
0
  return(ret);
7219
0
    }
7220
7221
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7222
0
}
7223
7224
/**
7225
 * xmlXPathNotEqualValues:
7226
 * @ctxt:  the XPath Parser context
7227
 *
7228
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7229
 *
7230
 * Returns 0 or 1 depending on the results of the test.
7231
 */
7232
int
7233
0
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7234
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
7235
0
    int ret = 0;
7236
7237
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7238
0
    arg2 = valuePop(ctxt);
7239
0
    arg1 = valuePop(ctxt);
7240
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7241
0
  if (arg1 != NULL)
7242
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7243
0
  else
7244
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7245
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7246
0
    }
7247
7248
0
    if (arg1 == arg2) {
7249
#ifdef DEBUG_EXPR
7250
        xmlGenericError(xmlGenericErrorContext,
7251
    "NotEqual: by pointer\n");
7252
#endif
7253
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7254
0
        return(0);
7255
0
    }
7256
7257
    /*
7258
     *If either argument is a nodeset, it's a 'special case'
7259
     */
7260
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7261
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7262
  /*
7263
   *Hack it to assure arg1 is the nodeset
7264
   */
7265
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7266
0
    argtmp = arg2;
7267
0
    arg2 = arg1;
7268
0
    arg1 = argtmp;
7269
0
  }
7270
0
  switch (arg2->type) {
7271
0
      case XPATH_UNDEFINED:
7272
#ifdef DEBUG_EXPR
7273
    xmlGenericError(xmlGenericErrorContext,
7274
      "NotEqual: undefined\n");
7275
#endif
7276
0
    break;
7277
0
      case XPATH_NODESET:
7278
0
      case XPATH_XSLT_TREE:
7279
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7280
0
    break;
7281
0
      case XPATH_BOOLEAN:
7282
0
    if ((arg1->nodesetval == NULL) ||
7283
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7284
0
    else
7285
0
        ret = 1;
7286
0
    ret = (ret != arg2->boolval);
7287
0
    break;
7288
0
      case XPATH_NUMBER:
7289
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7290
0
    break;
7291
0
      case XPATH_STRING:
7292
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7293
0
    break;
7294
0
      case XPATH_USERS:
7295
#ifdef LIBXML_XPTR_LOCS_ENABLED
7296
      case XPATH_POINT:
7297
      case XPATH_RANGE:
7298
      case XPATH_LOCATIONSET:
7299
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7300
0
    TODO
7301
0
    break;
7302
0
  }
7303
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7304
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7305
0
  return(ret);
7306
0
    }
7307
7308
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7309
0
}
7310
7311
/**
7312
 * xmlXPathCompareValues:
7313
 * @ctxt:  the XPath Parser context
7314
 * @inf:  less than (1) or greater than (0)
7315
 * @strict:  is the comparison strict
7316
 *
7317
 * Implement the compare operation on XPath objects:
7318
 *     @arg1 < @arg2    (1, 1, ...
7319
 *     @arg1 <= @arg2   (1, 0, ...
7320
 *     @arg1 > @arg2    (0, 1, ...
7321
 *     @arg1 >= @arg2   (0, 0, ...
7322
 *
7323
 * When neither object to be compared is a node-set and the operator is
7324
 * <=, <, >=, >, then the objects are compared by converted both objects
7325
 * to numbers and comparing the numbers according to IEEE 754. The <
7326
 * comparison will be true if and only if the first number is less than the
7327
 * second number. The <= comparison will be true if and only if the first
7328
 * number is less than or equal to the second number. The > comparison
7329
 * will be true if and only if the first number is greater than the second
7330
 * number. The >= comparison will be true if and only if the first number
7331
 * is greater than or equal to the second number.
7332
 *
7333
 * Returns 1 if the comparison succeeded, 0 if it failed
7334
 */
7335
int
7336
0
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7337
0
    int ret = 0, arg1i = 0, arg2i = 0;
7338
0
    xmlXPathObjectPtr arg1, arg2;
7339
7340
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7341
0
    arg2 = valuePop(ctxt);
7342
0
    arg1 = valuePop(ctxt);
7343
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7344
0
  if (arg1 != NULL)
7345
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7346
0
  else
7347
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7348
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7349
0
    }
7350
7351
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7352
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7353
  /*
7354
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7355
   * are not freed from within this routine; they will be freed from the
7356
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7357
   */
7358
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7359
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7360
0
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7361
0
  } else {
7362
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7363
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7364
0
                                arg1, arg2);
7365
0
      } else {
7366
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7367
0
                                arg2, arg1);
7368
0
      }
7369
0
  }
7370
0
  return(ret);
7371
0
    }
7372
7373
0
    if (arg1->type != XPATH_NUMBER) {
7374
0
  valuePush(ctxt, arg1);
7375
0
  xmlXPathNumberFunction(ctxt, 1);
7376
0
  arg1 = valuePop(ctxt);
7377
0
    }
7378
0
    if (arg2->type != XPATH_NUMBER) {
7379
0
  valuePush(ctxt, arg2);
7380
0
  xmlXPathNumberFunction(ctxt, 1);
7381
0
  arg2 = valuePop(ctxt);
7382
0
    }
7383
0
    if (ctxt->error)
7384
0
        goto error;
7385
    /*
7386
     * Add tests for infinity and nan
7387
     * => feedback on 3.4 for Inf and NaN
7388
     */
7389
    /* Hand check NaN and Infinity comparisons */
7390
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7391
0
  ret=0;
7392
0
    } else {
7393
0
  arg1i=xmlXPathIsInf(arg1->floatval);
7394
0
  arg2i=xmlXPathIsInf(arg2->floatval);
7395
0
  if (inf && strict) {
7396
0
      if ((arg1i == -1 && arg2i != -1) ||
7397
0
    (arg2i == 1 && arg1i != 1)) {
7398
0
    ret = 1;
7399
0
      } else if (arg1i == 0 && arg2i == 0) {
7400
0
    ret = (arg1->floatval < arg2->floatval);
7401
0
      } else {
7402
0
    ret = 0;
7403
0
      }
7404
0
  }
7405
0
  else if (inf && !strict) {
7406
0
      if (arg1i == -1 || arg2i == 1) {
7407
0
    ret = 1;
7408
0
      } else if (arg1i == 0 && arg2i == 0) {
7409
0
    ret = (arg1->floatval <= arg2->floatval);
7410
0
      } else {
7411
0
    ret = 0;
7412
0
      }
7413
0
  }
7414
0
  else if (!inf && strict) {
7415
0
      if ((arg1i == 1 && arg2i != 1) ||
7416
0
    (arg2i == -1 && arg1i != -1)) {
7417
0
    ret = 1;
7418
0
      } else if (arg1i == 0 && arg2i == 0) {
7419
0
    ret = (arg1->floatval > arg2->floatval);
7420
0
      } else {
7421
0
    ret = 0;
7422
0
      }
7423
0
  }
7424
0
  else if (!inf && !strict) {
7425
0
      if (arg1i == 1 || arg2i == -1) {
7426
0
    ret = 1;
7427
0
      } else if (arg1i == 0 && arg2i == 0) {
7428
0
    ret = (arg1->floatval >= arg2->floatval);
7429
0
      } else {
7430
0
    ret = 0;
7431
0
      }
7432
0
  }
7433
0
    }
7434
0
error:
7435
0
    xmlXPathReleaseObject(ctxt->context, arg1);
7436
0
    xmlXPathReleaseObject(ctxt->context, arg2);
7437
0
    return(ret);
7438
0
}
7439
7440
/**
7441
 * xmlXPathValueFlipSign:
7442
 * @ctxt:  the XPath Parser context
7443
 *
7444
 * Implement the unary - operation on an XPath object
7445
 * The numeric operators convert their operands to numbers as if
7446
 * by calling the number function.
7447
 */
7448
void
7449
0
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7450
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7451
0
    CAST_TO_NUMBER;
7452
0
    CHECK_TYPE(XPATH_NUMBER);
7453
0
    ctxt->value->floatval = -ctxt->value->floatval;
7454
0
}
7455
7456
/**
7457
 * xmlXPathAddValues:
7458
 * @ctxt:  the XPath Parser context
7459
 *
7460
 * Implement the add operation on XPath objects:
7461
 * The numeric operators convert their operands to numbers as if
7462
 * by calling the number function.
7463
 */
7464
void
7465
0
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7466
0
    xmlXPathObjectPtr arg;
7467
0
    double val;
7468
7469
0
    arg = valuePop(ctxt);
7470
0
    if (arg == NULL)
7471
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7472
0
    val = xmlXPathCastToNumber(arg);
7473
0
    xmlXPathReleaseObject(ctxt->context, arg);
7474
0
    CAST_TO_NUMBER;
7475
0
    CHECK_TYPE(XPATH_NUMBER);
7476
0
    ctxt->value->floatval += val;
7477
0
}
7478
7479
/**
7480
 * xmlXPathSubValues:
7481
 * @ctxt:  the XPath Parser context
7482
 *
7483
 * Implement the subtraction operation on XPath objects:
7484
 * The numeric operators convert their operands to numbers as if
7485
 * by calling the number function.
7486
 */
7487
void
7488
0
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7489
0
    xmlXPathObjectPtr arg;
7490
0
    double val;
7491
7492
0
    arg = valuePop(ctxt);
7493
0
    if (arg == NULL)
7494
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7495
0
    val = xmlXPathCastToNumber(arg);
7496
0
    xmlXPathReleaseObject(ctxt->context, arg);
7497
0
    CAST_TO_NUMBER;
7498
0
    CHECK_TYPE(XPATH_NUMBER);
7499
0
    ctxt->value->floatval -= val;
7500
0
}
7501
7502
/**
7503
 * xmlXPathMultValues:
7504
 * @ctxt:  the XPath Parser context
7505
 *
7506
 * Implement the multiply operation on XPath objects:
7507
 * The numeric operators convert their operands to numbers as if
7508
 * by calling the number function.
7509
 */
7510
void
7511
0
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7512
0
    xmlXPathObjectPtr arg;
7513
0
    double val;
7514
7515
0
    arg = valuePop(ctxt);
7516
0
    if (arg == NULL)
7517
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7518
0
    val = xmlXPathCastToNumber(arg);
7519
0
    xmlXPathReleaseObject(ctxt->context, arg);
7520
0
    CAST_TO_NUMBER;
7521
0
    CHECK_TYPE(XPATH_NUMBER);
7522
0
    ctxt->value->floatval *= val;
7523
0
}
7524
7525
/**
7526
 * xmlXPathDivValues:
7527
 * @ctxt:  the XPath Parser context
7528
 *
7529
 * Implement the div operation on XPath objects @arg1 / @arg2:
7530
 * The numeric operators convert their operands to numbers as if
7531
 * by calling the number function.
7532
 */
7533
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7534
void
7535
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7536
0
    xmlXPathObjectPtr arg;
7537
0
    double val;
7538
7539
0
    arg = valuePop(ctxt);
7540
0
    if (arg == NULL)
7541
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7542
0
    val = xmlXPathCastToNumber(arg);
7543
0
    xmlXPathReleaseObject(ctxt->context, arg);
7544
0
    CAST_TO_NUMBER;
7545
0
    CHECK_TYPE(XPATH_NUMBER);
7546
0
    ctxt->value->floatval /= val;
7547
0
}
7548
7549
/**
7550
 * xmlXPathModValues:
7551
 * @ctxt:  the XPath Parser context
7552
 *
7553
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7554
 * The numeric operators convert their operands to numbers as if
7555
 * by calling the number function.
7556
 */
7557
void
7558
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7559
0
    xmlXPathObjectPtr arg;
7560
0
    double arg1, arg2;
7561
7562
0
    arg = valuePop(ctxt);
7563
0
    if (arg == NULL)
7564
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7565
0
    arg2 = xmlXPathCastToNumber(arg);
7566
0
    xmlXPathReleaseObject(ctxt->context, arg);
7567
0
    CAST_TO_NUMBER;
7568
0
    CHECK_TYPE(XPATH_NUMBER);
7569
0
    arg1 = ctxt->value->floatval;
7570
0
    if (arg2 == 0)
7571
0
  ctxt->value->floatval = xmlXPathNAN;
7572
0
    else {
7573
0
  ctxt->value->floatval = fmod(arg1, arg2);
7574
0
    }
7575
0
}
7576
7577
/************************************************************************
7578
 *                  *
7579
 *    The traversal functions         *
7580
 *                  *
7581
 ************************************************************************/
7582
7583
/*
7584
 * A traversal function enumerates nodes along an axis.
7585
 * Initially it must be called with NULL, and it indicates
7586
 * termination on the axis by returning NULL.
7587
 */
7588
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7589
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7590
7591
/*
7592
 * xmlXPathTraversalFunctionExt:
7593
 * A traversal function enumerates nodes along an axis.
7594
 * Initially it must be called with NULL, and it indicates
7595
 * termination on the axis by returning NULL.
7596
 * The context node of the traversal is specified via @contextNode.
7597
 */
7598
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7599
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7600
7601
/*
7602
 * xmlXPathNodeSetMergeFunction:
7603
 * Used for merging node sets in xmlXPathCollectAndTest().
7604
 */
7605
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7606
        (xmlNodeSetPtr, xmlNodeSetPtr);
7607
7608
7609
/**
7610
 * xmlXPathNextSelf:
7611
 * @ctxt:  the XPath Parser context
7612
 * @cur:  the current node in the traversal
7613
 *
7614
 * Traversal function for the "self" direction
7615
 * The self axis contains just the context node itself
7616
 *
7617
 * Returns the next element following that axis
7618
 */
7619
xmlNodePtr
7620
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7621
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7622
0
    if (cur == NULL)
7623
0
        return(ctxt->context->node);
7624
0
    return(NULL);
7625
0
}
7626
7627
/**
7628
 * xmlXPathNextChild:
7629
 * @ctxt:  the XPath Parser context
7630
 * @cur:  the current node in the traversal
7631
 *
7632
 * Traversal function for the "child" direction
7633
 * The child axis contains the children of the context node in document order.
7634
 *
7635
 * Returns the next element following that axis
7636
 */
7637
xmlNodePtr
7638
0
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7639
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7640
0
    if (cur == NULL) {
7641
0
  if (ctxt->context->node == NULL) return(NULL);
7642
0
  switch (ctxt->context->node->type) {
7643
0
            case XML_ELEMENT_NODE:
7644
0
            case XML_TEXT_NODE:
7645
0
            case XML_CDATA_SECTION_NODE:
7646
0
            case XML_ENTITY_REF_NODE:
7647
0
            case XML_ENTITY_NODE:
7648
0
            case XML_PI_NODE:
7649
0
            case XML_COMMENT_NODE:
7650
0
            case XML_NOTATION_NODE:
7651
0
            case XML_DTD_NODE:
7652
0
    return(ctxt->context->node->children);
7653
0
            case XML_DOCUMENT_NODE:
7654
0
            case XML_DOCUMENT_TYPE_NODE:
7655
0
            case XML_DOCUMENT_FRAG_NODE:
7656
0
            case XML_HTML_DOCUMENT_NODE:
7657
0
    return(((xmlDocPtr) ctxt->context->node)->children);
7658
0
      case XML_ELEMENT_DECL:
7659
0
      case XML_ATTRIBUTE_DECL:
7660
0
      case XML_ENTITY_DECL:
7661
0
            case XML_ATTRIBUTE_NODE:
7662
0
      case XML_NAMESPACE_DECL:
7663
0
      case XML_XINCLUDE_START:
7664
0
      case XML_XINCLUDE_END:
7665
0
    return(NULL);
7666
0
  }
7667
0
  return(NULL);
7668
0
    }
7669
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
7670
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
7671
0
  return(NULL);
7672
0
    return(cur->next);
7673
0
}
7674
7675
/**
7676
 * xmlXPathNextChildElement:
7677
 * @ctxt:  the XPath Parser context
7678
 * @cur:  the current node in the traversal
7679
 *
7680
 * Traversal function for the "child" direction and nodes of type element.
7681
 * The child axis contains the children of the context node in document order.
7682
 *
7683
 * Returns the next element following that axis
7684
 */
7685
static xmlNodePtr
7686
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7687
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7688
0
    if (cur == NULL) {
7689
0
  cur = ctxt->context->node;
7690
0
  if (cur == NULL) return(NULL);
7691
  /*
7692
  * Get the first element child.
7693
  */
7694
0
  switch (cur->type) {
7695
0
            case XML_ELEMENT_NODE:
7696
0
      case XML_DOCUMENT_FRAG_NODE:
7697
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7698
0
            case XML_ENTITY_NODE:
7699
0
    cur = cur->children;
7700
0
    if (cur != NULL) {
7701
0
        if (cur->type == XML_ELEMENT_NODE)
7702
0
      return(cur);
7703
0
        do {
7704
0
      cur = cur->next;
7705
0
        } while ((cur != NULL) &&
7706
0
      (cur->type != XML_ELEMENT_NODE));
7707
0
        return(cur);
7708
0
    }
7709
0
    return(NULL);
7710
0
            case XML_DOCUMENT_NODE:
7711
0
            case XML_HTML_DOCUMENT_NODE:
7712
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7713
0
      default:
7714
0
    return(NULL);
7715
0
  }
7716
0
  return(NULL);
7717
0
    }
7718
    /*
7719
    * Get the next sibling element node.
7720
    */
7721
0
    switch (cur->type) {
7722
0
  case XML_ELEMENT_NODE:
7723
0
  case XML_TEXT_NODE:
7724
0
  case XML_ENTITY_REF_NODE:
7725
0
  case XML_ENTITY_NODE:
7726
0
  case XML_CDATA_SECTION_NODE:
7727
0
  case XML_PI_NODE:
7728
0
  case XML_COMMENT_NODE:
7729
0
  case XML_XINCLUDE_END:
7730
0
      break;
7731
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7732
0
  default:
7733
0
      return(NULL);
7734
0
    }
7735
0
    if (cur->next != NULL) {
7736
0
  if (cur->next->type == XML_ELEMENT_NODE)
7737
0
      return(cur->next);
7738
0
  cur = cur->next;
7739
0
  do {
7740
0
      cur = cur->next;
7741
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7742
0
  return(cur);
7743
0
    }
7744
0
    return(NULL);
7745
0
}
7746
7747
#if 0
7748
/**
7749
 * xmlXPathNextDescendantOrSelfElemParent:
7750
 * @ctxt:  the XPath Parser context
7751
 * @cur:  the current node in the traversal
7752
 *
7753
 * Traversal function for the "descendant-or-self" axis.
7754
 * Additionally it returns only nodes which can be parents of
7755
 * element nodes.
7756
 *
7757
 *
7758
 * Returns the next element following that axis
7759
 */
7760
static xmlNodePtr
7761
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7762
               xmlNodePtr contextNode)
7763
{
7764
    if (cur == NULL) {
7765
  if (contextNode == NULL)
7766
      return(NULL);
7767
  switch (contextNode->type) {
7768
      case XML_ELEMENT_NODE:
7769
      case XML_XINCLUDE_START:
7770
      case XML_DOCUMENT_FRAG_NODE:
7771
      case XML_DOCUMENT_NODE:
7772
      case XML_HTML_DOCUMENT_NODE:
7773
    return(contextNode);
7774
      default:
7775
    return(NULL);
7776
  }
7777
  return(NULL);
7778
    } else {
7779
  xmlNodePtr start = cur;
7780
7781
  while (cur != NULL) {
7782
      switch (cur->type) {
7783
    case XML_ELEMENT_NODE:
7784
    /* TODO: OK to have XInclude here? */
7785
    case XML_XINCLUDE_START:
7786
    case XML_DOCUMENT_FRAG_NODE:
7787
        if (cur != start)
7788
      return(cur);
7789
        if (cur->children != NULL) {
7790
      cur = cur->children;
7791
      continue;
7792
        }
7793
        break;
7794
    /* Not sure if we need those here. */
7795
    case XML_DOCUMENT_NODE:
7796
    case XML_HTML_DOCUMENT_NODE:
7797
        if (cur != start)
7798
      return(cur);
7799
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7800
    default:
7801
        break;
7802
      }
7803
7804
next_sibling:
7805
      if ((cur == NULL) || (cur == contextNode))
7806
    return(NULL);
7807
      if (cur->next != NULL) {
7808
    cur = cur->next;
7809
      } else {
7810
    cur = cur->parent;
7811
    goto next_sibling;
7812
      }
7813
  }
7814
    }
7815
    return(NULL);
7816
}
7817
#endif
7818
7819
/**
7820
 * xmlXPathNextDescendant:
7821
 * @ctxt:  the XPath Parser context
7822
 * @cur:  the current node in the traversal
7823
 *
7824
 * Traversal function for the "descendant" direction
7825
 * the descendant axis contains the descendants of the context node in document
7826
 * order; a descendant is a child or a child of a child and so on.
7827
 *
7828
 * Returns the next element following that axis
7829
 */
7830
xmlNodePtr
7831
0
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7832
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7833
0
    if (cur == NULL) {
7834
0
  if (ctxt->context->node == NULL)
7835
0
      return(NULL);
7836
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7837
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7838
0
      return(NULL);
7839
7840
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7841
0
      return(ctxt->context->doc->children);
7842
0
        return(ctxt->context->node->children);
7843
0
    }
7844
7845
0
    if (cur->type == XML_NAMESPACE_DECL)
7846
0
        return(NULL);
7847
0
    if (cur->children != NULL) {
7848
  /*
7849
   * Do not descend on entities declarations
7850
   */
7851
0
  if (cur->children->type != XML_ENTITY_DECL) {
7852
0
      cur = cur->children;
7853
      /*
7854
       * Skip DTDs
7855
       */
7856
0
      if (cur->type != XML_DTD_NODE)
7857
0
    return(cur);
7858
0
  }
7859
0
    }
7860
7861
0
    if (cur == ctxt->context->node) return(NULL);
7862
7863
0
    while (cur->next != NULL) {
7864
0
  cur = cur->next;
7865
0
  if ((cur->type != XML_ENTITY_DECL) &&
7866
0
      (cur->type != XML_DTD_NODE))
7867
0
      return(cur);
7868
0
    }
7869
7870
0
    do {
7871
0
        cur = cur->parent;
7872
0
  if (cur == NULL) break;
7873
0
  if (cur == ctxt->context->node) return(NULL);
7874
0
  if (cur->next != NULL) {
7875
0
      cur = cur->next;
7876
0
      return(cur);
7877
0
  }
7878
0
    } while (cur != NULL);
7879
0
    return(cur);
7880
0
}
7881
7882
/**
7883
 * xmlXPathNextDescendantOrSelf:
7884
 * @ctxt:  the XPath Parser context
7885
 * @cur:  the current node in the traversal
7886
 *
7887
 * Traversal function for the "descendant-or-self" direction
7888
 * the descendant-or-self axis contains the context node and the descendants
7889
 * of the context node in document order; thus the context node is the first
7890
 * node on the axis, and the first child of the context node is the second node
7891
 * on the axis
7892
 *
7893
 * Returns the next element following that axis
7894
 */
7895
xmlNodePtr
7896
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7897
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7898
0
    if (cur == NULL)
7899
0
        return(ctxt->context->node);
7900
7901
0
    if (ctxt->context->node == NULL)
7902
0
        return(NULL);
7903
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7904
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7905
0
        return(NULL);
7906
7907
0
    return(xmlXPathNextDescendant(ctxt, cur));
7908
0
}
7909
7910
/**
7911
 * xmlXPathNextParent:
7912
 * @ctxt:  the XPath Parser context
7913
 * @cur:  the current node in the traversal
7914
 *
7915
 * Traversal function for the "parent" direction
7916
 * The parent axis contains the parent of the context node, if there is one.
7917
 *
7918
 * Returns the next element following that axis
7919
 */
7920
xmlNodePtr
7921
0
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923
    /*
7924
     * the parent of an attribute or namespace node is the element
7925
     * to which the attribute or namespace node is attached
7926
     * Namespace handling !!!
7927
     */
7928
0
    if (cur == NULL) {
7929
0
  if (ctxt->context->node == NULL) return(NULL);
7930
0
  switch (ctxt->context->node->type) {
7931
0
            case XML_ELEMENT_NODE:
7932
0
            case XML_TEXT_NODE:
7933
0
            case XML_CDATA_SECTION_NODE:
7934
0
            case XML_ENTITY_REF_NODE:
7935
0
            case XML_ENTITY_NODE:
7936
0
            case XML_PI_NODE:
7937
0
            case XML_COMMENT_NODE:
7938
0
            case XML_NOTATION_NODE:
7939
0
            case XML_DTD_NODE:
7940
0
      case XML_ELEMENT_DECL:
7941
0
      case XML_ATTRIBUTE_DECL:
7942
0
      case XML_XINCLUDE_START:
7943
0
      case XML_XINCLUDE_END:
7944
0
      case XML_ENTITY_DECL:
7945
0
    if (ctxt->context->node->parent == NULL)
7946
0
        return((xmlNodePtr) ctxt->context->doc);
7947
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7948
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
7949
0
         (xmlStrEqual(ctxt->context->node->parent->name,
7950
0
         BAD_CAST "fake node libxslt"))))
7951
0
        return(NULL);
7952
0
    return(ctxt->context->node->parent);
7953
0
            case XML_ATTRIBUTE_NODE: {
7954
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7955
7956
0
    return(att->parent);
7957
0
      }
7958
0
            case XML_DOCUMENT_NODE:
7959
0
            case XML_DOCUMENT_TYPE_NODE:
7960
0
            case XML_DOCUMENT_FRAG_NODE:
7961
0
            case XML_HTML_DOCUMENT_NODE:
7962
0
                return(NULL);
7963
0
      case XML_NAMESPACE_DECL: {
7964
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7965
7966
0
    if ((ns->next != NULL) &&
7967
0
        (ns->next->type != XML_NAMESPACE_DECL))
7968
0
        return((xmlNodePtr) ns->next);
7969
0
                return(NULL);
7970
0
      }
7971
0
  }
7972
0
    }
7973
0
    return(NULL);
7974
0
}
7975
7976
/**
7977
 * xmlXPathNextAncestor:
7978
 * @ctxt:  the XPath Parser context
7979
 * @cur:  the current node in the traversal
7980
 *
7981
 * Traversal function for the "ancestor" direction
7982
 * the ancestor axis contains the ancestors of the context node; the ancestors
7983
 * of the context node consist of the parent of context node and the parent's
7984
 * parent and so on; the nodes are ordered in reverse document order; thus the
7985
 * parent is the first node on the axis, and the parent's parent is the second
7986
 * node on the axis
7987
 *
7988
 * Returns the next element following that axis
7989
 */
7990
xmlNodePtr
7991
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7992
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7993
    /*
7994
     * the parent of an attribute or namespace node is the element
7995
     * to which the attribute or namespace node is attached
7996
     * !!!!!!!!!!!!!
7997
     */
7998
0
    if (cur == NULL) {
7999
0
  if (ctxt->context->node == NULL) return(NULL);
8000
0
  switch (ctxt->context->node->type) {
8001
0
            case XML_ELEMENT_NODE:
8002
0
            case XML_TEXT_NODE:
8003
0
            case XML_CDATA_SECTION_NODE:
8004
0
            case XML_ENTITY_REF_NODE:
8005
0
            case XML_ENTITY_NODE:
8006
0
            case XML_PI_NODE:
8007
0
            case XML_COMMENT_NODE:
8008
0
      case XML_DTD_NODE:
8009
0
      case XML_ELEMENT_DECL:
8010
0
      case XML_ATTRIBUTE_DECL:
8011
0
      case XML_ENTITY_DECL:
8012
0
            case XML_NOTATION_NODE:
8013
0
      case XML_XINCLUDE_START:
8014
0
      case XML_XINCLUDE_END:
8015
0
    if (ctxt->context->node->parent == NULL)
8016
0
        return((xmlNodePtr) ctxt->context->doc);
8017
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8018
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
8019
0
         (xmlStrEqual(ctxt->context->node->parent->name,
8020
0
         BAD_CAST "fake node libxslt"))))
8021
0
        return(NULL);
8022
0
    return(ctxt->context->node->parent);
8023
0
            case XML_ATTRIBUTE_NODE: {
8024
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8025
8026
0
    return(tmp->parent);
8027
0
      }
8028
0
            case XML_DOCUMENT_NODE:
8029
0
            case XML_DOCUMENT_TYPE_NODE:
8030
0
            case XML_DOCUMENT_FRAG_NODE:
8031
0
            case XML_HTML_DOCUMENT_NODE:
8032
0
                return(NULL);
8033
0
      case XML_NAMESPACE_DECL: {
8034
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8035
8036
0
    if ((ns->next != NULL) &&
8037
0
        (ns->next->type != XML_NAMESPACE_DECL))
8038
0
        return((xmlNodePtr) ns->next);
8039
    /* Bad, how did that namespace end up here ? */
8040
0
                return(NULL);
8041
0
      }
8042
0
  }
8043
0
  return(NULL);
8044
0
    }
8045
0
    if (cur == ctxt->context->doc->children)
8046
0
  return((xmlNodePtr) ctxt->context->doc);
8047
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8048
0
  return(NULL);
8049
0
    switch (cur->type) {
8050
0
  case XML_ELEMENT_NODE:
8051
0
  case XML_TEXT_NODE:
8052
0
  case XML_CDATA_SECTION_NODE:
8053
0
  case XML_ENTITY_REF_NODE:
8054
0
  case XML_ENTITY_NODE:
8055
0
  case XML_PI_NODE:
8056
0
  case XML_COMMENT_NODE:
8057
0
  case XML_NOTATION_NODE:
8058
0
  case XML_DTD_NODE:
8059
0
        case XML_ELEMENT_DECL:
8060
0
        case XML_ATTRIBUTE_DECL:
8061
0
        case XML_ENTITY_DECL:
8062
0
  case XML_XINCLUDE_START:
8063
0
  case XML_XINCLUDE_END:
8064
0
      if (cur->parent == NULL)
8065
0
    return(NULL);
8066
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8067
0
    ((cur->parent->name[0] == ' ') ||
8068
0
     (xmlStrEqual(cur->parent->name,
8069
0
            BAD_CAST "fake node libxslt"))))
8070
0
    return(NULL);
8071
0
      return(cur->parent);
8072
0
  case XML_ATTRIBUTE_NODE: {
8073
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8074
8075
0
      return(att->parent);
8076
0
  }
8077
0
  case XML_NAMESPACE_DECL: {
8078
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8079
8080
0
      if ((ns->next != NULL) &&
8081
0
          (ns->next->type != XML_NAMESPACE_DECL))
8082
0
          return((xmlNodePtr) ns->next);
8083
      /* Bad, how did that namespace end up here ? */
8084
0
            return(NULL);
8085
0
  }
8086
0
  case XML_DOCUMENT_NODE:
8087
0
  case XML_DOCUMENT_TYPE_NODE:
8088
0
  case XML_DOCUMENT_FRAG_NODE:
8089
0
  case XML_HTML_DOCUMENT_NODE:
8090
0
      return(NULL);
8091
0
    }
8092
0
    return(NULL);
8093
0
}
8094
8095
/**
8096
 * xmlXPathNextAncestorOrSelf:
8097
 * @ctxt:  the XPath Parser context
8098
 * @cur:  the current node in the traversal
8099
 *
8100
 * Traversal function for the "ancestor-or-self" direction
8101
 * he ancestor-or-self axis contains the context node and ancestors of
8102
 * the context node in reverse document order; thus the context node is
8103
 * the first node on the axis, and the context node's parent the second;
8104
 * parent here is defined the same as with the parent axis.
8105
 *
8106
 * Returns the next element following that axis
8107
 */
8108
xmlNodePtr
8109
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8110
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8111
0
    if (cur == NULL)
8112
0
        return(ctxt->context->node);
8113
0
    return(xmlXPathNextAncestor(ctxt, cur));
8114
0
}
8115
8116
/**
8117
 * xmlXPathNextFollowingSibling:
8118
 * @ctxt:  the XPath Parser context
8119
 * @cur:  the current node in the traversal
8120
 *
8121
 * Traversal function for the "following-sibling" direction
8122
 * The following-sibling axis contains the following siblings of the context
8123
 * node in document order.
8124
 *
8125
 * Returns the next element following that axis
8126
 */
8127
xmlNodePtr
8128
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8129
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8130
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8131
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8132
0
  return(NULL);
8133
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8134
0
        return(NULL);
8135
0
    if (cur == NULL)
8136
0
        return(ctxt->context->node->next);
8137
0
    return(cur->next);
8138
0
}
8139
8140
/**
8141
 * xmlXPathNextPrecedingSibling:
8142
 * @ctxt:  the XPath Parser context
8143
 * @cur:  the current node in the traversal
8144
 *
8145
 * Traversal function for the "preceding-sibling" direction
8146
 * The preceding-sibling axis contains the preceding siblings of the context
8147
 * node in reverse document order; the first preceding sibling is first on the
8148
 * axis; the sibling preceding that node is the second on the axis and so on.
8149
 *
8150
 * Returns the next element following that axis
8151
 */
8152
xmlNodePtr
8153
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8154
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8155
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8156
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8157
0
  return(NULL);
8158
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8159
0
        return(NULL);
8160
0
    if (cur == NULL)
8161
0
        return(ctxt->context->node->prev);
8162
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8163
0
  cur = cur->prev;
8164
0
  if (cur == NULL)
8165
0
      return(ctxt->context->node->prev);
8166
0
    }
8167
0
    return(cur->prev);
8168
0
}
8169
8170
/**
8171
 * xmlXPathNextFollowing:
8172
 * @ctxt:  the XPath Parser context
8173
 * @cur:  the current node in the traversal
8174
 *
8175
 * Traversal function for the "following" direction
8176
 * The following axis contains all nodes in the same document as the context
8177
 * node that are after the context node in document order, excluding any
8178
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8179
 * are ordered in document order
8180
 *
8181
 * Returns the next element following that axis
8182
 */
8183
xmlNodePtr
8184
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8185
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8186
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8187
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8188
0
        return(cur->children);
8189
8190
0
    if (cur == NULL) {
8191
0
        cur = ctxt->context->node;
8192
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8193
0
            cur = cur->parent;
8194
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8195
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8196
8197
0
            if ((ns->next == NULL) ||
8198
0
                (ns->next->type == XML_NAMESPACE_DECL))
8199
0
                return (NULL);
8200
0
            cur = (xmlNodePtr) ns->next;
8201
0
        }
8202
0
    }
8203
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8204
0
    if (cur->next != NULL) return(cur->next) ;
8205
0
    do {
8206
0
        cur = cur->parent;
8207
0
        if (cur == NULL) break;
8208
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8209
0
        if (cur->next != NULL) return(cur->next);
8210
0
    } while (cur != NULL);
8211
0
    return(cur);
8212
0
}
8213
8214
/*
8215
 * xmlXPathIsAncestor:
8216
 * @ancestor:  the ancestor node
8217
 * @node:  the current node
8218
 *
8219
 * Check that @ancestor is a @node's ancestor
8220
 *
8221
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8222
 */
8223
static int
8224
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8225
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8226
0
    if (node->type == XML_NAMESPACE_DECL)
8227
0
        return(0);
8228
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8229
0
        return(0);
8230
    /* nodes need to be in the same document */
8231
0
    if (ancestor->doc != node->doc) return(0);
8232
    /* avoid searching if ancestor or node is the root node */
8233
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8234
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8235
0
    while (node->parent != NULL) {
8236
0
        if (node->parent == ancestor)
8237
0
            return(1);
8238
0
  node = node->parent;
8239
0
    }
8240
0
    return(0);
8241
0
}
8242
8243
/**
8244
 * xmlXPathNextPreceding:
8245
 * @ctxt:  the XPath Parser context
8246
 * @cur:  the current node in the traversal
8247
 *
8248
 * Traversal function for the "preceding" direction
8249
 * the preceding axis contains all nodes in the same document as the context
8250
 * node that are before the context node in document order, excluding any
8251
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8252
 * ordered in reverse document order
8253
 *
8254
 * Returns the next element following that axis
8255
 */
8256
xmlNodePtr
8257
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8258
0
{
8259
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8260
0
    if (cur == NULL) {
8261
0
        cur = ctxt->context->node;
8262
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8263
0
            cur = cur->parent;
8264
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8265
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8266
8267
0
            if ((ns->next == NULL) ||
8268
0
                (ns->next->type == XML_NAMESPACE_DECL))
8269
0
                return (NULL);
8270
0
            cur = (xmlNodePtr) ns->next;
8271
0
        }
8272
0
    }
8273
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8274
0
  return (NULL);
8275
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8276
0
  cur = cur->prev;
8277
0
    do {
8278
0
        if (cur->prev != NULL) {
8279
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8280
0
            return (cur);
8281
0
        }
8282
8283
0
        cur = cur->parent;
8284
0
        if (cur == NULL)
8285
0
            return (NULL);
8286
0
        if (cur == ctxt->context->doc->children)
8287
0
            return (NULL);
8288
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8289
0
    return (cur);
8290
0
}
8291
8292
/**
8293
 * xmlXPathNextPrecedingInternal:
8294
 * @ctxt:  the XPath Parser context
8295
 * @cur:  the current node in the traversal
8296
 *
8297
 * Traversal function for the "preceding" direction
8298
 * the preceding axis contains all nodes in the same document as the context
8299
 * node that are before the context node in document order, excluding any
8300
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8301
 * ordered in reverse document order
8302
 * This is a faster implementation but internal only since it requires a
8303
 * state kept in the parser context: ctxt->ancestor.
8304
 *
8305
 * Returns the next element following that axis
8306
 */
8307
static xmlNodePtr
8308
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8309
                              xmlNodePtr cur)
8310
0
{
8311
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8312
0
    if (cur == NULL) {
8313
0
        cur = ctxt->context->node;
8314
0
        if (cur == NULL)
8315
0
            return (NULL);
8316
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8317
0
            cur = cur->parent;
8318
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8319
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8320
8321
0
            if ((ns->next == NULL) ||
8322
0
                (ns->next->type == XML_NAMESPACE_DECL))
8323
0
                return (NULL);
8324
0
            cur = (xmlNodePtr) ns->next;
8325
0
        }
8326
0
        ctxt->ancestor = cur->parent;
8327
0
    }
8328
0
    if (cur->type == XML_NAMESPACE_DECL)
8329
0
        return(NULL);
8330
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8331
0
  cur = cur->prev;
8332
0
    while (cur->prev == NULL) {
8333
0
        cur = cur->parent;
8334
0
        if (cur == NULL)
8335
0
            return (NULL);
8336
0
        if (cur == ctxt->context->doc->children)
8337
0
            return (NULL);
8338
0
        if (cur != ctxt->ancestor)
8339
0
            return (cur);
8340
0
        ctxt->ancestor = cur->parent;
8341
0
    }
8342
0
    cur = cur->prev;
8343
0
    while (cur->last != NULL)
8344
0
        cur = cur->last;
8345
0
    return (cur);
8346
0
}
8347
8348
/**
8349
 * xmlXPathNextNamespace:
8350
 * @ctxt:  the XPath Parser context
8351
 * @cur:  the current attribute in the traversal
8352
 *
8353
 * Traversal function for the "namespace" direction
8354
 * the namespace axis contains the namespace nodes of the context node;
8355
 * the order of nodes on this axis is implementation-defined; the axis will
8356
 * be empty unless the context node is an element
8357
 *
8358
 * We keep the XML namespace node at the end of the list.
8359
 *
8360
 * Returns the next element following that axis
8361
 */
8362
xmlNodePtr
8363
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8364
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8365
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8366
0
    if (cur == NULL) {
8367
0
        if (ctxt->context->tmpNsList != NULL)
8368
0
      xmlFree(ctxt->context->tmpNsList);
8369
0
  ctxt->context->tmpNsList =
8370
0
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8371
0
  ctxt->context->tmpNsNr = 0;
8372
0
  if (ctxt->context->tmpNsList != NULL) {
8373
0
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8374
0
    ctxt->context->tmpNsNr++;
8375
0
      }
8376
0
  }
8377
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
8378
0
    }
8379
0
    if (ctxt->context->tmpNsNr > 0) {
8380
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8381
0
    } else {
8382
0
  if (ctxt->context->tmpNsList != NULL)
8383
0
      xmlFree(ctxt->context->tmpNsList);
8384
0
  ctxt->context->tmpNsList = NULL;
8385
0
  return(NULL);
8386
0
    }
8387
0
}
8388
8389
/**
8390
 * xmlXPathNextAttribute:
8391
 * @ctxt:  the XPath Parser context
8392
 * @cur:  the current attribute in the traversal
8393
 *
8394
 * Traversal function for the "attribute" direction
8395
 * TODO: support DTD inherited default attributes
8396
 *
8397
 * Returns the next element following that axis
8398
 */
8399
xmlNodePtr
8400
0
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8401
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8402
0
    if (ctxt->context->node == NULL)
8403
0
  return(NULL);
8404
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8405
0
  return(NULL);
8406
0
    if (cur == NULL) {
8407
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8408
0
      return(NULL);
8409
0
        return((xmlNodePtr)ctxt->context->node->properties);
8410
0
    }
8411
0
    return((xmlNodePtr)cur->next);
8412
0
}
8413
8414
/************************************************************************
8415
 *                  *
8416
 *    NodeTest Functions          *
8417
 *                  *
8418
 ************************************************************************/
8419
8420
#define IS_FUNCTION     200
8421
8422
8423
/************************************************************************
8424
 *                  *
8425
 *    Implicit tree core function library     *
8426
 *                  *
8427
 ************************************************************************/
8428
8429
/**
8430
 * xmlXPathRoot:
8431
 * @ctxt:  the XPath Parser context
8432
 *
8433
 * Initialize the context to the root of the document
8434
 */
8435
void
8436
0
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8437
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
8438
0
  return;
8439
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8440
0
  (xmlNodePtr) ctxt->context->doc));
8441
0
}
8442
8443
/************************************************************************
8444
 *                  *
8445
 *    The explicit core function library      *
8446
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8447
 *                  *
8448
 ************************************************************************/
8449
8450
8451
/**
8452
 * xmlXPathLastFunction:
8453
 * @ctxt:  the XPath Parser context
8454
 * @nargs:  the number of arguments
8455
 *
8456
 * Implement the last() XPath function
8457
 *    number last()
8458
 * The last function returns the number of nodes in the context node list.
8459
 */
8460
void
8461
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8462
0
    CHECK_ARITY(0);
8463
0
    if (ctxt->context->contextSize >= 0) {
8464
0
  valuePush(ctxt,
8465
0
      xmlXPathCacheNewFloat(ctxt->context,
8466
0
    (double) ctxt->context->contextSize));
8467
#ifdef DEBUG_EXPR
8468
  xmlGenericError(xmlGenericErrorContext,
8469
    "last() : %d\n", ctxt->context->contextSize);
8470
#endif
8471
0
    } else {
8472
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8473
0
    }
8474
0
}
8475
8476
/**
8477
 * xmlXPathPositionFunction:
8478
 * @ctxt:  the XPath Parser context
8479
 * @nargs:  the number of arguments
8480
 *
8481
 * Implement the position() XPath function
8482
 *    number position()
8483
 * The position function returns the position of the context node in the
8484
 * context node list. The first position is 1, and so the last position
8485
 * will be equal to last().
8486
 */
8487
void
8488
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8489
0
    CHECK_ARITY(0);
8490
0
    if (ctxt->context->proximityPosition >= 0) {
8491
0
  valuePush(ctxt,
8492
0
        xmlXPathCacheNewFloat(ctxt->context,
8493
0
    (double) ctxt->context->proximityPosition));
8494
#ifdef DEBUG_EXPR
8495
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8496
    ctxt->context->proximityPosition);
8497
#endif
8498
0
    } else {
8499
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8500
0
    }
8501
0
}
8502
8503
/**
8504
 * xmlXPathCountFunction:
8505
 * @ctxt:  the XPath Parser context
8506
 * @nargs:  the number of arguments
8507
 *
8508
 * Implement the count() XPath function
8509
 *    number count(node-set)
8510
 */
8511
void
8512
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8513
0
    xmlXPathObjectPtr cur;
8514
8515
0
    CHECK_ARITY(1);
8516
0
    if ((ctxt->value == NULL) ||
8517
0
  ((ctxt->value->type != XPATH_NODESET) &&
8518
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8519
0
  XP_ERROR(XPATH_INVALID_TYPE);
8520
0
    cur = valuePop(ctxt);
8521
8522
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
8523
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8524
0
    else
8525
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8526
0
      (double) cur->nodesetval->nodeNr));
8527
0
    xmlXPathReleaseObject(ctxt->context, cur);
8528
0
}
8529
8530
/**
8531
 * xmlXPathGetElementsByIds:
8532
 * @doc:  the document
8533
 * @ids:  a whitespace separated list of IDs
8534
 *
8535
 * Selects elements by their unique ID.
8536
 *
8537
 * Returns a node-set of selected elements.
8538
 */
8539
static xmlNodeSetPtr
8540
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8541
0
    xmlNodeSetPtr ret;
8542
0
    const xmlChar *cur = ids;
8543
0
    xmlChar *ID;
8544
0
    xmlAttrPtr attr;
8545
0
    xmlNodePtr elem = NULL;
8546
8547
0
    if (ids == NULL) return(NULL);
8548
8549
0
    ret = xmlXPathNodeSetCreate(NULL);
8550
0
    if (ret == NULL)
8551
0
        return(ret);
8552
8553
0
    while (IS_BLANK_CH(*cur)) cur++;
8554
0
    while (*cur != 0) {
8555
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8556
0
      cur++;
8557
8558
0
        ID = xmlStrndup(ids, cur - ids);
8559
0
  if (ID != NULL) {
8560
      /*
8561
       * We used to check the fact that the value passed
8562
       * was an NCName, but this generated much troubles for
8563
       * me and Aleksey Sanin, people blatantly violated that
8564
       * constraint, like Visa3D spec.
8565
       * if (xmlValidateNCName(ID, 1) == 0)
8566
       */
8567
0
      attr = xmlGetID(doc, ID);
8568
0
      if (attr != NULL) {
8569
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8570
0
        elem = attr->parent;
8571
0
    else if (attr->type == XML_ELEMENT_NODE)
8572
0
        elem = (xmlNodePtr) attr;
8573
0
    else
8574
0
        elem = NULL;
8575
                /* TODO: Check memory error. */
8576
0
    if (elem != NULL)
8577
0
        xmlXPathNodeSetAdd(ret, elem);
8578
0
      }
8579
0
      xmlFree(ID);
8580
0
  }
8581
8582
0
  while (IS_BLANK_CH(*cur)) cur++;
8583
0
  ids = cur;
8584
0
    }
8585
0
    return(ret);
8586
0
}
8587
8588
/**
8589
 * xmlXPathIdFunction:
8590
 * @ctxt:  the XPath Parser context
8591
 * @nargs:  the number of arguments
8592
 *
8593
 * Implement the id() XPath function
8594
 *    node-set id(object)
8595
 * The id function selects elements by their unique ID
8596
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8597
 * then the result is the union of the result of applying id to the
8598
 * string value of each of the nodes in the argument node-set. When the
8599
 * argument to id is of any other type, the argument is converted to a
8600
 * string as if by a call to the string function; the string is split
8601
 * into a whitespace-separated list of tokens (whitespace is any sequence
8602
 * of characters matching the production S); the result is a node-set
8603
 * containing the elements in the same document as the context node that
8604
 * have a unique ID equal to any of the tokens in the list.
8605
 */
8606
void
8607
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8608
0
    xmlChar *tokens;
8609
0
    xmlNodeSetPtr ret;
8610
0
    xmlXPathObjectPtr obj;
8611
8612
0
    CHECK_ARITY(1);
8613
0
    obj = valuePop(ctxt);
8614
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8615
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8616
0
  xmlNodeSetPtr ns;
8617
0
  int i;
8618
8619
        /* TODO: Check memory error. */
8620
0
  ret = xmlXPathNodeSetCreate(NULL);
8621
8622
0
  if (obj->nodesetval != NULL) {
8623
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8624
0
    tokens =
8625
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8626
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8627
                /* TODO: Check memory error. */
8628
0
    ret = xmlXPathNodeSetMerge(ret, ns);
8629
0
    xmlXPathFreeNodeSet(ns);
8630
0
    if (tokens != NULL)
8631
0
        xmlFree(tokens);
8632
0
      }
8633
0
  }
8634
0
  xmlXPathReleaseObject(ctxt->context, obj);
8635
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8636
0
  return;
8637
0
    }
8638
0
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8639
0
    if (obj == NULL) return;
8640
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8641
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8642
0
    xmlXPathReleaseObject(ctxt->context, obj);
8643
0
    return;
8644
0
}
8645
8646
/**
8647
 * xmlXPathLocalNameFunction:
8648
 * @ctxt:  the XPath Parser context
8649
 * @nargs:  the number of arguments
8650
 *
8651
 * Implement the local-name() XPath function
8652
 *    string local-name(node-set?)
8653
 * The local-name function returns a string containing the local part
8654
 * of the name of the node in the argument node-set that is first in
8655
 * document order. If the node-set is empty or the first node has no
8656
 * name, an empty string is returned. If the argument is omitted it
8657
 * defaults to the context node.
8658
 */
8659
void
8660
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8661
0
    xmlXPathObjectPtr cur;
8662
8663
0
    if (ctxt == NULL) return;
8664
8665
0
    if (nargs == 0) {
8666
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8667
0
      ctxt->context->node));
8668
0
  nargs = 1;
8669
0
    }
8670
8671
0
    CHECK_ARITY(1);
8672
0
    if ((ctxt->value == NULL) ||
8673
0
  ((ctxt->value->type != XPATH_NODESET) &&
8674
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8675
0
  XP_ERROR(XPATH_INVALID_TYPE);
8676
0
    cur = valuePop(ctxt);
8677
8678
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8679
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8680
0
    } else {
8681
0
  int i = 0; /* Should be first in document order !!!!! */
8682
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8683
0
  case XML_ELEMENT_NODE:
8684
0
  case XML_ATTRIBUTE_NODE:
8685
0
  case XML_PI_NODE:
8686
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8687
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8688
0
      else
8689
0
    valuePush(ctxt,
8690
0
          xmlXPathCacheNewString(ctxt->context,
8691
0
      cur->nodesetval->nodeTab[i]->name));
8692
0
      break;
8693
0
  case XML_NAMESPACE_DECL:
8694
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8695
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8696
0
      break;
8697
0
  default:
8698
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8699
0
  }
8700
0
    }
8701
0
    xmlXPathReleaseObject(ctxt->context, cur);
8702
0
}
8703
8704
/**
8705
 * xmlXPathNamespaceURIFunction:
8706
 * @ctxt:  the XPath Parser context
8707
 * @nargs:  the number of arguments
8708
 *
8709
 * Implement the namespace-uri() XPath function
8710
 *    string namespace-uri(node-set?)
8711
 * The namespace-uri function returns a string containing the
8712
 * namespace URI of the expanded name of the node in the argument
8713
 * node-set that is first in document order. If the node-set is empty,
8714
 * the first node has no name, or the expanded name has no namespace
8715
 * URI, an empty string is returned. If the argument is omitted it
8716
 * defaults to the context node.
8717
 */
8718
void
8719
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8720
0
    xmlXPathObjectPtr cur;
8721
8722
0
    if (ctxt == NULL) return;
8723
8724
0
    if (nargs == 0) {
8725
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8726
0
      ctxt->context->node));
8727
0
  nargs = 1;
8728
0
    }
8729
0
    CHECK_ARITY(1);
8730
0
    if ((ctxt->value == NULL) ||
8731
0
  ((ctxt->value->type != XPATH_NODESET) &&
8732
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8733
0
  XP_ERROR(XPATH_INVALID_TYPE);
8734
0
    cur = valuePop(ctxt);
8735
8736
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8737
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8738
0
    } else {
8739
0
  int i = 0; /* Should be first in document order !!!!! */
8740
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8741
0
  case XML_ELEMENT_NODE:
8742
0
  case XML_ATTRIBUTE_NODE:
8743
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8744
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8745
0
      else
8746
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8747
0
        cur->nodesetval->nodeTab[i]->ns->href));
8748
0
      break;
8749
0
  default:
8750
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8751
0
  }
8752
0
    }
8753
0
    xmlXPathReleaseObject(ctxt->context, cur);
8754
0
}
8755
8756
/**
8757
 * xmlXPathNameFunction:
8758
 * @ctxt:  the XPath Parser context
8759
 * @nargs:  the number of arguments
8760
 *
8761
 * Implement the name() XPath function
8762
 *    string name(node-set?)
8763
 * The name function returns a string containing a QName representing
8764
 * the name of the node in the argument node-set that is first in document
8765
 * order. The QName must represent the name with respect to the namespace
8766
 * declarations in effect on the node whose name is being represented.
8767
 * Typically, this will be the form in which the name occurred in the XML
8768
 * source. This need not be the case if there are namespace declarations
8769
 * in effect on the node that associate multiple prefixes with the same
8770
 * namespace. However, an implementation may include information about
8771
 * the original prefix in its representation of nodes; in this case, an
8772
 * implementation can ensure that the returned string is always the same
8773
 * as the QName used in the XML source. If the argument it omitted it
8774
 * defaults to the context node.
8775
 * Libxml keep the original prefix so the "real qualified name" used is
8776
 * returned.
8777
 */
8778
static void
8779
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8780
0
{
8781
0
    xmlXPathObjectPtr cur;
8782
8783
0
    if (nargs == 0) {
8784
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8785
0
      ctxt->context->node));
8786
0
        nargs = 1;
8787
0
    }
8788
8789
0
    CHECK_ARITY(1);
8790
0
    if ((ctxt->value == NULL) ||
8791
0
        ((ctxt->value->type != XPATH_NODESET) &&
8792
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
8793
0
        XP_ERROR(XPATH_INVALID_TYPE);
8794
0
    cur = valuePop(ctxt);
8795
8796
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8797
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8798
0
    } else {
8799
0
        int i = 0;              /* Should be first in document order !!!!! */
8800
8801
0
        switch (cur->nodesetval->nodeTab[i]->type) {
8802
0
            case XML_ELEMENT_NODE:
8803
0
            case XML_ATTRIBUTE_NODE:
8804
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8805
0
        valuePush(ctxt,
8806
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8807
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8808
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8809
0
        valuePush(ctxt,
8810
0
            xmlXPathCacheNewString(ctxt->context,
8811
0
          cur->nodesetval->nodeTab[i]->name));
8812
0
    } else {
8813
0
        xmlChar *fullname;
8814
8815
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8816
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8817
0
             NULL, 0);
8818
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8819
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8820
0
        if (fullname == NULL)
8821
0
                        xmlXPathPErrMemory(ctxt, NULL);
8822
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8823
0
      ctxt->context, fullname));
8824
0
                }
8825
0
                break;
8826
0
            default:
8827
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8828
0
        cur->nodesetval->nodeTab[i]));
8829
0
                xmlXPathLocalNameFunction(ctxt, 1);
8830
0
        }
8831
0
    }
8832
0
    xmlXPathReleaseObject(ctxt->context, cur);
8833
0
}
8834
8835
8836
/**
8837
 * xmlXPathStringFunction:
8838
 * @ctxt:  the XPath Parser context
8839
 * @nargs:  the number of arguments
8840
 *
8841
 * Implement the string() XPath function
8842
 *    string string(object?)
8843
 * The string function converts an object to a string as follows:
8844
 *    - A node-set is converted to a string by returning the value of
8845
 *      the node in the node-set that is first in document order.
8846
 *      If the node-set is empty, an empty string is returned.
8847
 *    - A number is converted to a string as follows
8848
 *      + NaN is converted to the string NaN
8849
 *      + positive zero is converted to the string 0
8850
 *      + negative zero is converted to the string 0
8851
 *      + positive infinity is converted to the string Infinity
8852
 *      + negative infinity is converted to the string -Infinity
8853
 *      + if the number is an integer, the number is represented in
8854
 *        decimal form as a Number with no decimal point and no leading
8855
 *        zeros, preceded by a minus sign (-) if the number is negative
8856
 *      + otherwise, the number is represented in decimal form as a
8857
 *        Number including a decimal point with at least one digit
8858
 *        before the decimal point and at least one digit after the
8859
 *        decimal point, preceded by a minus sign (-) if the number
8860
 *        is negative; there must be no leading zeros before the decimal
8861
 *        point apart possibly from the one required digit immediately
8862
 *        before the decimal point; beyond the one required digit
8863
 *        after the decimal point there must be as many, but only as
8864
 *        many, more digits as are needed to uniquely distinguish the
8865
 *        number from all other IEEE 754 numeric values.
8866
 *    - The boolean false value is converted to the string false.
8867
 *      The boolean true value is converted to the string true.
8868
 *
8869
 * If the argument is omitted, it defaults to a node-set with the
8870
 * context node as its only member.
8871
 */
8872
void
8873
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8874
0
    xmlXPathObjectPtr cur;
8875
8876
0
    if (ctxt == NULL) return;
8877
0
    if (nargs == 0) {
8878
0
    valuePush(ctxt,
8879
0
  xmlXPathCacheWrapString(ctxt->context,
8880
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8881
0
  return;
8882
0
    }
8883
8884
0
    CHECK_ARITY(1);
8885
0
    cur = valuePop(ctxt);
8886
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8887
0
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8888
0
}
8889
8890
/**
8891
 * xmlXPathStringLengthFunction:
8892
 * @ctxt:  the XPath Parser context
8893
 * @nargs:  the number of arguments
8894
 *
8895
 * Implement the string-length() XPath function
8896
 *    number string-length(string?)
8897
 * The string-length returns the number of characters in the string
8898
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8899
 * the context node converted to a string, in other words the value
8900
 * of the context node.
8901
 */
8902
void
8903
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8904
0
    xmlXPathObjectPtr cur;
8905
8906
0
    if (nargs == 0) {
8907
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8908
0
      return;
8909
0
  if (ctxt->context->node == NULL) {
8910
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8911
0
  } else {
8912
0
      xmlChar *content;
8913
8914
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8915
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8916
0
    xmlUTF8Strlen(content)));
8917
0
      xmlFree(content);
8918
0
  }
8919
0
  return;
8920
0
    }
8921
0
    CHECK_ARITY(1);
8922
0
    CAST_TO_STRING;
8923
0
    CHECK_TYPE(XPATH_STRING);
8924
0
    cur = valuePop(ctxt);
8925
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8926
0
  xmlUTF8Strlen(cur->stringval)));
8927
0
    xmlXPathReleaseObject(ctxt->context, cur);
8928
0
}
8929
8930
/**
8931
 * xmlXPathConcatFunction:
8932
 * @ctxt:  the XPath Parser context
8933
 * @nargs:  the number of arguments
8934
 *
8935
 * Implement the concat() XPath function
8936
 *    string concat(string, string, string*)
8937
 * The concat function returns the concatenation of its arguments.
8938
 */
8939
void
8940
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8941
0
    xmlXPathObjectPtr cur, newobj;
8942
0
    xmlChar *tmp;
8943
8944
0
    if (ctxt == NULL) return;
8945
0
    if (nargs < 2) {
8946
0
  CHECK_ARITY(2);
8947
0
    }
8948
8949
0
    CAST_TO_STRING;
8950
0
    cur = valuePop(ctxt);
8951
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8952
0
  xmlXPathReleaseObject(ctxt->context, cur);
8953
0
  return;
8954
0
    }
8955
0
    nargs--;
8956
8957
0
    while (nargs > 0) {
8958
0
  CAST_TO_STRING;
8959
0
  newobj = valuePop(ctxt);
8960
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8961
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8962
0
      xmlXPathReleaseObject(ctxt->context, cur);
8963
0
      XP_ERROR(XPATH_INVALID_TYPE);
8964
0
  }
8965
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8966
0
  newobj->stringval = cur->stringval;
8967
0
  cur->stringval = tmp;
8968
0
  xmlXPathReleaseObject(ctxt->context, newobj);
8969
0
  nargs--;
8970
0
    }
8971
0
    valuePush(ctxt, cur);
8972
0
}
8973
8974
/**
8975
 * xmlXPathContainsFunction:
8976
 * @ctxt:  the XPath Parser context
8977
 * @nargs:  the number of arguments
8978
 *
8979
 * Implement the contains() XPath function
8980
 *    boolean contains(string, string)
8981
 * The contains function returns true if the first argument string
8982
 * contains the second argument string, and otherwise returns false.
8983
 */
8984
void
8985
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8986
0
    xmlXPathObjectPtr hay, needle;
8987
8988
0
    CHECK_ARITY(2);
8989
0
    CAST_TO_STRING;
8990
0
    CHECK_TYPE(XPATH_STRING);
8991
0
    needle = valuePop(ctxt);
8992
0
    CAST_TO_STRING;
8993
0
    hay = valuePop(ctxt);
8994
8995
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8996
0
  xmlXPathReleaseObject(ctxt->context, hay);
8997
0
  xmlXPathReleaseObject(ctxt->context, needle);
8998
0
  XP_ERROR(XPATH_INVALID_TYPE);
8999
0
    }
9000
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9001
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9002
0
    else
9003
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9004
0
    xmlXPathReleaseObject(ctxt->context, hay);
9005
0
    xmlXPathReleaseObject(ctxt->context, needle);
9006
0
}
9007
9008
/**
9009
 * xmlXPathStartsWithFunction:
9010
 * @ctxt:  the XPath Parser context
9011
 * @nargs:  the number of arguments
9012
 *
9013
 * Implement the starts-with() XPath function
9014
 *    boolean starts-with(string, string)
9015
 * The starts-with function returns true if the first argument string
9016
 * starts with the second argument string, and otherwise returns false.
9017
 */
9018
void
9019
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9020
0
    xmlXPathObjectPtr hay, needle;
9021
0
    int n;
9022
9023
0
    CHECK_ARITY(2);
9024
0
    CAST_TO_STRING;
9025
0
    CHECK_TYPE(XPATH_STRING);
9026
0
    needle = valuePop(ctxt);
9027
0
    CAST_TO_STRING;
9028
0
    hay = valuePop(ctxt);
9029
9030
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9031
0
  xmlXPathReleaseObject(ctxt->context, hay);
9032
0
  xmlXPathReleaseObject(ctxt->context, needle);
9033
0
  XP_ERROR(XPATH_INVALID_TYPE);
9034
0
    }
9035
0
    n = xmlStrlen(needle->stringval);
9036
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9037
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9038
0
    else
9039
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9040
0
    xmlXPathReleaseObject(ctxt->context, hay);
9041
0
    xmlXPathReleaseObject(ctxt->context, needle);
9042
0
}
9043
9044
/**
9045
 * xmlXPathSubstringFunction:
9046
 * @ctxt:  the XPath Parser context
9047
 * @nargs:  the number of arguments
9048
 *
9049
 * Implement the substring() XPath function
9050
 *    string substring(string, number, number?)
9051
 * The substring function returns the substring of the first argument
9052
 * starting at the position specified in the second argument with
9053
 * length specified in the third argument. For example,
9054
 * substring("12345",2,3) returns "234". If the third argument is not
9055
 * specified, it returns the substring starting at the position specified
9056
 * in the second argument and continuing to the end of the string. For
9057
 * example, substring("12345",2) returns "2345".  More precisely, each
9058
 * character in the string (see [3.6 Strings]) is considered to have a
9059
 * numeric position: the position of the first character is 1, the position
9060
 * of the second character is 2 and so on. The returned substring contains
9061
 * those characters for which the position of the character is greater than
9062
 * or equal to the second argument and, if the third argument is specified,
9063
 * less than the sum of the second and third arguments; the comparisons
9064
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9065
 *  - substring("12345", 1.5, 2.6) returns "234"
9066
 *  - substring("12345", 0, 3) returns "12"
9067
 *  - substring("12345", 0 div 0, 3) returns ""
9068
 *  - substring("12345", 1, 0 div 0) returns ""
9069
 *  - substring("12345", -42, 1 div 0) returns "12345"
9070
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9071
 */
9072
void
9073
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9074
0
    xmlXPathObjectPtr str, start, len;
9075
0
    double le=0, in;
9076
0
    int i = 1, j = INT_MAX;
9077
9078
0
    if (nargs < 2) {
9079
0
  CHECK_ARITY(2);
9080
0
    }
9081
0
    if (nargs > 3) {
9082
0
  CHECK_ARITY(3);
9083
0
    }
9084
    /*
9085
     * take care of possible last (position) argument
9086
    */
9087
0
    if (nargs == 3) {
9088
0
  CAST_TO_NUMBER;
9089
0
  CHECK_TYPE(XPATH_NUMBER);
9090
0
  len = valuePop(ctxt);
9091
0
  le = len->floatval;
9092
0
  xmlXPathReleaseObject(ctxt->context, len);
9093
0
    }
9094
9095
0
    CAST_TO_NUMBER;
9096
0
    CHECK_TYPE(XPATH_NUMBER);
9097
0
    start = valuePop(ctxt);
9098
0
    in = start->floatval;
9099
0
    xmlXPathReleaseObject(ctxt->context, start);
9100
0
    CAST_TO_STRING;
9101
0
    CHECK_TYPE(XPATH_STRING);
9102
0
    str = valuePop(ctxt);
9103
9104
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9105
0
        i = INT_MAX;
9106
0
    } else if (in >= 1.0) {
9107
0
        i = (int)in;
9108
0
        if (in - floor(in) >= 0.5)
9109
0
            i += 1;
9110
0
    }
9111
9112
0
    if (nargs == 3) {
9113
0
        double rin, rle, end;
9114
9115
0
        rin = floor(in);
9116
0
        if (in - rin >= 0.5)
9117
0
            rin += 1.0;
9118
9119
0
        rle = floor(le);
9120
0
        if (le - rle >= 0.5)
9121
0
            rle += 1.0;
9122
9123
0
        end = rin + rle;
9124
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9125
0
            j = 1;
9126
0
        } else if (end < INT_MAX) {
9127
0
            j = (int)end;
9128
0
        }
9129
0
    }
9130
9131
0
    if (i < j) {
9132
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9133
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9134
0
  xmlFree(ret);
9135
0
    } else {
9136
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9137
0
    }
9138
9139
0
    xmlXPathReleaseObject(ctxt->context, str);
9140
0
}
9141
9142
/**
9143
 * xmlXPathSubstringBeforeFunction:
9144
 * @ctxt:  the XPath Parser context
9145
 * @nargs:  the number of arguments
9146
 *
9147
 * Implement the substring-before() XPath function
9148
 *    string substring-before(string, string)
9149
 * The substring-before function returns the substring of the first
9150
 * argument string that precedes the first occurrence of the second
9151
 * argument string in the first argument string, or the empty string
9152
 * if the first argument string does not contain the second argument
9153
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9154
 */
9155
void
9156
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9157
0
  xmlXPathObjectPtr str;
9158
0
  xmlXPathObjectPtr find;
9159
0
  xmlBufPtr target;
9160
0
  const xmlChar *point;
9161
0
  int offset;
9162
9163
0
  CHECK_ARITY(2);
9164
0
  CAST_TO_STRING;
9165
0
  find = valuePop(ctxt);
9166
0
  CAST_TO_STRING;
9167
0
  str = valuePop(ctxt);
9168
9169
0
  target = xmlBufCreate();
9170
0
  if (target) {
9171
0
    point = xmlStrstr(str->stringval, find->stringval);
9172
0
    if (point) {
9173
0
      offset = point - str->stringval;
9174
0
      xmlBufAdd(target, str->stringval, offset);
9175
0
    }
9176
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9177
0
  xmlBufContent(target)));
9178
0
    xmlBufFree(target);
9179
0
  }
9180
0
  xmlXPathReleaseObject(ctxt->context, str);
9181
0
  xmlXPathReleaseObject(ctxt->context, find);
9182
0
}
9183
9184
/**
9185
 * xmlXPathSubstringAfterFunction:
9186
 * @ctxt:  the XPath Parser context
9187
 * @nargs:  the number of arguments
9188
 *
9189
 * Implement the substring-after() XPath function
9190
 *    string substring-after(string, string)
9191
 * The substring-after function returns the substring of the first
9192
 * argument string that follows the first occurrence of the second
9193
 * argument string in the first argument string, or the empty stringi
9194
 * if the first argument string does not contain the second argument
9195
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9196
 * and substring-after("1999/04/01","19") returns 99/04/01.
9197
 */
9198
void
9199
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9200
0
  xmlXPathObjectPtr str;
9201
0
  xmlXPathObjectPtr find;
9202
0
  xmlBufPtr target;
9203
0
  const xmlChar *point;
9204
0
  int offset;
9205
9206
0
  CHECK_ARITY(2);
9207
0
  CAST_TO_STRING;
9208
0
  find = valuePop(ctxt);
9209
0
  CAST_TO_STRING;
9210
0
  str = valuePop(ctxt);
9211
9212
0
  target = xmlBufCreate();
9213
0
  if (target) {
9214
0
    point = xmlStrstr(str->stringval, find->stringval);
9215
0
    if (point) {
9216
0
      offset = point - str->stringval + xmlStrlen(find->stringval);
9217
0
      xmlBufAdd(target, &str->stringval[offset],
9218
0
       xmlStrlen(str->stringval) - offset);
9219
0
    }
9220
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9221
0
  xmlBufContent(target)));
9222
0
    xmlBufFree(target);
9223
0
  }
9224
0
  xmlXPathReleaseObject(ctxt->context, str);
9225
0
  xmlXPathReleaseObject(ctxt->context, find);
9226
0
}
9227
9228
/**
9229
 * xmlXPathNormalizeFunction:
9230
 * @ctxt:  the XPath Parser context
9231
 * @nargs:  the number of arguments
9232
 *
9233
 * Implement the normalize-space() XPath function
9234
 *    string normalize-space(string?)
9235
 * The normalize-space function returns the argument string with white
9236
 * space normalized by stripping leading and trailing whitespace
9237
 * and replacing sequences of whitespace characters by a single
9238
 * space. Whitespace characters are the same allowed by the S production
9239
 * in XML. If the argument is omitted, it defaults to the context
9240
 * node converted to a string, in other words the value of the context node.
9241
 */
9242
void
9243
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9244
0
    xmlChar *source, *target;
9245
0
    int blank;
9246
9247
0
    if (ctxt == NULL) return;
9248
0
    if (nargs == 0) {
9249
        /* Use current context node */
9250
0
        valuePush(ctxt,
9251
0
            xmlXPathCacheWrapString(ctxt->context,
9252
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9253
0
        nargs = 1;
9254
0
    }
9255
9256
0
    CHECK_ARITY(1);
9257
0
    CAST_TO_STRING;
9258
0
    CHECK_TYPE(XPATH_STRING);
9259
0
    source = ctxt->value->stringval;
9260
0
    if (source == NULL)
9261
0
        return;
9262
0
    target = source;
9263
9264
    /* Skip leading whitespaces */
9265
0
    while (IS_BLANK_CH(*source))
9266
0
        source++;
9267
9268
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9269
0
    blank = 0;
9270
0
    while (*source) {
9271
0
        if (IS_BLANK_CH(*source)) {
9272
0
      blank = 1;
9273
0
        } else {
9274
0
            if (blank) {
9275
0
                *target++ = 0x20;
9276
0
                blank = 0;
9277
0
            }
9278
0
            *target++ = *source;
9279
0
        }
9280
0
        source++;
9281
0
    }
9282
0
    *target = 0;
9283
0
}
9284
9285
/**
9286
 * xmlXPathTranslateFunction:
9287
 * @ctxt:  the XPath Parser context
9288
 * @nargs:  the number of arguments
9289
 *
9290
 * Implement the translate() XPath function
9291
 *    string translate(string, string, string)
9292
 * The translate function returns the first argument string with
9293
 * occurrences of characters in the second argument string replaced
9294
 * by the character at the corresponding position in the third argument
9295
 * string. For example, translate("bar","abc","ABC") returns the string
9296
 * BAr. If there is a character in the second argument string with no
9297
 * character at a corresponding position in the third argument string
9298
 * (because the second argument string is longer than the third argument
9299
 * string), then occurrences of that character in the first argument
9300
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9301
 * returns "AAA". If a character occurs more than once in second
9302
 * argument string, then the first occurrence determines the replacement
9303
 * character. If the third argument string is longer than the second
9304
 * argument string, then excess characters are ignored.
9305
 */
9306
void
9307
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9308
0
    xmlXPathObjectPtr str;
9309
0
    xmlXPathObjectPtr from;
9310
0
    xmlXPathObjectPtr to;
9311
0
    xmlBufPtr target;
9312
0
    int offset, max;
9313
0
    int ch;
9314
0
    const xmlChar *point;
9315
0
    xmlChar *cptr;
9316
9317
0
    CHECK_ARITY(3);
9318
9319
0
    CAST_TO_STRING;
9320
0
    to = valuePop(ctxt);
9321
0
    CAST_TO_STRING;
9322
0
    from = valuePop(ctxt);
9323
0
    CAST_TO_STRING;
9324
0
    str = valuePop(ctxt);
9325
9326
0
    target = xmlBufCreate();
9327
0
    if (target) {
9328
0
  max = xmlUTF8Strlen(to->stringval);
9329
0
  for (cptr = str->stringval; (ch=*cptr); ) {
9330
0
      offset = xmlUTF8Strloc(from->stringval, cptr);
9331
0
      if (offset >= 0) {
9332
0
    if (offset < max) {
9333
0
        point = xmlUTF8Strpos(to->stringval, offset);
9334
0
        if (point)
9335
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9336
0
    }
9337
0
      } else
9338
0
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9339
9340
      /* Step to next character in input */
9341
0
      cptr++;
9342
0
      if ( ch & 0x80 ) {
9343
    /* if not simple ascii, verify proper format */
9344
0
    if ( (ch & 0xc0) != 0xc0 ) {
9345
0
        xmlGenericError(xmlGenericErrorContext,
9346
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9347
                    /* not asserting an XPath error is probably better */
9348
0
        break;
9349
0
    }
9350
    /* then skip over remaining bytes for this char */
9351
0
    while ( (ch <<= 1) & 0x80 )
9352
0
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9353
0
      xmlGenericError(xmlGenericErrorContext,
9354
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9355
                        /* not asserting an XPath error is probably better */
9356
0
      break;
9357
0
        }
9358
0
    if (ch & 0x80) /* must have had error encountered */
9359
0
        break;
9360
0
      }
9361
0
  }
9362
0
    }
9363
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9364
0
  xmlBufContent(target)));
9365
0
    xmlBufFree(target);
9366
0
    xmlXPathReleaseObject(ctxt->context, str);
9367
0
    xmlXPathReleaseObject(ctxt->context, from);
9368
0
    xmlXPathReleaseObject(ctxt->context, to);
9369
0
}
9370
9371
/**
9372
 * xmlXPathBooleanFunction:
9373
 * @ctxt:  the XPath Parser context
9374
 * @nargs:  the number of arguments
9375
 *
9376
 * Implement the boolean() XPath function
9377
 *    boolean boolean(object)
9378
 * The boolean function converts its argument to a boolean as follows:
9379
 *    - a number is true if and only if it is neither positive or
9380
 *      negative zero nor NaN
9381
 *    - a node-set is true if and only if it is non-empty
9382
 *    - a string is true if and only if its length is non-zero
9383
 */
9384
void
9385
0
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9386
0
    xmlXPathObjectPtr cur;
9387
9388
0
    CHECK_ARITY(1);
9389
0
    cur = valuePop(ctxt);
9390
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9391
0
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9392
0
    valuePush(ctxt, cur);
9393
0
}
9394
9395
/**
9396
 * xmlXPathNotFunction:
9397
 * @ctxt:  the XPath Parser context
9398
 * @nargs:  the number of arguments
9399
 *
9400
 * Implement the not() XPath function
9401
 *    boolean not(boolean)
9402
 * The not function returns true if its argument is false,
9403
 * and false otherwise.
9404
 */
9405
void
9406
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9407
0
    CHECK_ARITY(1);
9408
0
    CAST_TO_BOOLEAN;
9409
0
    CHECK_TYPE(XPATH_BOOLEAN);
9410
0
    ctxt->value->boolval = ! ctxt->value->boolval;
9411
0
}
9412
9413
/**
9414
 * xmlXPathTrueFunction:
9415
 * @ctxt:  the XPath Parser context
9416
 * @nargs:  the number of arguments
9417
 *
9418
 * Implement the true() XPath function
9419
 *    boolean true()
9420
 */
9421
void
9422
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9423
0
    CHECK_ARITY(0);
9424
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9425
0
}
9426
9427
/**
9428
 * xmlXPathFalseFunction:
9429
 * @ctxt:  the XPath Parser context
9430
 * @nargs:  the number of arguments
9431
 *
9432
 * Implement the false() XPath function
9433
 *    boolean false()
9434
 */
9435
void
9436
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9437
0
    CHECK_ARITY(0);
9438
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9439
0
}
9440
9441
/**
9442
 * xmlXPathLangFunction:
9443
 * @ctxt:  the XPath Parser context
9444
 * @nargs:  the number of arguments
9445
 *
9446
 * Implement the lang() XPath function
9447
 *    boolean lang(string)
9448
 * The lang function returns true or false depending on whether the
9449
 * language of the context node as specified by xml:lang attributes
9450
 * is the same as or is a sublanguage of the language specified by
9451
 * the argument string. The language of the context node is determined
9452
 * by the value of the xml:lang attribute on the context node, or, if
9453
 * the context node has no xml:lang attribute, by the value of the
9454
 * xml:lang attribute on the nearest ancestor of the context node that
9455
 * has an xml:lang attribute. If there is no such attribute, then lang
9456
 * returns false. If there is such an attribute, then lang returns
9457
 * true if the attribute value is equal to the argument ignoring case,
9458
 * or if there is some suffix starting with - such that the attribute
9459
 * value is equal to the argument ignoring that suffix of the attribute
9460
 * value and ignoring case.
9461
 */
9462
void
9463
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9464
0
    xmlXPathObjectPtr val = NULL;
9465
0
    const xmlChar *theLang = NULL;
9466
0
    const xmlChar *lang;
9467
0
    int ret = 0;
9468
0
    int i;
9469
9470
0
    CHECK_ARITY(1);
9471
0
    CAST_TO_STRING;
9472
0
    CHECK_TYPE(XPATH_STRING);
9473
0
    val = valuePop(ctxt);
9474
0
    lang = val->stringval;
9475
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9476
0
    if ((theLang != NULL) && (lang != NULL)) {
9477
0
        for (i = 0;lang[i] != 0;i++)
9478
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9479
0
          goto not_equal;
9480
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9481
0
      ret = 1;
9482
0
    }
9483
0
not_equal:
9484
0
    if (theLang != NULL)
9485
0
  xmlFree((void *)theLang);
9486
9487
0
    xmlXPathReleaseObject(ctxt->context, val);
9488
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9489
0
}
9490
9491
/**
9492
 * xmlXPathNumberFunction:
9493
 * @ctxt:  the XPath Parser context
9494
 * @nargs:  the number of arguments
9495
 *
9496
 * Implement the number() XPath function
9497
 *    number number(object?)
9498
 */
9499
void
9500
0
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9501
0
    xmlXPathObjectPtr cur;
9502
0
    double res;
9503
9504
0
    if (ctxt == NULL) return;
9505
0
    if (nargs == 0) {
9506
0
  if (ctxt->context->node == NULL) {
9507
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9508
0
  } else {
9509
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9510
9511
0
      res = xmlXPathStringEvalNumber(content);
9512
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9513
0
      xmlFree(content);
9514
0
  }
9515
0
  return;
9516
0
    }
9517
9518
0
    CHECK_ARITY(1);
9519
0
    cur = valuePop(ctxt);
9520
0
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9521
0
}
9522
9523
/**
9524
 * xmlXPathSumFunction:
9525
 * @ctxt:  the XPath Parser context
9526
 * @nargs:  the number of arguments
9527
 *
9528
 * Implement the sum() XPath function
9529
 *    number sum(node-set)
9530
 * The sum function returns the sum of the values of the nodes in
9531
 * the argument node-set.
9532
 */
9533
void
9534
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9535
0
    xmlXPathObjectPtr cur;
9536
0
    int i;
9537
0
    double res = 0.0;
9538
9539
0
    CHECK_ARITY(1);
9540
0
    if ((ctxt->value == NULL) ||
9541
0
  ((ctxt->value->type != XPATH_NODESET) &&
9542
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
9543
0
  XP_ERROR(XPATH_INVALID_TYPE);
9544
0
    cur = valuePop(ctxt);
9545
9546
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9547
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9548
0
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9549
0
  }
9550
0
    }
9551
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9552
0
    xmlXPathReleaseObject(ctxt->context, cur);
9553
0
}
9554
9555
/**
9556
 * xmlXPathFloorFunction:
9557
 * @ctxt:  the XPath Parser context
9558
 * @nargs:  the number of arguments
9559
 *
9560
 * Implement the floor() XPath function
9561
 *    number floor(number)
9562
 * The floor function returns the largest (closest to positive infinity)
9563
 * number that is not greater than the argument and that is an integer.
9564
 */
9565
void
9566
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9567
0
    CHECK_ARITY(1);
9568
0
    CAST_TO_NUMBER;
9569
0
    CHECK_TYPE(XPATH_NUMBER);
9570
9571
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9572
0
}
9573
9574
/**
9575
 * xmlXPathCeilingFunction:
9576
 * @ctxt:  the XPath Parser context
9577
 * @nargs:  the number of arguments
9578
 *
9579
 * Implement the ceiling() XPath function
9580
 *    number ceiling(number)
9581
 * The ceiling function returns the smallest (closest to negative infinity)
9582
 * number that is not less than the argument and that is an integer.
9583
 */
9584
void
9585
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9586
0
    CHECK_ARITY(1);
9587
0
    CAST_TO_NUMBER;
9588
0
    CHECK_TYPE(XPATH_NUMBER);
9589
9590
#ifdef _AIX
9591
    /* Work around buggy ceil() function on AIX */
9592
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9593
#else
9594
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9595
0
#endif
9596
0
}
9597
9598
/**
9599
 * xmlXPathRoundFunction:
9600
 * @ctxt:  the XPath Parser context
9601
 * @nargs:  the number of arguments
9602
 *
9603
 * Implement the round() XPath function
9604
 *    number round(number)
9605
 * The round function returns the number that is closest to the
9606
 * argument and that is an integer. If there are two such numbers,
9607
 * then the one that is closest to positive infinity is returned.
9608
 */
9609
void
9610
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9611
0
    double f;
9612
9613
0
    CHECK_ARITY(1);
9614
0
    CAST_TO_NUMBER;
9615
0
    CHECK_TYPE(XPATH_NUMBER);
9616
9617
0
    f = ctxt->value->floatval;
9618
9619
0
    if ((f >= -0.5) && (f < 0.5)) {
9620
        /* Handles negative zero. */
9621
0
        ctxt->value->floatval *= 0.0;
9622
0
    }
9623
0
    else {
9624
0
        double rounded = floor(f);
9625
0
        if (f - rounded >= 0.5)
9626
0
            rounded += 1.0;
9627
0
        ctxt->value->floatval = rounded;
9628
0
    }
9629
0
}
9630
9631
/************************************************************************
9632
 *                  *
9633
 *      The Parser          *
9634
 *                  *
9635
 ************************************************************************/
9636
9637
/*
9638
 * a few forward declarations since we use a recursive call based
9639
 * implementation.
9640
 */
9641
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9642
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9643
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9644
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9645
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9646
                                    int qualified);
9647
9648
/**
9649
 * xmlXPathCurrentChar:
9650
 * @ctxt:  the XPath parser context
9651
 * @cur:  pointer to the beginning of the char
9652
 * @len:  pointer to the length of the char read
9653
 *
9654
 * The current char value, if using UTF-8 this may actually span multiple
9655
 * bytes in the input buffer.
9656
 *
9657
 * Returns the current char value and its length
9658
 */
9659
9660
static int
9661
0
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9662
0
    unsigned char c;
9663
0
    unsigned int val;
9664
0
    const xmlChar *cur;
9665
9666
0
    if (ctxt == NULL)
9667
0
  return(0);
9668
0
    cur = ctxt->cur;
9669
9670
    /*
9671
     * We are supposed to handle UTF8, check it's valid
9672
     * From rfc2044: encoding of the Unicode values on UTF-8:
9673
     *
9674
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9675
     * 0000 0000-0000 007F   0xxxxxxx
9676
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9677
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9678
     *
9679
     * Check for the 0x110000 limit too
9680
     */
9681
0
    c = *cur;
9682
0
    if (c & 0x80) {
9683
0
  if ((cur[1] & 0xc0) != 0x80)
9684
0
      goto encoding_error;
9685
0
  if ((c & 0xe0) == 0xe0) {
9686
9687
0
      if ((cur[2] & 0xc0) != 0x80)
9688
0
    goto encoding_error;
9689
0
      if ((c & 0xf0) == 0xf0) {
9690
0
    if (((c & 0xf8) != 0xf0) ||
9691
0
        ((cur[3] & 0xc0) != 0x80))
9692
0
        goto encoding_error;
9693
    /* 4-byte code */
9694
0
    *len = 4;
9695
0
    val = (cur[0] & 0x7) << 18;
9696
0
    val |= (cur[1] & 0x3f) << 12;
9697
0
    val |= (cur[2] & 0x3f) << 6;
9698
0
    val |= cur[3] & 0x3f;
9699
0
      } else {
9700
        /* 3-byte code */
9701
0
    *len = 3;
9702
0
    val = (cur[0] & 0xf) << 12;
9703
0
    val |= (cur[1] & 0x3f) << 6;
9704
0
    val |= cur[2] & 0x3f;
9705
0
      }
9706
0
  } else {
9707
    /* 2-byte code */
9708
0
      *len = 2;
9709
0
      val = (cur[0] & 0x1f) << 6;
9710
0
      val |= cur[1] & 0x3f;
9711
0
  }
9712
0
  if (!IS_CHAR(val)) {
9713
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9714
0
  }
9715
0
  return(val);
9716
0
    } else {
9717
  /* 1-byte code */
9718
0
  *len = 1;
9719
0
  return(*cur);
9720
0
    }
9721
0
encoding_error:
9722
    /*
9723
     * If we detect an UTF8 error that probably means that the
9724
     * input encoding didn't get properly advertised in the
9725
     * declaration header. Report the error and switch the encoding
9726
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9727
     * encoding !)
9728
     */
9729
0
    *len = 0;
9730
0
    XP_ERROR0(XPATH_ENCODING_ERROR);
9731
0
}
9732
9733
/**
9734
 * xmlXPathParseNCName:
9735
 * @ctxt:  the XPath Parser context
9736
 *
9737
 * parse an XML namespace non qualified name.
9738
 *
9739
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9740
 *
9741
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9742
 *                       CombiningChar | Extender
9743
 *
9744
 * Returns the namespace name or NULL
9745
 */
9746
9747
xmlChar *
9748
0
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9749
0
    const xmlChar *in;
9750
0
    xmlChar *ret;
9751
0
    int count = 0;
9752
9753
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9754
    /*
9755
     * Accelerator for simple ASCII names
9756
     */
9757
0
    in = ctxt->cur;
9758
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9759
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9760
0
  (*in == '_')) {
9761
0
  in++;
9762
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9763
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9764
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9765
0
         (*in == '_') || (*in == '.') ||
9766
0
         (*in == '-'))
9767
0
      in++;
9768
0
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9769
0
            (*in == '[') || (*in == ']') || (*in == ':') ||
9770
0
            (*in == '@') || (*in == '*')) {
9771
0
      count = in - ctxt->cur;
9772
0
      if (count == 0)
9773
0
    return(NULL);
9774
0
      ret = xmlStrndup(ctxt->cur, count);
9775
0
      ctxt->cur = in;
9776
0
      return(ret);
9777
0
  }
9778
0
    }
9779
0
    return(xmlXPathParseNameComplex(ctxt, 0));
9780
0
}
9781
9782
9783
/**
9784
 * xmlXPathParseQName:
9785
 * @ctxt:  the XPath Parser context
9786
 * @prefix:  a xmlChar **
9787
 *
9788
 * parse an XML qualified name
9789
 *
9790
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9791
 *
9792
 * [NS 6] Prefix ::= NCName
9793
 *
9794
 * [NS 7] LocalPart ::= NCName
9795
 *
9796
 * Returns the function returns the local part, and prefix is updated
9797
 *   to get the Prefix if any.
9798
 */
9799
9800
static xmlChar *
9801
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9802
0
    xmlChar *ret = NULL;
9803
9804
0
    *prefix = NULL;
9805
0
    ret = xmlXPathParseNCName(ctxt);
9806
0
    if (ret && CUR == ':') {
9807
0
        *prefix = ret;
9808
0
  NEXT;
9809
0
  ret = xmlXPathParseNCName(ctxt);
9810
0
    }
9811
0
    return(ret);
9812
0
}
9813
9814
/**
9815
 * xmlXPathParseName:
9816
 * @ctxt:  the XPath Parser context
9817
 *
9818
 * parse an XML name
9819
 *
9820
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9821
 *                  CombiningChar | Extender
9822
 *
9823
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9824
 *
9825
 * Returns the namespace name or NULL
9826
 */
9827
9828
xmlChar *
9829
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9830
0
    const xmlChar *in;
9831
0
    xmlChar *ret;
9832
0
    size_t count = 0;
9833
9834
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9835
    /*
9836
     * Accelerator for simple ASCII names
9837
     */
9838
0
    in = ctxt->cur;
9839
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9840
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9841
0
  (*in == '_') || (*in == ':')) {
9842
0
  in++;
9843
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9844
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9845
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9846
0
         (*in == '_') || (*in == '-') ||
9847
0
         (*in == ':') || (*in == '.'))
9848
0
      in++;
9849
0
  if ((*in > 0) && (*in < 0x80)) {
9850
0
      count = in - ctxt->cur;
9851
0
            if (count > XML_MAX_NAME_LENGTH) {
9852
0
                ctxt->cur = in;
9853
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9854
0
            }
9855
0
      ret = xmlStrndup(ctxt->cur, count);
9856
0
      ctxt->cur = in;
9857
0
      return(ret);
9858
0
  }
9859
0
    }
9860
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9861
0
}
9862
9863
static xmlChar *
9864
0
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9865
0
    xmlChar buf[XML_MAX_NAMELEN + 5];
9866
0
    int len = 0, l;
9867
0
    int c;
9868
9869
    /*
9870
     * Handler for more complex cases
9871
     */
9872
0
    c = CUR_CHAR(l);
9873
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9874
0
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9875
0
        (c == '*') || /* accelerators */
9876
0
  (!IS_LETTER(c) && (c != '_') &&
9877
0
         ((!qualified) || (c != ':')))) {
9878
0
  return(NULL);
9879
0
    }
9880
9881
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9882
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9883
0
            (c == '.') || (c == '-') ||
9884
0
      (c == '_') || ((qualified) && (c == ':')) ||
9885
0
      (IS_COMBINING(c)) ||
9886
0
      (IS_EXTENDER(c)))) {
9887
0
  COPY_BUF(l,buf,len,c);
9888
0
  NEXTL(l);
9889
0
  c = CUR_CHAR(l);
9890
0
  if (len >= XML_MAX_NAMELEN) {
9891
      /*
9892
       * Okay someone managed to make a huge name, so he's ready to pay
9893
       * for the processing speed.
9894
       */
9895
0
      xmlChar *buffer;
9896
0
      int max = len * 2;
9897
9898
0
            if (len > XML_MAX_NAME_LENGTH) {
9899
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9900
0
            }
9901
0
      buffer = (xmlChar *) xmlMallocAtomic(max);
9902
0
      if (buffer == NULL) {
9903
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9904
0
      }
9905
0
      memcpy(buffer, buf, len);
9906
0
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9907
0
       (c == '.') || (c == '-') ||
9908
0
       (c == '_') || ((qualified) && (c == ':')) ||
9909
0
       (IS_COMBINING(c)) ||
9910
0
       (IS_EXTENDER(c))) {
9911
0
    if (len + 10 > max) {
9912
0
                    xmlChar *tmp;
9913
0
                    if (max > XML_MAX_NAME_LENGTH) {
9914
0
                        xmlFree(buffer);
9915
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9916
0
                    }
9917
0
        max *= 2;
9918
0
        tmp = (xmlChar *) xmlRealloc(buffer, max);
9919
0
        if (tmp == NULL) {
9920
0
                        xmlFree(buffer);
9921
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9922
0
        }
9923
0
                    buffer = tmp;
9924
0
    }
9925
0
    COPY_BUF(l,buffer,len,c);
9926
0
    NEXTL(l);
9927
0
    c = CUR_CHAR(l);
9928
0
      }
9929
0
      buffer[len] = 0;
9930
0
      return(buffer);
9931
0
  }
9932
0
    }
9933
0
    if (len == 0)
9934
0
  return(NULL);
9935
0
    return(xmlStrndup(buf, len));
9936
0
}
9937
9938
0
#define MAX_FRAC 20
9939
9940
/**
9941
 * xmlXPathStringEvalNumber:
9942
 * @str:  A string to scan
9943
 *
9944
 *  [30a]  Float  ::= Number ('e' Digits?)?
9945
 *
9946
 *  [30]   Number ::=   Digits ('.' Digits?)?
9947
 *                    | '.' Digits
9948
 *  [31]   Digits ::=   [0-9]+
9949
 *
9950
 * Compile a Number in the string
9951
 * In complement of the Number expression, this function also handles
9952
 * negative values : '-' Number.
9953
 *
9954
 * Returns the double value.
9955
 */
9956
double
9957
0
xmlXPathStringEvalNumber(const xmlChar *str) {
9958
0
    const xmlChar *cur = str;
9959
0
    double ret;
9960
0
    int ok = 0;
9961
0
    int isneg = 0;
9962
0
    int exponent = 0;
9963
0
    int is_exponent_negative = 0;
9964
0
#ifdef __GNUC__
9965
0
    unsigned long tmp = 0;
9966
0
    double temp;
9967
0
#endif
9968
0
    if (cur == NULL) return(0);
9969
0
    while (IS_BLANK_CH(*cur)) cur++;
9970
0
    if (*cur == '-') {
9971
0
  isneg = 1;
9972
0
  cur++;
9973
0
    }
9974
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9975
0
        return(xmlXPathNAN);
9976
0
    }
9977
9978
0
#ifdef __GNUC__
9979
    /*
9980
     * tmp/temp is a workaround against a gcc compiler bug
9981
     * http://veillard.com/gcc.bug
9982
     */
9983
0
    ret = 0;
9984
0
    while ((*cur >= '0') && (*cur <= '9')) {
9985
0
  ret = ret * 10;
9986
0
  tmp = (*cur - '0');
9987
0
  ok = 1;
9988
0
  cur++;
9989
0
  temp = (double) tmp;
9990
0
  ret = ret + temp;
9991
0
    }
9992
#else
9993
    ret = 0;
9994
    while ((*cur >= '0') && (*cur <= '9')) {
9995
  ret = ret * 10 + (*cur - '0');
9996
  ok = 1;
9997
  cur++;
9998
    }
9999
#endif
10000
10001
0
    if (*cur == '.') {
10002
0
  int v, frac = 0, max;
10003
0
  double fraction = 0;
10004
10005
0
        cur++;
10006
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10007
0
      return(xmlXPathNAN);
10008
0
  }
10009
0
        while (*cur == '0') {
10010
0
      frac = frac + 1;
10011
0
      cur++;
10012
0
        }
10013
0
        max = frac + MAX_FRAC;
10014
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10015
0
      v = (*cur - '0');
10016
0
      fraction = fraction * 10 + v;
10017
0
      frac = frac + 1;
10018
0
      cur++;
10019
0
  }
10020
0
  fraction /= pow(10.0, frac);
10021
0
  ret = ret + fraction;
10022
0
  while ((*cur >= '0') && (*cur <= '9'))
10023
0
      cur++;
10024
0
    }
10025
0
    if ((*cur == 'e') || (*cur == 'E')) {
10026
0
      cur++;
10027
0
      if (*cur == '-') {
10028
0
  is_exponent_negative = 1;
10029
0
  cur++;
10030
0
      } else if (*cur == '+') {
10031
0
        cur++;
10032
0
      }
10033
0
      while ((*cur >= '0') && (*cur <= '9')) {
10034
0
        if (exponent < 1000000)
10035
0
    exponent = exponent * 10 + (*cur - '0');
10036
0
  cur++;
10037
0
      }
10038
0
    }
10039
0
    while (IS_BLANK_CH(*cur)) cur++;
10040
0
    if (*cur != 0) return(xmlXPathNAN);
10041
0
    if (isneg) ret = -ret;
10042
0
    if (is_exponent_negative) exponent = -exponent;
10043
0
    ret *= pow(10.0, (double)exponent);
10044
0
    return(ret);
10045
0
}
10046
10047
/**
10048
 * xmlXPathCompNumber:
10049
 * @ctxt:  the XPath Parser context
10050
 *
10051
 *  [30]   Number ::=   Digits ('.' Digits?)?
10052
 *                    | '.' Digits
10053
 *  [31]   Digits ::=   [0-9]+
10054
 *
10055
 * Compile a Number, then push it on the stack
10056
 *
10057
 */
10058
static void
10059
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10060
0
{
10061
0
    double ret = 0.0;
10062
0
    int ok = 0;
10063
0
    int exponent = 0;
10064
0
    int is_exponent_negative = 0;
10065
0
    xmlXPathObjectPtr num;
10066
0
#ifdef __GNUC__
10067
0
    unsigned long tmp = 0;
10068
0
    double temp;
10069
0
#endif
10070
10071
0
    CHECK_ERROR;
10072
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10073
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10074
0
    }
10075
0
#ifdef __GNUC__
10076
    /*
10077
     * tmp/temp is a workaround against a gcc compiler bug
10078
     * http://veillard.com/gcc.bug
10079
     */
10080
0
    ret = 0;
10081
0
    while ((CUR >= '0') && (CUR <= '9')) {
10082
0
  ret = ret * 10;
10083
0
  tmp = (CUR - '0');
10084
0
        ok = 1;
10085
0
        NEXT;
10086
0
  temp = (double) tmp;
10087
0
  ret = ret + temp;
10088
0
    }
10089
#else
10090
    ret = 0;
10091
    while ((CUR >= '0') && (CUR <= '9')) {
10092
  ret = ret * 10 + (CUR - '0');
10093
  ok = 1;
10094
  NEXT;
10095
    }
10096
#endif
10097
0
    if (CUR == '.') {
10098
0
  int v, frac = 0, max;
10099
0
  double fraction = 0;
10100
10101
0
        NEXT;
10102
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10103
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10104
0
        }
10105
0
        while (CUR == '0') {
10106
0
            frac = frac + 1;
10107
0
            NEXT;
10108
0
        }
10109
0
        max = frac + MAX_FRAC;
10110
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10111
0
      v = (CUR - '0');
10112
0
      fraction = fraction * 10 + v;
10113
0
      frac = frac + 1;
10114
0
            NEXT;
10115
0
        }
10116
0
        fraction /= pow(10.0, frac);
10117
0
        ret = ret + fraction;
10118
0
        while ((CUR >= '0') && (CUR <= '9'))
10119
0
            NEXT;
10120
0
    }
10121
0
    if ((CUR == 'e') || (CUR == 'E')) {
10122
0
        NEXT;
10123
0
        if (CUR == '-') {
10124
0
            is_exponent_negative = 1;
10125
0
            NEXT;
10126
0
        } else if (CUR == '+') {
10127
0
      NEXT;
10128
0
  }
10129
0
        while ((CUR >= '0') && (CUR <= '9')) {
10130
0
            if (exponent < 1000000)
10131
0
                exponent = exponent * 10 + (CUR - '0');
10132
0
            NEXT;
10133
0
        }
10134
0
        if (is_exponent_negative)
10135
0
            exponent = -exponent;
10136
0
        ret *= pow(10.0, (double) exponent);
10137
0
    }
10138
0
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10139
0
    if (num == NULL) {
10140
0
  ctxt->error = XPATH_MEMORY_ERROR;
10141
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10142
0
                              NULL) == -1) {
10143
0
        xmlXPathReleaseObject(ctxt->context, num);
10144
0
    }
10145
0
}
10146
10147
/**
10148
 * xmlXPathParseLiteral:
10149
 * @ctxt:  the XPath Parser context
10150
 *
10151
 * Parse a Literal
10152
 *
10153
 *  [29]   Literal ::=   '"' [^"]* '"'
10154
 *                    | "'" [^']* "'"
10155
 *
10156
 * Returns the value found or NULL in case of error
10157
 */
10158
static xmlChar *
10159
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10160
0
    const xmlChar *q;
10161
0
    xmlChar *ret = NULL;
10162
10163
0
    if (CUR == '"') {
10164
0
        NEXT;
10165
0
  q = CUR_PTR;
10166
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10167
0
      NEXT;
10168
0
  if (!IS_CHAR_CH(CUR)) {
10169
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10170
0
  } else {
10171
0
      ret = xmlStrndup(q, CUR_PTR - q);
10172
0
      NEXT;
10173
0
        }
10174
0
    } else if (CUR == '\'') {
10175
0
        NEXT;
10176
0
  q = CUR_PTR;
10177
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10178
0
      NEXT;
10179
0
  if (!IS_CHAR_CH(CUR)) {
10180
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10181
0
  } else {
10182
0
      ret = xmlStrndup(q, CUR_PTR - q);
10183
0
      NEXT;
10184
0
        }
10185
0
    } else {
10186
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10187
0
    }
10188
0
    return(ret);
10189
0
}
10190
10191
/**
10192
 * xmlXPathCompLiteral:
10193
 * @ctxt:  the XPath Parser context
10194
 *
10195
 * Parse a Literal and push it on the stack.
10196
 *
10197
 *  [29]   Literal ::=   '"' [^"]* '"'
10198
 *                    | "'" [^']* "'"
10199
 *
10200
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10201
 */
10202
static void
10203
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10204
0
    const xmlChar *q;
10205
0
    xmlChar *ret = NULL;
10206
0
    xmlXPathObjectPtr lit;
10207
10208
0
    if (CUR == '"') {
10209
0
        NEXT;
10210
0
  q = CUR_PTR;
10211
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10212
0
      NEXT;
10213
0
  if (!IS_CHAR_CH(CUR)) {
10214
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10215
0
  } else {
10216
0
      ret = xmlStrndup(q, CUR_PTR - q);
10217
0
      NEXT;
10218
0
        }
10219
0
    } else if (CUR == '\'') {
10220
0
        NEXT;
10221
0
  q = CUR_PTR;
10222
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10223
0
      NEXT;
10224
0
  if (!IS_CHAR_CH(CUR)) {
10225
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10226
0
  } else {
10227
0
      ret = xmlStrndup(q, CUR_PTR - q);
10228
0
      NEXT;
10229
0
        }
10230
0
    } else {
10231
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10232
0
    }
10233
0
    if (ret == NULL) {
10234
0
        xmlXPathPErrMemory(ctxt, NULL);
10235
0
        return;
10236
0
    }
10237
0
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10238
0
    if (lit == NULL) {
10239
0
  ctxt->error = XPATH_MEMORY_ERROR;
10240
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10241
0
                              NULL) == -1) {
10242
0
        xmlXPathReleaseObject(ctxt->context, lit);
10243
0
    }
10244
0
    xmlFree(ret);
10245
0
}
10246
10247
/**
10248
 * xmlXPathCompVariableReference:
10249
 * @ctxt:  the XPath Parser context
10250
 *
10251
 * Parse a VariableReference, evaluate it and push it on the stack.
10252
 *
10253
 * The variable bindings consist of a mapping from variable names
10254
 * to variable values. The value of a variable is an object, which can be
10255
 * of any of the types that are possible for the value of an expression,
10256
 * and may also be of additional types not specified here.
10257
 *
10258
 * Early evaluation is possible since:
10259
 * The variable bindings [...] used to evaluate a subexpression are
10260
 * always the same as those used to evaluate the containing expression.
10261
 *
10262
 *  [36]   VariableReference ::=   '$' QName
10263
 */
10264
static void
10265
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10266
0
    xmlChar *name;
10267
0
    xmlChar *prefix;
10268
10269
0
    SKIP_BLANKS;
10270
0
    if (CUR != '$') {
10271
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10272
0
    }
10273
0
    NEXT;
10274
0
    name = xmlXPathParseQName(ctxt, &prefix);
10275
0
    if (name == NULL) {
10276
0
        xmlFree(prefix);
10277
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10278
0
    }
10279
0
    ctxt->comp->last = -1;
10280
0
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10281
0
        xmlFree(prefix);
10282
0
        xmlFree(name);
10283
0
    }
10284
0
    SKIP_BLANKS;
10285
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10286
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10287
0
    }
10288
0
}
10289
10290
/**
10291
 * xmlXPathIsNodeType:
10292
 * @name:  a name string
10293
 *
10294
 * Is the name given a NodeType one.
10295
 *
10296
 *  [38]   NodeType ::=   'comment'
10297
 *                    | 'text'
10298
 *                    | 'processing-instruction'
10299
 *                    | 'node'
10300
 *
10301
 * Returns 1 if true 0 otherwise
10302
 */
10303
int
10304
0
xmlXPathIsNodeType(const xmlChar *name) {
10305
0
    if (name == NULL)
10306
0
  return(0);
10307
10308
0
    if (xmlStrEqual(name, BAD_CAST "node"))
10309
0
  return(1);
10310
0
    if (xmlStrEqual(name, BAD_CAST "text"))
10311
0
  return(1);
10312
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
10313
0
  return(1);
10314
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10315
0
  return(1);
10316
0
    return(0);
10317
0
}
10318
10319
/**
10320
 * xmlXPathCompFunctionCall:
10321
 * @ctxt:  the XPath Parser context
10322
 *
10323
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10324
 *  [17]   Argument ::=   Expr
10325
 *
10326
 * Compile a function call, the evaluation of all arguments are
10327
 * pushed on the stack
10328
 */
10329
static void
10330
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10331
0
    xmlChar *name;
10332
0
    xmlChar *prefix;
10333
0
    int nbargs = 0;
10334
0
    int sort = 1;
10335
10336
0
    name = xmlXPathParseQName(ctxt, &prefix);
10337
0
    if (name == NULL) {
10338
0
  xmlFree(prefix);
10339
0
  XP_ERROR(XPATH_EXPR_ERROR);
10340
0
    }
10341
0
    SKIP_BLANKS;
10342
#ifdef DEBUG_EXPR
10343
    if (prefix == NULL)
10344
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10345
      name);
10346
    else
10347
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10348
      prefix, name);
10349
#endif
10350
10351
0
    if (CUR != '(') {
10352
0
  xmlFree(name);
10353
0
  xmlFree(prefix);
10354
0
  XP_ERROR(XPATH_EXPR_ERROR);
10355
0
    }
10356
0
    NEXT;
10357
0
    SKIP_BLANKS;
10358
10359
    /*
10360
    * Optimization for count(): we don't need the node-set to be sorted.
10361
    */
10362
0
    if ((prefix == NULL) && (name[0] == 'c') &&
10363
0
  xmlStrEqual(name, BAD_CAST "count"))
10364
0
    {
10365
0
  sort = 0;
10366
0
    }
10367
0
    ctxt->comp->last = -1;
10368
0
    if (CUR != ')') {
10369
0
  while (CUR != 0) {
10370
0
      int op1 = ctxt->comp->last;
10371
0
      ctxt->comp->last = -1;
10372
0
      xmlXPathCompileExpr(ctxt, sort);
10373
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10374
0
    xmlFree(name);
10375
0
    xmlFree(prefix);
10376
0
    return;
10377
0
      }
10378
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10379
0
      nbargs++;
10380
0
      if (CUR == ')') break;
10381
0
      if (CUR != ',') {
10382
0
    xmlFree(name);
10383
0
    xmlFree(prefix);
10384
0
    XP_ERROR(XPATH_EXPR_ERROR);
10385
0
      }
10386
0
      NEXT;
10387
0
      SKIP_BLANKS;
10388
0
  }
10389
0
    }
10390
0
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10391
0
        xmlFree(prefix);
10392
0
        xmlFree(name);
10393
0
    }
10394
0
    NEXT;
10395
0
    SKIP_BLANKS;
10396
0
}
10397
10398
/**
10399
 * xmlXPathCompPrimaryExpr:
10400
 * @ctxt:  the XPath Parser context
10401
 *
10402
 *  [15]   PrimaryExpr ::=   VariableReference
10403
 *                | '(' Expr ')'
10404
 *                | Literal
10405
 *                | Number
10406
 *                | FunctionCall
10407
 *
10408
 * Compile a primary expression.
10409
 */
10410
static void
10411
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10412
0
    SKIP_BLANKS;
10413
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10414
0
    else if (CUR == '(') {
10415
0
  NEXT;
10416
0
  SKIP_BLANKS;
10417
0
  xmlXPathCompileExpr(ctxt, 1);
10418
0
  CHECK_ERROR;
10419
0
  if (CUR != ')') {
10420
0
      XP_ERROR(XPATH_EXPR_ERROR);
10421
0
  }
10422
0
  NEXT;
10423
0
  SKIP_BLANKS;
10424
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10425
0
  xmlXPathCompNumber(ctxt);
10426
0
    } else if ((CUR == '\'') || (CUR == '"')) {
10427
0
  xmlXPathCompLiteral(ctxt);
10428
0
    } else {
10429
0
  xmlXPathCompFunctionCall(ctxt);
10430
0
    }
10431
0
    SKIP_BLANKS;
10432
0
}
10433
10434
/**
10435
 * xmlXPathCompFilterExpr:
10436
 * @ctxt:  the XPath Parser context
10437
 *
10438
 *  [20]   FilterExpr ::=   PrimaryExpr
10439
 *               | FilterExpr Predicate
10440
 *
10441
 * Compile a filter expression.
10442
 * Square brackets are used to filter expressions in the same way that
10443
 * they are used in location paths. It is an error if the expression to
10444
 * be filtered does not evaluate to a node-set. The context node list
10445
 * used for evaluating the expression in square brackets is the node-set
10446
 * to be filtered listed in document order.
10447
 */
10448
10449
static void
10450
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10451
0
    xmlXPathCompPrimaryExpr(ctxt);
10452
0
    CHECK_ERROR;
10453
0
    SKIP_BLANKS;
10454
10455
0
    while (CUR == '[') {
10456
0
  xmlXPathCompPredicate(ctxt, 1);
10457
0
  SKIP_BLANKS;
10458
0
    }
10459
10460
10461
0
}
10462
10463
/**
10464
 * xmlXPathScanName:
10465
 * @ctxt:  the XPath Parser context
10466
 *
10467
 * Trickery: parse an XML name but without consuming the input flow
10468
 * Needed to avoid insanity in the parser state.
10469
 *
10470
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10471
 *                  CombiningChar | Extender
10472
 *
10473
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10474
 *
10475
 * [6] Names ::= Name (S Name)*
10476
 *
10477
 * Returns the Name parsed or NULL
10478
 */
10479
10480
static xmlChar *
10481
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10482
0
    int l;
10483
0
    int c;
10484
0
    const xmlChar *cur;
10485
0
    xmlChar *ret;
10486
10487
0
    cur = ctxt->cur;
10488
10489
0
    c = CUR_CHAR(l);
10490
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10491
0
  (!IS_LETTER(c) && (c != '_') &&
10492
0
         (c != ':'))) {
10493
0
  return(NULL);
10494
0
    }
10495
10496
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10497
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10498
0
            (c == '.') || (c == '-') ||
10499
0
      (c == '_') || (c == ':') ||
10500
0
      (IS_COMBINING(c)) ||
10501
0
      (IS_EXTENDER(c)))) {
10502
0
  NEXTL(l);
10503
0
  c = CUR_CHAR(l);
10504
0
    }
10505
0
    ret = xmlStrndup(cur, ctxt->cur - cur);
10506
0
    ctxt->cur = cur;
10507
0
    return(ret);
10508
0
}
10509
10510
/**
10511
 * xmlXPathCompPathExpr:
10512
 * @ctxt:  the XPath Parser context
10513
 *
10514
 *  [19]   PathExpr ::=   LocationPath
10515
 *               | FilterExpr
10516
 *               | FilterExpr '/' RelativeLocationPath
10517
 *               | FilterExpr '//' RelativeLocationPath
10518
 *
10519
 * Compile a path expression.
10520
 * The / operator and // operators combine an arbitrary expression
10521
 * and a relative location path. It is an error if the expression
10522
 * does not evaluate to a node-set.
10523
 * The / operator does composition in the same way as when / is
10524
 * used in a location path. As in location paths, // is short for
10525
 * /descendant-or-self::node()/.
10526
 */
10527
10528
static void
10529
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10530
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
10531
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10532
10533
0
    SKIP_BLANKS;
10534
0
    if ((CUR == '$') || (CUR == '(') ||
10535
0
  (IS_ASCII_DIGIT(CUR)) ||
10536
0
        (CUR == '\'') || (CUR == '"') ||
10537
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10538
0
  lc = 0;
10539
0
    } else if (CUR == '*') {
10540
  /* relative or absolute location path */
10541
0
  lc = 1;
10542
0
    } else if (CUR == '/') {
10543
  /* relative or absolute location path */
10544
0
  lc = 1;
10545
0
    } else if (CUR == '@') {
10546
  /* relative abbreviated attribute location path */
10547
0
  lc = 1;
10548
0
    } else if (CUR == '.') {
10549
  /* relative abbreviated attribute location path */
10550
0
  lc = 1;
10551
0
    } else {
10552
  /*
10553
   * Problem is finding if we have a name here whether it's:
10554
   *   - a nodetype
10555
   *   - a function call in which case it's followed by '('
10556
   *   - an axis in which case it's followed by ':'
10557
   *   - a element name
10558
   * We do an a priori analysis here rather than having to
10559
   * maintain parsed token content through the recursive function
10560
   * calls. This looks uglier but makes the code easier to
10561
   * read/write/debug.
10562
   */
10563
0
  SKIP_BLANKS;
10564
0
  name = xmlXPathScanName(ctxt);
10565
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10566
#ifdef DEBUG_STEP
10567
      xmlGenericError(xmlGenericErrorContext,
10568
        "PathExpr: Axis\n");
10569
#endif
10570
0
      lc = 1;
10571
0
      xmlFree(name);
10572
0
  } else if (name != NULL) {
10573
0
      int len =xmlStrlen(name);
10574
10575
10576
0
      while (NXT(len) != 0) {
10577
0
    if (NXT(len) == '/') {
10578
        /* element name */
10579
#ifdef DEBUG_STEP
10580
        xmlGenericError(xmlGenericErrorContext,
10581
          "PathExpr: AbbrRelLocation\n");
10582
#endif
10583
0
        lc = 1;
10584
0
        break;
10585
0
    } else if (IS_BLANK_CH(NXT(len))) {
10586
        /* ignore blanks */
10587
0
        ;
10588
0
    } else if (NXT(len) == ':') {
10589
#ifdef DEBUG_STEP
10590
        xmlGenericError(xmlGenericErrorContext,
10591
          "PathExpr: AbbrRelLocation\n");
10592
#endif
10593
0
        lc = 1;
10594
0
        break;
10595
0
    } else if ((NXT(len) == '(')) {
10596
        /* Node Type or Function */
10597
0
        if (xmlXPathIsNodeType(name)) {
10598
#ifdef DEBUG_STEP
10599
            xmlGenericError(xmlGenericErrorContext,
10600
        "PathExpr: Type search\n");
10601
#endif
10602
0
      lc = 1;
10603
#ifdef LIBXML_XPTR_LOCS_ENABLED
10604
                    } else if (ctxt->xptr &&
10605
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10606
                        lc = 1;
10607
#endif
10608
0
        } else {
10609
#ifdef DEBUG_STEP
10610
            xmlGenericError(xmlGenericErrorContext,
10611
        "PathExpr: function call\n");
10612
#endif
10613
0
      lc = 0;
10614
0
        }
10615
0
                    break;
10616
0
    } else if ((NXT(len) == '[')) {
10617
        /* element name */
10618
#ifdef DEBUG_STEP
10619
        xmlGenericError(xmlGenericErrorContext,
10620
          "PathExpr: AbbrRelLocation\n");
10621
#endif
10622
0
        lc = 1;
10623
0
        break;
10624
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10625
0
         (NXT(len) == '=')) {
10626
0
        lc = 1;
10627
0
        break;
10628
0
    } else {
10629
0
        lc = 1;
10630
0
        break;
10631
0
    }
10632
0
    len++;
10633
0
      }
10634
0
      if (NXT(len) == 0) {
10635
#ifdef DEBUG_STEP
10636
    xmlGenericError(xmlGenericErrorContext,
10637
      "PathExpr: AbbrRelLocation\n");
10638
#endif
10639
    /* element name */
10640
0
    lc = 1;
10641
0
      }
10642
0
      xmlFree(name);
10643
0
  } else {
10644
      /* make sure all cases are covered explicitly */
10645
0
      XP_ERROR(XPATH_EXPR_ERROR);
10646
0
  }
10647
0
    }
10648
10649
0
    if (lc) {
10650
0
  if (CUR == '/') {
10651
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10652
0
  } else {
10653
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10654
0
  }
10655
0
  xmlXPathCompLocationPath(ctxt);
10656
0
    } else {
10657
0
  xmlXPathCompFilterExpr(ctxt);
10658
0
  CHECK_ERROR;
10659
0
  if ((CUR == '/') && (NXT(1) == '/')) {
10660
0
      SKIP(2);
10661
0
      SKIP_BLANKS;
10662
10663
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10664
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10665
10666
0
      xmlXPathCompRelativeLocationPath(ctxt);
10667
0
  } else if (CUR == '/') {
10668
0
      xmlXPathCompRelativeLocationPath(ctxt);
10669
0
  }
10670
0
    }
10671
0
    SKIP_BLANKS;
10672
0
}
10673
10674
/**
10675
 * xmlXPathCompUnionExpr:
10676
 * @ctxt:  the XPath Parser context
10677
 *
10678
 *  [18]   UnionExpr ::=   PathExpr
10679
 *               | UnionExpr '|' PathExpr
10680
 *
10681
 * Compile an union expression.
10682
 */
10683
10684
static void
10685
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10686
0
    xmlXPathCompPathExpr(ctxt);
10687
0
    CHECK_ERROR;
10688
0
    SKIP_BLANKS;
10689
0
    while (CUR == '|') {
10690
0
  int op1 = ctxt->comp->last;
10691
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10692
10693
0
  NEXT;
10694
0
  SKIP_BLANKS;
10695
0
  xmlXPathCompPathExpr(ctxt);
10696
10697
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10698
10699
0
  SKIP_BLANKS;
10700
0
    }
10701
0
}
10702
10703
/**
10704
 * xmlXPathCompUnaryExpr:
10705
 * @ctxt:  the XPath Parser context
10706
 *
10707
 *  [27]   UnaryExpr ::=   UnionExpr
10708
 *                   | '-' UnaryExpr
10709
 *
10710
 * Compile an unary expression.
10711
 */
10712
10713
static void
10714
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10715
0
    int minus = 0;
10716
0
    int found = 0;
10717
10718
0
    SKIP_BLANKS;
10719
0
    while (CUR == '-') {
10720
0
        minus = 1 - minus;
10721
0
  found = 1;
10722
0
  NEXT;
10723
0
  SKIP_BLANKS;
10724
0
    }
10725
10726
0
    xmlXPathCompUnionExpr(ctxt);
10727
0
    CHECK_ERROR;
10728
0
    if (found) {
10729
0
  if (minus)
10730
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10731
0
  else
10732
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10733
0
    }
10734
0
}
10735
10736
/**
10737
 * xmlXPathCompMultiplicativeExpr:
10738
 * @ctxt:  the XPath Parser context
10739
 *
10740
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10741
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10742
 *                   | MultiplicativeExpr 'div' UnaryExpr
10743
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10744
 *  [34]   MultiplyOperator ::=   '*'
10745
 *
10746
 * Compile an Additive expression.
10747
 */
10748
10749
static void
10750
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10751
0
    xmlXPathCompUnaryExpr(ctxt);
10752
0
    CHECK_ERROR;
10753
0
    SKIP_BLANKS;
10754
0
    while ((CUR == '*') ||
10755
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10756
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10757
0
  int op = -1;
10758
0
  int op1 = ctxt->comp->last;
10759
10760
0
        if (CUR == '*') {
10761
0
      op = 0;
10762
0
      NEXT;
10763
0
  } else if (CUR == 'd') {
10764
0
      op = 1;
10765
0
      SKIP(3);
10766
0
  } else if (CUR == 'm') {
10767
0
      op = 2;
10768
0
      SKIP(3);
10769
0
  }
10770
0
  SKIP_BLANKS;
10771
0
        xmlXPathCompUnaryExpr(ctxt);
10772
0
  CHECK_ERROR;
10773
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10774
0
  SKIP_BLANKS;
10775
0
    }
10776
0
}
10777
10778
/**
10779
 * xmlXPathCompAdditiveExpr:
10780
 * @ctxt:  the XPath Parser context
10781
 *
10782
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10783
 *                   | AdditiveExpr '+' MultiplicativeExpr
10784
 *                   | AdditiveExpr '-' MultiplicativeExpr
10785
 *
10786
 * Compile an Additive expression.
10787
 */
10788
10789
static void
10790
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10791
10792
0
    xmlXPathCompMultiplicativeExpr(ctxt);
10793
0
    CHECK_ERROR;
10794
0
    SKIP_BLANKS;
10795
0
    while ((CUR == '+') || (CUR == '-')) {
10796
0
  int plus;
10797
0
  int op1 = ctxt->comp->last;
10798
10799
0
        if (CUR == '+') plus = 1;
10800
0
  else plus = 0;
10801
0
  NEXT;
10802
0
  SKIP_BLANKS;
10803
0
        xmlXPathCompMultiplicativeExpr(ctxt);
10804
0
  CHECK_ERROR;
10805
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10806
0
  SKIP_BLANKS;
10807
0
    }
10808
0
}
10809
10810
/**
10811
 * xmlXPathCompRelationalExpr:
10812
 * @ctxt:  the XPath Parser context
10813
 *
10814
 *  [24]   RelationalExpr ::=   AdditiveExpr
10815
 *                 | RelationalExpr '<' AdditiveExpr
10816
 *                 | RelationalExpr '>' AdditiveExpr
10817
 *                 | RelationalExpr '<=' AdditiveExpr
10818
 *                 | RelationalExpr '>=' AdditiveExpr
10819
 *
10820
 *  A <= B > C is allowed ? Answer from James, yes with
10821
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10822
 *  which is basically what got implemented.
10823
 *
10824
 * Compile a Relational expression, then push the result
10825
 * on the stack
10826
 */
10827
10828
static void
10829
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10830
0
    xmlXPathCompAdditiveExpr(ctxt);
10831
0
    CHECK_ERROR;
10832
0
    SKIP_BLANKS;
10833
0
    while ((CUR == '<') || (CUR == '>')) {
10834
0
  int inf, strict;
10835
0
  int op1 = ctxt->comp->last;
10836
10837
0
        if (CUR == '<') inf = 1;
10838
0
  else inf = 0;
10839
0
  if (NXT(1) == '=') strict = 0;
10840
0
  else strict = 1;
10841
0
  NEXT;
10842
0
  if (!strict) NEXT;
10843
0
  SKIP_BLANKS;
10844
0
        xmlXPathCompAdditiveExpr(ctxt);
10845
0
  CHECK_ERROR;
10846
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10847
0
  SKIP_BLANKS;
10848
0
    }
10849
0
}
10850
10851
/**
10852
 * xmlXPathCompEqualityExpr:
10853
 * @ctxt:  the XPath Parser context
10854
 *
10855
 *  [23]   EqualityExpr ::=   RelationalExpr
10856
 *                 | EqualityExpr '=' RelationalExpr
10857
 *                 | EqualityExpr '!=' RelationalExpr
10858
 *
10859
 *  A != B != C is allowed ? Answer from James, yes with
10860
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10861
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10862
 *  which is basically what got implemented.
10863
 *
10864
 * Compile an Equality expression.
10865
 *
10866
 */
10867
static void
10868
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10869
0
    xmlXPathCompRelationalExpr(ctxt);
10870
0
    CHECK_ERROR;
10871
0
    SKIP_BLANKS;
10872
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10873
0
  int eq;
10874
0
  int op1 = ctxt->comp->last;
10875
10876
0
        if (CUR == '=') eq = 1;
10877
0
  else eq = 0;
10878
0
  NEXT;
10879
0
  if (!eq) NEXT;
10880
0
  SKIP_BLANKS;
10881
0
        xmlXPathCompRelationalExpr(ctxt);
10882
0
  CHECK_ERROR;
10883
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10884
0
  SKIP_BLANKS;
10885
0
    }
10886
0
}
10887
10888
/**
10889
 * xmlXPathCompAndExpr:
10890
 * @ctxt:  the XPath Parser context
10891
 *
10892
 *  [22]   AndExpr ::=   EqualityExpr
10893
 *                 | AndExpr 'and' EqualityExpr
10894
 *
10895
 * Compile an AND expression.
10896
 *
10897
 */
10898
static void
10899
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10900
0
    xmlXPathCompEqualityExpr(ctxt);
10901
0
    CHECK_ERROR;
10902
0
    SKIP_BLANKS;
10903
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10904
0
  int op1 = ctxt->comp->last;
10905
0
        SKIP(3);
10906
0
  SKIP_BLANKS;
10907
0
        xmlXPathCompEqualityExpr(ctxt);
10908
0
  CHECK_ERROR;
10909
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10910
0
  SKIP_BLANKS;
10911
0
    }
10912
0
}
10913
10914
/**
10915
 * xmlXPathCompileExpr:
10916
 * @ctxt:  the XPath Parser context
10917
 *
10918
 *  [14]   Expr ::=   OrExpr
10919
 *  [21]   OrExpr ::=   AndExpr
10920
 *                 | OrExpr 'or' AndExpr
10921
 *
10922
 * Parse and compile an expression
10923
 */
10924
static void
10925
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10926
0
    xmlXPathContextPtr xpctxt = ctxt->context;
10927
10928
0
    if (xpctxt != NULL) {
10929
0
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10930
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10931
        /*
10932
         * Parsing a single '(' pushes about 10 functions on the call stack
10933
         * before recursing!
10934
         */
10935
0
        xpctxt->depth += 10;
10936
0
    }
10937
10938
0
    xmlXPathCompAndExpr(ctxt);
10939
0
    CHECK_ERROR;
10940
0
    SKIP_BLANKS;
10941
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10942
0
  int op1 = ctxt->comp->last;
10943
0
        SKIP(2);
10944
0
  SKIP_BLANKS;
10945
0
        xmlXPathCompAndExpr(ctxt);
10946
0
  CHECK_ERROR;
10947
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10948
0
  SKIP_BLANKS;
10949
0
    }
10950
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10951
  /* more ops could be optimized too */
10952
  /*
10953
  * This is the main place to eliminate sorting for
10954
  * operations which don't require a sorted node-set.
10955
  * E.g. count().
10956
  */
10957
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10958
0
    }
10959
10960
0
    if (xpctxt != NULL)
10961
0
        xpctxt->depth -= 10;
10962
0
}
10963
10964
/**
10965
 * xmlXPathCompPredicate:
10966
 * @ctxt:  the XPath Parser context
10967
 * @filter:  act as a filter
10968
 *
10969
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10970
 *  [9]   PredicateExpr ::=   Expr
10971
 *
10972
 * Compile a predicate expression
10973
 */
10974
static void
10975
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10976
0
    int op1 = ctxt->comp->last;
10977
10978
0
    SKIP_BLANKS;
10979
0
    if (CUR != '[') {
10980
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10981
0
    }
10982
0
    NEXT;
10983
0
    SKIP_BLANKS;
10984
10985
0
    ctxt->comp->last = -1;
10986
    /*
10987
    * This call to xmlXPathCompileExpr() will deactivate sorting
10988
    * of the predicate result.
10989
    * TODO: Sorting is still activated for filters, since I'm not
10990
    *  sure if needed. Normally sorting should not be needed, since
10991
    *  a filter can only diminish the number of items in a sequence,
10992
    *  but won't change its order; so if the initial sequence is sorted,
10993
    *  subsequent sorting is not needed.
10994
    */
10995
0
    if (! filter)
10996
0
  xmlXPathCompileExpr(ctxt, 0);
10997
0
    else
10998
0
  xmlXPathCompileExpr(ctxt, 1);
10999
0
    CHECK_ERROR;
11000
11001
0
    if (CUR != ']') {
11002
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11003
0
    }
11004
11005
0
    if (filter)
11006
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11007
0
    else
11008
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11009
11010
0
    NEXT;
11011
0
    SKIP_BLANKS;
11012
0
}
11013
11014
/**
11015
 * xmlXPathCompNodeTest:
11016
 * @ctxt:  the XPath Parser context
11017
 * @test:  pointer to a xmlXPathTestVal
11018
 * @type:  pointer to a xmlXPathTypeVal
11019
 * @prefix:  placeholder for a possible name prefix
11020
 *
11021
 * [7] NodeTest ::=   NameTest
11022
 *        | NodeType '(' ')'
11023
 *        | 'processing-instruction' '(' Literal ')'
11024
 *
11025
 * [37] NameTest ::=  '*'
11026
 *        | NCName ':' '*'
11027
 *        | QName
11028
 * [38] NodeType ::= 'comment'
11029
 *       | 'text'
11030
 *       | 'processing-instruction'
11031
 *       | 'node'
11032
 *
11033
 * Returns the name found and updates @test, @type and @prefix appropriately
11034
 */
11035
static xmlChar *
11036
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11037
               xmlXPathTypeVal *type, xmlChar **prefix,
11038
0
         xmlChar *name) {
11039
0
    int blanks;
11040
11041
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11042
0
  STRANGE;
11043
0
  return(NULL);
11044
0
    }
11045
0
    *type = (xmlXPathTypeVal) 0;
11046
0
    *test = (xmlXPathTestVal) 0;
11047
0
    *prefix = NULL;
11048
0
    SKIP_BLANKS;
11049
11050
0
    if ((name == NULL) && (CUR == '*')) {
11051
  /*
11052
   * All elements
11053
   */
11054
0
  NEXT;
11055
0
  *test = NODE_TEST_ALL;
11056
0
  return(NULL);
11057
0
    }
11058
11059
0
    if (name == NULL)
11060
0
  name = xmlXPathParseNCName(ctxt);
11061
0
    if (name == NULL) {
11062
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11063
0
    }
11064
11065
0
    blanks = IS_BLANK_CH(CUR);
11066
0
    SKIP_BLANKS;
11067
0
    if (CUR == '(') {
11068
0
  NEXT;
11069
  /*
11070
   * NodeType or PI search
11071
   */
11072
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
11073
0
      *type = NODE_TYPE_COMMENT;
11074
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
11075
0
      *type = NODE_TYPE_NODE;
11076
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11077
0
      *type = NODE_TYPE_PI;
11078
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
11079
0
      *type = NODE_TYPE_TEXT;
11080
0
  else {
11081
0
      if (name != NULL)
11082
0
    xmlFree(name);
11083
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11084
0
  }
11085
11086
0
  *test = NODE_TEST_TYPE;
11087
11088
0
  SKIP_BLANKS;
11089
0
  if (*type == NODE_TYPE_PI) {
11090
      /*
11091
       * Specific case: search a PI by name.
11092
       */
11093
0
      if (name != NULL)
11094
0
    xmlFree(name);
11095
0
      name = NULL;
11096
0
      if (CUR != ')') {
11097
0
    name = xmlXPathParseLiteral(ctxt);
11098
0
                if (name == NULL) {
11099
0
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11100
0
                }
11101
0
    *test = NODE_TEST_PI;
11102
0
    SKIP_BLANKS;
11103
0
      }
11104
0
  }
11105
0
  if (CUR != ')') {
11106
0
      if (name != NULL)
11107
0
    xmlFree(name);
11108
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11109
0
  }
11110
0
  NEXT;
11111
0
  return(name);
11112
0
    }
11113
0
    *test = NODE_TEST_NAME;
11114
0
    if ((!blanks) && (CUR == ':')) {
11115
0
  NEXT;
11116
11117
  /*
11118
   * Since currently the parser context don't have a
11119
   * namespace list associated:
11120
   * The namespace name for this prefix can be computed
11121
   * only at evaluation time. The compilation is done
11122
   * outside of any context.
11123
   */
11124
#if 0
11125
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11126
  if (name != NULL)
11127
      xmlFree(name);
11128
  if (*prefix == NULL) {
11129
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11130
  }
11131
#else
11132
0
  *prefix = name;
11133
0
#endif
11134
11135
0
  if (CUR == '*') {
11136
      /*
11137
       * All elements
11138
       */
11139
0
      NEXT;
11140
0
      *test = NODE_TEST_ALL;
11141
0
      return(NULL);
11142
0
  }
11143
11144
0
  name = xmlXPathParseNCName(ctxt);
11145
0
  if (name == NULL) {
11146
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11147
0
  }
11148
0
    }
11149
0
    return(name);
11150
0
}
11151
11152
/**
11153
 * xmlXPathIsAxisName:
11154
 * @name:  a preparsed name token
11155
 *
11156
 * [6] AxisName ::=   'ancestor'
11157
 *                  | 'ancestor-or-self'
11158
 *                  | 'attribute'
11159
 *                  | 'child'
11160
 *                  | 'descendant'
11161
 *                  | 'descendant-or-self'
11162
 *                  | 'following'
11163
 *                  | 'following-sibling'
11164
 *                  | 'namespace'
11165
 *                  | 'parent'
11166
 *                  | 'preceding'
11167
 *                  | 'preceding-sibling'
11168
 *                  | 'self'
11169
 *
11170
 * Returns the axis or 0
11171
 */
11172
static xmlXPathAxisVal
11173
0
xmlXPathIsAxisName(const xmlChar *name) {
11174
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11175
0
    switch (name[0]) {
11176
0
  case 'a':
11177
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11178
0
    ret = AXIS_ANCESTOR;
11179
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11180
0
    ret = AXIS_ANCESTOR_OR_SELF;
11181
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11182
0
    ret = AXIS_ATTRIBUTE;
11183
0
      break;
11184
0
  case 'c':
11185
0
      if (xmlStrEqual(name, BAD_CAST "child"))
11186
0
    ret = AXIS_CHILD;
11187
0
      break;
11188
0
  case 'd':
11189
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11190
0
    ret = AXIS_DESCENDANT;
11191
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11192
0
    ret = AXIS_DESCENDANT_OR_SELF;
11193
0
      break;
11194
0
  case 'f':
11195
0
      if (xmlStrEqual(name, BAD_CAST "following"))
11196
0
    ret = AXIS_FOLLOWING;
11197
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11198
0
    ret = AXIS_FOLLOWING_SIBLING;
11199
0
      break;
11200
0
  case 'n':
11201
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11202
0
    ret = AXIS_NAMESPACE;
11203
0
      break;
11204
0
  case 'p':
11205
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
11206
0
    ret = AXIS_PARENT;
11207
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11208
0
    ret = AXIS_PRECEDING;
11209
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11210
0
    ret = AXIS_PRECEDING_SIBLING;
11211
0
      break;
11212
0
  case 's':
11213
0
      if (xmlStrEqual(name, BAD_CAST "self"))
11214
0
    ret = AXIS_SELF;
11215
0
      break;
11216
0
    }
11217
0
    return(ret);
11218
0
}
11219
11220
/**
11221
 * xmlXPathCompStep:
11222
 * @ctxt:  the XPath Parser context
11223
 *
11224
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11225
 *                  | AbbreviatedStep
11226
 *
11227
 * [12] AbbreviatedStep ::=   '.' | '..'
11228
 *
11229
 * [5] AxisSpecifier ::= AxisName '::'
11230
 *                  | AbbreviatedAxisSpecifier
11231
 *
11232
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11233
 *
11234
 * Modified for XPtr range support as:
11235
 *
11236
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11237
 *                     | AbbreviatedStep
11238
 *                     | 'range-to' '(' Expr ')' Predicate*
11239
 *
11240
 * Compile one step in a Location Path
11241
 * A location step of . is short for self::node(). This is
11242
 * particularly useful in conjunction with //. For example, the
11243
 * location path .//para is short for
11244
 * self::node()/descendant-or-self::node()/child::para
11245
 * and so will select all para descendant elements of the context
11246
 * node.
11247
 * Similarly, a location step of .. is short for parent::node().
11248
 * For example, ../title is short for parent::node()/child::title
11249
 * and so will select the title children of the parent of the context
11250
 * node.
11251
 */
11252
static void
11253
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11254
#ifdef LIBXML_XPTR_LOCS_ENABLED
11255
    int rangeto = 0;
11256
    int op2 = -1;
11257
#endif
11258
11259
0
    SKIP_BLANKS;
11260
0
    if ((CUR == '.') && (NXT(1) == '.')) {
11261
0
  SKIP(2);
11262
0
  SKIP_BLANKS;
11263
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11264
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11265
0
    } else if (CUR == '.') {
11266
0
  NEXT;
11267
0
  SKIP_BLANKS;
11268
0
    } else {
11269
0
  xmlChar *name = NULL;
11270
0
  xmlChar *prefix = NULL;
11271
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11272
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11273
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11274
0
  int op1;
11275
11276
  /*
11277
   * The modification needed for XPointer change to the production
11278
   */
11279
#ifdef LIBXML_XPTR_LOCS_ENABLED
11280
  if (ctxt->xptr) {
11281
      name = xmlXPathParseNCName(ctxt);
11282
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11283
                op2 = ctxt->comp->last;
11284
    xmlFree(name);
11285
    SKIP_BLANKS;
11286
    if (CUR != '(') {
11287
        XP_ERROR(XPATH_EXPR_ERROR);
11288
    }
11289
    NEXT;
11290
    SKIP_BLANKS;
11291
11292
    xmlXPathCompileExpr(ctxt, 1);
11293
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11294
    CHECK_ERROR;
11295
11296
    SKIP_BLANKS;
11297
    if (CUR != ')') {
11298
        XP_ERROR(XPATH_EXPR_ERROR);
11299
    }
11300
    NEXT;
11301
    rangeto = 1;
11302
    goto eval_predicates;
11303
      }
11304
  }
11305
#endif
11306
0
  if (CUR == '*') {
11307
0
      axis = AXIS_CHILD;
11308
0
  } else {
11309
0
      if (name == NULL)
11310
0
    name = xmlXPathParseNCName(ctxt);
11311
0
      if (name != NULL) {
11312
0
    axis = xmlXPathIsAxisName(name);
11313
0
    if (axis != 0) {
11314
0
        SKIP_BLANKS;
11315
0
        if ((CUR == ':') && (NXT(1) == ':')) {
11316
0
      SKIP(2);
11317
0
      xmlFree(name);
11318
0
      name = NULL;
11319
0
        } else {
11320
      /* an element name can conflict with an axis one :-\ */
11321
0
      axis = AXIS_CHILD;
11322
0
        }
11323
0
    } else {
11324
0
        axis = AXIS_CHILD;
11325
0
    }
11326
0
      } else if (CUR == '@') {
11327
0
    NEXT;
11328
0
    axis = AXIS_ATTRIBUTE;
11329
0
      } else {
11330
0
    axis = AXIS_CHILD;
11331
0
      }
11332
0
  }
11333
11334
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11335
0
            xmlFree(name);
11336
0
            return;
11337
0
        }
11338
11339
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11340
0
  if (test == 0)
11341
0
      return;
11342
11343
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11344
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11345
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11346
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11347
0
      }
11348
0
  }
11349
#ifdef DEBUG_STEP
11350
  xmlGenericError(xmlGenericErrorContext,
11351
    "Basis : computing new set\n");
11352
#endif
11353
11354
#ifdef DEBUG_STEP
11355
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11356
  if (ctxt->value == NULL)
11357
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11358
  else if (ctxt->value->nodesetval == NULL)
11359
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11360
  else
11361
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11362
#endif
11363
11364
#ifdef LIBXML_XPTR_LOCS_ENABLED
11365
eval_predicates:
11366
#endif
11367
0
  op1 = ctxt->comp->last;
11368
0
  ctxt->comp->last = -1;
11369
11370
0
  SKIP_BLANKS;
11371
0
  while (CUR == '[') {
11372
0
      xmlXPathCompPredicate(ctxt, 0);
11373
0
  }
11374
11375
#ifdef LIBXML_XPTR_LOCS_ENABLED
11376
  if (rangeto) {
11377
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11378
  } else
11379
#endif
11380
0
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11381
0
                           test, type, (void *)prefix, (void *)name) == -1) {
11382
0
            xmlFree(prefix);
11383
0
            xmlFree(name);
11384
0
        }
11385
0
    }
11386
#ifdef DEBUG_STEP
11387
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11388
    if (ctxt->value == NULL)
11389
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11390
    else if (ctxt->value->nodesetval == NULL)
11391
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11392
    else
11393
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11394
    ctxt->value->nodesetval);
11395
#endif
11396
0
}
11397
11398
/**
11399
 * xmlXPathCompRelativeLocationPath:
11400
 * @ctxt:  the XPath Parser context
11401
 *
11402
 *  [3]   RelativeLocationPath ::=   Step
11403
 *                     | RelativeLocationPath '/' Step
11404
 *                     | AbbreviatedRelativeLocationPath
11405
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11406
 *
11407
 * Compile a relative location path.
11408
 */
11409
static void
11410
xmlXPathCompRelativeLocationPath
11411
0
(xmlXPathParserContextPtr ctxt) {
11412
0
    SKIP_BLANKS;
11413
0
    if ((CUR == '/') && (NXT(1) == '/')) {
11414
0
  SKIP(2);
11415
0
  SKIP_BLANKS;
11416
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11417
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11418
0
    } else if (CUR == '/') {
11419
0
      NEXT;
11420
0
  SKIP_BLANKS;
11421
0
    }
11422
0
    xmlXPathCompStep(ctxt);
11423
0
    CHECK_ERROR;
11424
0
    SKIP_BLANKS;
11425
0
    while (CUR == '/') {
11426
0
  if ((CUR == '/') && (NXT(1) == '/')) {
11427
0
      SKIP(2);
11428
0
      SKIP_BLANKS;
11429
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11430
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11431
0
      xmlXPathCompStep(ctxt);
11432
0
  } else if (CUR == '/') {
11433
0
      NEXT;
11434
0
      SKIP_BLANKS;
11435
0
      xmlXPathCompStep(ctxt);
11436
0
  }
11437
0
  SKIP_BLANKS;
11438
0
    }
11439
0
}
11440
11441
/**
11442
 * xmlXPathCompLocationPath:
11443
 * @ctxt:  the XPath Parser context
11444
 *
11445
 *  [1]   LocationPath ::=   RelativeLocationPath
11446
 *                     | AbsoluteLocationPath
11447
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11448
 *                     | AbbreviatedAbsoluteLocationPath
11449
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11450
 *                           '//' RelativeLocationPath
11451
 *
11452
 * Compile a location path
11453
 *
11454
 * // is short for /descendant-or-self::node()/. For example,
11455
 * //para is short for /descendant-or-self::node()/child::para and
11456
 * so will select any para element in the document (even a para element
11457
 * that is a document element will be selected by //para since the
11458
 * document element node is a child of the root node); div//para is
11459
 * short for div/descendant-or-self::node()/child::para and so will
11460
 * select all para descendants of div children.
11461
 */
11462
static void
11463
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11464
0
    SKIP_BLANKS;
11465
0
    if (CUR != '/') {
11466
0
        xmlXPathCompRelativeLocationPath(ctxt);
11467
0
    } else {
11468
0
  while (CUR == '/') {
11469
0
      if ((CUR == '/') && (NXT(1) == '/')) {
11470
0
    SKIP(2);
11471
0
    SKIP_BLANKS;
11472
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11473
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11474
0
    xmlXPathCompRelativeLocationPath(ctxt);
11475
0
      } else if (CUR == '/') {
11476
0
    NEXT;
11477
0
    SKIP_BLANKS;
11478
0
    if ((CUR != 0 ) &&
11479
0
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11480
0
         (CUR == '@') || (CUR == '*')))
11481
0
        xmlXPathCompRelativeLocationPath(ctxt);
11482
0
      }
11483
0
      CHECK_ERROR;
11484
0
  }
11485
0
    }
11486
0
}
11487
11488
/************************************************************************
11489
 *                  *
11490
 *    XPath precompiled expression evaluation     *
11491
 *                  *
11492
 ************************************************************************/
11493
11494
static int
11495
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11496
11497
#ifdef DEBUG_STEP
11498
static void
11499
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11500
        int nbNodes)
11501
{
11502
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11503
    switch (op->value) {
11504
        case AXIS_ANCESTOR:
11505
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11506
            break;
11507
        case AXIS_ANCESTOR_OR_SELF:
11508
            xmlGenericError(xmlGenericErrorContext,
11509
                            "axis 'ancestors-or-self' ");
11510
            break;
11511
        case AXIS_ATTRIBUTE:
11512
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11513
            break;
11514
        case AXIS_CHILD:
11515
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11516
            break;
11517
        case AXIS_DESCENDANT:
11518
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11519
            break;
11520
        case AXIS_DESCENDANT_OR_SELF:
11521
            xmlGenericError(xmlGenericErrorContext,
11522
                            "axis 'descendant-or-self' ");
11523
            break;
11524
        case AXIS_FOLLOWING:
11525
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11526
            break;
11527
        case AXIS_FOLLOWING_SIBLING:
11528
            xmlGenericError(xmlGenericErrorContext,
11529
                            "axis 'following-siblings' ");
11530
            break;
11531
        case AXIS_NAMESPACE:
11532
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11533
            break;
11534
        case AXIS_PARENT:
11535
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11536
            break;
11537
        case AXIS_PRECEDING:
11538
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11539
            break;
11540
        case AXIS_PRECEDING_SIBLING:
11541
            xmlGenericError(xmlGenericErrorContext,
11542
                            "axis 'preceding-sibling' ");
11543
            break;
11544
        case AXIS_SELF:
11545
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11546
            break;
11547
    }
11548
    xmlGenericError(xmlGenericErrorContext,
11549
  " context contains %d nodes\n", nbNodes);
11550
    switch (op->value2) {
11551
        case NODE_TEST_NONE:
11552
            xmlGenericError(xmlGenericErrorContext,
11553
                            "           searching for none !!!\n");
11554
            break;
11555
        case NODE_TEST_TYPE:
11556
            xmlGenericError(xmlGenericErrorContext,
11557
                            "           searching for type %d\n", op->value3);
11558
            break;
11559
        case NODE_TEST_PI:
11560
            xmlGenericError(xmlGenericErrorContext,
11561
                            "           searching for PI !!!\n");
11562
            break;
11563
        case NODE_TEST_ALL:
11564
            xmlGenericError(xmlGenericErrorContext,
11565
                            "           searching for *\n");
11566
            break;
11567
        case NODE_TEST_NS:
11568
            xmlGenericError(xmlGenericErrorContext,
11569
                            "           searching for namespace %s\n",
11570
                            op->value5);
11571
            break;
11572
        case NODE_TEST_NAME:
11573
            xmlGenericError(xmlGenericErrorContext,
11574
                            "           searching for name %s\n", op->value5);
11575
            if (op->value4)
11576
                xmlGenericError(xmlGenericErrorContext,
11577
                                "           with namespace %s\n", op->value4);
11578
            break;
11579
    }
11580
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11581
}
11582
#endif /* DEBUG_STEP */
11583
11584
/**
11585
 * xmlXPathNodeSetFilter:
11586
 * @ctxt:  the XPath Parser context
11587
 * @set: the node set to filter
11588
 * @filterOpIndex: the index of the predicate/filter op
11589
 * @minPos: minimum position in the filtered set (1-based)
11590
 * @maxPos: maximum position in the filtered set (1-based)
11591
 * @hasNsNodes: true if the node set may contain namespace nodes
11592
 *
11593
 * Filter a node set, keeping only nodes for which the predicate expression
11594
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11595
 * filtered result.
11596
 */
11597
static void
11598
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11599
          xmlNodeSetPtr set,
11600
          int filterOpIndex,
11601
                      int minPos, int maxPos,
11602
          int hasNsNodes)
11603
0
{
11604
0
    xmlXPathContextPtr xpctxt;
11605
0
    xmlNodePtr oldnode;
11606
0
    xmlDocPtr olddoc;
11607
0
    xmlXPathStepOpPtr filterOp;
11608
0
    int oldcs, oldpp;
11609
0
    int i, j, pos;
11610
11611
0
    if ((set == NULL) || (set->nodeNr == 0))
11612
0
        return;
11613
11614
    /*
11615
    * Check if the node set contains a sufficient number of nodes for
11616
    * the requested range.
11617
    */
11618
0
    if (set->nodeNr < minPos) {
11619
0
        xmlXPathNodeSetClear(set, hasNsNodes);
11620
0
        return;
11621
0
    }
11622
11623
0
    xpctxt = ctxt->context;
11624
0
    oldnode = xpctxt->node;
11625
0
    olddoc = xpctxt->doc;
11626
0
    oldcs = xpctxt->contextSize;
11627
0
    oldpp = xpctxt->proximityPosition;
11628
0
    filterOp = &ctxt->comp->steps[filterOpIndex];
11629
11630
0
    xpctxt->contextSize = set->nodeNr;
11631
11632
0
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11633
0
        xmlNodePtr node = set->nodeTab[i];
11634
0
        int res;
11635
11636
0
        xpctxt->node = node;
11637
0
        xpctxt->proximityPosition = i + 1;
11638
11639
        /*
11640
        * Also set the xpath document in case things like
11641
        * key() are evaluated in the predicate.
11642
        *
11643
        * TODO: Get real doc for namespace nodes.
11644
        */
11645
0
        if ((node->type != XML_NAMESPACE_DECL) &&
11646
0
            (node->doc != NULL))
11647
0
            xpctxt->doc = node->doc;
11648
11649
0
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11650
11651
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
11652
0
            break;
11653
0
        if (res < 0) {
11654
            /* Shouldn't happen */
11655
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11656
0
            break;
11657
0
        }
11658
11659
0
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11660
0
            if (i != j) {
11661
0
                set->nodeTab[j] = node;
11662
0
                set->nodeTab[i] = NULL;
11663
0
            }
11664
11665
0
            j += 1;
11666
0
        } else {
11667
            /* Remove the entry from the initial node set. */
11668
0
            set->nodeTab[i] = NULL;
11669
0
            if (node->type == XML_NAMESPACE_DECL)
11670
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11671
0
        }
11672
11673
0
        if (res != 0) {
11674
0
            if (pos == maxPos) {
11675
0
                i += 1;
11676
0
                break;
11677
0
            }
11678
11679
0
            pos += 1;
11680
0
        }
11681
0
    }
11682
11683
    /* Free remaining nodes. */
11684
0
    if (hasNsNodes) {
11685
0
        for (; i < set->nodeNr; i++) {
11686
0
            xmlNodePtr node = set->nodeTab[i];
11687
0
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11688
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11689
0
        }
11690
0
    }
11691
11692
0
    set->nodeNr = j;
11693
11694
    /* If too many elements were removed, shrink table to preserve memory. */
11695
0
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11696
0
        (set->nodeNr < set->nodeMax / 2)) {
11697
0
        xmlNodePtr *tmp;
11698
0
        int nodeMax = set->nodeNr;
11699
11700
0
        if (nodeMax < XML_NODESET_DEFAULT)
11701
0
            nodeMax = XML_NODESET_DEFAULT;
11702
0
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11703
0
                nodeMax * sizeof(xmlNodePtr));
11704
0
        if (tmp == NULL) {
11705
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11706
0
        } else {
11707
0
            set->nodeTab = tmp;
11708
0
            set->nodeMax = nodeMax;
11709
0
        }
11710
0
    }
11711
11712
0
    xpctxt->node = oldnode;
11713
0
    xpctxt->doc = olddoc;
11714
0
    xpctxt->contextSize = oldcs;
11715
0
    xpctxt->proximityPosition = oldpp;
11716
0
}
11717
11718
#ifdef LIBXML_XPTR_LOCS_ENABLED
11719
/**
11720
 * xmlXPathLocationSetFilter:
11721
 * @ctxt:  the XPath Parser context
11722
 * @locset: the location set to filter
11723
 * @filterOpIndex: the index of the predicate/filter op
11724
 * @minPos: minimum position in the filtered set (1-based)
11725
 * @maxPos: maximum position in the filtered set (1-based)
11726
 *
11727
 * Filter a location set, keeping only nodes for which the predicate
11728
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11729
 * in the filtered result.
11730
 */
11731
static void
11732
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11733
              xmlLocationSetPtr locset,
11734
              int filterOpIndex,
11735
                          int minPos, int maxPos)
11736
{
11737
    xmlXPathContextPtr xpctxt;
11738
    xmlNodePtr oldnode;
11739
    xmlDocPtr olddoc;
11740
    xmlXPathStepOpPtr filterOp;
11741
    int oldcs, oldpp;
11742
    int i, j, pos;
11743
11744
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11745
        return;
11746
11747
    xpctxt = ctxt->context;
11748
    oldnode = xpctxt->node;
11749
    olddoc = xpctxt->doc;
11750
    oldcs = xpctxt->contextSize;
11751
    oldpp = xpctxt->proximityPosition;
11752
    filterOp = &ctxt->comp->steps[filterOpIndex];
11753
11754
    xpctxt->contextSize = locset->locNr;
11755
11756
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11757
        xmlNodePtr contextNode = locset->locTab[i]->user;
11758
        int res;
11759
11760
        xpctxt->node = contextNode;
11761
        xpctxt->proximityPosition = i + 1;
11762
11763
        /*
11764
        * Also set the xpath document in case things like
11765
        * key() are evaluated in the predicate.
11766
        *
11767
        * TODO: Get real doc for namespace nodes.
11768
        */
11769
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11770
            (contextNode->doc != NULL))
11771
            xpctxt->doc = contextNode->doc;
11772
11773
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11774
11775
        if (ctxt->error != XPATH_EXPRESSION_OK)
11776
            break;
11777
        if (res < 0) {
11778
            /* Shouldn't happen */
11779
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11780
            break;
11781
        }
11782
11783
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11784
            if (i != j) {
11785
                locset->locTab[j] = locset->locTab[i];
11786
                locset->locTab[i] = NULL;
11787
            }
11788
11789
            j += 1;
11790
        } else {
11791
            /* Remove the entry from the initial location set. */
11792
            xmlXPathFreeObject(locset->locTab[i]);
11793
            locset->locTab[i] = NULL;
11794
        }
11795
11796
        if (res != 0) {
11797
            if (pos == maxPos) {
11798
                i += 1;
11799
                break;
11800
            }
11801
11802
            pos += 1;
11803
        }
11804
    }
11805
11806
    /* Free remaining nodes. */
11807
    for (; i < locset->locNr; i++)
11808
        xmlXPathFreeObject(locset->locTab[i]);
11809
11810
    locset->locNr = j;
11811
11812
    /* If too many elements were removed, shrink table to preserve memory. */
11813
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11814
        (locset->locNr < locset->locMax / 2)) {
11815
        xmlXPathObjectPtr *tmp;
11816
        int locMax = locset->locNr;
11817
11818
        if (locMax < XML_NODESET_DEFAULT)
11819
            locMax = XML_NODESET_DEFAULT;
11820
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11821
                locMax * sizeof(xmlXPathObjectPtr));
11822
        if (tmp == NULL) {
11823
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11824
        } else {
11825
            locset->locTab = tmp;
11826
            locset->locMax = locMax;
11827
        }
11828
    }
11829
11830
    xpctxt->node = oldnode;
11831
    xpctxt->doc = olddoc;
11832
    xpctxt->contextSize = oldcs;
11833
    xpctxt->proximityPosition = oldpp;
11834
}
11835
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11836
11837
/**
11838
 * xmlXPathCompOpEvalPredicate:
11839
 * @ctxt:  the XPath Parser context
11840
 * @op: the predicate op
11841
 * @set: the node set to filter
11842
 * @minPos: minimum position in the filtered set (1-based)
11843
 * @maxPos: maximum position in the filtered set (1-based)
11844
 * @hasNsNodes: true if the node set may contain namespace nodes
11845
 *
11846
 * Filter a node set, keeping only nodes for which the sequence of predicate
11847
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11848
 * in the filtered result.
11849
 */
11850
static void
11851
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11852
          xmlXPathStepOpPtr op,
11853
          xmlNodeSetPtr set,
11854
                            int minPos, int maxPos,
11855
          int hasNsNodes)
11856
0
{
11857
0
    if (op->ch1 != -1) {
11858
0
  xmlXPathCompExprPtr comp = ctxt->comp;
11859
  /*
11860
  * Process inner predicates first.
11861
  */
11862
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11863
0
            xmlGenericError(xmlGenericErrorContext,
11864
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11865
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11866
0
  }
11867
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11868
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11869
0
        ctxt->context->depth += 1;
11870
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11871
0
                                    1, set->nodeNr, hasNsNodes);
11872
0
        ctxt->context->depth -= 1;
11873
0
  CHECK_ERROR;
11874
0
    }
11875
11876
0
    if (op->ch2 != -1)
11877
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11878
0
}
11879
11880
static int
11881
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11882
          xmlXPathStepOpPtr op,
11883
          int *maxPos)
11884
0
{
11885
11886
0
    xmlXPathStepOpPtr exprOp;
11887
11888
    /*
11889
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11890
    */
11891
11892
    /*
11893
    * If not -1, then ch1 will point to:
11894
    * 1) For predicates (XPATH_OP_PREDICATE):
11895
    *    - an inner predicate operator
11896
    * 2) For filters (XPATH_OP_FILTER):
11897
    *    - an inner filter operator OR
11898
    *    - an expression selecting the node set.
11899
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11900
    */
11901
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11902
0
  return(0);
11903
11904
0
    if (op->ch2 != -1) {
11905
0
  exprOp = &ctxt->comp->steps[op->ch2];
11906
0
    } else
11907
0
  return(0);
11908
11909
0
    if ((exprOp != NULL) &&
11910
0
  (exprOp->op == XPATH_OP_VALUE) &&
11911
0
  (exprOp->value4 != NULL) &&
11912
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11913
0
    {
11914
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11915
11916
  /*
11917
  * We have a "[n]" predicate here.
11918
  * TODO: Unfortunately this simplistic test here is not
11919
  * able to detect a position() predicate in compound
11920
  * expressions like "[@attr = 'a" and position() = 1],
11921
  * and even not the usage of position() in
11922
  * "[position() = 1]"; thus - obviously - a position-range,
11923
  * like it "[position() < 5]", is also not detected.
11924
  * Maybe we could rewrite the AST to ease the optimization.
11925
  */
11926
11927
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11928
0
      *maxPos = (int) floatval;
11929
0
            if (floatval == (double) *maxPos)
11930
0
                return(1);
11931
0
        }
11932
0
    }
11933
0
    return(0);
11934
0
}
11935
11936
static int
11937
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11938
                           xmlXPathStepOpPtr op,
11939
         xmlNodePtr * first, xmlNodePtr * last,
11940
         int toBool)
11941
0
{
11942
11943
0
#define XP_TEST_HIT \
11944
0
    if (hasAxisRange != 0) { \
11945
0
  if (++pos == maxPos) { \
11946
0
      if (addNode(seq, cur) < 0) \
11947
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11948
0
      goto axis_range_end; } \
11949
0
    } else { \
11950
0
  if (addNode(seq, cur) < 0) \
11951
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11952
0
  if (breakOnFirstHit) goto first_hit; }
11953
11954
0
#define XP_TEST_HIT_NS \
11955
0
    if (hasAxisRange != 0) { \
11956
0
  if (++pos == maxPos) { \
11957
0
      hasNsNodes = 1; \
11958
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11959
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11960
0
  goto axis_range_end; } \
11961
0
    } else { \
11962
0
  hasNsNodes = 1; \
11963
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11964
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11965
0
  if (breakOnFirstHit) goto first_hit; }
11966
11967
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11968
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11969
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11970
0
    const xmlChar *prefix = op->value4;
11971
0
    const xmlChar *name = op->value5;
11972
0
    const xmlChar *URI = NULL;
11973
11974
#ifdef DEBUG_STEP
11975
    int nbMatches = 0, prevMatches = 0;
11976
#endif
11977
0
    int total = 0, hasNsNodes = 0;
11978
    /* The popped object holding the context nodes */
11979
0
    xmlXPathObjectPtr obj;
11980
    /* The set of context nodes for the node tests */
11981
0
    xmlNodeSetPtr contextSeq;
11982
0
    int contextIdx;
11983
0
    xmlNodePtr contextNode;
11984
    /* The final resulting node set wrt to all context nodes */
11985
0
    xmlNodeSetPtr outSeq;
11986
    /*
11987
    * The temporary resulting node set wrt 1 context node.
11988
    * Used to feed predicate evaluation.
11989
    */
11990
0
    xmlNodeSetPtr seq;
11991
0
    xmlNodePtr cur;
11992
    /* First predicate operator */
11993
0
    xmlXPathStepOpPtr predOp;
11994
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
11995
0
    int hasPredicateRange, hasAxisRange, pos;
11996
0
    int breakOnFirstHit;
11997
11998
0
    xmlXPathTraversalFunction next = NULL;
11999
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12000
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
12001
0
    xmlNodePtr oldContextNode;
12002
0
    xmlXPathContextPtr xpctxt = ctxt->context;
12003
12004
12005
0
    CHECK_TYPE0(XPATH_NODESET);
12006
0
    obj = valuePop(ctxt);
12007
    /*
12008
    * Setup namespaces.
12009
    */
12010
0
    if (prefix != NULL) {
12011
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
12012
0
        if (URI == NULL) {
12013
0
      xmlXPathReleaseObject(xpctxt, obj);
12014
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12015
0
  }
12016
0
    }
12017
    /*
12018
    * Setup axis.
12019
    *
12020
    * MAYBE FUTURE TODO: merging optimizations:
12021
    * - If the nodes to be traversed wrt to the initial nodes and
12022
    *   the current axis cannot overlap, then we could avoid searching
12023
    *   for duplicates during the merge.
12024
    *   But the question is how/when to evaluate if they cannot overlap.
12025
    *   Example: if we know that for two initial nodes, the one is
12026
    *   not in the ancestor-or-self axis of the other, then we could safely
12027
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12028
    *   the descendant-or-self axis.
12029
    */
12030
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12031
0
    switch (axis) {
12032
0
        case AXIS_ANCESTOR:
12033
0
            first = NULL;
12034
0
            next = xmlXPathNextAncestor;
12035
0
            break;
12036
0
        case AXIS_ANCESTOR_OR_SELF:
12037
0
            first = NULL;
12038
0
            next = xmlXPathNextAncestorOrSelf;
12039
0
            break;
12040
0
        case AXIS_ATTRIBUTE:
12041
0
            first = NULL;
12042
0
      last = NULL;
12043
0
            next = xmlXPathNextAttribute;
12044
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12045
0
            break;
12046
0
        case AXIS_CHILD:
12047
0
      last = NULL;
12048
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12049
0
    (type == NODE_TYPE_NODE))
12050
0
      {
12051
    /*
12052
    * Optimization if an element node type is 'element'.
12053
    */
12054
0
    next = xmlXPathNextChildElement;
12055
0
      } else
12056
0
    next = xmlXPathNextChild;
12057
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12058
0
            break;
12059
0
        case AXIS_DESCENDANT:
12060
0
      last = NULL;
12061
0
            next = xmlXPathNextDescendant;
12062
0
            break;
12063
0
        case AXIS_DESCENDANT_OR_SELF:
12064
0
      last = NULL;
12065
0
            next = xmlXPathNextDescendantOrSelf;
12066
0
            break;
12067
0
        case AXIS_FOLLOWING:
12068
0
      last = NULL;
12069
0
            next = xmlXPathNextFollowing;
12070
0
            break;
12071
0
        case AXIS_FOLLOWING_SIBLING:
12072
0
      last = NULL;
12073
0
            next = xmlXPathNextFollowingSibling;
12074
0
            break;
12075
0
        case AXIS_NAMESPACE:
12076
0
            first = NULL;
12077
0
      last = NULL;
12078
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12079
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12080
0
            break;
12081
0
        case AXIS_PARENT:
12082
0
            first = NULL;
12083
0
            next = xmlXPathNextParent;
12084
0
            break;
12085
0
        case AXIS_PRECEDING:
12086
0
            first = NULL;
12087
0
            next = xmlXPathNextPrecedingInternal;
12088
0
            break;
12089
0
        case AXIS_PRECEDING_SIBLING:
12090
0
            first = NULL;
12091
0
            next = xmlXPathNextPrecedingSibling;
12092
0
            break;
12093
0
        case AXIS_SELF:
12094
0
            first = NULL;
12095
0
      last = NULL;
12096
0
            next = xmlXPathNextSelf;
12097
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12098
0
            break;
12099
0
    }
12100
12101
#ifdef DEBUG_STEP
12102
    xmlXPathDebugDumpStepAxis(op,
12103
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12104
#endif
12105
12106
0
    if (next == NULL) {
12107
0
  xmlXPathReleaseObject(xpctxt, obj);
12108
0
        return(0);
12109
0
    }
12110
0
    contextSeq = obj->nodesetval;
12111
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12112
0
  xmlXPathReleaseObject(xpctxt, obj);
12113
0
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12114
0
        return(0);
12115
0
    }
12116
    /*
12117
    * Predicate optimization ---------------------------------------------
12118
    * If this step has a last predicate, which contains a position(),
12119
    * then we'll optimize (although not exactly "position()", but only
12120
    * the  short-hand form, i.e., "[n]".
12121
    *
12122
    * Example - expression "/foo[parent::bar][1]":
12123
    *
12124
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12125
    *   ROOT                               -- op->ch1
12126
    *   PREDICATE                          -- op->ch2 (predOp)
12127
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12128
    *       SORT
12129
    *         COLLECT  'parent' 'name' 'node' bar
12130
    *           NODE
12131
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12132
    *
12133
    */
12134
0
    maxPos = 0;
12135
0
    predOp = NULL;
12136
0
    hasPredicateRange = 0;
12137
0
    hasAxisRange = 0;
12138
0
    if (op->ch2 != -1) {
12139
  /*
12140
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12141
  */
12142
0
  predOp = &ctxt->comp->steps[op->ch2];
12143
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12144
0
      if (predOp->ch1 != -1) {
12145
    /*
12146
    * Use the next inner predicate operator.
12147
    */
12148
0
    predOp = &ctxt->comp->steps[predOp->ch1];
12149
0
    hasPredicateRange = 1;
12150
0
      } else {
12151
    /*
12152
    * There's no other predicate than the [n] predicate.
12153
    */
12154
0
    predOp = NULL;
12155
0
    hasAxisRange = 1;
12156
0
      }
12157
0
  }
12158
0
    }
12159
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12160
    /*
12161
    * Axis traversal -----------------------------------------------------
12162
    */
12163
    /*
12164
     * 2.3 Node Tests
12165
     *  - For the attribute axis, the principal node type is attribute.
12166
     *  - For the namespace axis, the principal node type is namespace.
12167
     *  - For other axes, the principal node type is element.
12168
     *
12169
     * A node test * is true for any node of the
12170
     * principal node type. For example, child::* will
12171
     * select all element children of the context node
12172
     */
12173
0
    oldContextNode = xpctxt->node;
12174
0
    addNode = xmlXPathNodeSetAddUnique;
12175
0
    outSeq = NULL;
12176
0
    seq = NULL;
12177
0
    contextNode = NULL;
12178
0
    contextIdx = 0;
12179
12180
12181
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12182
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12183
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12184
12185
0
  if (seq == NULL) {
12186
0
      seq = xmlXPathNodeSetCreate(NULL);
12187
0
      if (seq == NULL) {
12188
                /* TODO: Propagate memory error. */
12189
0
    total = 0;
12190
0
    goto error;
12191
0
      }
12192
0
  }
12193
  /*
12194
  * Traverse the axis and test the nodes.
12195
  */
12196
0
  pos = 0;
12197
0
  cur = NULL;
12198
0
  hasNsNodes = 0;
12199
0
        do {
12200
0
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12201
0
                goto error;
12202
12203
0
            cur = next(ctxt, cur);
12204
0
            if (cur == NULL)
12205
0
                break;
12206
12207
      /*
12208
      * QUESTION TODO: What does the "first" and "last" stuff do?
12209
      */
12210
0
            if ((first != NULL) && (*first != NULL)) {
12211
0
    if (*first == cur)
12212
0
        break;
12213
0
    if (((total % 256) == 0) &&
12214
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12215
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12216
#else
12217
        (xmlXPathCmpNodes(*first, cur) >= 0))
12218
#endif
12219
0
    {
12220
0
        break;
12221
0
    }
12222
0
      }
12223
0
      if ((last != NULL) && (*last != NULL)) {
12224
0
    if (*last == cur)
12225
0
        break;
12226
0
    if (((total % 256) == 0) &&
12227
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12228
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12229
#else
12230
        (xmlXPathCmpNodes(cur, *last) >= 0))
12231
#endif
12232
0
    {
12233
0
        break;
12234
0
    }
12235
0
      }
12236
12237
0
            total++;
12238
12239
#ifdef DEBUG_STEP
12240
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12241
#endif
12242
12243
0
      switch (test) {
12244
0
                case NODE_TEST_NONE:
12245
0
        total = 0;
12246
0
                    STRANGE
12247
0
        goto error;
12248
0
                case NODE_TEST_TYPE:
12249
0
        if (type == NODE_TYPE_NODE) {
12250
0
      switch (cur->type) {
12251
0
          case XML_DOCUMENT_NODE:
12252
0
          case XML_HTML_DOCUMENT_NODE:
12253
0
          case XML_ELEMENT_NODE:
12254
0
          case XML_ATTRIBUTE_NODE:
12255
0
          case XML_PI_NODE:
12256
0
          case XML_COMMENT_NODE:
12257
0
          case XML_CDATA_SECTION_NODE:
12258
0
          case XML_TEXT_NODE:
12259
0
        XP_TEST_HIT
12260
0
        break;
12261
0
          case XML_NAMESPACE_DECL: {
12262
0
        if (axis == AXIS_NAMESPACE) {
12263
0
            XP_TEST_HIT_NS
12264
0
        } else {
12265
0
                              hasNsNodes = 1;
12266
0
            XP_TEST_HIT
12267
0
        }
12268
0
        break;
12269
0
                            }
12270
0
          default:
12271
0
        break;
12272
0
      }
12273
0
        } else if (cur->type == (xmlElementType) type) {
12274
0
      if (cur->type == XML_NAMESPACE_DECL)
12275
0
          XP_TEST_HIT_NS
12276
0
      else
12277
0
          XP_TEST_HIT
12278
0
        } else if ((type == NODE_TYPE_TEXT) &&
12279
0
       (cur->type == XML_CDATA_SECTION_NODE))
12280
0
        {
12281
0
      XP_TEST_HIT
12282
0
        }
12283
0
        break;
12284
0
                case NODE_TEST_PI:
12285
0
                    if ((cur->type == XML_PI_NODE) &&
12286
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12287
0
        {
12288
0
      XP_TEST_HIT
12289
0
                    }
12290
0
                    break;
12291
0
                case NODE_TEST_ALL:
12292
0
                    if (axis == AXIS_ATTRIBUTE) {
12293
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
12294
0
      {
12295
0
                            if (prefix == NULL)
12296
0
          {
12297
0
        XP_TEST_HIT
12298
0
                            } else if ((cur->ns != NULL) &&
12299
0
        (xmlStrEqual(URI, cur->ns->href)))
12300
0
          {
12301
0
        XP_TEST_HIT
12302
0
                            }
12303
0
                        }
12304
0
                    } else if (axis == AXIS_NAMESPACE) {
12305
0
                        if (cur->type == XML_NAMESPACE_DECL)
12306
0
      {
12307
0
          XP_TEST_HIT_NS
12308
0
                        }
12309
0
                    } else {
12310
0
                        if (cur->type == XML_ELEMENT_NODE) {
12311
0
                            if (prefix == NULL)
12312
0
          {
12313
0
        XP_TEST_HIT
12314
12315
0
                            } else if ((cur->ns != NULL) &&
12316
0
        (xmlStrEqual(URI, cur->ns->href)))
12317
0
          {
12318
0
        XP_TEST_HIT
12319
0
                            }
12320
0
                        }
12321
0
                    }
12322
0
                    break;
12323
0
                case NODE_TEST_NS:{
12324
0
                        TODO;
12325
0
                        break;
12326
0
                    }
12327
0
                case NODE_TEST_NAME:
12328
0
                    if (axis == AXIS_ATTRIBUTE) {
12329
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
12330
0
          break;
12331
0
        } else if (axis == AXIS_NAMESPACE) {
12332
0
                        if (cur->type != XML_NAMESPACE_DECL)
12333
0
          break;
12334
0
        } else {
12335
0
            if (cur->type != XML_ELEMENT_NODE)
12336
0
          break;
12337
0
        }
12338
0
                    switch (cur->type) {
12339
0
                        case XML_ELEMENT_NODE:
12340
0
                            if (xmlStrEqual(name, cur->name)) {
12341
0
                                if (prefix == NULL) {
12342
0
                                    if (cur->ns == NULL)
12343
0
            {
12344
0
          XP_TEST_HIT
12345
0
                                    }
12346
0
                                } else {
12347
0
                                    if ((cur->ns != NULL) &&
12348
0
                                        (xmlStrEqual(URI, cur->ns->href)))
12349
0
            {
12350
0
          XP_TEST_HIT
12351
0
                                    }
12352
0
                                }
12353
0
                            }
12354
0
                            break;
12355
0
                        case XML_ATTRIBUTE_NODE:{
12356
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12357
12358
0
                                if (xmlStrEqual(name, attr->name)) {
12359
0
                                    if (prefix == NULL) {
12360
0
                                        if ((attr->ns == NULL) ||
12361
0
                                            (attr->ns->prefix == NULL))
12362
0
          {
12363
0
              XP_TEST_HIT
12364
0
                                        }
12365
0
                                    } else {
12366
0
                                        if ((attr->ns != NULL) &&
12367
0
                                            (xmlStrEqual(URI,
12368
0
                attr->ns->href)))
12369
0
          {
12370
0
              XP_TEST_HIT
12371
0
                                        }
12372
0
                                    }
12373
0
                                }
12374
0
                                break;
12375
0
                            }
12376
0
                        case XML_NAMESPACE_DECL:
12377
0
                            if (cur->type == XML_NAMESPACE_DECL) {
12378
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
12379
12380
0
                                if ((ns->prefix != NULL) && (name != NULL)
12381
0
                                    && (xmlStrEqual(ns->prefix, name)))
12382
0
        {
12383
0
            XP_TEST_HIT_NS
12384
0
                                }
12385
0
                            }
12386
0
                            break;
12387
0
                        default:
12388
0
                            break;
12389
0
                    }
12390
0
                    break;
12391
0
      } /* switch(test) */
12392
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12393
12394
0
  goto apply_predicates;
12395
12396
0
axis_range_end: /* ----------------------------------------------------- */
12397
  /*
12398
  * We have a "/foo[n]", and position() = n was reached.
12399
  * Note that we can have as well "/foo/::parent::foo[1]", so
12400
  * a duplicate-aware merge is still needed.
12401
  * Merge with the result.
12402
  */
12403
0
  if (outSeq == NULL) {
12404
0
      outSeq = seq;
12405
0
      seq = NULL;
12406
0
  } else
12407
            /* TODO: Check memory error. */
12408
0
      outSeq = mergeAndClear(outSeq, seq);
12409
  /*
12410
  * Break if only a true/false result was requested.
12411
  */
12412
0
  if (toBool)
12413
0
      break;
12414
0
  continue;
12415
12416
0
first_hit: /* ---------------------------------------------------------- */
12417
  /*
12418
  * Break if only a true/false result was requested and
12419
  * no predicates existed and a node test succeeded.
12420
  */
12421
0
  if (outSeq == NULL) {
12422
0
      outSeq = seq;
12423
0
      seq = NULL;
12424
0
  } else
12425
            /* TODO: Check memory error. */
12426
0
      outSeq = mergeAndClear(outSeq, seq);
12427
0
  break;
12428
12429
#ifdef DEBUG_STEP
12430
  if (seq != NULL)
12431
      nbMatches += seq->nodeNr;
12432
#endif
12433
12434
0
apply_predicates: /* --------------------------------------------------- */
12435
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
12436
0
      goto error;
12437
12438
        /*
12439
  * Apply predicates.
12440
  */
12441
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12442
      /*
12443
      * E.g. when we have a "/foo[some expression][n]".
12444
      */
12445
      /*
12446
      * QUESTION TODO: The old predicate evaluation took into
12447
      *  account location-sets.
12448
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12449
      *  Do we expect such a set here?
12450
      *  All what I learned now from the evaluation semantics
12451
      *  does not indicate that a location-set will be processed
12452
      *  here, so this looks OK.
12453
      */
12454
      /*
12455
      * Iterate over all predicates, starting with the outermost
12456
      * predicate.
12457
      * TODO: Problem: we cannot execute the inner predicates first
12458
      *  since we cannot go back *up* the operator tree!
12459
      *  Options we have:
12460
      *  1) Use of recursive functions (like is it currently done
12461
      *     via xmlXPathCompOpEval())
12462
      *  2) Add a predicate evaluation information stack to the
12463
      *     context struct
12464
      *  3) Change the way the operators are linked; we need a
12465
      *     "parent" field on xmlXPathStepOp
12466
      *
12467
      * For the moment, I'll try to solve this with a recursive
12468
      * function: xmlXPathCompOpEvalPredicate().
12469
      */
12470
0
      if (hasPredicateRange != 0)
12471
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12472
0
              hasNsNodes);
12473
0
      else
12474
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12475
0
              hasNsNodes);
12476
12477
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12478
0
    total = 0;
12479
0
    goto error;
12480
0
      }
12481
0
        }
12482
12483
0
        if (seq->nodeNr > 0) {
12484
      /*
12485
      * Add to result set.
12486
      */
12487
0
      if (outSeq == NULL) {
12488
0
    outSeq = seq;
12489
0
    seq = NULL;
12490
0
      } else {
12491
                /* TODO: Check memory error. */
12492
0
    outSeq = mergeAndClear(outSeq, seq);
12493
0
      }
12494
12495
0
            if (toBool)
12496
0
                break;
12497
0
  }
12498
0
    }
12499
12500
0
error:
12501
0
    if ((obj->boolval) && (obj->user != NULL)) {
12502
  /*
12503
  * QUESTION TODO: What does this do and why?
12504
  * TODO: Do we have to do this also for the "error"
12505
  * cleanup further down?
12506
  */
12507
0
  ctxt->value->boolval = 1;
12508
0
  ctxt->value->user = obj->user;
12509
0
  obj->user = NULL;
12510
0
  obj->boolval = 0;
12511
0
    }
12512
0
    xmlXPathReleaseObject(xpctxt, obj);
12513
12514
    /*
12515
    * Ensure we return at least an empty set.
12516
    */
12517
0
    if (outSeq == NULL) {
12518
0
  if ((seq != NULL) && (seq->nodeNr == 0))
12519
0
      outSeq = seq;
12520
0
  else
12521
            /* TODO: Check memory error. */
12522
0
      outSeq = xmlXPathNodeSetCreate(NULL);
12523
0
    }
12524
0
    if ((seq != NULL) && (seq != outSeq)) {
12525
0
   xmlXPathFreeNodeSet(seq);
12526
0
    }
12527
    /*
12528
    * Hand over the result. Better to push the set also in
12529
    * case of errors.
12530
    */
12531
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12532
    /*
12533
    * Reset the context node.
12534
    */
12535
0
    xpctxt->node = oldContextNode;
12536
    /*
12537
    * When traversing the namespace axis in "toBool" mode, it's
12538
    * possible that tmpNsList wasn't freed.
12539
    */
12540
0
    if (xpctxt->tmpNsList != NULL) {
12541
0
        xmlFree(xpctxt->tmpNsList);
12542
0
        xpctxt->tmpNsList = NULL;
12543
0
    }
12544
12545
#ifdef DEBUG_STEP
12546
    xmlGenericError(xmlGenericErrorContext,
12547
  "\nExamined %d nodes, found %d nodes at that step\n",
12548
  total, nbMatches);
12549
#endif
12550
12551
0
    return(total);
12552
0
}
12553
12554
static int
12555
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12556
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12557
12558
/**
12559
 * xmlXPathCompOpEvalFirst:
12560
 * @ctxt:  the XPath parser context with the compiled expression
12561
 * @op:  an XPath compiled operation
12562
 * @first:  the first elem found so far
12563
 *
12564
 * Evaluate the Precompiled XPath operation searching only the first
12565
 * element in document order
12566
 *
12567
 * Returns the number of examined objects.
12568
 */
12569
static int
12570
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12571
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12572
0
{
12573
0
    int total = 0, cur;
12574
0
    xmlXPathCompExprPtr comp;
12575
0
    xmlXPathObjectPtr arg1, arg2;
12576
12577
0
    CHECK_ERROR0;
12578
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12579
0
        return(0);
12580
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12581
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12582
0
    ctxt->context->depth += 1;
12583
0
    comp = ctxt->comp;
12584
0
    switch (op->op) {
12585
0
        case XPATH_OP_END:
12586
0
            break;
12587
0
        case XPATH_OP_UNION:
12588
0
            total =
12589
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12590
0
                                        first);
12591
0
      CHECK_ERROR0;
12592
0
            if ((ctxt->value != NULL)
12593
0
                && (ctxt->value->type == XPATH_NODESET)
12594
0
                && (ctxt->value->nodesetval != NULL)
12595
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12596
                /*
12597
                 * limit tree traversing to first node in the result
12598
                 */
12599
    /*
12600
    * OPTIMIZE TODO: This implicitly sorts
12601
    *  the result, even if not needed. E.g. if the argument
12602
    *  of the count() function, no sorting is needed.
12603
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12604
    *  already sorted?
12605
    */
12606
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12607
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12608
0
                *first = ctxt->value->nodesetval->nodeTab[0];
12609
0
            }
12610
0
            cur =
12611
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12612
0
                                        first);
12613
0
      CHECK_ERROR0;
12614
12615
0
            arg2 = valuePop(ctxt);
12616
0
            arg1 = valuePop(ctxt);
12617
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12618
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12619
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12620
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12621
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12622
0
            }
12623
0
            if ((ctxt->context->opLimit != 0) &&
12624
0
                (((arg1->nodesetval != NULL) &&
12625
0
                  (xmlXPathCheckOpLimit(ctxt,
12626
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12627
0
                 ((arg2->nodesetval != NULL) &&
12628
0
                  (xmlXPathCheckOpLimit(ctxt,
12629
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12630
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12631
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12632
0
                break;
12633
0
            }
12634
12635
            /* TODO: Check memory error. */
12636
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12637
0
                                                    arg2->nodesetval);
12638
0
            valuePush(ctxt, arg1);
12639
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12640
            /* optimizer */
12641
0
      if (total > cur)
12642
0
    xmlXPathCompSwap(op);
12643
0
            total += cur;
12644
0
            break;
12645
0
        case XPATH_OP_ROOT:
12646
0
            xmlXPathRoot(ctxt);
12647
0
            break;
12648
0
        case XPATH_OP_NODE:
12649
0
            if (op->ch1 != -1)
12650
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12651
0
      CHECK_ERROR0;
12652
0
            if (op->ch2 != -1)
12653
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12654
0
      CHECK_ERROR0;
12655
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12656
0
    ctxt->context->node));
12657
0
            break;
12658
0
        case XPATH_OP_COLLECT:{
12659
0
                if (op->ch1 == -1)
12660
0
                    break;
12661
12662
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12663
0
    CHECK_ERROR0;
12664
12665
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12666
0
                break;
12667
0
            }
12668
0
        case XPATH_OP_VALUE:
12669
0
            valuePush(ctxt,
12670
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12671
0
      (xmlXPathObjectPtr) op->value4));
12672
0
            break;
12673
0
        case XPATH_OP_SORT:
12674
0
            if (op->ch1 != -1)
12675
0
                total +=
12676
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12677
0
                                            first);
12678
0
      CHECK_ERROR0;
12679
0
            if ((ctxt->value != NULL)
12680
0
                && (ctxt->value->type == XPATH_NODESET)
12681
0
                && (ctxt->value->nodesetval != NULL)
12682
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12683
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12684
0
            break;
12685
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12686
0
  case XPATH_OP_FILTER:
12687
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12688
0
            break;
12689
0
#endif
12690
0
        default:
12691
0
            total += xmlXPathCompOpEval(ctxt, op);
12692
0
            break;
12693
0
    }
12694
12695
0
    ctxt->context->depth -= 1;
12696
0
    return(total);
12697
0
}
12698
12699
/**
12700
 * xmlXPathCompOpEvalLast:
12701
 * @ctxt:  the XPath parser context with the compiled expression
12702
 * @op:  an XPath compiled operation
12703
 * @last:  the last elem found so far
12704
 *
12705
 * Evaluate the Precompiled XPath operation searching only the last
12706
 * element in document order
12707
 *
12708
 * Returns the number of nodes traversed
12709
 */
12710
static int
12711
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12712
                       xmlNodePtr * last)
12713
0
{
12714
0
    int total = 0, cur;
12715
0
    xmlXPathCompExprPtr comp;
12716
0
    xmlXPathObjectPtr arg1, arg2;
12717
12718
0
    CHECK_ERROR0;
12719
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12720
0
        return(0);
12721
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12722
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12723
0
    ctxt->context->depth += 1;
12724
0
    comp = ctxt->comp;
12725
0
    switch (op->op) {
12726
0
        case XPATH_OP_END:
12727
0
            break;
12728
0
        case XPATH_OP_UNION:
12729
0
            total =
12730
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12731
0
      CHECK_ERROR0;
12732
0
            if ((ctxt->value != NULL)
12733
0
                && (ctxt->value->type == XPATH_NODESET)
12734
0
                && (ctxt->value->nodesetval != NULL)
12735
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12736
                /*
12737
                 * limit tree traversing to first node in the result
12738
                 */
12739
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12740
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12741
0
                *last =
12742
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12743
0
                                                     nodesetval->nodeNr -
12744
0
                                                     1];
12745
0
            }
12746
0
            cur =
12747
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12748
0
      CHECK_ERROR0;
12749
0
            if ((ctxt->value != NULL)
12750
0
                && (ctxt->value->type == XPATH_NODESET)
12751
0
                && (ctxt->value->nodesetval != NULL)
12752
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12753
0
            }
12754
12755
0
            arg2 = valuePop(ctxt);
12756
0
            arg1 = valuePop(ctxt);
12757
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12758
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12759
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12760
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12761
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12762
0
            }
12763
0
            if ((ctxt->context->opLimit != 0) &&
12764
0
                (((arg1->nodesetval != NULL) &&
12765
0
                  (xmlXPathCheckOpLimit(ctxt,
12766
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12767
0
                 ((arg2->nodesetval != NULL) &&
12768
0
                  (xmlXPathCheckOpLimit(ctxt,
12769
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12770
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12771
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12772
0
                break;
12773
0
            }
12774
12775
            /* TODO: Check memory error. */
12776
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12777
0
                                                    arg2->nodesetval);
12778
0
            valuePush(ctxt, arg1);
12779
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12780
            /* optimizer */
12781
0
      if (total > cur)
12782
0
    xmlXPathCompSwap(op);
12783
0
            total += cur;
12784
0
            break;
12785
0
        case XPATH_OP_ROOT:
12786
0
            xmlXPathRoot(ctxt);
12787
0
            break;
12788
0
        case XPATH_OP_NODE:
12789
0
            if (op->ch1 != -1)
12790
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12791
0
      CHECK_ERROR0;
12792
0
            if (op->ch2 != -1)
12793
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12794
0
      CHECK_ERROR0;
12795
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12796
0
    ctxt->context->node));
12797
0
            break;
12798
0
        case XPATH_OP_COLLECT:{
12799
0
                if (op->ch1 == -1)
12800
0
                    break;
12801
12802
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12803
0
    CHECK_ERROR0;
12804
12805
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12806
0
                break;
12807
0
            }
12808
0
        case XPATH_OP_VALUE:
12809
0
            valuePush(ctxt,
12810
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12811
0
      (xmlXPathObjectPtr) op->value4));
12812
0
            break;
12813
0
        case XPATH_OP_SORT:
12814
0
            if (op->ch1 != -1)
12815
0
                total +=
12816
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12817
0
                                           last);
12818
0
      CHECK_ERROR0;
12819
0
            if ((ctxt->value != NULL)
12820
0
                && (ctxt->value->type == XPATH_NODESET)
12821
0
                && (ctxt->value->nodesetval != NULL)
12822
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12823
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12824
0
            break;
12825
0
        default:
12826
0
            total += xmlXPathCompOpEval(ctxt, op);
12827
0
            break;
12828
0
    }
12829
12830
0
    ctxt->context->depth -= 1;
12831
0
    return (total);
12832
0
}
12833
12834
#ifdef XP_OPTIMIZED_FILTER_FIRST
12835
static int
12836
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12837
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12838
0
{
12839
0
    int total = 0;
12840
0
    xmlXPathCompExprPtr comp;
12841
0
    xmlXPathObjectPtr obj;
12842
0
    xmlNodeSetPtr set;
12843
12844
0
    CHECK_ERROR0;
12845
0
    comp = ctxt->comp;
12846
    /*
12847
    * Optimization for ()[last()] selection i.e. the last elem
12848
    */
12849
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12850
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12851
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12852
0
  int f = comp->steps[op->ch2].ch1;
12853
12854
0
  if ((f != -1) &&
12855
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12856
0
      (comp->steps[f].value5 == NULL) &&
12857
0
      (comp->steps[f].value == 0) &&
12858
0
      (comp->steps[f].value4 != NULL) &&
12859
0
      (xmlStrEqual
12860
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
12861
0
      xmlNodePtr last = NULL;
12862
12863
0
      total +=
12864
0
    xmlXPathCompOpEvalLast(ctxt,
12865
0
        &comp->steps[op->ch1],
12866
0
        &last);
12867
0
      CHECK_ERROR0;
12868
      /*
12869
      * The nodeset should be in document order,
12870
      * Keep only the last value
12871
      */
12872
0
      if ((ctxt->value != NULL) &&
12873
0
    (ctxt->value->type == XPATH_NODESET) &&
12874
0
    (ctxt->value->nodesetval != NULL) &&
12875
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12876
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
12877
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12878
0
    *first = *(ctxt->value->nodesetval->nodeTab);
12879
0
      }
12880
0
      return (total);
12881
0
  }
12882
0
    }
12883
12884
0
    if (op->ch1 != -1)
12885
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12886
0
    CHECK_ERROR0;
12887
0
    if (op->ch2 == -1)
12888
0
  return (total);
12889
0
    if (ctxt->value == NULL)
12890
0
  return (total);
12891
12892
#ifdef LIBXML_XPTR_LOCS_ENABLED
12893
    /*
12894
    * Hum are we filtering the result of an XPointer expression
12895
    */
12896
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12897
        xmlLocationSetPtr locset = ctxt->value->user;
12898
12899
        if (locset != NULL) {
12900
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12901
            if (locset->locNr > 0)
12902
                *first = (xmlNodePtr) locset->locTab[0]->user;
12903
        }
12904
12905
  return (total);
12906
    }
12907
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12908
12909
    /*
12910
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12911
     * the stack. We have to temporarily remove the nodeset object from the
12912
     * stack to avoid freeing it prematurely.
12913
     */
12914
0
    CHECK_TYPE0(XPATH_NODESET);
12915
0
    obj = valuePop(ctxt);
12916
0
    set = obj->nodesetval;
12917
0
    if (set != NULL) {
12918
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12919
0
        if (set->nodeNr > 0)
12920
0
            *first = set->nodeTab[0];
12921
0
    }
12922
0
    valuePush(ctxt, obj);
12923
12924
0
    return (total);
12925
0
}
12926
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12927
12928
/**
12929
 * xmlXPathCompOpEval:
12930
 * @ctxt:  the XPath parser context with the compiled expression
12931
 * @op:  an XPath compiled operation
12932
 *
12933
 * Evaluate the Precompiled XPath operation
12934
 * Returns the number of nodes traversed
12935
 */
12936
static int
12937
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12938
0
{
12939
0
    int total = 0;
12940
0
    int equal, ret;
12941
0
    xmlXPathCompExprPtr comp;
12942
0
    xmlXPathObjectPtr arg1, arg2;
12943
12944
0
    CHECK_ERROR0;
12945
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12946
0
        return(0);
12947
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12948
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12949
0
    ctxt->context->depth += 1;
12950
0
    comp = ctxt->comp;
12951
0
    switch (op->op) {
12952
0
        case XPATH_OP_END:
12953
0
            break;
12954
0
        case XPATH_OP_AND:
12955
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12956
0
      CHECK_ERROR0;
12957
0
            xmlXPathBooleanFunction(ctxt, 1);
12958
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12959
0
                break;
12960
0
            arg2 = valuePop(ctxt);
12961
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12962
0
      if (ctxt->error) {
12963
0
    xmlXPathFreeObject(arg2);
12964
0
    break;
12965
0
      }
12966
0
            xmlXPathBooleanFunction(ctxt, 1);
12967
0
            if (ctxt->value != NULL)
12968
0
                ctxt->value->boolval &= arg2->boolval;
12969
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12970
0
            break;
12971
0
        case XPATH_OP_OR:
12972
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12973
0
      CHECK_ERROR0;
12974
0
            xmlXPathBooleanFunction(ctxt, 1);
12975
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12976
0
                break;
12977
0
            arg2 = valuePop(ctxt);
12978
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12979
0
      if (ctxt->error) {
12980
0
    xmlXPathFreeObject(arg2);
12981
0
    break;
12982
0
      }
12983
0
            xmlXPathBooleanFunction(ctxt, 1);
12984
0
            if (ctxt->value != NULL)
12985
0
                ctxt->value->boolval |= arg2->boolval;
12986
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12987
0
            break;
12988
0
        case XPATH_OP_EQUAL:
12989
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12990
0
      CHECK_ERROR0;
12991
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12992
0
      CHECK_ERROR0;
12993
0
      if (op->value)
12994
0
    equal = xmlXPathEqualValues(ctxt);
12995
0
      else
12996
0
    equal = xmlXPathNotEqualValues(ctxt);
12997
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12998
0
            break;
12999
0
        case XPATH_OP_CMP:
13000
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13001
0
      CHECK_ERROR0;
13002
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13003
0
      CHECK_ERROR0;
13004
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13005
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13006
0
            break;
13007
0
        case XPATH_OP_PLUS:
13008
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13009
0
      CHECK_ERROR0;
13010
0
            if (op->ch2 != -1) {
13011
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13012
0
      }
13013
0
      CHECK_ERROR0;
13014
0
            if (op->value == 0)
13015
0
                xmlXPathSubValues(ctxt);
13016
0
            else if (op->value == 1)
13017
0
                xmlXPathAddValues(ctxt);
13018
0
            else if (op->value == 2)
13019
0
                xmlXPathValueFlipSign(ctxt);
13020
0
            else if (op->value == 3) {
13021
0
                CAST_TO_NUMBER;
13022
0
                CHECK_TYPE0(XPATH_NUMBER);
13023
0
            }
13024
0
            break;
13025
0
        case XPATH_OP_MULT:
13026
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13027
0
      CHECK_ERROR0;
13028
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13029
0
      CHECK_ERROR0;
13030
0
            if (op->value == 0)
13031
0
                xmlXPathMultValues(ctxt);
13032
0
            else if (op->value == 1)
13033
0
                xmlXPathDivValues(ctxt);
13034
0
            else if (op->value == 2)
13035
0
                xmlXPathModValues(ctxt);
13036
0
            break;
13037
0
        case XPATH_OP_UNION:
13038
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13039
0
      CHECK_ERROR0;
13040
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13041
0
      CHECK_ERROR0;
13042
13043
0
            arg2 = valuePop(ctxt);
13044
0
            arg1 = valuePop(ctxt);
13045
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13046
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13047
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13048
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13049
0
                XP_ERROR0(XPATH_INVALID_TYPE);
13050
0
            }
13051
0
            if ((ctxt->context->opLimit != 0) &&
13052
0
                (((arg1->nodesetval != NULL) &&
13053
0
                  (xmlXPathCheckOpLimit(ctxt,
13054
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
13055
0
                 ((arg2->nodesetval != NULL) &&
13056
0
                  (xmlXPathCheckOpLimit(ctxt,
13057
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
13058
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13059
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13060
0
                break;
13061
0
            }
13062
13063
0
      if ((arg1->nodesetval == NULL) ||
13064
0
    ((arg2->nodesetval != NULL) &&
13065
0
     (arg2->nodesetval->nodeNr != 0)))
13066
0
      {
13067
                /* TODO: Check memory error. */
13068
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13069
0
              arg2->nodesetval);
13070
0
      }
13071
13072
0
            valuePush(ctxt, arg1);
13073
0
      xmlXPathReleaseObject(ctxt->context, arg2);
13074
0
            break;
13075
0
        case XPATH_OP_ROOT:
13076
0
            xmlXPathRoot(ctxt);
13077
0
            break;
13078
0
        case XPATH_OP_NODE:
13079
0
            if (op->ch1 != -1)
13080
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13081
0
      CHECK_ERROR0;
13082
0
            if (op->ch2 != -1)
13083
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13084
0
      CHECK_ERROR0;
13085
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13086
0
    ctxt->context->node));
13087
0
            break;
13088
0
        case XPATH_OP_COLLECT:{
13089
0
                if (op->ch1 == -1)
13090
0
                    break;
13091
13092
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13093
0
    CHECK_ERROR0;
13094
13095
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13096
0
                break;
13097
0
            }
13098
0
        case XPATH_OP_VALUE:
13099
0
            valuePush(ctxt,
13100
0
                      xmlXPathCacheObjectCopy(ctxt->context,
13101
0
      (xmlXPathObjectPtr) op->value4));
13102
0
            break;
13103
0
        case XPATH_OP_VARIABLE:{
13104
0
    xmlXPathObjectPtr val;
13105
13106
0
                if (op->ch1 != -1)
13107
0
                    total +=
13108
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13109
0
                if (op->value5 == NULL) {
13110
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13111
0
        if (val == NULL)
13112
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13113
0
                    valuePush(ctxt, val);
13114
0
    } else {
13115
0
                    const xmlChar *URI;
13116
13117
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13118
0
                    if (URI == NULL) {
13119
0
                        xmlGenericError(xmlGenericErrorContext,
13120
0
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13121
0
                                    (char *) op->value4, (char *)op->value5);
13122
0
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13123
0
                        break;
13124
0
                    }
13125
0
        val = xmlXPathVariableLookupNS(ctxt->context,
13126
0
                                                       op->value4, URI);
13127
0
        if (val == NULL)
13128
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13129
0
                    valuePush(ctxt, val);
13130
0
                }
13131
0
                break;
13132
0
            }
13133
0
        case XPATH_OP_FUNCTION:{
13134
0
                xmlXPathFunction func;
13135
0
                const xmlChar *oldFunc, *oldFuncURI;
13136
0
    int i;
13137
0
                int frame;
13138
13139
0
                frame = ctxt->valueNr;
13140
0
                if (op->ch1 != -1) {
13141
0
                    total +=
13142
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13143
0
                    if (ctxt->error != XPATH_EXPRESSION_OK)
13144
0
                        break;
13145
0
                }
13146
0
    if (ctxt->valueNr < frame + op->value) {
13147
0
        xmlGenericError(xmlGenericErrorContext,
13148
0
          "xmlXPathCompOpEval: parameter error\n");
13149
0
        ctxt->error = XPATH_INVALID_OPERAND;
13150
0
        break;
13151
0
    }
13152
0
    for (i = 0; i < op->value; i++) {
13153
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13154
0
      xmlGenericError(xmlGenericErrorContext,
13155
0
        "xmlXPathCompOpEval: parameter error\n");
13156
0
      ctxt->error = XPATH_INVALID_OPERAND;
13157
0
      break;
13158
0
        }
13159
0
                }
13160
0
                if (op->cache != NULL)
13161
0
                    func = op->cache;
13162
0
                else {
13163
0
                    const xmlChar *URI = NULL;
13164
13165
0
                    if (op->value5 == NULL)
13166
0
                        func =
13167
0
                            xmlXPathFunctionLookup(ctxt->context,
13168
0
                                                   op->value4);
13169
0
                    else {
13170
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13171
0
                        if (URI == NULL) {
13172
0
                            xmlGenericError(xmlGenericErrorContext,
13173
0
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13174
0
                                    (char *)op->value4, (char *)op->value5);
13175
0
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13176
0
                            break;
13177
0
                        }
13178
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13179
0
                                                        op->value4, URI);
13180
0
                    }
13181
0
                    if (func == NULL) {
13182
0
                        xmlGenericError(xmlGenericErrorContext,
13183
0
                                "xmlXPathCompOpEval: function %s not found\n",
13184
0
                                        (char *)op->value4);
13185
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13186
0
                    }
13187
0
                    op->cache = func;
13188
0
                    op->cacheURI = (void *) URI;
13189
0
                }
13190
0
                oldFunc = ctxt->context->function;
13191
0
                oldFuncURI = ctxt->context->functionURI;
13192
0
                ctxt->context->function = op->value4;
13193
0
                ctxt->context->functionURI = op->cacheURI;
13194
0
                func(ctxt, op->value);
13195
0
                ctxt->context->function = oldFunc;
13196
0
                ctxt->context->functionURI = oldFuncURI;
13197
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13198
0
                    (ctxt->valueNr != frame + 1))
13199
0
                    XP_ERROR0(XPATH_STACK_ERROR);
13200
0
                break;
13201
0
            }
13202
0
        case XPATH_OP_ARG:
13203
0
            if (op->ch1 != -1) {
13204
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13205
0
          CHECK_ERROR0;
13206
0
            }
13207
0
            if (op->ch2 != -1) {
13208
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13209
0
          CHECK_ERROR0;
13210
0
      }
13211
0
            break;
13212
0
        case XPATH_OP_PREDICATE:
13213
0
        case XPATH_OP_FILTER:{
13214
0
                xmlXPathObjectPtr obj;
13215
0
                xmlNodeSetPtr set;
13216
13217
                /*
13218
                 * Optimization for ()[1] selection i.e. the first elem
13219
                 */
13220
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13221
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
13222
        /*
13223
        * FILTER TODO: Can we assume that the inner processing
13224
        *  will result in an ordered list if we have an
13225
        *  XPATH_OP_FILTER?
13226
        *  What about an additional field or flag on
13227
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13228
        *  to assume anything, so it would be more robust and
13229
        *  easier to optimize.
13230
        */
13231
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13232
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13233
#else
13234
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13235
#endif
13236
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13237
0
                    xmlXPathObjectPtr val;
13238
13239
0
                    val = comp->steps[op->ch2].value4;
13240
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13241
0
                        (val->floatval == 1.0)) {
13242
0
                        xmlNodePtr first = NULL;
13243
13244
0
                        total +=
13245
0
                            xmlXPathCompOpEvalFirst(ctxt,
13246
0
                                                    &comp->steps[op->ch1],
13247
0
                                                    &first);
13248
0
      CHECK_ERROR0;
13249
                        /*
13250
                         * The nodeset should be in document order,
13251
                         * Keep only the first value
13252
                         */
13253
0
                        if ((ctxt->value != NULL) &&
13254
0
                            (ctxt->value->type == XPATH_NODESET) &&
13255
0
                            (ctxt->value->nodesetval != NULL) &&
13256
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13257
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13258
0
                                                        1, 1);
13259
0
                        break;
13260
0
                    }
13261
0
                }
13262
                /*
13263
                 * Optimization for ()[last()] selection i.e. the last elem
13264
                 */
13265
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13266
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13267
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13268
0
                    int f = comp->steps[op->ch2].ch1;
13269
13270
0
                    if ((f != -1) &&
13271
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13272
0
                        (comp->steps[f].value5 == NULL) &&
13273
0
                        (comp->steps[f].value == 0) &&
13274
0
                        (comp->steps[f].value4 != NULL) &&
13275
0
                        (xmlStrEqual
13276
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13277
0
                        xmlNodePtr last = NULL;
13278
13279
0
                        total +=
13280
0
                            xmlXPathCompOpEvalLast(ctxt,
13281
0
                                                   &comp->steps[op->ch1],
13282
0
                                                   &last);
13283
0
      CHECK_ERROR0;
13284
                        /*
13285
                         * The nodeset should be in document order,
13286
                         * Keep only the last value
13287
                         */
13288
0
                        if ((ctxt->value != NULL) &&
13289
0
                            (ctxt->value->type == XPATH_NODESET) &&
13290
0
                            (ctxt->value->nodesetval != NULL) &&
13291
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13292
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13293
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13294
0
                        break;
13295
0
                    }
13296
0
                }
13297
    /*
13298
    * Process inner predicates first.
13299
    * Example "index[parent::book][1]":
13300
    * ...
13301
    *   PREDICATE   <-- we are here "[1]"
13302
    *     PREDICATE <-- process "[parent::book]" first
13303
    *       SORT
13304
    *         COLLECT  'parent' 'name' 'node' book
13305
    *           NODE
13306
    *     ELEM Object is a number : 1
13307
    */
13308
0
                if (op->ch1 != -1)
13309
0
                    total +=
13310
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13311
0
    CHECK_ERROR0;
13312
0
                if (op->ch2 == -1)
13313
0
                    break;
13314
0
                if (ctxt->value == NULL)
13315
0
                    break;
13316
13317
#ifdef LIBXML_XPTR_LOCS_ENABLED
13318
                /*
13319
                 * Hum are we filtering the result of an XPointer expression
13320
                 */
13321
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13322
                    xmlLocationSetPtr locset = ctxt->value->user;
13323
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13324
                                              1, locset->locNr);
13325
                    break;
13326
                }
13327
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13328
13329
                /*
13330
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
13331
                 * nodes from the stack. We have to temporarily remove the
13332
                 * nodeset object from the stack to avoid freeing it
13333
                 * prematurely.
13334
                 */
13335
0
                CHECK_TYPE0(XPATH_NODESET);
13336
0
                obj = valuePop(ctxt);
13337
0
                set = obj->nodesetval;
13338
0
                if (set != NULL)
13339
0
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13340
0
                                          1, set->nodeNr, 1);
13341
0
                valuePush(ctxt, obj);
13342
0
                break;
13343
0
            }
13344
0
        case XPATH_OP_SORT:
13345
0
            if (op->ch1 != -1)
13346
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13347
0
      CHECK_ERROR0;
13348
0
            if ((ctxt->value != NULL) &&
13349
0
                (ctxt->value->type == XPATH_NODESET) &&
13350
0
                (ctxt->value->nodesetval != NULL) &&
13351
0
    (ctxt->value->nodesetval->nodeNr > 1))
13352
0
      {
13353
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13354
0
      }
13355
0
            break;
13356
#ifdef LIBXML_XPTR_LOCS_ENABLED
13357
        case XPATH_OP_RANGETO:{
13358
                xmlXPathObjectPtr range;
13359
                xmlXPathObjectPtr res, obj;
13360
                xmlXPathObjectPtr tmp;
13361
                xmlLocationSetPtr newlocset = NULL;
13362
        xmlLocationSetPtr oldlocset;
13363
                xmlNodeSetPtr oldset;
13364
                xmlNodePtr oldnode = ctxt->context->node;
13365
                int oldcs = ctxt->context->contextSize;
13366
                int oldpp = ctxt->context->proximityPosition;
13367
                int i, j;
13368
13369
                if (op->ch1 != -1) {
13370
                    total +=
13371
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13372
                    CHECK_ERROR0;
13373
                }
13374
                if (ctxt->value == NULL) {
13375
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13376
                }
13377
                if (op->ch2 == -1)
13378
                    break;
13379
13380
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13381
                    /*
13382
                     * Extract the old locset, and then evaluate the result of the
13383
                     * expression for all the element in the locset. use it to grow
13384
                     * up a new locset.
13385
                     */
13386
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13387
13388
                    if ((ctxt->value->user == NULL) ||
13389
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13390
                        break;
13391
13392
                    obj = valuePop(ctxt);
13393
                    oldlocset = obj->user;
13394
13395
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13396
13397
                    for (i = 0; i < oldlocset->locNr; i++) {
13398
                        /*
13399
                         * Run the evaluation with a node list made of a
13400
                         * single item in the nodelocset.
13401
                         */
13402
                        ctxt->context->node = oldlocset->locTab[i]->user;
13403
                        ctxt->context->contextSize = oldlocset->locNr;
13404
                        ctxt->context->proximityPosition = i + 1;
13405
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13406
          ctxt->context->node);
13407
                        valuePush(ctxt, tmp);
13408
13409
                        if (op->ch2 != -1)
13410
                            total +=
13411
                                xmlXPathCompOpEval(ctxt,
13412
                                                   &comp->steps[op->ch2]);
13413
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13414
                            xmlXPtrFreeLocationSet(newlocset);
13415
                            goto rangeto_error;
13416
      }
13417
13418
                        res = valuePop(ctxt);
13419
      if (res->type == XPATH_LOCATIONSET) {
13420
          xmlLocationSetPtr rloc =
13421
              (xmlLocationSetPtr)res->user;
13422
          for (j=0; j<rloc->locNr; j++) {
13423
              range = xmlXPtrNewRange(
13424
          oldlocset->locTab[i]->user,
13425
          oldlocset->locTab[i]->index,
13426
          rloc->locTab[j]->user2,
13427
          rloc->locTab[j]->index2);
13428
        if (range != NULL) {
13429
            xmlXPtrLocationSetAdd(newlocset, range);
13430
        }
13431
          }
13432
      } else {
13433
          range = xmlXPtrNewRangeNodeObject(
13434
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13435
                            if (range != NULL) {
13436
                                xmlXPtrLocationSetAdd(newlocset,range);
13437
          }
13438
                        }
13439
13440
                        /*
13441
                         * Cleanup
13442
                         */
13443
                        if (res != NULL) {
13444
          xmlXPathReleaseObject(ctxt->context, res);
13445
      }
13446
                        if (ctxt->value == tmp) {
13447
                            res = valuePop(ctxt);
13448
          xmlXPathReleaseObject(ctxt->context, res);
13449
                        }
13450
                    }
13451
    } else {  /* Not a location set */
13452
                    CHECK_TYPE0(XPATH_NODESET);
13453
                    obj = valuePop(ctxt);
13454
                    oldset = obj->nodesetval;
13455
13456
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13457
13458
                    if (oldset != NULL) {
13459
                        for (i = 0; i < oldset->nodeNr; i++) {
13460
                            /*
13461
                             * Run the evaluation with a node list made of a single item
13462
                             * in the nodeset.
13463
                             */
13464
                            ctxt->context->node = oldset->nodeTab[i];
13465
          /*
13466
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13467
          */
13468
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13469
        ctxt->context->node);
13470
                            valuePush(ctxt, tmp);
13471
13472
                            if (op->ch2 != -1)
13473
                                total +=
13474
                                    xmlXPathCompOpEval(ctxt,
13475
                                                   &comp->steps[op->ch2]);
13476
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13477
                                xmlXPtrFreeLocationSet(newlocset);
13478
                                goto rangeto_error;
13479
          }
13480
13481
                            res = valuePop(ctxt);
13482
                            range =
13483
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13484
                                                      res);
13485
                            if (range != NULL) {
13486
                                xmlXPtrLocationSetAdd(newlocset, range);
13487
                            }
13488
13489
                            /*
13490
                             * Cleanup
13491
                             */
13492
                            if (res != NULL) {
13493
        xmlXPathReleaseObject(ctxt->context, res);
13494
          }
13495
                            if (ctxt->value == tmp) {
13496
                                res = valuePop(ctxt);
13497
        xmlXPathReleaseObject(ctxt->context, res);
13498
                            }
13499
                        }
13500
                    }
13501
                }
13502
13503
                /*
13504
                 * The result is used as the new evaluation set.
13505
                 */
13506
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13507
rangeto_error:
13508
    xmlXPathReleaseObject(ctxt->context, obj);
13509
                ctxt->context->node = oldnode;
13510
                ctxt->context->contextSize = oldcs;
13511
                ctxt->context->proximityPosition = oldpp;
13512
                break;
13513
            }
13514
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13515
0
        default:
13516
0
            xmlGenericError(xmlGenericErrorContext,
13517
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13518
0
            ctxt->error = XPATH_INVALID_OPERAND;
13519
0
            break;
13520
0
    }
13521
13522
0
    ctxt->context->depth -= 1;
13523
0
    return (total);
13524
0
}
13525
13526
/**
13527
 * xmlXPathCompOpEvalToBoolean:
13528
 * @ctxt:  the XPath parser context
13529
 *
13530
 * Evaluates if the expression evaluates to true.
13531
 *
13532
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13533
 */
13534
static int
13535
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13536
          xmlXPathStepOpPtr op,
13537
          int isPredicate)
13538
0
{
13539
0
    xmlXPathObjectPtr resObj = NULL;
13540
13541
0
start:
13542
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13543
0
        return(0);
13544
    /* comp = ctxt->comp; */
13545
0
    switch (op->op) {
13546
0
        case XPATH_OP_END:
13547
0
            return (0);
13548
0
  case XPATH_OP_VALUE:
13549
0
      resObj = (xmlXPathObjectPtr) op->value4;
13550
0
      if (isPredicate)
13551
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13552
0
      return(xmlXPathCastToBoolean(resObj));
13553
0
  case XPATH_OP_SORT:
13554
      /*
13555
      * We don't need sorting for boolean results. Skip this one.
13556
      */
13557
0
            if (op->ch1 != -1) {
13558
0
    op = &ctxt->comp->steps[op->ch1];
13559
0
    goto start;
13560
0
      }
13561
0
      return(0);
13562
0
  case XPATH_OP_COLLECT:
13563
0
      if (op->ch1 == -1)
13564
0
    return(0);
13565
13566
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13567
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13568
0
    return(-1);
13569
13570
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13571
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13572
0
    return(-1);
13573
13574
0
      resObj = valuePop(ctxt);
13575
0
      if (resObj == NULL)
13576
0
    return(-1);
13577
0
      break;
13578
0
  default:
13579
      /*
13580
      * Fallback to call xmlXPathCompOpEval().
13581
      */
13582
0
      xmlXPathCompOpEval(ctxt, op);
13583
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13584
0
    return(-1);
13585
13586
0
      resObj = valuePop(ctxt);
13587
0
      if (resObj == NULL)
13588
0
    return(-1);
13589
0
      break;
13590
0
    }
13591
13592
0
    if (resObj) {
13593
0
  int res;
13594
13595
0
  if (resObj->type == XPATH_BOOLEAN) {
13596
0
      res = resObj->boolval;
13597
0
  } else if (isPredicate) {
13598
      /*
13599
      * For predicates a result of type "number" is handled
13600
      * differently:
13601
      * SPEC XPath 1.0:
13602
      * "If the result is a number, the result will be converted
13603
      *  to true if the number is equal to the context position
13604
      *  and will be converted to false otherwise;"
13605
      */
13606
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13607
0
  } else {
13608
0
      res = xmlXPathCastToBoolean(resObj);
13609
0
  }
13610
0
  xmlXPathReleaseObject(ctxt->context, resObj);
13611
0
  return(res);
13612
0
    }
13613
13614
0
    return(0);
13615
0
}
13616
13617
#ifdef XPATH_STREAMING
13618
/**
13619
 * xmlXPathRunStreamEval:
13620
 * @ctxt:  the XPath parser context with the compiled expression
13621
 *
13622
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13623
 */
13624
static int
13625
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13626
          xmlXPathObjectPtr *resultSeq, int toBool)
13627
0
{
13628
0
    int max_depth, min_depth;
13629
0
    int from_root;
13630
0
    int ret, depth;
13631
0
    int eval_all_nodes;
13632
0
    xmlNodePtr cur = NULL, limit = NULL;
13633
0
    xmlStreamCtxtPtr patstream = NULL;
13634
13635
0
    if ((ctxt == NULL) || (comp == NULL))
13636
0
        return(-1);
13637
0
    max_depth = xmlPatternMaxDepth(comp);
13638
0
    if (max_depth == -1)
13639
0
        return(-1);
13640
0
    if (max_depth == -2)
13641
0
        max_depth = 10000;
13642
0
    min_depth = xmlPatternMinDepth(comp);
13643
0
    if (min_depth == -1)
13644
0
        return(-1);
13645
0
    from_root = xmlPatternFromRoot(comp);
13646
0
    if (from_root < 0)
13647
0
        return(-1);
13648
#if 0
13649
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13650
#endif
13651
13652
0
    if (! toBool) {
13653
0
  if (resultSeq == NULL)
13654
0
      return(-1);
13655
0
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13656
0
  if (*resultSeq == NULL)
13657
0
      return(-1);
13658
0
    }
13659
13660
    /*
13661
     * handle the special cases of "/" amd "." being matched
13662
     */
13663
0
    if (min_depth == 0) {
13664
0
  if (from_root) {
13665
      /* Select "/" */
13666
0
      if (toBool)
13667
0
    return(1);
13668
            /* TODO: Check memory error. */
13669
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13670
0
                         (xmlNodePtr) ctxt->doc);
13671
0
  } else {
13672
      /* Select "self::node()" */
13673
0
      if (toBool)
13674
0
    return(1);
13675
            /* TODO: Check memory error. */
13676
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13677
0
  }
13678
0
    }
13679
0
    if (max_depth == 0) {
13680
0
  return(0);
13681
0
    }
13682
13683
0
    if (from_root) {
13684
0
        cur = (xmlNodePtr)ctxt->doc;
13685
0
    } else if (ctxt->node != NULL) {
13686
0
        switch (ctxt->node->type) {
13687
0
            case XML_ELEMENT_NODE:
13688
0
            case XML_DOCUMENT_NODE:
13689
0
            case XML_DOCUMENT_FRAG_NODE:
13690
0
            case XML_HTML_DOCUMENT_NODE:
13691
0
          cur = ctxt->node;
13692
0
    break;
13693
0
            case XML_ATTRIBUTE_NODE:
13694
0
            case XML_TEXT_NODE:
13695
0
            case XML_CDATA_SECTION_NODE:
13696
0
            case XML_ENTITY_REF_NODE:
13697
0
            case XML_ENTITY_NODE:
13698
0
            case XML_PI_NODE:
13699
0
            case XML_COMMENT_NODE:
13700
0
            case XML_NOTATION_NODE:
13701
0
            case XML_DTD_NODE:
13702
0
            case XML_DOCUMENT_TYPE_NODE:
13703
0
            case XML_ELEMENT_DECL:
13704
0
            case XML_ATTRIBUTE_DECL:
13705
0
            case XML_ENTITY_DECL:
13706
0
            case XML_NAMESPACE_DECL:
13707
0
            case XML_XINCLUDE_START:
13708
0
            case XML_XINCLUDE_END:
13709
0
    break;
13710
0
  }
13711
0
  limit = cur;
13712
0
    }
13713
0
    if (cur == NULL) {
13714
0
        return(0);
13715
0
    }
13716
13717
0
    patstream = xmlPatternGetStreamCtxt(comp);
13718
0
    if (patstream == NULL) {
13719
  /*
13720
  * QUESTION TODO: Is this an error?
13721
  */
13722
0
  return(0);
13723
0
    }
13724
13725
0
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13726
13727
0
    if (from_root) {
13728
0
  ret = xmlStreamPush(patstream, NULL, NULL);
13729
0
  if (ret < 0) {
13730
0
  } else if (ret == 1) {
13731
0
      if (toBool)
13732
0
    goto return_1;
13733
            /* TODO: Check memory error. */
13734
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13735
0
  }
13736
0
    }
13737
0
    depth = 0;
13738
0
    goto scan_children;
13739
0
next_node:
13740
0
    do {
13741
0
        if (ctxt->opLimit != 0) {
13742
0
            if (ctxt->opCount >= ctxt->opLimit) {
13743
0
                xmlGenericError(xmlGenericErrorContext,
13744
0
                        "XPath operation limit exceeded\n");
13745
0
                xmlFreeStreamCtxt(patstream);
13746
0
                return(-1);
13747
0
            }
13748
0
            ctxt->opCount++;
13749
0
        }
13750
13751
0
  switch (cur->type) {
13752
0
      case XML_ELEMENT_NODE:
13753
0
      case XML_TEXT_NODE:
13754
0
      case XML_CDATA_SECTION_NODE:
13755
0
      case XML_COMMENT_NODE:
13756
0
      case XML_PI_NODE:
13757
0
    if (cur->type == XML_ELEMENT_NODE) {
13758
0
        ret = xmlStreamPush(patstream, cur->name,
13759
0
        (cur->ns ? cur->ns->href : NULL));
13760
0
    } else if (eval_all_nodes)
13761
0
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13762
0
    else
13763
0
        break;
13764
13765
0
    if (ret < 0) {
13766
        /* NOP. */
13767
0
    } else if (ret == 1) {
13768
0
        if (toBool)
13769
0
      goto return_1;
13770
0
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13771
0
            < 0) {
13772
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13773
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13774
0
        }
13775
0
    }
13776
0
    if ((cur->children == NULL) || (depth >= max_depth)) {
13777
0
        ret = xmlStreamPop(patstream);
13778
0
        while (cur->next != NULL) {
13779
0
      cur = cur->next;
13780
0
      if ((cur->type != XML_ENTITY_DECL) &&
13781
0
          (cur->type != XML_DTD_NODE))
13782
0
          goto next_node;
13783
0
        }
13784
0
    }
13785
0
      default:
13786
0
    break;
13787
0
  }
13788
13789
0
scan_children:
13790
0
  if (cur->type == XML_NAMESPACE_DECL) break;
13791
0
  if ((cur->children != NULL) && (depth < max_depth)) {
13792
      /*
13793
       * Do not descend on entities declarations
13794
       */
13795
0
      if (cur->children->type != XML_ENTITY_DECL) {
13796
0
    cur = cur->children;
13797
0
    depth++;
13798
    /*
13799
     * Skip DTDs
13800
     */
13801
0
    if (cur->type != XML_DTD_NODE)
13802
0
        continue;
13803
0
      }
13804
0
  }
13805
13806
0
  if (cur == limit)
13807
0
      break;
13808
13809
0
  while (cur->next != NULL) {
13810
0
      cur = cur->next;
13811
0
      if ((cur->type != XML_ENTITY_DECL) &&
13812
0
    (cur->type != XML_DTD_NODE))
13813
0
    goto next_node;
13814
0
  }
13815
13816
0
  do {
13817
0
      cur = cur->parent;
13818
0
      depth--;
13819
0
      if ((cur == NULL) || (cur == limit) ||
13820
0
                (cur->type == XML_DOCUMENT_NODE))
13821
0
          goto done;
13822
0
      if (cur->type == XML_ELEMENT_NODE) {
13823
0
    ret = xmlStreamPop(patstream);
13824
0
      } else if ((eval_all_nodes) &&
13825
0
    ((cur->type == XML_TEXT_NODE) ||
13826
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13827
0
     (cur->type == XML_COMMENT_NODE) ||
13828
0
     (cur->type == XML_PI_NODE)))
13829
0
      {
13830
0
    ret = xmlStreamPop(patstream);
13831
0
      }
13832
0
      if (cur->next != NULL) {
13833
0
    cur = cur->next;
13834
0
    break;
13835
0
      }
13836
0
  } while (cur != NULL);
13837
13838
0
    } while ((cur != NULL) && (depth >= 0));
13839
13840
0
done:
13841
13842
0
    if (patstream)
13843
0
  xmlFreeStreamCtxt(patstream);
13844
0
    return(0);
13845
13846
0
return_1:
13847
0
    if (patstream)
13848
0
  xmlFreeStreamCtxt(patstream);
13849
0
    return(1);
13850
0
}
13851
#endif /* XPATH_STREAMING */
13852
13853
/**
13854
 * xmlXPathRunEval:
13855
 * @ctxt:  the XPath parser context with the compiled expression
13856
 * @toBool:  evaluate to a boolean result
13857
 *
13858
 * Evaluate the Precompiled XPath expression in the given context.
13859
 */
13860
static int
13861
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13862
0
{
13863
0
    xmlXPathCompExprPtr comp;
13864
0
    int oldDepth;
13865
13866
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13867
0
  return(-1);
13868
13869
0
    if (ctxt->valueTab == NULL) {
13870
  /* Allocate the value stack */
13871
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
13872
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13873
0
  if (ctxt->valueTab == NULL) {
13874
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13875
0
      return(-1);
13876
0
  }
13877
0
  ctxt->valueNr = 0;
13878
0
  ctxt->valueMax = 10;
13879
0
  ctxt->value = NULL;
13880
0
    }
13881
0
#ifdef XPATH_STREAMING
13882
0
    if (ctxt->comp->stream) {
13883
0
  int res;
13884
13885
0
  if (toBool) {
13886
      /*
13887
      * Evaluation to boolean result.
13888
      */
13889
0
      res = xmlXPathRunStreamEval(ctxt->context,
13890
0
    ctxt->comp->stream, NULL, 1);
13891
0
      if (res != -1)
13892
0
    return(res);
13893
0
  } else {
13894
0
      xmlXPathObjectPtr resObj = NULL;
13895
13896
      /*
13897
      * Evaluation to a sequence.
13898
      */
13899
0
      res = xmlXPathRunStreamEval(ctxt->context,
13900
0
    ctxt->comp->stream, &resObj, 0);
13901
13902
0
      if ((res != -1) && (resObj != NULL)) {
13903
0
    valuePush(ctxt, resObj);
13904
0
    return(0);
13905
0
      }
13906
0
      if (resObj != NULL)
13907
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13908
0
  }
13909
  /*
13910
  * QUESTION TODO: This falls back to normal XPath evaluation
13911
  * if res == -1. Is this intended?
13912
  */
13913
0
    }
13914
0
#endif
13915
0
    comp = ctxt->comp;
13916
0
    if (comp->last < 0) {
13917
0
  xmlGenericError(xmlGenericErrorContext,
13918
0
      "xmlXPathRunEval: last is less than zero\n");
13919
0
  return(-1);
13920
0
    }
13921
0
    oldDepth = ctxt->context->depth;
13922
0
    if (toBool)
13923
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13924
0
      &comp->steps[comp->last], 0));
13925
0
    else
13926
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13927
0
    ctxt->context->depth = oldDepth;
13928
13929
0
    return(0);
13930
0
}
13931
13932
/************************************************************************
13933
 *                  *
13934
 *      Public interfaces       *
13935
 *                  *
13936
 ************************************************************************/
13937
13938
/**
13939
 * xmlXPathEvalPredicate:
13940
 * @ctxt:  the XPath context
13941
 * @res:  the Predicate Expression evaluation result
13942
 *
13943
 * Evaluate a predicate result for the current node.
13944
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13945
 * the result to a boolean. If the result is a number, the result will
13946
 * be converted to true if the number is equal to the position of the
13947
 * context node in the context node list (as returned by the position
13948
 * function) and will be converted to false otherwise; if the result
13949
 * is not a number, then the result will be converted as if by a call
13950
 * to the boolean function.
13951
 *
13952
 * Returns 1 if predicate is true, 0 otherwise
13953
 */
13954
int
13955
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13956
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13957
0
    switch (res->type) {
13958
0
        case XPATH_BOOLEAN:
13959
0
      return(res->boolval);
13960
0
        case XPATH_NUMBER:
13961
0
      return(res->floatval == ctxt->proximityPosition);
13962
0
        case XPATH_NODESET:
13963
0
        case XPATH_XSLT_TREE:
13964
0
      if (res->nodesetval == NULL)
13965
0
    return(0);
13966
0
      return(res->nodesetval->nodeNr != 0);
13967
0
        case XPATH_STRING:
13968
0
      return((res->stringval != NULL) &&
13969
0
             (xmlStrlen(res->stringval) != 0));
13970
0
        default:
13971
0
      STRANGE
13972
0
    }
13973
0
    return(0);
13974
0
}
13975
13976
/**
13977
 * xmlXPathEvaluatePredicateResult:
13978
 * @ctxt:  the XPath Parser context
13979
 * @res:  the Predicate Expression evaluation result
13980
 *
13981
 * Evaluate a predicate result for the current node.
13982
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13983
 * the result to a boolean. If the result is a number, the result will
13984
 * be converted to true if the number is equal to the position of the
13985
 * context node in the context node list (as returned by the position
13986
 * function) and will be converted to false otherwise; if the result
13987
 * is not a number, then the result will be converted as if by a call
13988
 * to the boolean function.
13989
 *
13990
 * Returns 1 if predicate is true, 0 otherwise
13991
 */
13992
int
13993
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13994
0
                                xmlXPathObjectPtr res) {
13995
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13996
0
    switch (res->type) {
13997
0
        case XPATH_BOOLEAN:
13998
0
      return(res->boolval);
13999
0
        case XPATH_NUMBER:
14000
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14001
      return((res->floatval == ctxt->context->proximityPosition) &&
14002
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14003
#else
14004
0
      return(res->floatval == ctxt->context->proximityPosition);
14005
0
#endif
14006
0
        case XPATH_NODESET:
14007
0
        case XPATH_XSLT_TREE:
14008
0
      if (res->nodesetval == NULL)
14009
0
    return(0);
14010
0
      return(res->nodesetval->nodeNr != 0);
14011
0
        case XPATH_STRING:
14012
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14013
#ifdef LIBXML_XPTR_LOCS_ENABLED
14014
  case XPATH_LOCATIONSET:{
14015
      xmlLocationSetPtr ptr = res->user;
14016
      if (ptr == NULL)
14017
          return(0);
14018
      return (ptr->locNr != 0);
14019
      }
14020
#endif
14021
0
        default:
14022
0
      STRANGE
14023
0
    }
14024
0
    return(0);
14025
0
}
14026
14027
#ifdef XPATH_STREAMING
14028
/**
14029
 * xmlXPathTryStreamCompile:
14030
 * @ctxt: an XPath context
14031
 * @str:  the XPath expression
14032
 *
14033
 * Try to compile the XPath expression as a streamable subset.
14034
 *
14035
 * Returns the compiled expression or NULL if failed to compile.
14036
 */
14037
static xmlXPathCompExprPtr
14038
0
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14039
    /*
14040
     * Optimization: use streaming patterns when the XPath expression can
14041
     * be compiled to a stream lookup
14042
     */
14043
0
    xmlPatternPtr stream;
14044
0
    xmlXPathCompExprPtr comp;
14045
0
    xmlDictPtr dict = NULL;
14046
0
    const xmlChar **namespaces = NULL;
14047
0
    xmlNsPtr ns;
14048
0
    int i, j;
14049
14050
0
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14051
0
        (!xmlStrchr(str, '@'))) {
14052
0
  const xmlChar *tmp;
14053
14054
  /*
14055
   * We don't try to handle expressions using the verbose axis
14056
   * specifiers ("::"), just the simplified form at this point.
14057
   * Additionally, if there is no list of namespaces available and
14058
   *  there's a ":" in the expression, indicating a prefixed QName,
14059
   *  then we won't try to compile either. xmlPatterncompile() needs
14060
   *  to have a list of namespaces at compilation time in order to
14061
   *  compile prefixed name tests.
14062
   */
14063
0
  tmp = xmlStrchr(str, ':');
14064
0
  if ((tmp != NULL) &&
14065
0
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14066
0
      return(NULL);
14067
14068
0
  if (ctxt != NULL) {
14069
0
      dict = ctxt->dict;
14070
0
      if (ctxt->nsNr > 0) {
14071
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14072
0
    if (namespaces == NULL) {
14073
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14074
0
        return(NULL);
14075
0
    }
14076
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14077
0
        ns = ctxt->namespaces[j];
14078
0
        namespaces[i++] = ns->href;
14079
0
        namespaces[i++] = ns->prefix;
14080
0
    }
14081
0
    namespaces[i++] = NULL;
14082
0
    namespaces[i] = NULL;
14083
0
      }
14084
0
  }
14085
14086
0
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14087
0
  if (namespaces != NULL) {
14088
0
      xmlFree((xmlChar **)namespaces);
14089
0
  }
14090
0
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14091
0
      comp = xmlXPathNewCompExpr();
14092
0
      if (comp == NULL) {
14093
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14094
0
          xmlFreePattern(stream);
14095
0
    return(NULL);
14096
0
      }
14097
0
      comp->stream = stream;
14098
0
      comp->dict = dict;
14099
0
      if (comp->dict)
14100
0
    xmlDictReference(comp->dict);
14101
0
      return(comp);
14102
0
  }
14103
0
  xmlFreePattern(stream);
14104
0
    }
14105
0
    return(NULL);
14106
0
}
14107
#endif /* XPATH_STREAMING */
14108
14109
static void
14110
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14111
                           xmlXPathStepOpPtr op)
14112
0
{
14113
0
    xmlXPathCompExprPtr comp = pctxt->comp;
14114
0
    xmlXPathContextPtr ctxt;
14115
14116
    /*
14117
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14118
    * internal representation.
14119
    */
14120
14121
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14122
0
        (op->ch1 != -1) &&
14123
0
        (op->ch2 == -1 /* no predicate */))
14124
0
    {
14125
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14126
14127
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14128
0
            ((xmlXPathAxisVal) prevop->value ==
14129
0
                AXIS_DESCENDANT_OR_SELF) &&
14130
0
            (prevop->ch2 == -1) &&
14131
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14132
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14133
0
        {
14134
            /*
14135
            * This is a "descendant-or-self::node()" without predicates.
14136
            * Try to eliminate it.
14137
            */
14138
14139
0
            switch ((xmlXPathAxisVal) op->value) {
14140
0
                case AXIS_CHILD:
14141
0
                case AXIS_DESCENDANT:
14142
                    /*
14143
                    * Convert "descendant-or-self::node()/child::" or
14144
                    * "descendant-or-self::node()/descendant::" to
14145
                    * "descendant::"
14146
                    */
14147
0
                    op->ch1   = prevop->ch1;
14148
0
                    op->value = AXIS_DESCENDANT;
14149
0
                    break;
14150
0
                case AXIS_SELF:
14151
0
                case AXIS_DESCENDANT_OR_SELF:
14152
                    /*
14153
                    * Convert "descendant-or-self::node()/self::" or
14154
                    * "descendant-or-self::node()/descendant-or-self::" to
14155
                    * to "descendant-or-self::"
14156
                    */
14157
0
                    op->ch1   = prevop->ch1;
14158
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
14159
0
                    break;
14160
0
                default:
14161
0
                    break;
14162
0
            }
14163
0
  }
14164
0
    }
14165
14166
    /* OP_VALUE has invalid ch1. */
14167
0
    if (op->op == XPATH_OP_VALUE)
14168
0
        return;
14169
14170
    /* Recurse */
14171
0
    ctxt = pctxt->context;
14172
0
    if (ctxt != NULL) {
14173
0
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14174
0
            return;
14175
0
        ctxt->depth += 1;
14176
0
    }
14177
0
    if (op->ch1 != -1)
14178
0
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14179
0
    if (op->ch2 != -1)
14180
0
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14181
0
    if (ctxt != NULL)
14182
0
        ctxt->depth -= 1;
14183
0
}
14184
14185
/**
14186
 * xmlXPathCtxtCompile:
14187
 * @ctxt: an XPath context
14188
 * @str:  the XPath expression
14189
 *
14190
 * Compile an XPath expression
14191
 *
14192
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14193
 *         the caller has to free the object.
14194
 */
14195
xmlXPathCompExprPtr
14196
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14197
0
    xmlXPathParserContextPtr pctxt;
14198
0
    xmlXPathCompExprPtr comp;
14199
0
    int oldDepth = 0;
14200
14201
0
#ifdef XPATH_STREAMING
14202
0
    comp = xmlXPathTryStreamCompile(ctxt, str);
14203
0
    if (comp != NULL)
14204
0
        return(comp);
14205
0
#endif
14206
14207
0
    xmlInitParser();
14208
14209
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
14210
0
    if (pctxt == NULL)
14211
0
        return NULL;
14212
0
    if (ctxt != NULL)
14213
0
        oldDepth = ctxt->depth;
14214
0
    xmlXPathCompileExpr(pctxt, 1);
14215
0
    if (ctxt != NULL)
14216
0
        ctxt->depth = oldDepth;
14217
14218
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
14219
0
    {
14220
0
        xmlXPathFreeParserContext(pctxt);
14221
0
        return(NULL);
14222
0
    }
14223
14224
0
    if (*pctxt->cur != 0) {
14225
  /*
14226
   * aleksey: in some cases this line prints *second* error message
14227
   * (see bug #78858) and probably this should be fixed.
14228
   * However, we are not sure that all error messages are printed
14229
   * out in other places. It's not critical so we leave it as-is for now
14230
   */
14231
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14232
0
  comp = NULL;
14233
0
    } else {
14234
0
  comp = pctxt->comp;
14235
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14236
0
            if (ctxt != NULL)
14237
0
                oldDepth = ctxt->depth;
14238
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14239
0
            if (ctxt != NULL)
14240
0
                ctxt->depth = oldDepth;
14241
0
  }
14242
0
  pctxt->comp = NULL;
14243
0
    }
14244
0
    xmlXPathFreeParserContext(pctxt);
14245
14246
0
    if (comp != NULL) {
14247
0
  comp->expr = xmlStrdup(str);
14248
#ifdef DEBUG_EVAL_COUNTS
14249
  comp->string = xmlStrdup(str);
14250
  comp->nb = 0;
14251
#endif
14252
0
    }
14253
0
    return(comp);
14254
0
}
14255
14256
/**
14257
 * xmlXPathCompile:
14258
 * @str:  the XPath expression
14259
 *
14260
 * Compile an XPath expression
14261
 *
14262
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14263
 *         the caller has to free the object.
14264
 */
14265
xmlXPathCompExprPtr
14266
0
xmlXPathCompile(const xmlChar *str) {
14267
0
    return(xmlXPathCtxtCompile(NULL, str));
14268
0
}
14269
14270
/**
14271
 * xmlXPathCompiledEvalInternal:
14272
 * @comp:  the compiled XPath expression
14273
 * @ctxt:  the XPath context
14274
 * @resObj: the resulting XPath object or NULL
14275
 * @toBool: 1 if only a boolean result is requested
14276
 *
14277
 * Evaluate the Precompiled XPath expression in the given context.
14278
 * The caller has to free @resObj.
14279
 *
14280
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14281
 *         the caller has to free the object.
14282
 */
14283
static int
14284
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14285
           xmlXPathContextPtr ctxt,
14286
           xmlXPathObjectPtr *resObjPtr,
14287
           int toBool)
14288
0
{
14289
0
    xmlXPathParserContextPtr pctxt;
14290
0
    xmlXPathObjectPtr resObj;
14291
#ifndef LIBXML_THREAD_ENABLED
14292
    static int reentance = 0;
14293
#endif
14294
0
    int res;
14295
14296
0
    CHECK_CTXT_NEG(ctxt)
14297
14298
0
    if (comp == NULL)
14299
0
  return(-1);
14300
0
    xmlInitParser();
14301
14302
#ifndef LIBXML_THREAD_ENABLED
14303
    reentance++;
14304
    if (reentance > 1)
14305
  xmlXPathDisableOptimizer = 1;
14306
#endif
14307
14308
#ifdef DEBUG_EVAL_COUNTS
14309
    comp->nb++;
14310
    if ((comp->string != NULL) && (comp->nb > 100)) {
14311
  fprintf(stderr, "100 x %s\n", comp->string);
14312
  comp->nb = 0;
14313
    }
14314
#endif
14315
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14316
0
    if (pctxt == NULL)
14317
0
        return(-1);
14318
0
    res = xmlXPathRunEval(pctxt, toBool);
14319
14320
0
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14321
0
        resObj = NULL;
14322
0
    } else {
14323
0
        resObj = valuePop(pctxt);
14324
0
        if (resObj == NULL) {
14325
0
            if (!toBool)
14326
0
                xmlGenericError(xmlGenericErrorContext,
14327
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14328
0
        } else if (pctxt->valueNr > 0) {
14329
0
            xmlGenericError(xmlGenericErrorContext,
14330
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14331
0
                pctxt->valueNr);
14332
0
        }
14333
0
    }
14334
14335
0
    if (resObjPtr)
14336
0
        *resObjPtr = resObj;
14337
0
    else
14338
0
        xmlXPathReleaseObject(ctxt, resObj);
14339
14340
0
    pctxt->comp = NULL;
14341
0
    xmlXPathFreeParserContext(pctxt);
14342
#ifndef LIBXML_THREAD_ENABLED
14343
    reentance--;
14344
#endif
14345
14346
0
    return(res);
14347
0
}
14348
14349
/**
14350
 * xmlXPathCompiledEval:
14351
 * @comp:  the compiled XPath expression
14352
 * @ctx:  the XPath context
14353
 *
14354
 * Evaluate the Precompiled XPath expression in the given context.
14355
 *
14356
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14357
 *         the caller has to free the object.
14358
 */
14359
xmlXPathObjectPtr
14360
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14361
0
{
14362
0
    xmlXPathObjectPtr res = NULL;
14363
14364
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14365
0
    return(res);
14366
0
}
14367
14368
/**
14369
 * xmlXPathCompiledEvalToBoolean:
14370
 * @comp:  the compiled XPath expression
14371
 * @ctxt:  the XPath context
14372
 *
14373
 * Applies the XPath boolean() function on the result of the given
14374
 * compiled expression.
14375
 *
14376
 * Returns 1 if the expression evaluated to true, 0 if to false and
14377
 *         -1 in API and internal errors.
14378
 */
14379
int
14380
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14381
            xmlXPathContextPtr ctxt)
14382
0
{
14383
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14384
0
}
14385
14386
/**
14387
 * xmlXPathEvalExpr:
14388
 * @ctxt:  the XPath Parser context
14389
 *
14390
 * Parse and evaluate an XPath expression in the given context,
14391
 * then push the result on the context stack
14392
 */
14393
void
14394
0
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14395
0
#ifdef XPATH_STREAMING
14396
0
    xmlXPathCompExprPtr comp;
14397
0
#endif
14398
0
    int oldDepth = 0;
14399
14400
0
    if (ctxt == NULL) return;
14401
14402
0
#ifdef XPATH_STREAMING
14403
0
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14404
0
    if (comp != NULL) {
14405
0
        if (ctxt->comp != NULL)
14406
0
      xmlXPathFreeCompExpr(ctxt->comp);
14407
0
        ctxt->comp = comp;
14408
0
    } else
14409
0
#endif
14410
0
    {
14411
0
        if (ctxt->context != NULL)
14412
0
            oldDepth = ctxt->context->depth;
14413
0
  xmlXPathCompileExpr(ctxt, 1);
14414
0
        if (ctxt->context != NULL)
14415
0
            ctxt->context->depth = oldDepth;
14416
0
        CHECK_ERROR;
14417
14418
        /* Check for trailing characters. */
14419
0
        if (*ctxt->cur != 0)
14420
0
            XP_ERROR(XPATH_EXPR_ERROR);
14421
14422
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14423
0
            if (ctxt->context != NULL)
14424
0
                oldDepth = ctxt->context->depth;
14425
0
      xmlXPathOptimizeExpression(ctxt,
14426
0
    &ctxt->comp->steps[ctxt->comp->last]);
14427
0
            if (ctxt->context != NULL)
14428
0
                ctxt->context->depth = oldDepth;
14429
0
        }
14430
0
    }
14431
14432
0
    xmlXPathRunEval(ctxt, 0);
14433
0
}
14434
14435
/**
14436
 * xmlXPathEval:
14437
 * @str:  the XPath expression
14438
 * @ctx:  the XPath context
14439
 *
14440
 * Evaluate the XPath Location Path in the given context.
14441
 *
14442
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14443
 *         the caller has to free the object.
14444
 */
14445
xmlXPathObjectPtr
14446
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14447
0
    xmlXPathParserContextPtr ctxt;
14448
0
    xmlXPathObjectPtr res;
14449
14450
0
    CHECK_CTXT(ctx)
14451
14452
0
    xmlInitParser();
14453
14454
0
    ctxt = xmlXPathNewParserContext(str, ctx);
14455
0
    if (ctxt == NULL)
14456
0
        return NULL;
14457
0
    xmlXPathEvalExpr(ctxt);
14458
14459
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14460
0
  res = NULL;
14461
0
    } else {
14462
0
  res = valuePop(ctxt);
14463
0
        if (res == NULL) {
14464
0
            xmlGenericError(xmlGenericErrorContext,
14465
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14466
0
        } else if (ctxt->valueNr > 0) {
14467
0
            xmlGenericError(xmlGenericErrorContext,
14468
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14469
0
                ctxt->valueNr);
14470
0
        }
14471
0
    }
14472
14473
0
    xmlXPathFreeParserContext(ctxt);
14474
0
    return(res);
14475
0
}
14476
14477
/**
14478
 * xmlXPathSetContextNode:
14479
 * @node: the node to to use as the context node
14480
 * @ctx:  the XPath context
14481
 *
14482
 * Sets 'node' as the context node. The node must be in the same
14483
 * document as that associated with the context.
14484
 *
14485
 * Returns -1 in case of error or 0 if successful
14486
 */
14487
int
14488
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14489
0
    if ((node == NULL) || (ctx == NULL))
14490
0
        return(-1);
14491
14492
0
    if (node->doc == ctx->doc) {
14493
0
        ctx->node = node;
14494
0
  return(0);
14495
0
    }
14496
0
    return(-1);
14497
0
}
14498
14499
/**
14500
 * xmlXPathNodeEval:
14501
 * @node: the node to to use as the context node
14502
 * @str:  the XPath expression
14503
 * @ctx:  the XPath context
14504
 *
14505
 * Evaluate the XPath Location Path in the given context. The node 'node'
14506
 * is set as the context node. The context node is not restored.
14507
 *
14508
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14509
 *         the caller has to free the object.
14510
 */
14511
xmlXPathObjectPtr
14512
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14513
0
    if (str == NULL)
14514
0
        return(NULL);
14515
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14516
0
        return(NULL);
14517
0
    return(xmlXPathEval(str, ctx));
14518
0
}
14519
14520
/**
14521
 * xmlXPathEvalExpression:
14522
 * @str:  the XPath expression
14523
 * @ctxt:  the XPath context
14524
 *
14525
 * Alias for xmlXPathEval().
14526
 *
14527
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14528
 *         the caller has to free the object.
14529
 */
14530
xmlXPathObjectPtr
14531
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14532
0
    return(xmlXPathEval(str, ctxt));
14533
0
}
14534
14535
/************************************************************************
14536
 *                  *
14537
 *  Extra functions not pertaining to the XPath spec    *
14538
 *                  *
14539
 ************************************************************************/
14540
/**
14541
 * xmlXPathEscapeUriFunction:
14542
 * @ctxt:  the XPath Parser context
14543
 * @nargs:  the number of arguments
14544
 *
14545
 * Implement the escape-uri() XPath function
14546
 *    string escape-uri(string $str, bool $escape-reserved)
14547
 *
14548
 * This function applies the URI escaping rules defined in section 2 of [RFC
14549
 * 2396] to the string supplied as $uri-part, which typically represents all
14550
 * or part of a URI. The effect of the function is to replace any special
14551
 * character in the string by an escape sequence of the form %xx%yy...,
14552
 * where xxyy... is the hexadecimal representation of the octets used to
14553
 * represent the character in UTF-8.
14554
 *
14555
 * The set of characters that are escaped depends on the setting of the
14556
 * boolean argument $escape-reserved.
14557
 *
14558
 * If $escape-reserved is true, all characters are escaped other than lower
14559
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14560
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14561
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14562
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14563
 * A-F).
14564
 *
14565
 * If $escape-reserved is false, the behavior differs in that characters
14566
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14567
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14568
 *
14569
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14570
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14571
 * compared using string comparison functions, this function must always use
14572
 * the upper-case letters A-F.
14573
 *
14574
 * Generally, $escape-reserved should be set to true when escaping a string
14575
 * that is to form a single part of a URI, and to false when escaping an
14576
 * entire URI or URI reference.
14577
 *
14578
 * In the case of non-ascii characters, the string is encoded according to
14579
 * utf-8 and then converted according to RFC 2396.
14580
 *
14581
 * Examples
14582
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14583
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14584
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14585
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14586
 *
14587
 */
14588
static void
14589
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14590
0
    xmlXPathObjectPtr str;
14591
0
    int escape_reserved;
14592
0
    xmlBufPtr target;
14593
0
    xmlChar *cptr;
14594
0
    xmlChar escape[4];
14595
14596
0
    CHECK_ARITY(2);
14597
14598
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14599
14600
0
    CAST_TO_STRING;
14601
0
    str = valuePop(ctxt);
14602
14603
0
    target = xmlBufCreate();
14604
14605
0
    escape[0] = '%';
14606
0
    escape[3] = 0;
14607
14608
0
    if (target) {
14609
0
  for (cptr = str->stringval; *cptr; cptr++) {
14610
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14611
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14612
0
    (*cptr >= '0' && *cptr <= '9') ||
14613
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14614
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14615
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14616
0
    (*cptr == '%' &&
14617
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14618
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14619
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14620
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14621
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14622
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14623
0
    (!escape_reserved &&
14624
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14625
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14626
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14627
0
      *cptr == ','))) {
14628
0
    xmlBufAdd(target, cptr, 1);
14629
0
      } else {
14630
0
    if ((*cptr >> 4) < 10)
14631
0
        escape[1] = '0' + (*cptr >> 4);
14632
0
    else
14633
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14634
0
    if ((*cptr & 0xF) < 10)
14635
0
        escape[2] = '0' + (*cptr & 0xF);
14636
0
    else
14637
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14638
14639
0
    xmlBufAdd(target, &escape[0], 3);
14640
0
      }
14641
0
  }
14642
0
    }
14643
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14644
0
  xmlBufContent(target)));
14645
0
    xmlBufFree(target);
14646
0
    xmlXPathReleaseObject(ctxt->context, str);
14647
0
}
14648
14649
/**
14650
 * xmlXPathRegisterAllFunctions:
14651
 * @ctxt:  the XPath context
14652
 *
14653
 * Registers all default XPath functions in this context
14654
 */
14655
void
14656
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14657
0
{
14658
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14659
0
                         xmlXPathBooleanFunction);
14660
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14661
0
                         xmlXPathCeilingFunction);
14662
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14663
0
                         xmlXPathCountFunction);
14664
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14665
0
                         xmlXPathConcatFunction);
14666
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14667
0
                         xmlXPathContainsFunction);
14668
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14669
0
                         xmlXPathIdFunction);
14670
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14671
0
                         xmlXPathFalseFunction);
14672
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14673
0
                         xmlXPathFloorFunction);
14674
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14675
0
                         xmlXPathLastFunction);
14676
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14677
0
                         xmlXPathLangFunction);
14678
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14679
0
                         xmlXPathLocalNameFunction);
14680
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14681
0
                         xmlXPathNotFunction);
14682
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14683
0
                         xmlXPathNameFunction);
14684
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14685
0
                         xmlXPathNamespaceURIFunction);
14686
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14687
0
                         xmlXPathNormalizeFunction);
14688
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14689
0
                         xmlXPathNumberFunction);
14690
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14691
0
                         xmlXPathPositionFunction);
14692
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14693
0
                         xmlXPathRoundFunction);
14694
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14695
0
                         xmlXPathStringFunction);
14696
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14697
0
                         xmlXPathStringLengthFunction);
14698
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14699
0
                         xmlXPathStartsWithFunction);
14700
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14701
0
                         xmlXPathSubstringFunction);
14702
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14703
0
                         xmlXPathSubstringBeforeFunction);
14704
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14705
0
                         xmlXPathSubstringAfterFunction);
14706
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14707
0
                         xmlXPathSumFunction);
14708
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14709
0
                         xmlXPathTrueFunction);
14710
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14711
0
                         xmlXPathTranslateFunction);
14712
14713
0
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14714
0
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14715
0
                         xmlXPathEscapeUriFunction);
14716
0
}
14717
14718
#endif /* LIBXML_XPATH_ENABLED */