Coverage Report

Created: 2023-06-07 06:06

/src/libxml2-2.10.3/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 "buf.h"
53
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
58
#define TODO                \
59
0
    xmlGenericError(xmlGenericErrorContext,       \
60
0
      "Unimplemented block at %s:%d\n",       \
61
0
            __FILE__, __LINE__);
62
63
/**
64
 * WITH_TIM_SORT:
65
 *
66
 * Use the Timsort algorithm provided in timsort.h to sort
67
 * nodeset as this is a great improvement over the old Shell sort
68
 * used in xmlXPathNodeSetSort()
69
 */
70
#define WITH_TIM_SORT
71
72
/*
73
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
74
* If defined, this will use xmlXPathCmpNodesExt() instead of
75
* xmlXPathCmpNodes(). The new function is optimized comparison of
76
* non-element nodes; actually it will speed up comparison only if
77
* xmlXPathOrderDocElems() was called in order to index the elements of
78
* a tree in document order; Libxslt does such an indexing, thus it will
79
* benefit from this optimization.
80
*/
81
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
82
83
/*
84
* XP_OPTIMIZED_FILTER_FIRST:
85
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86
* in a way, that it stop evaluation at the first node.
87
*/
88
#define XP_OPTIMIZED_FILTER_FIRST
89
90
/*
91
* XP_DEBUG_OBJ_USAGE:
92
* Internal flag to enable tracking of how much XPath objects have been
93
* created.
94
*/
95
/* #define XP_DEBUG_OBJ_USAGE */
96
97
/*
98
 * XPATH_MAX_STEPS:
99
 * when compiling an XPath expression we arbitrary limit the maximum
100
 * number of step operation in the compiled expression. 1000000 is
101
 * an insanely large value which should never be reached under normal
102
 * circumstances
103
 */
104
0
#define XPATH_MAX_STEPS 1000000
105
106
/*
107
 * XPATH_MAX_STACK_DEPTH:
108
 * when evaluating an XPath expression we arbitrary limit the maximum
109
 * number of object allowed to be pushed on the stack. 1000000 is
110
 * an insanely large value which should never be reached under normal
111
 * circumstances
112
 */
113
0
#define XPATH_MAX_STACK_DEPTH 1000000
114
115
/*
116
 * XPATH_MAX_NODESET_LENGTH:
117
 * when evaluating an XPath expression nodesets are created and we
118
 * arbitrary limit the maximum length of those node set. 10000000 is
119
 * an insanely large value which should never be reached under normal
120
 * circumstances, one would first need to construct an in memory tree
121
 * with more than 10 millions nodes.
122
 */
123
0
#define XPATH_MAX_NODESET_LENGTH 10000000
124
125
/*
126
 * XPATH_MAX_RECRUSION_DEPTH:
127
 * Maximum amount of nested functions calls when parsing or evaluating
128
 * expressions
129
 */
130
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
131
0
#define XPATH_MAX_RECURSION_DEPTH 500
132
#else
133
#define XPATH_MAX_RECURSION_DEPTH 5000
134
#endif
135
136
/*
137
 * TODO:
138
 * There are a few spots where some tests are done which depend upon ascii
139
 * data.  These should be enhanced for full UTF8 support (see particularly
140
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
141
 */
142
143
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
144
/**
145
 * xmlXPathCmpNodesExt:
146
 * @node1:  the first node
147
 * @node2:  the second node
148
 *
149
 * Compare two nodes w.r.t document order.
150
 * This one is optimized for handling of non-element nodes.
151
 *
152
 * Returns -2 in case of error 1 if first point < second point, 0 if
153
 *         it's the same node, -1 otherwise
154
 */
155
static int
156
0
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
157
0
    int depth1, depth2;
158
0
    int misc = 0, precedence1 = 0, precedence2 = 0;
159
0
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
160
0
    xmlNodePtr cur, root;
161
0
    ptrdiff_t l1, l2;
162
163
0
    if ((node1 == NULL) || (node2 == NULL))
164
0
  return(-2);
165
166
0
    if (node1 == node2)
167
0
  return(0);
168
169
    /*
170
     * a couple of optimizations which will avoid computations in most cases
171
     */
172
0
    switch (node1->type) {
173
0
  case XML_ELEMENT_NODE:
174
0
      if (node2->type == XML_ELEMENT_NODE) {
175
0
    if ((0 > (ptrdiff_t) node1->content) &&
176
0
        (0 > (ptrdiff_t) node2->content) &&
177
0
        (node1->doc == node2->doc))
178
0
    {
179
0
        l1 = -((ptrdiff_t) node1->content);
180
0
        l2 = -((ptrdiff_t) node2->content);
181
0
        if (l1 < l2)
182
0
      return(1);
183
0
        if (l1 > l2)
184
0
      return(-1);
185
0
    } else
186
0
        goto turtle_comparison;
187
0
      }
188
0
      break;
189
0
  case XML_ATTRIBUTE_NODE:
190
0
      precedence1 = 1; /* element is owner */
191
0
      miscNode1 = node1;
192
0
      node1 = node1->parent;
193
0
      misc = 1;
194
0
      break;
195
0
  case XML_TEXT_NODE:
196
0
  case XML_CDATA_SECTION_NODE:
197
0
  case XML_COMMENT_NODE:
198
0
  case XML_PI_NODE: {
199
0
      miscNode1 = node1;
200
      /*
201
      * Find nearest element node.
202
      */
203
0
      if (node1->prev != NULL) {
204
0
    do {
205
0
        node1 = node1->prev;
206
0
        if (node1->type == XML_ELEMENT_NODE) {
207
0
      precedence1 = 3; /* element in prev-sibl axis */
208
0
      break;
209
0
        }
210
0
        if (node1->prev == NULL) {
211
0
      precedence1 = 2; /* element is parent */
212
      /*
213
      * URGENT TODO: Are there any cases, where the
214
      * parent of such a node is not an element node?
215
      */
216
0
      node1 = node1->parent;
217
0
      break;
218
0
        }
219
0
    } while (1);
220
0
      } else {
221
0
    precedence1 = 2; /* element is parent */
222
0
    node1 = node1->parent;
223
0
      }
224
0
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
225
0
    (0 <= (ptrdiff_t) node1->content)) {
226
    /*
227
    * Fallback for whatever case.
228
    */
229
0
    node1 = miscNode1;
230
0
    precedence1 = 0;
231
0
      } else
232
0
    misc = 1;
233
0
  }
234
0
      break;
235
0
  case XML_NAMESPACE_DECL:
236
      /*
237
      * TODO: why do we return 1 for namespace nodes?
238
      */
239
0
      return(1);
240
0
  default:
241
0
      break;
242
0
    }
243
0
    switch (node2->type) {
244
0
  case XML_ELEMENT_NODE:
245
0
      break;
246
0
  case XML_ATTRIBUTE_NODE:
247
0
      precedence2 = 1; /* element is owner */
248
0
      miscNode2 = node2;
249
0
      node2 = node2->parent;
250
0
      misc = 1;
251
0
      break;
252
0
  case XML_TEXT_NODE:
253
0
  case XML_CDATA_SECTION_NODE:
254
0
  case XML_COMMENT_NODE:
255
0
  case XML_PI_NODE: {
256
0
      miscNode2 = node2;
257
0
      if (node2->prev != NULL) {
258
0
    do {
259
0
        node2 = node2->prev;
260
0
        if (node2->type == XML_ELEMENT_NODE) {
261
0
      precedence2 = 3; /* element in prev-sibl axis */
262
0
      break;
263
0
        }
264
0
        if (node2->prev == NULL) {
265
0
      precedence2 = 2; /* element is parent */
266
0
      node2 = node2->parent;
267
0
      break;
268
0
        }
269
0
    } while (1);
270
0
      } else {
271
0
    precedence2 = 2; /* element is parent */
272
0
    node2 = node2->parent;
273
0
      }
274
0
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
275
0
    (0 <= (ptrdiff_t) node2->content))
276
0
      {
277
0
    node2 = miscNode2;
278
0
    precedence2 = 0;
279
0
      } else
280
0
    misc = 1;
281
0
  }
282
0
      break;
283
0
  case XML_NAMESPACE_DECL:
284
0
      return(1);
285
0
  default:
286
0
      break;
287
0
    }
288
0
    if (misc) {
289
0
  if (node1 == node2) {
290
0
      if (precedence1 == precedence2) {
291
    /*
292
    * The ugly case; but normally there aren't many
293
    * adjacent non-element nodes around.
294
    */
295
0
    cur = miscNode2->prev;
296
0
    while (cur != NULL) {
297
0
        if (cur == miscNode1)
298
0
      return(1);
299
0
        if (cur->type == XML_ELEMENT_NODE)
300
0
      return(-1);
301
0
        cur = cur->prev;
302
0
    }
303
0
    return (-1);
304
0
      } else {
305
    /*
306
    * Evaluate based on higher precedence wrt to the element.
307
    * TODO: This assumes attributes are sorted before content.
308
    *   Is this 100% correct?
309
    */
310
0
    if (precedence1 < precedence2)
311
0
        return(1);
312
0
    else
313
0
        return(-1);
314
0
      }
315
0
  }
316
  /*
317
  * Special case: One of the helper-elements is contained by the other.
318
  * <foo>
319
  *   <node2>
320
  *     <node1>Text-1(precedence1 == 2)</node1>
321
  *   </node2>
322
  *   Text-6(precedence2 == 3)
323
  * </foo>
324
  */
325
0
  if ((precedence2 == 3) && (precedence1 > 1)) {
326
0
      cur = node1->parent;
327
0
      while (cur) {
328
0
    if (cur == node2)
329
0
        return(1);
330
0
    cur = cur->parent;
331
0
      }
332
0
  }
333
0
  if ((precedence1 == 3) && (precedence2 > 1)) {
334
0
      cur = node2->parent;
335
0
      while (cur) {
336
0
    if (cur == node1)
337
0
        return(-1);
338
0
    cur = cur->parent;
339
0
      }
340
0
  }
341
0
    }
342
343
    /*
344
     * Speedup using document order if available.
345
     */
346
0
    if ((node1->type == XML_ELEMENT_NODE) &&
347
0
  (node2->type == XML_ELEMENT_NODE) &&
348
0
  (0 > (ptrdiff_t) node1->content) &&
349
0
  (0 > (ptrdiff_t) node2->content) &&
350
0
  (node1->doc == node2->doc)) {
351
352
0
  l1 = -((ptrdiff_t) node1->content);
353
0
  l2 = -((ptrdiff_t) node2->content);
354
0
  if (l1 < l2)
355
0
      return(1);
356
0
  if (l1 > l2)
357
0
      return(-1);
358
0
    }
359
360
0
turtle_comparison:
361
362
0
    if (node1 == node2->prev)
363
0
  return(1);
364
0
    if (node1 == node2->next)
365
0
  return(-1);
366
    /*
367
     * compute depth to root
368
     */
369
0
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
370
0
  if (cur->parent == node1)
371
0
      return(1);
372
0
  depth2++;
373
0
    }
374
0
    root = cur;
375
0
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
376
0
  if (cur->parent == node2)
377
0
      return(-1);
378
0
  depth1++;
379
0
    }
380
    /*
381
     * Distinct document (or distinct entities :-( ) case.
382
     */
383
0
    if (root != cur) {
384
0
  return(-2);
385
0
    }
386
    /*
387
     * get the nearest common ancestor.
388
     */
389
0
    while (depth1 > depth2) {
390
0
  depth1--;
391
0
  node1 = node1->parent;
392
0
    }
393
0
    while (depth2 > depth1) {
394
0
  depth2--;
395
0
  node2 = node2->parent;
396
0
    }
397
0
    while (node1->parent != node2->parent) {
398
0
  node1 = node1->parent;
399
0
  node2 = node2->parent;
400
  /* should not happen but just in case ... */
401
0
  if ((node1 == NULL) || (node2 == NULL))
402
0
      return(-2);
403
0
    }
404
    /*
405
     * Find who's first.
406
     */
407
0
    if (node1 == node2->prev)
408
0
  return(1);
409
0
    if (node1 == node2->next)
410
0
  return(-1);
411
    /*
412
     * Speedup using document order if available.
413
     */
414
0
    if ((node1->type == XML_ELEMENT_NODE) &&
415
0
  (node2->type == XML_ELEMENT_NODE) &&
416
0
  (0 > (ptrdiff_t) node1->content) &&
417
0
  (0 > (ptrdiff_t) node2->content) &&
418
0
  (node1->doc == node2->doc)) {
419
420
0
  l1 = -((ptrdiff_t) node1->content);
421
0
  l2 = -((ptrdiff_t) node2->content);
422
0
  if (l1 < l2)
423
0
      return(1);
424
0
  if (l1 > l2)
425
0
      return(-1);
426
0
    }
427
428
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
429
0
  if (cur == node2)
430
0
      return(1);
431
0
    return(-1); /* assume there is no sibling list corruption */
432
0
}
433
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
434
435
/*
436
 * Wrapper for the Timsort algorithm from timsort.h
437
 */
438
#ifdef WITH_TIM_SORT
439
#define SORT_NAME libxml_domnode
440
0
#define SORT_TYPE xmlNodePtr
441
/**
442
 * wrap_cmp:
443
 * @x: a node
444
 * @y: another node
445
 *
446
 * Comparison function for the Timsort implementation
447
 *
448
 * Returns -2 in case of error -1 if first point < second point, 0 if
449
 *         it's the same node, +1 otherwise
450
 */
451
static
452
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
453
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
454
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
455
0
    {
456
0
        int res = xmlXPathCmpNodesExt(x, y);
457
0
        return res == -2 ? res : -res;
458
0
    }
459
#else
460
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
461
    {
462
        int res = xmlXPathCmpNodes(x, y);
463
        return res == -2 ? res : -res;
464
    }
465
#endif
466
0
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
467
#include "timsort.h"
468
#endif /* WITH_TIM_SORT */
469
470
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
471
472
/************************************************************************
473
 *                  *
474
 *      Floating point stuff        *
475
 *                  *
476
 ************************************************************************/
477
478
double xmlXPathNAN = 0.0;
479
double xmlXPathPINF = 0.0;
480
double xmlXPathNINF = 0.0;
481
482
/**
483
 * xmlXPathInit:
484
 *
485
 * DEPRECATED: This function will be made private. Call xmlInitParser to
486
 * initialize the library.
487
 *
488
 * Initialize the XPath environment
489
 */
490
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
491
void
492
1
xmlXPathInit(void) {
493
1
#if defined(NAN) && defined(INFINITY)
494
1
    xmlXPathNAN = NAN;
495
1
    xmlXPathPINF = INFINITY;
496
1
    xmlXPathNINF = -INFINITY;
497
#else
498
    /* MSVC doesn't allow division by zero in constant expressions. */
499
    double zero = 0.0;
500
    xmlXPathNAN = 0.0 / zero;
501
    xmlXPathPINF = 1.0 / zero;
502
    xmlXPathNINF = -xmlXPathPINF;
503
#endif
504
1
}
505
506
/**
507
 * xmlXPathIsNaN:
508
 * @val:  a double value
509
 *
510
 * Returns 1 if the value is a NaN, 0 otherwise
511
 */
512
int
513
0
xmlXPathIsNaN(double val) {
514
0
#ifdef isnan
515
0
    return isnan(val);
516
#else
517
    return !(val == val);
518
#endif
519
0
}
520
521
/**
522
 * xmlXPathIsInf:
523
 * @val:  a double value
524
 *
525
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
526
 */
527
int
528
0
xmlXPathIsInf(double val) {
529
0
#ifdef isinf
530
0
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
531
#else
532
    if (val >= xmlXPathPINF)
533
        return 1;
534
    if (val <= -xmlXPathPINF)
535
        return -1;
536
    return 0;
537
#endif
538
0
}
539
540
#endif /* SCHEMAS or XPATH */
541
542
#ifdef LIBXML_XPATH_ENABLED
543
544
/*
545
 * TODO: when compatibility allows remove all "fake node libxslt" strings
546
 *       the test should just be name[0] = ' '
547
 */
548
#ifdef DEBUG_XPATH_EXPRESSION
549
#define DEBUG_STEP
550
#define DEBUG_EXPR
551
#define DEBUG_EVAL_COUNTS
552
#endif
553
554
static xmlNs xmlXPathXMLNamespaceStruct = {
555
    NULL,
556
    XML_NAMESPACE_DECL,
557
    XML_XML_NAMESPACE,
558
    BAD_CAST "xml",
559
    NULL,
560
    NULL
561
};
562
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
563
#ifndef LIBXML_THREAD_ENABLED
564
/*
565
 * Optimizer is disabled only when threaded apps are detected while
566
 * the library ain't compiled for thread safety.
567
 */
568
static int xmlXPathDisableOptimizer = 0;
569
#endif
570
571
/************************************************************************
572
 *                  *
573
 *      Error handling routines       *
574
 *                  *
575
 ************************************************************************/
576
577
/**
578
 * XP_ERRORNULL:
579
 * @X:  the error code
580
 *
581
 * Macro to raise an XPath error and return NULL.
582
 */
583
#define XP_ERRORNULL(X)             \
584
0
    { xmlXPathErr(ctxt, X); return(NULL); }
585
586
/*
587
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
588
 */
589
static const char* const xmlXPathErrorMessages[] = {
590
    "Ok\n",
591
    "Number encoding\n",
592
    "Unfinished literal\n",
593
    "Start of literal\n",
594
    "Expected $ for variable reference\n",
595
    "Undefined variable\n",
596
    "Invalid predicate\n",
597
    "Invalid expression\n",
598
    "Missing closing curly brace\n",
599
    "Unregistered function\n",
600
    "Invalid operand\n",
601
    "Invalid type\n",
602
    "Invalid number of arguments\n",
603
    "Invalid context size\n",
604
    "Invalid context position\n",
605
    "Memory allocation error\n",
606
    "Syntax error\n",
607
    "Resource error\n",
608
    "Sub resource error\n",
609
    "Undefined namespace prefix\n",
610
    "Encoding error\n",
611
    "Char out of XML range\n",
612
    "Invalid or incomplete context\n",
613
    "Stack usage error\n",
614
    "Forbidden variable\n",
615
    "Operation limit exceeded\n",
616
    "Recursion limit exceeded\n",
617
    "?? Unknown error ??\n" /* Must be last in the list! */
618
};
619
0
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
620
0
       sizeof(xmlXPathErrorMessages[0])) - 1)
621
/**
622
 * xmlXPathErrMemory:
623
 * @ctxt:  an XPath context
624
 * @extra:  extra information
625
 *
626
 * Handle a redefinition of attribute error
627
 */
628
static void
629
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
630
0
{
631
0
    if (ctxt != NULL) {
632
0
        xmlResetError(&ctxt->lastError);
633
0
        if (extra) {
634
0
            xmlChar buf[200];
635
636
0
            xmlStrPrintf(buf, 200,
637
0
                         "Memory allocation failed : %s\n",
638
0
                         extra);
639
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
640
0
        } else {
641
0
            ctxt->lastError.message = (char *)
642
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
643
0
        }
644
0
        ctxt->lastError.domain = XML_FROM_XPATH;
645
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
646
0
  if (ctxt->error != NULL)
647
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
648
0
    } else {
649
0
        if (extra)
650
0
            __xmlRaiseError(NULL, NULL, NULL,
651
0
                            NULL, NULL, XML_FROM_XPATH,
652
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
653
0
                            extra, NULL, NULL, 0, 0,
654
0
                            "Memory allocation failed : %s\n", extra);
655
0
        else
656
0
            __xmlRaiseError(NULL, NULL, NULL,
657
0
                            NULL, NULL, XML_FROM_XPATH,
658
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
659
0
                            NULL, NULL, NULL, 0, 0,
660
0
                            "Memory allocation failed\n");
661
0
    }
662
0
}
663
664
/**
665
 * xmlXPathPErrMemory:
666
 * @ctxt:  an XPath parser context
667
 * @extra:  extra information
668
 *
669
 * Handle a redefinition of attribute error
670
 */
671
static void
672
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
673
0
{
674
0
    if (ctxt == NULL)
675
0
  xmlXPathErrMemory(NULL, extra);
676
0
    else {
677
0
  ctxt->error = XPATH_MEMORY_ERROR;
678
0
  xmlXPathErrMemory(ctxt->context, extra);
679
0
    }
680
0
}
681
682
/**
683
 * xmlXPathErr:
684
 * @ctxt:  a XPath parser context
685
 * @error:  the error code
686
 *
687
 * Handle an XPath error
688
 */
689
void
690
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
691
0
{
692
0
    if ((error < 0) || (error > MAXERRNO))
693
0
  error = MAXERRNO;
694
0
    if (ctxt == NULL) {
695
0
  __xmlRaiseError(NULL, NULL, NULL,
696
0
      NULL, NULL, XML_FROM_XPATH,
697
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
698
0
      XML_ERR_ERROR, NULL, 0,
699
0
      NULL, NULL, NULL, 0, 0,
700
0
      "%s", xmlXPathErrorMessages[error]);
701
0
  return;
702
0
    }
703
0
    ctxt->error = error;
704
0
    if (ctxt->context == NULL) {
705
0
  __xmlRaiseError(NULL, NULL, NULL,
706
0
      NULL, NULL, XML_FROM_XPATH,
707
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
708
0
      XML_ERR_ERROR, NULL, 0,
709
0
      (const char *) ctxt->base, NULL, NULL,
710
0
      ctxt->cur - ctxt->base, 0,
711
0
      "%s", xmlXPathErrorMessages[error]);
712
0
  return;
713
0
    }
714
715
    /* cleanup current last error */
716
0
    xmlResetError(&ctxt->context->lastError);
717
718
0
    ctxt->context->lastError.domain = XML_FROM_XPATH;
719
0
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
720
0
                           XPATH_EXPRESSION_OK;
721
0
    ctxt->context->lastError.level = XML_ERR_ERROR;
722
0
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
723
0
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
724
0
    ctxt->context->lastError.node = ctxt->context->debugNode;
725
0
    if (ctxt->context->error != NULL) {
726
0
  ctxt->context->error(ctxt->context->userData,
727
0
                       &ctxt->context->lastError);
728
0
    } else {
729
0
  __xmlRaiseError(NULL, NULL, NULL,
730
0
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
731
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
732
0
      XML_ERR_ERROR, NULL, 0,
733
0
      (const char *) ctxt->base, NULL, NULL,
734
0
      ctxt->cur - ctxt->base, 0,
735
0
      "%s", xmlXPathErrorMessages[error]);
736
0
    }
737
738
0
}
739
740
/**
741
 * xmlXPatherror:
742
 * @ctxt:  the XPath Parser context
743
 * @file:  the file name
744
 * @line:  the line number
745
 * @no:  the error number
746
 *
747
 * Formats an error message.
748
 */
749
void
750
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
751
0
              int line ATTRIBUTE_UNUSED, int no) {
752
0
    xmlXPathErr(ctxt, no);
753
0
}
754
755
/**
756
 * xmlXPathCheckOpLimit:
757
 * @ctxt:  the XPath Parser context
758
 * @opCount:  the number of operations to be added
759
 *
760
 * Adds opCount to the running total of operations and returns -1 if the
761
 * operation limit is exceeded. Returns 0 otherwise.
762
 */
763
static int
764
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
765
0
    xmlXPathContextPtr xpctxt = ctxt->context;
766
767
0
    if ((opCount > xpctxt->opLimit) ||
768
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
769
0
        xpctxt->opCount = xpctxt->opLimit;
770
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
771
0
        return(-1);
772
0
    }
773
774
0
    xpctxt->opCount += opCount;
775
0
    return(0);
776
0
}
777
778
#define OP_LIMIT_EXCEEDED(ctxt, n) \
779
0
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
780
781
/************************************************************************
782
 *                  *
783
 *      Utilities         *
784
 *                  *
785
 ************************************************************************/
786
787
/**
788
 * xsltPointerList:
789
 *
790
 * Pointer-list for various purposes.
791
 */
792
typedef struct _xmlPointerList xmlPointerList;
793
typedef xmlPointerList *xmlPointerListPtr;
794
struct _xmlPointerList {
795
    void **items;
796
    int number;
797
    int size;
798
};
799
/*
800
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
801
* and here, we should make the functions public.
802
*/
803
static int
804
xmlPointerListAddSize(xmlPointerListPtr list,
805
           void *item,
806
           int initialSize)
807
0
{
808
0
    if (list->items == NULL) {
809
0
  if (initialSize <= 0)
810
0
      initialSize = 1;
811
0
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
812
0
  if (list->items == NULL) {
813
0
      xmlXPathErrMemory(NULL,
814
0
    "xmlPointerListCreate: allocating item\n");
815
0
      return(-1);
816
0
  }
817
0
  list->number = 0;
818
0
  list->size = initialSize;
819
0
    } else if (list->size <= list->number) {
820
0
        if (list->size > 50000000) {
821
0
      xmlXPathErrMemory(NULL,
822
0
    "xmlPointerListAddSize: re-allocating item\n");
823
0
            return(-1);
824
0
        }
825
0
  list->size *= 2;
826
0
  list->items = (void **) xmlRealloc(list->items,
827
0
      list->size * sizeof(void *));
828
0
  if (list->items == NULL) {
829
0
      xmlXPathErrMemory(NULL,
830
0
    "xmlPointerListAddSize: re-allocating item\n");
831
0
      list->size = 0;
832
0
      return(-1);
833
0
  }
834
0
    }
835
0
    list->items[list->number++] = item;
836
0
    return(0);
837
0
}
838
839
/**
840
 * xsltPointerListCreate:
841
 *
842
 * Creates an xsltPointerList structure.
843
 *
844
 * Returns a xsltPointerList structure or NULL in case of an error.
845
 */
846
static xmlPointerListPtr
847
xmlPointerListCreate(int initialSize)
848
0
{
849
0
    xmlPointerListPtr ret;
850
851
0
    ret = xmlMalloc(sizeof(xmlPointerList));
852
0
    if (ret == NULL) {
853
0
  xmlXPathErrMemory(NULL,
854
0
      "xmlPointerListCreate: allocating item\n");
855
0
  return (NULL);
856
0
    }
857
0
    memset(ret, 0, sizeof(xmlPointerList));
858
0
    if (initialSize > 0) {
859
0
  xmlPointerListAddSize(ret, NULL, initialSize);
860
0
  ret->number = 0;
861
0
    }
862
0
    return (ret);
863
0
}
864
865
/**
866
 * xsltPointerListFree:
867
 *
868
 * Frees the xsltPointerList structure. This does not free
869
 * the content of the list.
870
 */
871
static void
872
xmlPointerListFree(xmlPointerListPtr list)
873
0
{
874
0
    if (list == NULL)
875
0
  return;
876
0
    if (list->items != NULL)
877
0
  xmlFree(list->items);
878
0
    xmlFree(list);
879
0
}
880
881
/************************************************************************
882
 *                  *
883
 *      Parser Types          *
884
 *                  *
885
 ************************************************************************/
886
887
/*
888
 * Types are private:
889
 */
890
891
typedef enum {
892
    XPATH_OP_END=0,
893
    XPATH_OP_AND,
894
    XPATH_OP_OR,
895
    XPATH_OP_EQUAL,
896
    XPATH_OP_CMP,
897
    XPATH_OP_PLUS,
898
    XPATH_OP_MULT,
899
    XPATH_OP_UNION,
900
    XPATH_OP_ROOT,
901
    XPATH_OP_NODE,
902
    XPATH_OP_COLLECT,
903
    XPATH_OP_VALUE, /* 11 */
904
    XPATH_OP_VARIABLE,
905
    XPATH_OP_FUNCTION,
906
    XPATH_OP_ARG,
907
    XPATH_OP_PREDICATE,
908
    XPATH_OP_FILTER, /* 16 */
909
    XPATH_OP_SORT /* 17 */
910
#ifdef LIBXML_XPTR_LOCS_ENABLED
911
    ,XPATH_OP_RANGETO
912
#endif
913
} xmlXPathOp;
914
915
typedef enum {
916
    AXIS_ANCESTOR = 1,
917
    AXIS_ANCESTOR_OR_SELF,
918
    AXIS_ATTRIBUTE,
919
    AXIS_CHILD,
920
    AXIS_DESCENDANT,
921
    AXIS_DESCENDANT_OR_SELF,
922
    AXIS_FOLLOWING,
923
    AXIS_FOLLOWING_SIBLING,
924
    AXIS_NAMESPACE,
925
    AXIS_PARENT,
926
    AXIS_PRECEDING,
927
    AXIS_PRECEDING_SIBLING,
928
    AXIS_SELF
929
} xmlXPathAxisVal;
930
931
typedef enum {
932
    NODE_TEST_NONE = 0,
933
    NODE_TEST_TYPE = 1,
934
    NODE_TEST_PI = 2,
935
    NODE_TEST_ALL = 3,
936
    NODE_TEST_NS = 4,
937
    NODE_TEST_NAME = 5
938
} xmlXPathTestVal;
939
940
typedef enum {
941
    NODE_TYPE_NODE = 0,
942
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
943
    NODE_TYPE_TEXT = XML_TEXT_NODE,
944
    NODE_TYPE_PI = XML_PI_NODE
945
} xmlXPathTypeVal;
946
947
typedef struct _xmlXPathStepOp xmlXPathStepOp;
948
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
949
struct _xmlXPathStepOp {
950
    xmlXPathOp op;    /* The identifier of the operation */
951
    int ch1;      /* First child */
952
    int ch2;      /* Second child */
953
    int value;
954
    int value2;
955
    int value3;
956
    void *value4;
957
    void *value5;
958
    xmlXPathFunction cache;
959
    void *cacheURI;
960
};
961
962
struct _xmlXPathCompExpr {
963
    int nbStep;     /* Number of steps in this expression */
964
    int maxStep;    /* Maximum number of steps allocated */
965
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
966
    int last;     /* index of last step in expression */
967
    xmlChar *expr;    /* the expression being computed */
968
    xmlDictPtr dict;    /* the dictionary to use if any */
969
#ifdef DEBUG_EVAL_COUNTS
970
    int nb;
971
    xmlChar *string;
972
#endif
973
#ifdef XPATH_STREAMING
974
    xmlPatternPtr stream;
975
#endif
976
};
977
978
/************************************************************************
979
 *                  *
980
 *      Forward declarations        *
981
 *                  *
982
 ************************************************************************/
983
static void
984
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
985
static void
986
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
987
static int
988
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
989
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
990
static int
991
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
992
          xmlXPathStepOpPtr op,
993
          int isPredicate);
994
static void
995
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
996
997
/************************************************************************
998
 *                  *
999
 *      Parser Type functions       *
1000
 *                  *
1001
 ************************************************************************/
1002
1003
/**
1004
 * xmlXPathNewCompExpr:
1005
 *
1006
 * Create a new Xpath component
1007
 *
1008
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1009
 */
1010
static xmlXPathCompExprPtr
1011
0
xmlXPathNewCompExpr(void) {
1012
0
    xmlXPathCompExprPtr cur;
1013
1014
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1015
0
    if (cur == NULL) {
1016
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1017
0
  return(NULL);
1018
0
    }
1019
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1020
0
    cur->maxStep = 10;
1021
0
    cur->nbStep = 0;
1022
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1023
0
                                     sizeof(xmlXPathStepOp));
1024
0
    if (cur->steps == NULL) {
1025
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1026
0
  xmlFree(cur);
1027
0
  return(NULL);
1028
0
    }
1029
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1030
0
    cur->last = -1;
1031
#ifdef DEBUG_EVAL_COUNTS
1032
    cur->nb = 0;
1033
#endif
1034
0
    return(cur);
1035
0
}
1036
1037
/**
1038
 * xmlXPathFreeCompExpr:
1039
 * @comp:  an XPATH comp
1040
 *
1041
 * Free up the memory allocated by @comp
1042
 */
1043
void
1044
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1045
0
{
1046
0
    xmlXPathStepOpPtr op;
1047
0
    int i;
1048
1049
0
    if (comp == NULL)
1050
0
        return;
1051
0
    if (comp->dict == NULL) {
1052
0
  for (i = 0; i < comp->nbStep; i++) {
1053
0
      op = &comp->steps[i];
1054
0
      if (op->value4 != NULL) {
1055
0
    if (op->op == XPATH_OP_VALUE)
1056
0
        xmlXPathFreeObject(op->value4);
1057
0
    else
1058
0
        xmlFree(op->value4);
1059
0
      }
1060
0
      if (op->value5 != NULL)
1061
0
    xmlFree(op->value5);
1062
0
  }
1063
0
    } else {
1064
0
  for (i = 0; i < comp->nbStep; i++) {
1065
0
      op = &comp->steps[i];
1066
0
      if (op->value4 != NULL) {
1067
0
    if (op->op == XPATH_OP_VALUE)
1068
0
        xmlXPathFreeObject(op->value4);
1069
0
      }
1070
0
  }
1071
0
        xmlDictFree(comp->dict);
1072
0
    }
1073
0
    if (comp->steps != NULL) {
1074
0
        xmlFree(comp->steps);
1075
0
    }
1076
#ifdef DEBUG_EVAL_COUNTS
1077
    if (comp->string != NULL) {
1078
        xmlFree(comp->string);
1079
    }
1080
#endif
1081
0
#ifdef XPATH_STREAMING
1082
0
    if (comp->stream != NULL) {
1083
0
        xmlFreePatternList(comp->stream);
1084
0
    }
1085
0
#endif
1086
0
    if (comp->expr != NULL) {
1087
0
        xmlFree(comp->expr);
1088
0
    }
1089
1090
0
    xmlFree(comp);
1091
0
}
1092
1093
/**
1094
 * xmlXPathCompExprAdd:
1095
 * @comp:  the compiled expression
1096
 * @ch1: first child index
1097
 * @ch2: second child index
1098
 * @op:  an op
1099
 * @value:  the first int value
1100
 * @value2:  the second int value
1101
 * @value3:  the third int value
1102
 * @value4:  the first string value
1103
 * @value5:  the second string value
1104
 *
1105
 * Add a step to an XPath Compiled Expression
1106
 *
1107
 * Returns -1 in case of failure, the index otherwise
1108
 */
1109
static int
1110
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1111
   xmlXPathOp op, int value,
1112
0
   int value2, int value3, void *value4, void *value5) {
1113
0
    xmlXPathCompExprPtr comp = ctxt->comp;
1114
0
    if (comp->nbStep >= comp->maxStep) {
1115
0
  xmlXPathStepOp *real;
1116
1117
0
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1118
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1119
0
      return(-1);
1120
0
        }
1121
0
  comp->maxStep *= 2;
1122
0
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1123
0
                          comp->maxStep * sizeof(xmlXPathStepOp));
1124
0
  if (real == NULL) {
1125
0
      comp->maxStep /= 2;
1126
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1127
0
      return(-1);
1128
0
  }
1129
0
  comp->steps = real;
1130
0
    }
1131
0
    comp->last = comp->nbStep;
1132
0
    comp->steps[comp->nbStep].ch1 = ch1;
1133
0
    comp->steps[comp->nbStep].ch2 = ch2;
1134
0
    comp->steps[comp->nbStep].op = op;
1135
0
    comp->steps[comp->nbStep].value = value;
1136
0
    comp->steps[comp->nbStep].value2 = value2;
1137
0
    comp->steps[comp->nbStep].value3 = value3;
1138
0
    if ((comp->dict != NULL) &&
1139
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1140
0
   (op == XPATH_OP_COLLECT))) {
1141
0
        if (value4 != NULL) {
1142
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1143
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1144
0
      xmlFree(value4);
1145
0
  } else
1146
0
      comp->steps[comp->nbStep].value4 = NULL;
1147
0
        if (value5 != NULL) {
1148
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1149
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1150
0
      xmlFree(value5);
1151
0
  } else
1152
0
      comp->steps[comp->nbStep].value5 = NULL;
1153
0
    } else {
1154
0
  comp->steps[comp->nbStep].value4 = value4;
1155
0
  comp->steps[comp->nbStep].value5 = value5;
1156
0
    }
1157
0
    comp->steps[comp->nbStep].cache = NULL;
1158
0
    return(comp->nbStep++);
1159
0
}
1160
1161
/**
1162
 * xmlXPathCompSwap:
1163
 * @comp:  the compiled expression
1164
 * @op: operation index
1165
 *
1166
 * Swaps 2 operations in the compiled expression
1167
 */
1168
static void
1169
0
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1170
0
    int tmp;
1171
1172
#ifndef LIBXML_THREAD_ENABLED
1173
    /*
1174
     * Since this manipulates possibly shared variables, this is
1175
     * disabled if one detects that the library is used in a multithreaded
1176
     * application
1177
     */
1178
    if (xmlXPathDisableOptimizer)
1179
  return;
1180
#endif
1181
1182
0
    tmp = op->ch1;
1183
0
    op->ch1 = op->ch2;
1184
0
    op->ch2 = tmp;
1185
0
}
1186
1187
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1188
0
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1189
0
                  (op), (val), (val2), (val3), (val4), (val5))
1190
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1191
0
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1192
0
                  (op), (val), (val2), (val3), (val4), (val5))
1193
1194
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1195
0
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1196
1197
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1198
0
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1199
1200
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1201
0
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1202
0
      (val), (val2), 0 ,NULL ,NULL)
1203
1204
/************************************************************************
1205
 *                  *
1206
 *    XPath object cache structures       *
1207
 *                  *
1208
 ************************************************************************/
1209
1210
/* #define XP_DEFAULT_CACHE_ON */
1211
1212
0
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1213
1214
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1215
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1216
struct _xmlXPathContextCache {
1217
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1218
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1219
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1220
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1221
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1222
    int maxNodeset;
1223
    int maxString;
1224
    int maxBoolean;
1225
    int maxNumber;
1226
    int maxMisc;
1227
#ifdef XP_DEBUG_OBJ_USAGE
1228
    int dbgCachedAll;
1229
    int dbgCachedNodeset;
1230
    int dbgCachedString;
1231
    int dbgCachedBool;
1232
    int dbgCachedNumber;
1233
    int dbgCachedPoint;
1234
    int dbgCachedRange;
1235
    int dbgCachedLocset;
1236
    int dbgCachedUsers;
1237
    int dbgCachedXSLTTree;
1238
    int dbgCachedUndefined;
1239
1240
1241
    int dbgReusedAll;
1242
    int dbgReusedNodeset;
1243
    int dbgReusedString;
1244
    int dbgReusedBool;
1245
    int dbgReusedNumber;
1246
    int dbgReusedPoint;
1247
    int dbgReusedRange;
1248
    int dbgReusedLocset;
1249
    int dbgReusedUsers;
1250
    int dbgReusedXSLTTree;
1251
    int dbgReusedUndefined;
1252
1253
#endif
1254
};
1255
1256
/************************************************************************
1257
 *                  *
1258
 *    Debugging related functions       *
1259
 *                  *
1260
 ************************************************************************/
1261
1262
#define STRANGE             \
1263
0
    xmlGenericError(xmlGenericErrorContext,       \
1264
0
      "Internal error at %s:%d\n",        \
1265
0
            __FILE__, __LINE__);
1266
1267
#ifdef LIBXML_DEBUG_ENABLED
1268
static void
1269
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1270
0
    int i;
1271
0
    char shift[100];
1272
1273
0
    for (i = 0;((i < depth) && (i < 25));i++)
1274
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1275
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1276
0
    if (cur == NULL) {
1277
0
  fprintf(output, "%s", shift);
1278
0
  fprintf(output, "Node is NULL !\n");
1279
0
  return;
1280
1281
0
    }
1282
1283
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1284
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1285
0
  fprintf(output, "%s", shift);
1286
0
  fprintf(output, " /\n");
1287
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1288
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1289
0
    else
1290
0
  xmlDebugDumpOneNode(output, cur, depth);
1291
0
}
1292
static void
1293
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1294
0
    xmlNodePtr tmp;
1295
0
    int i;
1296
0
    char shift[100];
1297
1298
0
    for (i = 0;((i < depth) && (i < 25));i++)
1299
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1300
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1301
0
    if (cur == NULL) {
1302
0
  fprintf(output, "%s", shift);
1303
0
  fprintf(output, "Node is NULL !\n");
1304
0
  return;
1305
1306
0
    }
1307
1308
0
    while (cur != NULL) {
1309
0
  tmp = cur;
1310
0
  cur = cur->next;
1311
0
  xmlDebugDumpOneNode(output, tmp, depth);
1312
0
    }
1313
0
}
1314
1315
static void
1316
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1317
0
    int i;
1318
0
    char shift[100];
1319
1320
0
    for (i = 0;((i < depth) && (i < 25));i++)
1321
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1322
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1323
1324
0
    if (cur == NULL) {
1325
0
  fprintf(output, "%s", shift);
1326
0
  fprintf(output, "NodeSet is NULL !\n");
1327
0
  return;
1328
1329
0
    }
1330
1331
0
    if (cur != NULL) {
1332
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1333
0
  for (i = 0;i < cur->nodeNr;i++) {
1334
0
      fprintf(output, "%s", shift);
1335
0
      fprintf(output, "%d", i + 1);
1336
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1337
0
  }
1338
0
    }
1339
0
}
1340
1341
static void
1342
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1343
0
    int i;
1344
0
    char shift[100];
1345
1346
0
    for (i = 0;((i < depth) && (i < 25));i++)
1347
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1348
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1349
1350
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1351
0
  fprintf(output, "%s", shift);
1352
0
  fprintf(output, "Value Tree is NULL !\n");
1353
0
  return;
1354
1355
0
    }
1356
1357
0
    fprintf(output, "%s", shift);
1358
0
    fprintf(output, "%d", i + 1);
1359
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1360
0
}
1361
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1362
static void
1363
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1364
    int i;
1365
    char shift[100];
1366
1367
    for (i = 0;((i < depth) && (i < 25));i++)
1368
        shift[2 * i] = shift[2 * i + 1] = ' ';
1369
    shift[2 * i] = shift[2 * i + 1] = 0;
1370
1371
    if (cur == NULL) {
1372
  fprintf(output, "%s", shift);
1373
  fprintf(output, "LocationSet is NULL !\n");
1374
  return;
1375
1376
    }
1377
1378
    for (i = 0;i < cur->locNr;i++) {
1379
  fprintf(output, "%s", shift);
1380
        fprintf(output, "%d : ", i + 1);
1381
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1382
    }
1383
}
1384
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1385
1386
/**
1387
 * xmlXPathDebugDumpObject:
1388
 * @output:  the FILE * to dump the output
1389
 * @cur:  the object to inspect
1390
 * @depth:  indentation level
1391
 *
1392
 * Dump the content of the object for debugging purposes
1393
 */
1394
void
1395
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1396
0
    int i;
1397
0
    char shift[100];
1398
1399
0
    if (output == NULL) return;
1400
1401
0
    for (i = 0;((i < depth) && (i < 25));i++)
1402
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1403
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1404
1405
1406
0
    fprintf(output, "%s", shift);
1407
1408
0
    if (cur == NULL) {
1409
0
        fprintf(output, "Object is empty (NULL)\n");
1410
0
  return;
1411
0
    }
1412
0
    switch(cur->type) {
1413
0
        case XPATH_UNDEFINED:
1414
0
      fprintf(output, "Object is uninitialized\n");
1415
0
      break;
1416
0
        case XPATH_NODESET:
1417
0
      fprintf(output, "Object is a Node Set :\n");
1418
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1419
0
      break;
1420
0
  case XPATH_XSLT_TREE:
1421
0
      fprintf(output, "Object is an XSLT value tree :\n");
1422
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1423
0
      break;
1424
0
        case XPATH_BOOLEAN:
1425
0
      fprintf(output, "Object is a Boolean : ");
1426
0
      if (cur->boolval) fprintf(output, "true\n");
1427
0
      else fprintf(output, "false\n");
1428
0
      break;
1429
0
        case XPATH_NUMBER:
1430
0
      switch (xmlXPathIsInf(cur->floatval)) {
1431
0
      case 1:
1432
0
    fprintf(output, "Object is a number : Infinity\n");
1433
0
    break;
1434
0
      case -1:
1435
0
    fprintf(output, "Object is a number : -Infinity\n");
1436
0
    break;
1437
0
      default:
1438
0
    if (xmlXPathIsNaN(cur->floatval)) {
1439
0
        fprintf(output, "Object is a number : NaN\n");
1440
0
    } else if (cur->floatval == 0) {
1441
                    /* Omit sign for negative zero. */
1442
0
        fprintf(output, "Object is a number : 0\n");
1443
0
    } else {
1444
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1445
0
    }
1446
0
      }
1447
0
      break;
1448
0
        case XPATH_STRING:
1449
0
      fprintf(output, "Object is a string : ");
1450
0
      xmlDebugDumpString(output, cur->stringval);
1451
0
      fprintf(output, "\n");
1452
0
      break;
1453
#ifdef LIBXML_XPTR_LOCS_ENABLED
1454
  case XPATH_POINT:
1455
      fprintf(output, "Object is a point : index %d in node", cur->index);
1456
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1457
      fprintf(output, "\n");
1458
      break;
1459
  case XPATH_RANGE:
1460
      if ((cur->user2 == NULL) ||
1461
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1462
    fprintf(output, "Object is a collapsed range :\n");
1463
    fprintf(output, "%s", shift);
1464
    if (cur->index >= 0)
1465
        fprintf(output, "index %d in ", cur->index);
1466
    fprintf(output, "node\n");
1467
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1468
                    depth + 1);
1469
      } else  {
1470
    fprintf(output, "Object is a range :\n");
1471
    fprintf(output, "%s", shift);
1472
    fprintf(output, "From ");
1473
    if (cur->index >= 0)
1474
        fprintf(output, "index %d in ", cur->index);
1475
    fprintf(output, "node\n");
1476
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1477
                    depth + 1);
1478
    fprintf(output, "%s", shift);
1479
    fprintf(output, "To ");
1480
    if (cur->index2 >= 0)
1481
        fprintf(output, "index %d in ", cur->index2);
1482
    fprintf(output, "node\n");
1483
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1484
                    depth + 1);
1485
    fprintf(output, "\n");
1486
      }
1487
      break;
1488
  case XPATH_LOCATIONSET:
1489
      fprintf(output, "Object is a Location Set:\n");
1490
      xmlXPathDebugDumpLocationSet(output,
1491
        (xmlLocationSetPtr) cur->user, depth);
1492
      break;
1493
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1494
0
  case XPATH_USERS:
1495
0
      fprintf(output, "Object is user defined\n");
1496
0
      break;
1497
0
    }
1498
0
}
1499
1500
static void
1501
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1502
0
                       xmlXPathStepOpPtr op, int depth) {
1503
0
    int i;
1504
0
    char shift[100];
1505
1506
0
    for (i = 0;((i < depth) && (i < 25));i++)
1507
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1508
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1509
1510
0
    fprintf(output, "%s", shift);
1511
0
    if (op == NULL) {
1512
0
  fprintf(output, "Step is NULL\n");
1513
0
  return;
1514
0
    }
1515
0
    switch (op->op) {
1516
0
        case XPATH_OP_END:
1517
0
      fprintf(output, "END"); break;
1518
0
        case XPATH_OP_AND:
1519
0
      fprintf(output, "AND"); break;
1520
0
        case XPATH_OP_OR:
1521
0
      fprintf(output, "OR"); break;
1522
0
        case XPATH_OP_EQUAL:
1523
0
       if (op->value)
1524
0
     fprintf(output, "EQUAL =");
1525
0
       else
1526
0
     fprintf(output, "EQUAL !=");
1527
0
       break;
1528
0
        case XPATH_OP_CMP:
1529
0
       if (op->value)
1530
0
     fprintf(output, "CMP <");
1531
0
       else
1532
0
     fprintf(output, "CMP >");
1533
0
       if (!op->value2)
1534
0
     fprintf(output, "=");
1535
0
       break;
1536
0
        case XPATH_OP_PLUS:
1537
0
       if (op->value == 0)
1538
0
     fprintf(output, "PLUS -");
1539
0
       else if (op->value == 1)
1540
0
     fprintf(output, "PLUS +");
1541
0
       else if (op->value == 2)
1542
0
     fprintf(output, "PLUS unary -");
1543
0
       else if (op->value == 3)
1544
0
     fprintf(output, "PLUS unary - -");
1545
0
       break;
1546
0
        case XPATH_OP_MULT:
1547
0
       if (op->value == 0)
1548
0
     fprintf(output, "MULT *");
1549
0
       else if (op->value == 1)
1550
0
     fprintf(output, "MULT div");
1551
0
       else
1552
0
     fprintf(output, "MULT mod");
1553
0
       break;
1554
0
        case XPATH_OP_UNION:
1555
0
       fprintf(output, "UNION"); break;
1556
0
        case XPATH_OP_ROOT:
1557
0
       fprintf(output, "ROOT"); break;
1558
0
        case XPATH_OP_NODE:
1559
0
       fprintf(output, "NODE"); break;
1560
0
        case XPATH_OP_SORT:
1561
0
       fprintf(output, "SORT"); break;
1562
0
        case XPATH_OP_COLLECT: {
1563
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1564
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1565
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1566
0
      const xmlChar *prefix = op->value4;
1567
0
      const xmlChar *name = op->value5;
1568
1569
0
      fprintf(output, "COLLECT ");
1570
0
      switch (axis) {
1571
0
    case AXIS_ANCESTOR:
1572
0
        fprintf(output, " 'ancestors' "); break;
1573
0
    case AXIS_ANCESTOR_OR_SELF:
1574
0
        fprintf(output, " 'ancestors-or-self' "); break;
1575
0
    case AXIS_ATTRIBUTE:
1576
0
        fprintf(output, " 'attributes' "); break;
1577
0
    case AXIS_CHILD:
1578
0
        fprintf(output, " 'child' "); break;
1579
0
    case AXIS_DESCENDANT:
1580
0
        fprintf(output, " 'descendant' "); break;
1581
0
    case AXIS_DESCENDANT_OR_SELF:
1582
0
        fprintf(output, " 'descendant-or-self' "); break;
1583
0
    case AXIS_FOLLOWING:
1584
0
        fprintf(output, " 'following' "); break;
1585
0
    case AXIS_FOLLOWING_SIBLING:
1586
0
        fprintf(output, " 'following-siblings' "); break;
1587
0
    case AXIS_NAMESPACE:
1588
0
        fprintf(output, " 'namespace' "); break;
1589
0
    case AXIS_PARENT:
1590
0
        fprintf(output, " 'parent' "); break;
1591
0
    case AXIS_PRECEDING:
1592
0
        fprintf(output, " 'preceding' "); break;
1593
0
    case AXIS_PRECEDING_SIBLING:
1594
0
        fprintf(output, " 'preceding-sibling' "); break;
1595
0
    case AXIS_SELF:
1596
0
        fprintf(output, " 'self' "); break;
1597
0
      }
1598
0
      switch (test) {
1599
0
                case NODE_TEST_NONE:
1600
0
        fprintf(output, "'none' "); break;
1601
0
                case NODE_TEST_TYPE:
1602
0
        fprintf(output, "'type' "); break;
1603
0
                case NODE_TEST_PI:
1604
0
        fprintf(output, "'PI' "); break;
1605
0
                case NODE_TEST_ALL:
1606
0
        fprintf(output, "'all' "); break;
1607
0
                case NODE_TEST_NS:
1608
0
        fprintf(output, "'namespace' "); break;
1609
0
                case NODE_TEST_NAME:
1610
0
        fprintf(output, "'name' "); break;
1611
0
      }
1612
0
      switch (type) {
1613
0
                case NODE_TYPE_NODE:
1614
0
        fprintf(output, "'node' "); break;
1615
0
                case NODE_TYPE_COMMENT:
1616
0
        fprintf(output, "'comment' "); break;
1617
0
                case NODE_TYPE_TEXT:
1618
0
        fprintf(output, "'text' "); break;
1619
0
                case NODE_TYPE_PI:
1620
0
        fprintf(output, "'PI' "); break;
1621
0
      }
1622
0
      if (prefix != NULL)
1623
0
    fprintf(output, "%s:", prefix);
1624
0
      if (name != NULL)
1625
0
    fprintf(output, "%s", (const char *) name);
1626
0
      break;
1627
1628
0
        }
1629
0
  case XPATH_OP_VALUE: {
1630
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1631
1632
0
      fprintf(output, "ELEM ");
1633
0
      xmlXPathDebugDumpObject(output, object, 0);
1634
0
      goto finish;
1635
0
  }
1636
0
  case XPATH_OP_VARIABLE: {
1637
0
      const xmlChar *prefix = op->value5;
1638
0
      const xmlChar *name = op->value4;
1639
1640
0
      if (prefix != NULL)
1641
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1642
0
      else
1643
0
    fprintf(output, "VARIABLE %s", name);
1644
0
      break;
1645
0
  }
1646
0
  case XPATH_OP_FUNCTION: {
1647
0
      int nbargs = op->value;
1648
0
      const xmlChar *prefix = op->value5;
1649
0
      const xmlChar *name = op->value4;
1650
1651
0
      if (prefix != NULL)
1652
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1653
0
      prefix, name, nbargs);
1654
0
      else
1655
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1656
0
      break;
1657
0
  }
1658
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1659
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1660
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1661
#ifdef LIBXML_XPTR_LOCS_ENABLED
1662
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1663
#endif
1664
0
  default:
1665
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1666
0
    }
1667
0
    fprintf(output, "\n");
1668
0
finish:
1669
0
    if (op->ch1 >= 0)
1670
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1671
0
    if (op->ch2 >= 0)
1672
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1673
0
}
1674
1675
/**
1676
 * xmlXPathDebugDumpCompExpr:
1677
 * @output:  the FILE * for the output
1678
 * @comp:  the precompiled XPath expression
1679
 * @depth:  the indentation level.
1680
 *
1681
 * Dumps the tree of the compiled XPath expression.
1682
 */
1683
void
1684
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1685
0
                    int depth) {
1686
0
    int i;
1687
0
    char shift[100];
1688
1689
0
    if ((output == NULL) || (comp == NULL)) return;
1690
1691
0
    for (i = 0;((i < depth) && (i < 25));i++)
1692
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1693
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1694
1695
0
    fprintf(output, "%s", shift);
1696
1697
0
#ifdef XPATH_STREAMING
1698
0
    if (comp->stream) {
1699
0
        fprintf(output, "Streaming Expression\n");
1700
0
    } else
1701
0
#endif
1702
0
    {
1703
0
        fprintf(output, "Compiled Expression : %d elements\n",
1704
0
                comp->nbStep);
1705
0
        i = comp->last;
1706
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1707
0
    }
1708
0
}
1709
1710
#ifdef XP_DEBUG_OBJ_USAGE
1711
1712
/*
1713
* XPath object usage related debugging variables.
1714
*/
1715
static int xmlXPathDebugObjCounterUndefined = 0;
1716
static int xmlXPathDebugObjCounterNodeset = 0;
1717
static int xmlXPathDebugObjCounterBool = 0;
1718
static int xmlXPathDebugObjCounterNumber = 0;
1719
static int xmlXPathDebugObjCounterString = 0;
1720
static int xmlXPathDebugObjCounterPoint = 0;
1721
static int xmlXPathDebugObjCounterRange = 0;
1722
static int xmlXPathDebugObjCounterLocset = 0;
1723
static int xmlXPathDebugObjCounterUsers = 0;
1724
static int xmlXPathDebugObjCounterXSLTTree = 0;
1725
static int xmlXPathDebugObjCounterAll = 0;
1726
1727
static int xmlXPathDebugObjTotalUndefined = 0;
1728
static int xmlXPathDebugObjTotalNodeset = 0;
1729
static int xmlXPathDebugObjTotalBool = 0;
1730
static int xmlXPathDebugObjTotalNumber = 0;
1731
static int xmlXPathDebugObjTotalString = 0;
1732
static int xmlXPathDebugObjTotalPoint = 0;
1733
static int xmlXPathDebugObjTotalRange = 0;
1734
static int xmlXPathDebugObjTotalLocset = 0;
1735
static int xmlXPathDebugObjTotalUsers = 0;
1736
static int xmlXPathDebugObjTotalXSLTTree = 0;
1737
static int xmlXPathDebugObjTotalAll = 0;
1738
1739
static int xmlXPathDebugObjMaxUndefined = 0;
1740
static int xmlXPathDebugObjMaxNodeset = 0;
1741
static int xmlXPathDebugObjMaxBool = 0;
1742
static int xmlXPathDebugObjMaxNumber = 0;
1743
static int xmlXPathDebugObjMaxString = 0;
1744
static int xmlXPathDebugObjMaxPoint = 0;
1745
static int xmlXPathDebugObjMaxRange = 0;
1746
static int xmlXPathDebugObjMaxLocset = 0;
1747
static int xmlXPathDebugObjMaxUsers = 0;
1748
static int xmlXPathDebugObjMaxXSLTTree = 0;
1749
static int xmlXPathDebugObjMaxAll = 0;
1750
1751
static void
1752
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1753
{
1754
    if (ctxt != NULL) {
1755
  if (ctxt->cache != NULL) {
1756
      xmlXPathContextCachePtr cache =
1757
    (xmlXPathContextCachePtr) ctxt->cache;
1758
1759
      cache->dbgCachedAll = 0;
1760
      cache->dbgCachedNodeset = 0;
1761
      cache->dbgCachedString = 0;
1762
      cache->dbgCachedBool = 0;
1763
      cache->dbgCachedNumber = 0;
1764
      cache->dbgCachedPoint = 0;
1765
      cache->dbgCachedRange = 0;
1766
      cache->dbgCachedLocset = 0;
1767
      cache->dbgCachedUsers = 0;
1768
      cache->dbgCachedXSLTTree = 0;
1769
      cache->dbgCachedUndefined = 0;
1770
1771
      cache->dbgReusedAll = 0;
1772
      cache->dbgReusedNodeset = 0;
1773
      cache->dbgReusedString = 0;
1774
      cache->dbgReusedBool = 0;
1775
      cache->dbgReusedNumber = 0;
1776
      cache->dbgReusedPoint = 0;
1777
      cache->dbgReusedRange = 0;
1778
      cache->dbgReusedLocset = 0;
1779
      cache->dbgReusedUsers = 0;
1780
      cache->dbgReusedXSLTTree = 0;
1781
      cache->dbgReusedUndefined = 0;
1782
  }
1783
    }
1784
1785
    xmlXPathDebugObjCounterUndefined = 0;
1786
    xmlXPathDebugObjCounterNodeset = 0;
1787
    xmlXPathDebugObjCounterBool = 0;
1788
    xmlXPathDebugObjCounterNumber = 0;
1789
    xmlXPathDebugObjCounterString = 0;
1790
    xmlXPathDebugObjCounterPoint = 0;
1791
    xmlXPathDebugObjCounterRange = 0;
1792
    xmlXPathDebugObjCounterLocset = 0;
1793
    xmlXPathDebugObjCounterUsers = 0;
1794
    xmlXPathDebugObjCounterXSLTTree = 0;
1795
    xmlXPathDebugObjCounterAll = 0;
1796
1797
    xmlXPathDebugObjTotalUndefined = 0;
1798
    xmlXPathDebugObjTotalNodeset = 0;
1799
    xmlXPathDebugObjTotalBool = 0;
1800
    xmlXPathDebugObjTotalNumber = 0;
1801
    xmlXPathDebugObjTotalString = 0;
1802
    xmlXPathDebugObjTotalPoint = 0;
1803
    xmlXPathDebugObjTotalRange = 0;
1804
    xmlXPathDebugObjTotalLocset = 0;
1805
    xmlXPathDebugObjTotalUsers = 0;
1806
    xmlXPathDebugObjTotalXSLTTree = 0;
1807
    xmlXPathDebugObjTotalAll = 0;
1808
1809
    xmlXPathDebugObjMaxUndefined = 0;
1810
    xmlXPathDebugObjMaxNodeset = 0;
1811
    xmlXPathDebugObjMaxBool = 0;
1812
    xmlXPathDebugObjMaxNumber = 0;
1813
    xmlXPathDebugObjMaxString = 0;
1814
    xmlXPathDebugObjMaxPoint = 0;
1815
    xmlXPathDebugObjMaxRange = 0;
1816
    xmlXPathDebugObjMaxLocset = 0;
1817
    xmlXPathDebugObjMaxUsers = 0;
1818
    xmlXPathDebugObjMaxXSLTTree = 0;
1819
    xmlXPathDebugObjMaxAll = 0;
1820
1821
}
1822
1823
static void
1824
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1825
            xmlXPathObjectType objType)
1826
{
1827
    int isCached = 0;
1828
1829
    if (ctxt != NULL) {
1830
  if (ctxt->cache != NULL) {
1831
      xmlXPathContextCachePtr cache =
1832
    (xmlXPathContextCachePtr) ctxt->cache;
1833
1834
      isCached = 1;
1835
1836
      cache->dbgReusedAll++;
1837
      switch (objType) {
1838
    case XPATH_UNDEFINED:
1839
        cache->dbgReusedUndefined++;
1840
        break;
1841
    case XPATH_NODESET:
1842
        cache->dbgReusedNodeset++;
1843
        break;
1844
    case XPATH_BOOLEAN:
1845
        cache->dbgReusedBool++;
1846
        break;
1847
    case XPATH_NUMBER:
1848
        cache->dbgReusedNumber++;
1849
        break;
1850
    case XPATH_STRING:
1851
        cache->dbgReusedString++;
1852
        break;
1853
#ifdef LIBXML_XPTR_LOCS_ENABLED
1854
    case XPATH_POINT:
1855
        cache->dbgReusedPoint++;
1856
        break;
1857
    case XPATH_RANGE:
1858
        cache->dbgReusedRange++;
1859
        break;
1860
    case XPATH_LOCATIONSET:
1861
        cache->dbgReusedLocset++;
1862
        break;
1863
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1864
    case XPATH_USERS:
1865
        cache->dbgReusedUsers++;
1866
        break;
1867
    case XPATH_XSLT_TREE:
1868
        cache->dbgReusedXSLTTree++;
1869
        break;
1870
    default:
1871
        break;
1872
      }
1873
  }
1874
    }
1875
1876
    switch (objType) {
1877
  case XPATH_UNDEFINED:
1878
      if (! isCached)
1879
    xmlXPathDebugObjTotalUndefined++;
1880
      xmlXPathDebugObjCounterUndefined++;
1881
      if (xmlXPathDebugObjCounterUndefined >
1882
    xmlXPathDebugObjMaxUndefined)
1883
    xmlXPathDebugObjMaxUndefined =
1884
        xmlXPathDebugObjCounterUndefined;
1885
      break;
1886
  case XPATH_NODESET:
1887
      if (! isCached)
1888
    xmlXPathDebugObjTotalNodeset++;
1889
      xmlXPathDebugObjCounterNodeset++;
1890
      if (xmlXPathDebugObjCounterNodeset >
1891
    xmlXPathDebugObjMaxNodeset)
1892
    xmlXPathDebugObjMaxNodeset =
1893
        xmlXPathDebugObjCounterNodeset;
1894
      break;
1895
  case XPATH_BOOLEAN:
1896
      if (! isCached)
1897
    xmlXPathDebugObjTotalBool++;
1898
      xmlXPathDebugObjCounterBool++;
1899
      if (xmlXPathDebugObjCounterBool >
1900
    xmlXPathDebugObjMaxBool)
1901
    xmlXPathDebugObjMaxBool =
1902
        xmlXPathDebugObjCounterBool;
1903
      break;
1904
  case XPATH_NUMBER:
1905
      if (! isCached)
1906
    xmlXPathDebugObjTotalNumber++;
1907
      xmlXPathDebugObjCounterNumber++;
1908
      if (xmlXPathDebugObjCounterNumber >
1909
    xmlXPathDebugObjMaxNumber)
1910
    xmlXPathDebugObjMaxNumber =
1911
        xmlXPathDebugObjCounterNumber;
1912
      break;
1913
  case XPATH_STRING:
1914
      if (! isCached)
1915
    xmlXPathDebugObjTotalString++;
1916
      xmlXPathDebugObjCounterString++;
1917
      if (xmlXPathDebugObjCounterString >
1918
    xmlXPathDebugObjMaxString)
1919
    xmlXPathDebugObjMaxString =
1920
        xmlXPathDebugObjCounterString;
1921
      break;
1922
#ifdef LIBXML_XPTR_LOCS_ENABLED
1923
  case XPATH_POINT:
1924
      if (! isCached)
1925
    xmlXPathDebugObjTotalPoint++;
1926
      xmlXPathDebugObjCounterPoint++;
1927
      if (xmlXPathDebugObjCounterPoint >
1928
    xmlXPathDebugObjMaxPoint)
1929
    xmlXPathDebugObjMaxPoint =
1930
        xmlXPathDebugObjCounterPoint;
1931
      break;
1932
  case XPATH_RANGE:
1933
      if (! isCached)
1934
    xmlXPathDebugObjTotalRange++;
1935
      xmlXPathDebugObjCounterRange++;
1936
      if (xmlXPathDebugObjCounterRange >
1937
    xmlXPathDebugObjMaxRange)
1938
    xmlXPathDebugObjMaxRange =
1939
        xmlXPathDebugObjCounterRange;
1940
      break;
1941
  case XPATH_LOCATIONSET:
1942
      if (! isCached)
1943
    xmlXPathDebugObjTotalLocset++;
1944
      xmlXPathDebugObjCounterLocset++;
1945
      if (xmlXPathDebugObjCounterLocset >
1946
    xmlXPathDebugObjMaxLocset)
1947
    xmlXPathDebugObjMaxLocset =
1948
        xmlXPathDebugObjCounterLocset;
1949
      break;
1950
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1951
  case XPATH_USERS:
1952
      if (! isCached)
1953
    xmlXPathDebugObjTotalUsers++;
1954
      xmlXPathDebugObjCounterUsers++;
1955
      if (xmlXPathDebugObjCounterUsers >
1956
    xmlXPathDebugObjMaxUsers)
1957
    xmlXPathDebugObjMaxUsers =
1958
        xmlXPathDebugObjCounterUsers;
1959
      break;
1960
  case XPATH_XSLT_TREE:
1961
      if (! isCached)
1962
    xmlXPathDebugObjTotalXSLTTree++;
1963
      xmlXPathDebugObjCounterXSLTTree++;
1964
      if (xmlXPathDebugObjCounterXSLTTree >
1965
    xmlXPathDebugObjMaxXSLTTree)
1966
    xmlXPathDebugObjMaxXSLTTree =
1967
        xmlXPathDebugObjCounterXSLTTree;
1968
      break;
1969
  default:
1970
      break;
1971
    }
1972
    if (! isCached)
1973
  xmlXPathDebugObjTotalAll++;
1974
    xmlXPathDebugObjCounterAll++;
1975
    if (xmlXPathDebugObjCounterAll >
1976
  xmlXPathDebugObjMaxAll)
1977
  xmlXPathDebugObjMaxAll =
1978
      xmlXPathDebugObjCounterAll;
1979
}
1980
1981
static void
1982
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1983
            xmlXPathObjectType objType)
1984
{
1985
    int isCached = 0;
1986
1987
    if (ctxt != NULL) {
1988
  if (ctxt->cache != NULL) {
1989
      xmlXPathContextCachePtr cache =
1990
    (xmlXPathContextCachePtr) ctxt->cache;
1991
1992
      isCached = 1;
1993
1994
      cache->dbgCachedAll++;
1995
      switch (objType) {
1996
    case XPATH_UNDEFINED:
1997
        cache->dbgCachedUndefined++;
1998
        break;
1999
    case XPATH_NODESET:
2000
        cache->dbgCachedNodeset++;
2001
        break;
2002
    case XPATH_BOOLEAN:
2003
        cache->dbgCachedBool++;
2004
        break;
2005
    case XPATH_NUMBER:
2006
        cache->dbgCachedNumber++;
2007
        break;
2008
    case XPATH_STRING:
2009
        cache->dbgCachedString++;
2010
        break;
2011
#ifdef LIBXML_XPTR_LOCS_ENABLED
2012
    case XPATH_POINT:
2013
        cache->dbgCachedPoint++;
2014
        break;
2015
    case XPATH_RANGE:
2016
        cache->dbgCachedRange++;
2017
        break;
2018
    case XPATH_LOCATIONSET:
2019
        cache->dbgCachedLocset++;
2020
        break;
2021
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2022
    case XPATH_USERS:
2023
        cache->dbgCachedUsers++;
2024
        break;
2025
    case XPATH_XSLT_TREE:
2026
        cache->dbgCachedXSLTTree++;
2027
        break;
2028
    default:
2029
        break;
2030
      }
2031
2032
  }
2033
    }
2034
    switch (objType) {
2035
  case XPATH_UNDEFINED:
2036
      xmlXPathDebugObjCounterUndefined--;
2037
      break;
2038
  case XPATH_NODESET:
2039
      xmlXPathDebugObjCounterNodeset--;
2040
      break;
2041
  case XPATH_BOOLEAN:
2042
      xmlXPathDebugObjCounterBool--;
2043
      break;
2044
  case XPATH_NUMBER:
2045
      xmlXPathDebugObjCounterNumber--;
2046
      break;
2047
  case XPATH_STRING:
2048
      xmlXPathDebugObjCounterString--;
2049
      break;
2050
#ifdef LIBXML_XPTR_LOCS_ENABLED
2051
  case XPATH_POINT:
2052
      xmlXPathDebugObjCounterPoint--;
2053
      break;
2054
  case XPATH_RANGE:
2055
      xmlXPathDebugObjCounterRange--;
2056
      break;
2057
  case XPATH_LOCATIONSET:
2058
      xmlXPathDebugObjCounterLocset--;
2059
      break;
2060
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2061
  case XPATH_USERS:
2062
      xmlXPathDebugObjCounterUsers--;
2063
      break;
2064
  case XPATH_XSLT_TREE:
2065
      xmlXPathDebugObjCounterXSLTTree--;
2066
      break;
2067
  default:
2068
      break;
2069
    }
2070
    xmlXPathDebugObjCounterAll--;
2071
}
2072
2073
static void
2074
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2075
{
2076
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2077
  reqXSLTTree, reqUndefined;
2078
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2079
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2080
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2081
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2082
    int leftObjs = xmlXPathDebugObjCounterAll;
2083
2084
    reqAll = xmlXPathDebugObjTotalAll;
2085
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2086
    reqString = xmlXPathDebugObjTotalString;
2087
    reqBool = xmlXPathDebugObjTotalBool;
2088
    reqNumber = xmlXPathDebugObjTotalNumber;
2089
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2090
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2091
2092
    printf("# XPath object usage:\n");
2093
2094
    if (ctxt != NULL) {
2095
  if (ctxt->cache != NULL) {
2096
      xmlXPathContextCachePtr cache =
2097
    (xmlXPathContextCachePtr) ctxt->cache;
2098
2099
      reAll = cache->dbgReusedAll;
2100
      reqAll += reAll;
2101
      reNodeset = cache->dbgReusedNodeset;
2102
      reqNodeset += reNodeset;
2103
      reString = cache->dbgReusedString;
2104
      reqString += reString;
2105
      reBool = cache->dbgReusedBool;
2106
      reqBool += reBool;
2107
      reNumber = cache->dbgReusedNumber;
2108
      reqNumber += reNumber;
2109
      reXSLTTree = cache->dbgReusedXSLTTree;
2110
      reqXSLTTree += reXSLTTree;
2111
      reUndefined = cache->dbgReusedUndefined;
2112
      reqUndefined += reUndefined;
2113
2114
      caAll = cache->dbgCachedAll;
2115
      caBool = cache->dbgCachedBool;
2116
      caNodeset = cache->dbgCachedNodeset;
2117
      caString = cache->dbgCachedString;
2118
      caNumber = cache->dbgCachedNumber;
2119
      caXSLTTree = cache->dbgCachedXSLTTree;
2120
      caUndefined = cache->dbgCachedUndefined;
2121
2122
      if (cache->nodesetObjs)
2123
    leftObjs -= cache->nodesetObjs->number;
2124
      if (cache->stringObjs)
2125
    leftObjs -= cache->stringObjs->number;
2126
      if (cache->booleanObjs)
2127
    leftObjs -= cache->booleanObjs->number;
2128
      if (cache->numberObjs)
2129
    leftObjs -= cache->numberObjs->number;
2130
      if (cache->miscObjs)
2131
    leftObjs -= cache->miscObjs->number;
2132
  }
2133
    }
2134
2135
    printf("# all\n");
2136
    printf("#   total  : %d\n", reqAll);
2137
    printf("#   left  : %d\n", leftObjs);
2138
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2139
    printf("#   reused : %d\n", reAll);
2140
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2141
2142
    printf("# node-sets\n");
2143
    printf("#   total  : %d\n", reqNodeset);
2144
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2145
    printf("#   reused : %d\n", reNodeset);
2146
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2147
2148
    printf("# strings\n");
2149
    printf("#   total  : %d\n", reqString);
2150
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2151
    printf("#   reused : %d\n", reString);
2152
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2153
2154
    printf("# booleans\n");
2155
    printf("#   total  : %d\n", reqBool);
2156
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2157
    printf("#   reused : %d\n", reBool);
2158
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2159
2160
    printf("# numbers\n");
2161
    printf("#   total  : %d\n", reqNumber);
2162
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2163
    printf("#   reused : %d\n", reNumber);
2164
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2165
2166
    printf("# XSLT result tree fragments\n");
2167
    printf("#   total  : %d\n", reqXSLTTree);
2168
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2169
    printf("#   reused : %d\n", reXSLTTree);
2170
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2171
2172
    printf("# undefined\n");
2173
    printf("#   total  : %d\n", reqUndefined);
2174
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2175
    printf("#   reused : %d\n", reUndefined);
2176
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2177
2178
}
2179
2180
#endif /* XP_DEBUG_OBJ_USAGE */
2181
2182
#endif /* LIBXML_DEBUG_ENABLED */
2183
2184
/************************************************************************
2185
 *                  *
2186
 *      XPath object caching        *
2187
 *                  *
2188
 ************************************************************************/
2189
2190
/**
2191
 * xmlXPathNewCache:
2192
 *
2193
 * Create a new object cache
2194
 *
2195
 * Returns the xmlXPathCache just allocated.
2196
 */
2197
static xmlXPathContextCachePtr
2198
xmlXPathNewCache(void)
2199
0
{
2200
0
    xmlXPathContextCachePtr ret;
2201
2202
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2203
0
    if (ret == NULL) {
2204
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2205
0
  return(NULL);
2206
0
    }
2207
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2208
0
    ret->maxNodeset = 100;
2209
0
    ret->maxString = 100;
2210
0
    ret->maxBoolean = 100;
2211
0
    ret->maxNumber = 100;
2212
0
    ret->maxMisc = 100;
2213
0
    return(ret);
2214
0
}
2215
2216
static void
2217
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2218
0
{
2219
0
    int i;
2220
0
    xmlXPathObjectPtr obj;
2221
2222
0
    if (list == NULL)
2223
0
  return;
2224
2225
0
    for (i = 0; i < list->number; i++) {
2226
0
  obj = list->items[i];
2227
  /*
2228
  * Note that it is already assured that we don't need to
2229
  * look out for namespace nodes in the node-set.
2230
  */
2231
0
  if (obj->nodesetval != NULL) {
2232
0
      if (obj->nodesetval->nodeTab != NULL)
2233
0
    xmlFree(obj->nodesetval->nodeTab);
2234
0
      xmlFree(obj->nodesetval);
2235
0
  }
2236
0
  xmlFree(obj);
2237
#ifdef XP_DEBUG_OBJ_USAGE
2238
  xmlXPathDebugObjCounterAll--;
2239
#endif
2240
0
    }
2241
0
    xmlPointerListFree(list);
2242
0
}
2243
2244
static void
2245
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2246
0
{
2247
0
    if (cache == NULL)
2248
0
  return;
2249
0
    if (cache->nodesetObjs)
2250
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2251
0
    if (cache->stringObjs)
2252
0
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2253
0
    if (cache->booleanObjs)
2254
0
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2255
0
    if (cache->numberObjs)
2256
0
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2257
0
    if (cache->miscObjs)
2258
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2259
0
    xmlFree(cache);
2260
0
}
2261
2262
/**
2263
 * xmlXPathContextSetCache:
2264
 *
2265
 * @ctxt:  the XPath context
2266
 * @active: enables/disables (creates/frees) the cache
2267
 * @value: a value with semantics dependent on @options
2268
 * @options: options (currently only the value 0 is used)
2269
 *
2270
 * Creates/frees an object cache on the XPath context.
2271
 * If activates XPath objects (xmlXPathObject) will be cached internally
2272
 * to be reused.
2273
 * @options:
2274
 *   0: This will set the XPath object caching:
2275
 *      @value:
2276
 *        This will set the maximum number of XPath objects
2277
 *        to be cached per slot
2278
 *        There are 5 slots for: node-set, string, number, boolean, and
2279
 *        misc objects. Use <0 for the default number (100).
2280
 *   Other values for @options have currently no effect.
2281
 *
2282
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2283
 */
2284
int
2285
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2286
      int active,
2287
      int value,
2288
      int options)
2289
0
{
2290
0
    if (ctxt == NULL)
2291
0
  return(-1);
2292
0
    if (active) {
2293
0
  xmlXPathContextCachePtr cache;
2294
2295
0
  if (ctxt->cache == NULL) {
2296
0
      ctxt->cache = xmlXPathNewCache();
2297
0
      if (ctxt->cache == NULL)
2298
0
    return(-1);
2299
0
  }
2300
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2301
0
  if (options == 0) {
2302
0
      if (value < 0)
2303
0
    value = 100;
2304
0
      cache->maxNodeset = value;
2305
0
      cache->maxString = value;
2306
0
      cache->maxNumber = value;
2307
0
      cache->maxBoolean = value;
2308
0
      cache->maxMisc = value;
2309
0
  }
2310
0
    } else if (ctxt->cache != NULL) {
2311
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2312
0
  ctxt->cache = NULL;
2313
0
    }
2314
0
    return(0);
2315
0
}
2316
2317
/**
2318
 * xmlXPathCacheWrapNodeSet:
2319
 * @ctxt: the XPath context
2320
 * @val:  the NodePtr value
2321
 *
2322
 * This is the cached version of xmlXPathWrapNodeSet().
2323
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2324
 *
2325
 * Returns the created or reused object.
2326
 */
2327
static xmlXPathObjectPtr
2328
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2329
0
{
2330
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2331
0
  xmlXPathContextCachePtr cache =
2332
0
      (xmlXPathContextCachePtr) ctxt->cache;
2333
2334
0
  if ((cache->miscObjs != NULL) &&
2335
0
      (cache->miscObjs->number != 0))
2336
0
  {
2337
0
      xmlXPathObjectPtr ret;
2338
2339
0
      ret = (xmlXPathObjectPtr)
2340
0
    cache->miscObjs->items[--cache->miscObjs->number];
2341
0
      ret->type = XPATH_NODESET;
2342
0
      ret->nodesetval = val;
2343
#ifdef XP_DEBUG_OBJ_USAGE
2344
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2345
#endif
2346
0
      return(ret);
2347
0
  }
2348
0
    }
2349
2350
0
    return(xmlXPathWrapNodeSet(val));
2351
2352
0
}
2353
2354
/**
2355
 * xmlXPathCacheWrapString:
2356
 * @ctxt: the XPath context
2357
 * @val:  the xmlChar * value
2358
 *
2359
 * This is the cached version of xmlXPathWrapString().
2360
 * Wraps the @val string into an XPath object.
2361
 *
2362
 * Returns the created or reused object.
2363
 */
2364
static xmlXPathObjectPtr
2365
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2366
0
{
2367
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2368
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2369
2370
0
  if ((cache->stringObjs != NULL) &&
2371
0
      (cache->stringObjs->number != 0))
2372
0
  {
2373
2374
0
      xmlXPathObjectPtr ret;
2375
2376
0
      ret = (xmlXPathObjectPtr)
2377
0
    cache->stringObjs->items[--cache->stringObjs->number];
2378
0
      ret->type = XPATH_STRING;
2379
0
      ret->stringval = val;
2380
#ifdef XP_DEBUG_OBJ_USAGE
2381
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2382
#endif
2383
0
      return(ret);
2384
0
  } else if ((cache->miscObjs != NULL) &&
2385
0
      (cache->miscObjs->number != 0))
2386
0
  {
2387
0
      xmlXPathObjectPtr ret;
2388
      /*
2389
      * Fallback to misc-cache.
2390
      */
2391
0
      ret = (xmlXPathObjectPtr)
2392
0
    cache->miscObjs->items[--cache->miscObjs->number];
2393
2394
0
      ret->type = XPATH_STRING;
2395
0
      ret->stringval = val;
2396
#ifdef XP_DEBUG_OBJ_USAGE
2397
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2398
#endif
2399
0
      return(ret);
2400
0
  }
2401
0
    }
2402
0
    return(xmlXPathWrapString(val));
2403
0
}
2404
2405
/**
2406
 * xmlXPathCacheNewNodeSet:
2407
 * @ctxt: the XPath context
2408
 * @val:  the NodePtr value
2409
 *
2410
 * This is the cached version of xmlXPathNewNodeSet().
2411
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2412
 * it with the single Node @val
2413
 *
2414
 * Returns the created or reused object.
2415
 */
2416
static xmlXPathObjectPtr
2417
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2418
0
{
2419
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2420
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2421
2422
0
  if ((cache->nodesetObjs != NULL) &&
2423
0
      (cache->nodesetObjs->number != 0))
2424
0
  {
2425
0
      xmlXPathObjectPtr ret;
2426
      /*
2427
      * Use the nodeset-cache.
2428
      */
2429
0
      ret = (xmlXPathObjectPtr)
2430
0
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2431
0
      ret->type = XPATH_NODESET;
2432
0
      ret->boolval = 0;
2433
0
      if (val) {
2434
0
    if ((ret->nodesetval->nodeMax == 0) ||
2435
0
        (val->type == XML_NAMESPACE_DECL))
2436
0
    {
2437
                    /* TODO: Check memory error. */
2438
0
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2439
0
    } else {
2440
0
        ret->nodesetval->nodeTab[0] = val;
2441
0
        ret->nodesetval->nodeNr = 1;
2442
0
    }
2443
0
      }
2444
#ifdef XP_DEBUG_OBJ_USAGE
2445
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2446
#endif
2447
0
      return(ret);
2448
0
  } else if ((cache->miscObjs != NULL) &&
2449
0
      (cache->miscObjs->number != 0))
2450
0
  {
2451
0
      xmlXPathObjectPtr ret;
2452
      /*
2453
      * Fallback to misc-cache.
2454
      */
2455
2456
0
      ret = (xmlXPathObjectPtr)
2457
0
    cache->miscObjs->items[--cache->miscObjs->number];
2458
2459
0
      ret->type = XPATH_NODESET;
2460
0
      ret->boolval = 0;
2461
0
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2462
0
      if (ret->nodesetval == NULL) {
2463
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2464
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2465
0
    return(NULL);
2466
0
      }
2467
#ifdef XP_DEBUG_OBJ_USAGE
2468
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2469
#endif
2470
0
      return(ret);
2471
0
  }
2472
0
    }
2473
0
    return(xmlXPathNewNodeSet(val));
2474
0
}
2475
2476
/**
2477
 * xmlXPathCacheNewCString:
2478
 * @ctxt: the XPath context
2479
 * @val:  the char * value
2480
 *
2481
 * This is the cached version of xmlXPathNewCString().
2482
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2483
 *
2484
 * Returns the created or reused object.
2485
 */
2486
static xmlXPathObjectPtr
2487
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2488
0
{
2489
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2490
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2491
2492
0
  if ((cache->stringObjs != NULL) &&
2493
0
      (cache->stringObjs->number != 0))
2494
0
  {
2495
0
      xmlXPathObjectPtr ret;
2496
2497
0
      ret = (xmlXPathObjectPtr)
2498
0
    cache->stringObjs->items[--cache->stringObjs->number];
2499
2500
0
      ret->type = XPATH_STRING;
2501
0
      ret->stringval = xmlStrdup(BAD_CAST val);
2502
#ifdef XP_DEBUG_OBJ_USAGE
2503
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2504
#endif
2505
0
      return(ret);
2506
0
  } else if ((cache->miscObjs != NULL) &&
2507
0
      (cache->miscObjs->number != 0))
2508
0
  {
2509
0
      xmlXPathObjectPtr ret;
2510
2511
0
      ret = (xmlXPathObjectPtr)
2512
0
    cache->miscObjs->items[--cache->miscObjs->number];
2513
2514
0
      ret->type = XPATH_STRING;
2515
0
      ret->stringval = xmlStrdup(BAD_CAST val);
2516
#ifdef XP_DEBUG_OBJ_USAGE
2517
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2518
#endif
2519
0
      return(ret);
2520
0
  }
2521
0
    }
2522
0
    return(xmlXPathNewCString(val));
2523
0
}
2524
2525
/**
2526
 * xmlXPathCacheNewString:
2527
 * @ctxt: the XPath context
2528
 * @val:  the xmlChar * value
2529
 *
2530
 * This is the cached version of xmlXPathNewString().
2531
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2532
 *
2533
 * Returns the created or reused object.
2534
 */
2535
static xmlXPathObjectPtr
2536
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2537
0
{
2538
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2539
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2540
2541
0
  if ((cache->stringObjs != NULL) &&
2542
0
      (cache->stringObjs->number != 0))
2543
0
  {
2544
0
      xmlXPathObjectPtr ret;
2545
2546
0
      ret = (xmlXPathObjectPtr)
2547
0
    cache->stringObjs->items[--cache->stringObjs->number];
2548
0
      ret->type = XPATH_STRING;
2549
0
      if (val != NULL)
2550
0
    ret->stringval = xmlStrdup(val);
2551
0
      else
2552
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2553
#ifdef XP_DEBUG_OBJ_USAGE
2554
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2555
#endif
2556
0
      return(ret);
2557
0
  } else if ((cache->miscObjs != NULL) &&
2558
0
      (cache->miscObjs->number != 0))
2559
0
  {
2560
0
      xmlXPathObjectPtr ret;
2561
2562
0
      ret = (xmlXPathObjectPtr)
2563
0
    cache->miscObjs->items[--cache->miscObjs->number];
2564
2565
0
      ret->type = XPATH_STRING;
2566
0
      if (val != NULL)
2567
0
    ret->stringval = xmlStrdup(val);
2568
0
      else
2569
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2570
#ifdef XP_DEBUG_OBJ_USAGE
2571
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2572
#endif
2573
0
      return(ret);
2574
0
  }
2575
0
    }
2576
0
    return(xmlXPathNewString(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
 * xmlXPathSetFrame:
2817
 * @ctxt: an XPath parser context
2818
 *
2819
 * Set the callee evaluation frame
2820
 *
2821
 * Returns the previous frame value to be restored once done
2822
 */
2823
static int
2824
0
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2825
0
    int ret;
2826
2827
0
    if (ctxt == NULL)
2828
0
        return(0);
2829
0
    ret = ctxt->valueFrame;
2830
0
    ctxt->valueFrame = ctxt->valueNr;
2831
0
    return(ret);
2832
0
}
2833
2834
/**
2835
 * xmlXPathPopFrame:
2836
 * @ctxt: an XPath parser context
2837
 * @frame: the previous frame value
2838
 *
2839
 * Remove the callee evaluation frame
2840
 */
2841
static void
2842
0
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2843
0
    if (ctxt == NULL)
2844
0
        return;
2845
0
    if (ctxt->valueNr < ctxt->valueFrame) {
2846
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2847
0
    }
2848
0
    ctxt->valueFrame = frame;
2849
0
}
2850
2851
/**
2852
 * valuePop:
2853
 * @ctxt: an XPath evaluation context
2854
 *
2855
 * Pops the top XPath object from the value stack
2856
 *
2857
 * Returns the XPath object just removed
2858
 */
2859
xmlXPathObjectPtr
2860
valuePop(xmlXPathParserContextPtr ctxt)
2861
0
{
2862
0
    xmlXPathObjectPtr ret;
2863
2864
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2865
0
        return (NULL);
2866
2867
0
    if (ctxt->valueNr <= ctxt->valueFrame) {
2868
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2869
0
        return (NULL);
2870
0
    }
2871
2872
0
    ctxt->valueNr--;
2873
0
    if (ctxt->valueNr > 0)
2874
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2875
0
    else
2876
0
        ctxt->value = NULL;
2877
0
    ret = ctxt->valueTab[ctxt->valueNr];
2878
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
2879
0
    return (ret);
2880
0
}
2881
/**
2882
 * valuePush:
2883
 * @ctxt:  an XPath evaluation context
2884
 * @value:  the XPath object
2885
 *
2886
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2887
 * a memory error is recorded in the parser context.
2888
 *
2889
 * Returns the number of items on the value stack, or -1 in case of error.
2890
 */
2891
int
2892
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2893
0
{
2894
0
    if (ctxt == NULL) return(-1);
2895
0
    if (value == NULL) {
2896
        /*
2897
         * A NULL value typically indicates that a memory allocation failed,
2898
         * so we set ctxt->error here to propagate the error.
2899
         */
2900
0
  ctxt->error = XPATH_MEMORY_ERROR;
2901
0
        return(-1);
2902
0
    }
2903
0
    if (ctxt->valueNr >= ctxt->valueMax) {
2904
0
        xmlXPathObjectPtr *tmp;
2905
2906
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2907
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2908
0
            return (-1);
2909
0
        }
2910
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2911
0
                                             2 * ctxt->valueMax *
2912
0
                                             sizeof(ctxt->valueTab[0]));
2913
0
        if (tmp == NULL) {
2914
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2915
0
            return (-1);
2916
0
        }
2917
0
        ctxt->valueMax *= 2;
2918
0
  ctxt->valueTab = tmp;
2919
0
    }
2920
0
    ctxt->valueTab[ctxt->valueNr] = value;
2921
0
    ctxt->value = value;
2922
0
    return (ctxt->valueNr++);
2923
0
}
2924
2925
/**
2926
 * xmlXPathPopBoolean:
2927
 * @ctxt:  an XPath parser context
2928
 *
2929
 * Pops a boolean from the stack, handling conversion if needed.
2930
 * Check error with #xmlXPathCheckError.
2931
 *
2932
 * Returns the boolean
2933
 */
2934
int
2935
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2936
0
    xmlXPathObjectPtr obj;
2937
0
    int ret;
2938
2939
0
    obj = valuePop(ctxt);
2940
0
    if (obj == NULL) {
2941
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2942
0
  return(0);
2943
0
    }
2944
0
    if (obj->type != XPATH_BOOLEAN)
2945
0
  ret = xmlXPathCastToBoolean(obj);
2946
0
    else
2947
0
        ret = obj->boolval;
2948
0
    xmlXPathReleaseObject(ctxt->context, obj);
2949
0
    return(ret);
2950
0
}
2951
2952
/**
2953
 * xmlXPathPopNumber:
2954
 * @ctxt:  an XPath parser context
2955
 *
2956
 * Pops a number from the stack, handling conversion if needed.
2957
 * Check error with #xmlXPathCheckError.
2958
 *
2959
 * Returns the number
2960
 */
2961
double
2962
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2963
0
    xmlXPathObjectPtr obj;
2964
0
    double ret;
2965
2966
0
    obj = valuePop(ctxt);
2967
0
    if (obj == NULL) {
2968
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2969
0
  return(0);
2970
0
    }
2971
0
    if (obj->type != XPATH_NUMBER)
2972
0
  ret = xmlXPathCastToNumber(obj);
2973
0
    else
2974
0
        ret = obj->floatval;
2975
0
    xmlXPathReleaseObject(ctxt->context, obj);
2976
0
    return(ret);
2977
0
}
2978
2979
/**
2980
 * xmlXPathPopString:
2981
 * @ctxt:  an XPath parser context
2982
 *
2983
 * Pops a string from the stack, handling conversion if needed.
2984
 * Check error with #xmlXPathCheckError.
2985
 *
2986
 * Returns the string
2987
 */
2988
xmlChar *
2989
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2990
0
    xmlXPathObjectPtr obj;
2991
0
    xmlChar * ret;
2992
2993
0
    obj = valuePop(ctxt);
2994
0
    if (obj == NULL) {
2995
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2996
0
  return(NULL);
2997
0
    }
2998
0
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2999
    /* TODO: needs refactoring somewhere else */
3000
0
    if (obj->stringval == ret)
3001
0
  obj->stringval = NULL;
3002
0
    xmlXPathReleaseObject(ctxt->context, obj);
3003
0
    return(ret);
3004
0
}
3005
3006
/**
3007
 * xmlXPathPopNodeSet:
3008
 * @ctxt:  an XPath parser context
3009
 *
3010
 * Pops a node-set from the stack, handling conversion if needed.
3011
 * Check error with #xmlXPathCheckError.
3012
 *
3013
 * Returns the node-set
3014
 */
3015
xmlNodeSetPtr
3016
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3017
0
    xmlXPathObjectPtr obj;
3018
0
    xmlNodeSetPtr ret;
3019
3020
0
    if (ctxt == NULL) return(NULL);
3021
0
    if (ctxt->value == NULL) {
3022
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3023
0
  return(NULL);
3024
0
    }
3025
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3026
0
  xmlXPathSetTypeError(ctxt);
3027
0
  return(NULL);
3028
0
    }
3029
0
    obj = valuePop(ctxt);
3030
0
    ret = obj->nodesetval;
3031
#if 0
3032
    /* to fix memory leak of not clearing obj->user */
3033
    if (obj->boolval && obj->user != NULL)
3034
        xmlFreeNodeList((xmlNodePtr) obj->user);
3035
#endif
3036
0
    obj->nodesetval = NULL;
3037
0
    xmlXPathReleaseObject(ctxt->context, obj);
3038
0
    return(ret);
3039
0
}
3040
3041
/**
3042
 * xmlXPathPopExternal:
3043
 * @ctxt:  an XPath parser context
3044
 *
3045
 * Pops an external object from the stack, handling conversion if needed.
3046
 * Check error with #xmlXPathCheckError.
3047
 *
3048
 * Returns the object
3049
 */
3050
void *
3051
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3052
0
    xmlXPathObjectPtr obj;
3053
0
    void * ret;
3054
3055
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3056
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3057
0
  return(NULL);
3058
0
    }
3059
0
    if (ctxt->value->type != XPATH_USERS) {
3060
0
  xmlXPathSetTypeError(ctxt);
3061
0
  return(NULL);
3062
0
    }
3063
0
    obj = valuePop(ctxt);
3064
0
    ret = obj->user;
3065
0
    obj->user = NULL;
3066
0
    xmlXPathReleaseObject(ctxt->context, obj);
3067
0
    return(ret);
3068
0
}
3069
3070
/*
3071
 * Macros for accessing the content. Those should be used only by the parser,
3072
 * and not exported.
3073
 *
3074
 * Dirty macros, i.e. one need to make assumption on the context to use them
3075
 *
3076
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3077
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3078
 *           in ISO-Latin or UTF-8.
3079
 *           This should be used internally by the parser
3080
 *           only to compare to ASCII values otherwise it would break when
3081
 *           running with UTF-8 encoding.
3082
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3083
 *           to compare on ASCII based substring.
3084
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3085
 *           strings within the parser.
3086
 *   CURRENT Returns the current char value, with the full decoding of
3087
 *           UTF-8 if we are using this mode. It returns an int.
3088
 *   NEXT    Skip to the next character, this does the proper decoding
3089
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3090
 *           It returns the pointer to the current xmlChar.
3091
 */
3092
3093
0
#define CUR (*ctxt->cur)
3094
0
#define SKIP(val) ctxt->cur += (val)
3095
0
#define NXT(val) ctxt->cur[(val)]
3096
0
#define CUR_PTR ctxt->cur
3097
0
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3098
3099
#define COPY_BUF(l,b,i,v)                                              \
3100
0
    if (l == 1) b[i++] = (xmlChar) v;                                  \
3101
0
    else i += xmlCopyChar(l,&b[i],v)
3102
3103
0
#define NEXTL(l)  ctxt->cur += l
3104
3105
#define SKIP_BLANKS             \
3106
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3107
3108
#define CURRENT (*ctxt->cur)
3109
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3110
3111
3112
#ifndef DBL_DIG
3113
#define DBL_DIG 16
3114
#endif
3115
#ifndef DBL_EPSILON
3116
#define DBL_EPSILON 1E-9
3117
#endif
3118
3119
0
#define UPPER_DOUBLE 1E9
3120
0
#define LOWER_DOUBLE 1E-5
3121
#define LOWER_DOUBLE_EXP 5
3122
3123
#define INTEGER_DIGITS DBL_DIG
3124
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3125
0
#define EXPONENT_DIGITS (3 + 2)
3126
3127
/**
3128
 * xmlXPathFormatNumber:
3129
 * @number:     number to format
3130
 * @buffer:     output buffer
3131
 * @buffersize: size of output buffer
3132
 *
3133
 * Convert the number into a string representation.
3134
 */
3135
static void
3136
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3137
0
{
3138
0
    switch (xmlXPathIsInf(number)) {
3139
0
    case 1:
3140
0
  if (buffersize > (int)sizeof("Infinity"))
3141
0
      snprintf(buffer, buffersize, "Infinity");
3142
0
  break;
3143
0
    case -1:
3144
0
  if (buffersize > (int)sizeof("-Infinity"))
3145
0
      snprintf(buffer, buffersize, "-Infinity");
3146
0
  break;
3147
0
    default:
3148
0
  if (xmlXPathIsNaN(number)) {
3149
0
      if (buffersize > (int)sizeof("NaN"))
3150
0
    snprintf(buffer, buffersize, "NaN");
3151
0
  } else if (number == 0) {
3152
            /* Omit sign for negative zero. */
3153
0
      snprintf(buffer, buffersize, "0");
3154
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3155
0
                   (number == (int) number)) {
3156
0
      char work[30];
3157
0
      char *ptr, *cur;
3158
0
      int value = (int) number;
3159
3160
0
            ptr = &buffer[0];
3161
0
      if (value == 0) {
3162
0
    *ptr++ = '0';
3163
0
      } else {
3164
0
    snprintf(work, 29, "%d", value);
3165
0
    cur = &work[0];
3166
0
    while ((*cur) && (ptr - buffer < buffersize)) {
3167
0
        *ptr++ = *cur++;
3168
0
    }
3169
0
      }
3170
0
      if (ptr - buffer < buffersize) {
3171
0
    *ptr = 0;
3172
0
      } else if (buffersize > 0) {
3173
0
    ptr--;
3174
0
    *ptr = 0;
3175
0
      }
3176
0
  } else {
3177
      /*
3178
        For the dimension of work,
3179
            DBL_DIG is number of significant digits
3180
      EXPONENT is only needed for "scientific notation"
3181
            3 is sign, decimal point, and terminating zero
3182
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3183
        Note that this dimension is slightly (a few characters)
3184
        larger than actually necessary.
3185
      */
3186
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3187
0
      int integer_place, fraction_place;
3188
0
      char *ptr;
3189
0
      char *after_fraction;
3190
0
      double absolute_value;
3191
0
      int size;
3192
3193
0
      absolute_value = fabs(number);
3194
3195
      /*
3196
       * First choose format - scientific or regular floating point.
3197
       * In either case, result is in work, and after_fraction points
3198
       * just past the fractional part.
3199
      */
3200
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
3201
0
      (absolute_value < LOWER_DOUBLE)) &&
3202
0
     (absolute_value != 0.0) ) {
3203
    /* Use scientific notation */
3204
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3205
0
    fraction_place = DBL_DIG - 1;
3206
0
    size = snprintf(work, sizeof(work),"%*.*e",
3207
0
       integer_place, fraction_place, number);
3208
0
    while ((size > 0) && (work[size] != 'e')) size--;
3209
3210
0
      }
3211
0
      else {
3212
    /* Use regular notation */
3213
0
    if (absolute_value > 0.0) {
3214
0
        integer_place = (int)log10(absolute_value);
3215
0
        if (integer_place > 0)
3216
0
            fraction_place = DBL_DIG - integer_place - 1;
3217
0
        else
3218
0
            fraction_place = DBL_DIG - integer_place;
3219
0
    } else {
3220
0
        fraction_place = 1;
3221
0
    }
3222
0
    size = snprintf(work, sizeof(work), "%0.*f",
3223
0
        fraction_place, number);
3224
0
      }
3225
3226
      /* Remove leading spaces sometimes inserted by snprintf */
3227
0
      while (work[0] == ' ') {
3228
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3229
0
    size--;
3230
0
      }
3231
3232
      /* Remove fractional trailing zeroes */
3233
0
      after_fraction = work + size;
3234
0
      ptr = after_fraction;
3235
0
      while (*(--ptr) == '0')
3236
0
    ;
3237
0
      if (*ptr != '.')
3238
0
          ptr++;
3239
0
      while ((*ptr++ = *after_fraction++) != 0);
3240
3241
      /* Finally copy result back to caller */
3242
0
      size = strlen(work) + 1;
3243
0
      if (size > buffersize) {
3244
0
    work[buffersize - 1] = 0;
3245
0
    size = buffersize;
3246
0
      }
3247
0
      memmove(buffer, work, size);
3248
0
  }
3249
0
  break;
3250
0
    }
3251
0
}
3252
3253
3254
/************************************************************************
3255
 *                  *
3256
 *      Routines to handle NodeSets     *
3257
 *                  *
3258
 ************************************************************************/
3259
3260
/**
3261
 * xmlXPathOrderDocElems:
3262
 * @doc:  an input document
3263
 *
3264
 * Call this routine to speed up XPath computation on static documents.
3265
 * This stamps all the element nodes with the document order
3266
 * Like for line information, the order is kept in the element->content
3267
 * field, the value stored is actually - the node number (starting at -1)
3268
 * to be able to differentiate from line numbers.
3269
 *
3270
 * Returns the number of elements found in the document or -1 in case
3271
 *    of error.
3272
 */
3273
long
3274
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
3275
0
    ptrdiff_t count = 0;
3276
0
    xmlNodePtr cur;
3277
3278
0
    if (doc == NULL)
3279
0
  return(-1);
3280
0
    cur = doc->children;
3281
0
    while (cur != NULL) {
3282
0
  if (cur->type == XML_ELEMENT_NODE) {
3283
0
      cur->content = (void *) (-(++count));
3284
0
      if (cur->children != NULL) {
3285
0
    cur = cur->children;
3286
0
    continue;
3287
0
      }
3288
0
  }
3289
0
  if (cur->next != NULL) {
3290
0
      cur = cur->next;
3291
0
      continue;
3292
0
  }
3293
0
  do {
3294
0
      cur = cur->parent;
3295
0
      if (cur == NULL)
3296
0
    break;
3297
0
      if (cur == (xmlNodePtr) doc) {
3298
0
    cur = NULL;
3299
0
    break;
3300
0
      }
3301
0
      if (cur->next != NULL) {
3302
0
    cur = cur->next;
3303
0
    break;
3304
0
      }
3305
0
  } while (cur != NULL);
3306
0
    }
3307
0
    return((long) count);
3308
0
}
3309
3310
/**
3311
 * xmlXPathCmpNodes:
3312
 * @node1:  the first node
3313
 * @node2:  the second node
3314
 *
3315
 * Compare two nodes w.r.t document order
3316
 *
3317
 * Returns -2 in case of error 1 if first point < second point, 0 if
3318
 *         it's the same node, -1 otherwise
3319
 */
3320
int
3321
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3322
0
    int depth1, depth2;
3323
0
    int attr1 = 0, attr2 = 0;
3324
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3325
0
    xmlNodePtr cur, root;
3326
3327
0
    if ((node1 == NULL) || (node2 == NULL))
3328
0
  return(-2);
3329
    /*
3330
     * a couple of optimizations which will avoid computations in most cases
3331
     */
3332
0
    if (node1 == node2)   /* trivial case */
3333
0
  return(0);
3334
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
3335
0
  attr1 = 1;
3336
0
  attrNode1 = node1;
3337
0
  node1 = node1->parent;
3338
0
    }
3339
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
3340
0
  attr2 = 1;
3341
0
  attrNode2 = node2;
3342
0
  node2 = node2->parent;
3343
0
    }
3344
0
    if (node1 == node2) {
3345
0
  if (attr1 == attr2) {
3346
      /* not required, but we keep attributes in order */
3347
0
      if (attr1 != 0) {
3348
0
          cur = attrNode2->prev;
3349
0
    while (cur != NULL) {
3350
0
        if (cur == attrNode1)
3351
0
            return (1);
3352
0
        cur = cur->prev;
3353
0
    }
3354
0
    return (-1);
3355
0
      }
3356
0
      return(0);
3357
0
  }
3358
0
  if (attr2 == 1)
3359
0
      return(1);
3360
0
  return(-1);
3361
0
    }
3362
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
3363
0
        (node2->type == XML_NAMESPACE_DECL))
3364
0
  return(1);
3365
0
    if (node1 == node2->prev)
3366
0
  return(1);
3367
0
    if (node1 == node2->next)
3368
0
  return(-1);
3369
3370
    /*
3371
     * Speedup using document order if available.
3372
     */
3373
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3374
0
  (node2->type == XML_ELEMENT_NODE) &&
3375
0
  (0 > (ptrdiff_t) node1->content) &&
3376
0
  (0 > (ptrdiff_t) node2->content) &&
3377
0
  (node1->doc == node2->doc)) {
3378
0
  ptrdiff_t l1, l2;
3379
3380
0
  l1 = -((ptrdiff_t) node1->content);
3381
0
  l2 = -((ptrdiff_t) node2->content);
3382
0
  if (l1 < l2)
3383
0
      return(1);
3384
0
  if (l1 > l2)
3385
0
      return(-1);
3386
0
    }
3387
3388
    /*
3389
     * compute depth to root
3390
     */
3391
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3392
0
  if (cur->parent == node1)
3393
0
      return(1);
3394
0
  depth2++;
3395
0
    }
3396
0
    root = cur;
3397
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3398
0
  if (cur->parent == node2)
3399
0
      return(-1);
3400
0
  depth1++;
3401
0
    }
3402
    /*
3403
     * Distinct document (or distinct entities :-( ) case.
3404
     */
3405
0
    if (root != cur) {
3406
0
  return(-2);
3407
0
    }
3408
    /*
3409
     * get the nearest common ancestor.
3410
     */
3411
0
    while (depth1 > depth2) {
3412
0
  depth1--;
3413
0
  node1 = node1->parent;
3414
0
    }
3415
0
    while (depth2 > depth1) {
3416
0
  depth2--;
3417
0
  node2 = node2->parent;
3418
0
    }
3419
0
    while (node1->parent != node2->parent) {
3420
0
  node1 = node1->parent;
3421
0
  node2 = node2->parent;
3422
  /* should not happen but just in case ... */
3423
0
  if ((node1 == NULL) || (node2 == NULL))
3424
0
      return(-2);
3425
0
    }
3426
    /*
3427
     * Find who's first.
3428
     */
3429
0
    if (node1 == node2->prev)
3430
0
  return(1);
3431
0
    if (node1 == node2->next)
3432
0
  return(-1);
3433
    /*
3434
     * Speedup using document order if available.
3435
     */
3436
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3437
0
  (node2->type == XML_ELEMENT_NODE) &&
3438
0
  (0 > (ptrdiff_t) node1->content) &&
3439
0
  (0 > (ptrdiff_t) node2->content) &&
3440
0
  (node1->doc == node2->doc)) {
3441
0
  ptrdiff_t l1, l2;
3442
3443
0
  l1 = -((ptrdiff_t) node1->content);
3444
0
  l2 = -((ptrdiff_t) node2->content);
3445
0
  if (l1 < l2)
3446
0
      return(1);
3447
0
  if (l1 > l2)
3448
0
      return(-1);
3449
0
    }
3450
3451
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
3452
0
  if (cur == node2)
3453
0
      return(1);
3454
0
    return(-1); /* assume there is no sibling list corruption */
3455
0
}
3456
3457
/**
3458
 * xmlXPathNodeSetSort:
3459
 * @set:  the node set
3460
 *
3461
 * Sort the node set in document order
3462
 */
3463
void
3464
0
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3465
#ifndef WITH_TIM_SORT
3466
    int i, j, incr, len;
3467
    xmlNodePtr tmp;
3468
#endif
3469
3470
0
    if (set == NULL)
3471
0
  return;
3472
3473
#ifndef WITH_TIM_SORT
3474
    /*
3475
     * Use the old Shell's sort implementation to sort the node-set
3476
     * Timsort ought to be quite faster
3477
     */
3478
    len = set->nodeNr;
3479
    for (incr = len / 2; incr > 0; incr /= 2) {
3480
  for (i = incr; i < len; i++) {
3481
      j = i - incr;
3482
      while (j >= 0) {
3483
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3484
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3485
      set->nodeTab[j + incr]) == -1)
3486
#else
3487
    if (xmlXPathCmpNodes(set->nodeTab[j],
3488
      set->nodeTab[j + incr]) == -1)
3489
#endif
3490
    {
3491
        tmp = set->nodeTab[j];
3492
        set->nodeTab[j] = set->nodeTab[j + incr];
3493
        set->nodeTab[j + incr] = tmp;
3494
        j -= incr;
3495
    } else
3496
        break;
3497
      }
3498
  }
3499
    }
3500
#else /* WITH_TIM_SORT */
3501
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3502
0
#endif /* WITH_TIM_SORT */
3503
0
}
3504
3505
0
#define XML_NODESET_DEFAULT 10
3506
/**
3507
 * xmlXPathNodeSetDupNs:
3508
 * @node:  the parent node of the namespace XPath node
3509
 * @ns:  the libxml namespace declaration node.
3510
 *
3511
 * Namespace node 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.
3514
 *
3515
 * Returns the newly created object.
3516
 */
3517
static xmlNodePtr
3518
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3519
0
    xmlNsPtr cur;
3520
3521
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3522
0
  return(NULL);
3523
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3524
0
  return((xmlNodePtr) ns);
3525
3526
    /*
3527
     * Allocate a new Namespace and fill the fields.
3528
     */
3529
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3530
0
    if (cur == NULL) {
3531
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3532
0
  return(NULL);
3533
0
    }
3534
0
    memset(cur, 0, sizeof(xmlNs));
3535
0
    cur->type = XML_NAMESPACE_DECL;
3536
0
    if (ns->href != NULL)
3537
0
  cur->href = xmlStrdup(ns->href);
3538
0
    if (ns->prefix != NULL)
3539
0
  cur->prefix = xmlStrdup(ns->prefix);
3540
0
    cur->next = (xmlNsPtr) node;
3541
0
    return((xmlNodePtr) cur);
3542
0
}
3543
3544
/**
3545
 * xmlXPathNodeSetFreeNs:
3546
 * @ns:  the XPath namespace node found in a nodeset.
3547
 *
3548
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3549
 * the namespace nodes are duplicated and the next pointer is set to the
3550
 * parent node in the XPath semantic. Check if such a node needs to be freed
3551
 */
3552
void
3553
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3554
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3555
0
  return;
3556
3557
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3558
0
  if (ns->href != NULL)
3559
0
      xmlFree((xmlChar *)ns->href);
3560
0
  if (ns->prefix != NULL)
3561
0
      xmlFree((xmlChar *)ns->prefix);
3562
0
  xmlFree(ns);
3563
0
    }
3564
0
}
3565
3566
/**
3567
 * xmlXPathNodeSetCreate:
3568
 * @val:  an initial xmlNodePtr, or NULL
3569
 *
3570
 * Create a new xmlNodeSetPtr of type double and of value @val
3571
 *
3572
 * Returns the newly created object.
3573
 */
3574
xmlNodeSetPtr
3575
0
xmlXPathNodeSetCreate(xmlNodePtr val) {
3576
0
    xmlNodeSetPtr ret;
3577
3578
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3579
0
    if (ret == NULL) {
3580
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3581
0
  return(NULL);
3582
0
    }
3583
0
    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3584
0
    if (val != NULL) {
3585
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3586
0
               sizeof(xmlNodePtr));
3587
0
  if (ret->nodeTab == NULL) {
3588
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3589
0
      xmlFree(ret);
3590
0
      return(NULL);
3591
0
  }
3592
0
  memset(ret->nodeTab, 0 ,
3593
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3594
0
        ret->nodeMax = XML_NODESET_DEFAULT;
3595
0
  if (val->type == XML_NAMESPACE_DECL) {
3596
0
      xmlNsPtr ns = (xmlNsPtr) val;
3597
3598
            /* TODO: Check memory error. */
3599
0
      ret->nodeTab[ret->nodeNr++] =
3600
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3601
0
  } else
3602
0
      ret->nodeTab[ret->nodeNr++] = val;
3603
0
    }
3604
0
    return(ret);
3605
0
}
3606
3607
/**
3608
 * xmlXPathNodeSetContains:
3609
 * @cur:  the node-set
3610
 * @val:  the node
3611
 *
3612
 * checks whether @cur contains @val
3613
 *
3614
 * Returns true (1) if @cur contains @val, false (0) otherwise
3615
 */
3616
int
3617
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3618
0
    int i;
3619
3620
0
    if ((cur == NULL) || (val == NULL)) return(0);
3621
0
    if (val->type == XML_NAMESPACE_DECL) {
3622
0
  for (i = 0; i < cur->nodeNr; i++) {
3623
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3624
0
    xmlNsPtr ns1, ns2;
3625
3626
0
    ns1 = (xmlNsPtr) val;
3627
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3628
0
    if (ns1 == ns2)
3629
0
        return(1);
3630
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3631
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3632
0
        return(1);
3633
0
      }
3634
0
  }
3635
0
    } else {
3636
0
  for (i = 0; i < cur->nodeNr; i++) {
3637
0
      if (cur->nodeTab[i] == val)
3638
0
    return(1);
3639
0
  }
3640
0
    }
3641
0
    return(0);
3642
0
}
3643
3644
/**
3645
 * xmlXPathNodeSetAddNs:
3646
 * @cur:  the initial node set
3647
 * @node:  the hosting node
3648
 * @ns:  a the namespace node
3649
 *
3650
 * add a new namespace node to an existing NodeSet
3651
 *
3652
 * Returns 0 in case of success and -1 in case of error
3653
 */
3654
int
3655
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3656
0
    int i;
3657
3658
3659
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3660
0
        (ns->type != XML_NAMESPACE_DECL) ||
3661
0
  (node->type != XML_ELEMENT_NODE))
3662
0
  return(-1);
3663
3664
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3665
    /*
3666
     * prevent duplicates
3667
     */
3668
0
    for (i = 0;i < cur->nodeNr;i++) {
3669
0
        if ((cur->nodeTab[i] != NULL) &&
3670
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3671
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3672
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3673
0
      return(0);
3674
0
    }
3675
3676
    /*
3677
     * grow the nodeTab if needed
3678
     */
3679
0
    if (cur->nodeMax == 0) {
3680
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3681
0
               sizeof(xmlNodePtr));
3682
0
  if (cur->nodeTab == NULL) {
3683
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3684
0
      return(-1);
3685
0
  }
3686
0
  memset(cur->nodeTab, 0 ,
3687
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3688
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3689
0
    } else if (cur->nodeNr == cur->nodeMax) {
3690
0
        xmlNodePtr *temp;
3691
3692
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3693
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3694
0
            return(-1);
3695
0
        }
3696
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3697
0
              sizeof(xmlNodePtr));
3698
0
  if (temp == NULL) {
3699
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3700
0
      return(-1);
3701
0
  }
3702
0
        cur->nodeMax *= 2;
3703
0
  cur->nodeTab = temp;
3704
0
    }
3705
    /* TODO: Check memory error. */
3706
0
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3707
0
    return(0);
3708
0
}
3709
3710
/**
3711
 * xmlXPathNodeSetAdd:
3712
 * @cur:  the initial node set
3713
 * @val:  a new xmlNodePtr
3714
 *
3715
 * add a new xmlNodePtr to an existing NodeSet
3716
 *
3717
 * Returns 0 in case of success, and -1 in case of error
3718
 */
3719
int
3720
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3721
0
    int i;
3722
3723
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3724
3725
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3726
    /*
3727
     * prevent duplicates
3728
     */
3729
0
    for (i = 0;i < cur->nodeNr;i++)
3730
0
        if (cur->nodeTab[i] == val) return(0);
3731
3732
    /*
3733
     * grow the nodeTab if needed
3734
     */
3735
0
    if (cur->nodeMax == 0) {
3736
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3737
0
               sizeof(xmlNodePtr));
3738
0
  if (cur->nodeTab == NULL) {
3739
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3740
0
      return(-1);
3741
0
  }
3742
0
  memset(cur->nodeTab, 0 ,
3743
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3744
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3745
0
    } else if (cur->nodeNr == cur->nodeMax) {
3746
0
        xmlNodePtr *temp;
3747
3748
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3749
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3750
0
            return(-1);
3751
0
        }
3752
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3753
0
              sizeof(xmlNodePtr));
3754
0
  if (temp == NULL) {
3755
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3756
0
      return(-1);
3757
0
  }
3758
0
        cur->nodeMax *= 2;
3759
0
  cur->nodeTab = temp;
3760
0
    }
3761
0
    if (val->type == XML_NAMESPACE_DECL) {
3762
0
  xmlNsPtr ns = (xmlNsPtr) val;
3763
3764
        /* TODO: Check memory error. */
3765
0
  cur->nodeTab[cur->nodeNr++] =
3766
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3767
0
    } else
3768
0
  cur->nodeTab[cur->nodeNr++] = val;
3769
0
    return(0);
3770
0
}
3771
3772
/**
3773
 * xmlXPathNodeSetAddUnique:
3774
 * @cur:  the initial node set
3775
 * @val:  a new xmlNodePtr
3776
 *
3777
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3778
 * when we are sure the node is not already in the set.
3779
 *
3780
 * Returns 0 in case of success and -1 in case of failure
3781
 */
3782
int
3783
0
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3784
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3785
3786
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3787
    /*
3788
     * grow the nodeTab if needed
3789
     */
3790
0
    if (cur->nodeMax == 0) {
3791
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792
0
               sizeof(xmlNodePtr));
3793
0
  if (cur->nodeTab == NULL) {
3794
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3795
0
      return(-1);
3796
0
  }
3797
0
  memset(cur->nodeTab, 0 ,
3798
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3800
0
    } else if (cur->nodeNr == cur->nodeMax) {
3801
0
        xmlNodePtr *temp;
3802
3803
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3804
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3805
0
            return(-1);
3806
0
        }
3807
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3808
0
              sizeof(xmlNodePtr));
3809
0
  if (temp == NULL) {
3810
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3811
0
      return(-1);
3812
0
  }
3813
0
  cur->nodeTab = temp;
3814
0
        cur->nodeMax *= 2;
3815
0
    }
3816
0
    if (val->type == XML_NAMESPACE_DECL) {
3817
0
  xmlNsPtr ns = (xmlNsPtr) val;
3818
3819
        /* TODO: Check memory error. */
3820
0
  cur->nodeTab[cur->nodeNr++] =
3821
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3822
0
    } else
3823
0
  cur->nodeTab[cur->nodeNr++] = val;
3824
0
    return(0);
3825
0
}
3826
3827
/**
3828
 * xmlXPathNodeSetMerge:
3829
 * @val1:  the first NodeSet or NULL
3830
 * @val2:  the second NodeSet
3831
 *
3832
 * Merges two nodesets, all nodes from @val2 are added to @val1
3833
 * if @val1 is NULL, a new set is created and copied from @val2
3834
 *
3835
 * Returns @val1 once extended or NULL in case of error.
3836
 */
3837
xmlNodeSetPtr
3838
0
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3839
0
    int i, j, initNr, skip;
3840
0
    xmlNodePtr n1, n2;
3841
3842
0
    if (val2 == NULL) return(val1);
3843
0
    if (val1 == NULL) {
3844
0
  val1 = xmlXPathNodeSetCreate(NULL);
3845
0
    if (val1 == NULL)
3846
0
        return (NULL);
3847
#if 0
3848
  /*
3849
  * TODO: The optimization won't work in every case, since
3850
  *  those nasty namespace nodes need to be added with
3851
  *  xmlXPathNodeSetDupNs() to the set; thus a pure
3852
  *  memcpy is not possible.
3853
  *  If there was a flag on the nodesetval, indicating that
3854
  *  some temporary nodes are in, that would be helpful.
3855
  */
3856
  /*
3857
  * Optimization: Create an equally sized node-set
3858
  * and memcpy the content.
3859
  */
3860
  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3861
  if (val1 == NULL)
3862
      return(NULL);
3863
  if (val2->nodeNr != 0) {
3864
      if (val2->nodeNr == 1)
3865
    *(val1->nodeTab) = *(val2->nodeTab);
3866
      else {
3867
    memcpy(val1->nodeTab, val2->nodeTab,
3868
        val2->nodeNr * sizeof(xmlNodePtr));
3869
      }
3870
      val1->nodeNr = val2->nodeNr;
3871
  }
3872
  return(val1);
3873
#endif
3874
0
    }
3875
3876
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3877
0
    initNr = val1->nodeNr;
3878
3879
0
    for (i = 0;i < val2->nodeNr;i++) {
3880
0
  n2 = val2->nodeTab[i];
3881
  /*
3882
   * check against duplicates
3883
   */
3884
0
  skip = 0;
3885
0
  for (j = 0; j < initNr; j++) {
3886
0
      n1 = val1->nodeTab[j];
3887
0
      if (n1 == n2) {
3888
0
    skip = 1;
3889
0
    break;
3890
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3891
0
           (n2->type == XML_NAMESPACE_DECL)) {
3892
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3893
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3894
0
      ((xmlNsPtr) n2)->prefix)))
3895
0
    {
3896
0
        skip = 1;
3897
0
        break;
3898
0
    }
3899
0
      }
3900
0
  }
3901
0
  if (skip)
3902
0
      continue;
3903
3904
  /*
3905
   * grow the nodeTab if needed
3906
   */
3907
0
  if (val1->nodeMax == 0) {
3908
0
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3909
0
                sizeof(xmlNodePtr));
3910
0
      if (val1->nodeTab == NULL) {
3911
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3912
0
    return(NULL);
3913
0
      }
3914
0
      memset(val1->nodeTab, 0 ,
3915
0
       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3916
0
      val1->nodeMax = XML_NODESET_DEFAULT;
3917
0
  } else if (val1->nodeNr == val1->nodeMax) {
3918
0
      xmlNodePtr *temp;
3919
3920
0
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3921
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3922
0
                return(NULL);
3923
0
            }
3924
0
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3925
0
               sizeof(xmlNodePtr));
3926
0
      if (temp == NULL) {
3927
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3928
0
    return(NULL);
3929
0
      }
3930
0
      val1->nodeTab = temp;
3931
0
      val1->nodeMax *= 2;
3932
0
  }
3933
0
  if (n2->type == XML_NAMESPACE_DECL) {
3934
0
      xmlNsPtr ns = (xmlNsPtr) n2;
3935
3936
            /* TODO: Check memory error. */
3937
0
      val1->nodeTab[val1->nodeNr++] =
3938
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3939
0
  } else
3940
0
      val1->nodeTab[val1->nodeNr++] = n2;
3941
0
    }
3942
3943
0
    return(val1);
3944
0
}
3945
3946
3947
/**
3948
 * xmlXPathNodeSetMergeAndClear:
3949
 * @set1:  the first NodeSet or NULL
3950
 * @set2:  the second NodeSet
3951
 *
3952
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3953
 * Checks for duplicate nodes. Clears set2.
3954
 *
3955
 * Returns @set1 once extended or NULL in case of error.
3956
 */
3957
static xmlNodeSetPtr
3958
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3959
0
{
3960
0
    {
3961
0
  int i, j, initNbSet1;
3962
0
  xmlNodePtr n1, n2;
3963
3964
0
  initNbSet1 = set1->nodeNr;
3965
0
  for (i = 0;i < set2->nodeNr;i++) {
3966
0
      n2 = set2->nodeTab[i];
3967
      /*
3968
      * Skip duplicates.
3969
      */
3970
0
      for (j = 0; j < initNbSet1; j++) {
3971
0
    n1 = set1->nodeTab[j];
3972
0
    if (n1 == n2) {
3973
0
        goto skip_node;
3974
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3975
0
        (n2->type == XML_NAMESPACE_DECL))
3976
0
    {
3977
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3978
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3979
0
      ((xmlNsPtr) n2)->prefix)))
3980
0
        {
3981
      /*
3982
      * Free the namespace node.
3983
      */
3984
0
      set2->nodeTab[i] = NULL;
3985
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3986
0
      goto skip_node;
3987
0
        }
3988
0
    }
3989
0
      }
3990
      /*
3991
      * grow the nodeTab if needed
3992
      */
3993
0
      if (set1->nodeMax == 0) {
3994
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3995
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3996
0
    if (set1->nodeTab == NULL) {
3997
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3998
0
        return(NULL);
3999
0
    }
4000
0
    memset(set1->nodeTab, 0,
4001
0
        XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4002
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4003
0
      } else if (set1->nodeNr >= set1->nodeMax) {
4004
0
    xmlNodePtr *temp;
4005
4006
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4007
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4008
0
                    return(NULL);
4009
0
                }
4010
0
    temp = (xmlNodePtr *) xmlRealloc(
4011
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4012
0
    if (temp == NULL) {
4013
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4014
0
        return(NULL);
4015
0
    }
4016
0
    set1->nodeTab = temp;
4017
0
    set1->nodeMax *= 2;
4018
0
      }
4019
0
      set1->nodeTab[set1->nodeNr++] = n2;
4020
0
skip_node:
4021
0
      {}
4022
0
  }
4023
0
    }
4024
0
    set2->nodeNr = 0;
4025
0
    return(set1);
4026
0
}
4027
4028
/**
4029
 * xmlXPathNodeSetMergeAndClearNoDupls:
4030
 * @set1:  the first NodeSet or NULL
4031
 * @set2:  the second NodeSet
4032
 *
4033
 * Merges two nodesets, all nodes from @set2 are added to @set1.
4034
 * Doesn't check for duplicate nodes. Clears set2.
4035
 *
4036
 * Returns @set1 once extended or NULL in case of error.
4037
 */
4038
static xmlNodeSetPtr
4039
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4040
0
{
4041
0
    {
4042
0
  int i;
4043
0
  xmlNodePtr n2;
4044
4045
0
  for (i = 0;i < set2->nodeNr;i++) {
4046
0
      n2 = set2->nodeTab[i];
4047
0
      if (set1->nodeMax == 0) {
4048
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4049
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4050
0
    if (set1->nodeTab == NULL) {
4051
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4052
0
        return(NULL);
4053
0
    }
4054
0
    memset(set1->nodeTab, 0,
4055
0
        XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4056
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4057
0
      } else if (set1->nodeNr >= set1->nodeMax) {
4058
0
    xmlNodePtr *temp;
4059
4060
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4061
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4062
0
                    return(NULL);
4063
0
                }
4064
0
    temp = (xmlNodePtr *) xmlRealloc(
4065
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4066
0
    if (temp == NULL) {
4067
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4068
0
        return(NULL);
4069
0
    }
4070
0
    set1->nodeTab = temp;
4071
0
    set1->nodeMax *= 2;
4072
0
      }
4073
0
      set1->nodeTab[set1->nodeNr++] = n2;
4074
0
  }
4075
0
    }
4076
0
    set2->nodeNr = 0;
4077
0
    return(set1);
4078
0
}
4079
4080
/**
4081
 * xmlXPathNodeSetDel:
4082
 * @cur:  the initial node set
4083
 * @val:  an xmlNodePtr
4084
 *
4085
 * Removes an xmlNodePtr from an existing NodeSet
4086
 */
4087
void
4088
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4089
0
    int i;
4090
4091
0
    if (cur == NULL) return;
4092
0
    if (val == NULL) return;
4093
4094
    /*
4095
     * find node in nodeTab
4096
     */
4097
0
    for (i = 0;i < cur->nodeNr;i++)
4098
0
        if (cur->nodeTab[i] == val) break;
4099
4100
0
    if (i >= cur->nodeNr) { /* not found */
4101
#ifdef DEBUG
4102
        xmlGenericError(xmlGenericErrorContext,
4103
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4104
    val->name);
4105
#endif
4106
0
        return;
4107
0
    }
4108
0
    if ((cur->nodeTab[i] != NULL) &&
4109
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4110
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4111
0
    cur->nodeNr--;
4112
0
    for (;i < cur->nodeNr;i++)
4113
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4114
0
    cur->nodeTab[cur->nodeNr] = NULL;
4115
0
}
4116
4117
/**
4118
 * xmlXPathNodeSetRemove:
4119
 * @cur:  the initial node set
4120
 * @val:  the index to remove
4121
 *
4122
 * Removes an entry from an existing NodeSet list.
4123
 */
4124
void
4125
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4126
0
    if (cur == NULL) return;
4127
0
    if (val >= cur->nodeNr) return;
4128
0
    if ((cur->nodeTab[val] != NULL) &&
4129
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4130
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4131
0
    cur->nodeNr--;
4132
0
    for (;val < cur->nodeNr;val++)
4133
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4134
0
    cur->nodeTab[cur->nodeNr] = NULL;
4135
0
}
4136
4137
/**
4138
 * xmlXPathFreeNodeSet:
4139
 * @obj:  the xmlNodeSetPtr to free
4140
 *
4141
 * Free the NodeSet compound (not the actual nodes !).
4142
 */
4143
void
4144
0
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4145
0
    if (obj == NULL) return;
4146
0
    if (obj->nodeTab != NULL) {
4147
0
  int i;
4148
4149
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4150
0
  for (i = 0;i < obj->nodeNr;i++)
4151
0
      if ((obj->nodeTab[i] != NULL) &&
4152
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4153
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4154
0
  xmlFree(obj->nodeTab);
4155
0
    }
4156
0
    xmlFree(obj);
4157
0
}
4158
4159
/**
4160
 * xmlXPathNodeSetClearFromPos:
4161
 * @set: the node set to be cleared
4162
 * @pos: the start position to clear from
4163
 *
4164
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4165
 * are feed) starting with the entry at @pos, but does *not* free the list
4166
 * itself. Sets the length of the list to @pos.
4167
 */
4168
static void
4169
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4170
0
{
4171
0
    if ((set == NULL) || (pos >= set->nodeNr))
4172
0
  return;
4173
0
    else if ((hasNsNodes)) {
4174
0
  int i;
4175
0
  xmlNodePtr node;
4176
4177
0
  for (i = pos; i < set->nodeNr; i++) {
4178
0
      node = set->nodeTab[i];
4179
0
      if ((node != NULL) &&
4180
0
    (node->type == XML_NAMESPACE_DECL))
4181
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4182
0
  }
4183
0
    }
4184
0
    set->nodeNr = pos;
4185
0
}
4186
4187
/**
4188
 * xmlXPathNodeSetClear:
4189
 * @set:  the node set to clear
4190
 *
4191
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4192
 * are feed), but does *not* free the list itself. Sets the length of the
4193
 * list to 0.
4194
 */
4195
static void
4196
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4197
0
{
4198
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4199
0
}
4200
4201
/**
4202
 * xmlXPathNodeSetKeepLast:
4203
 * @set: the node set to be cleared
4204
 *
4205
 * Move the last node to the first position and clear temporary XPath objects
4206
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4207
 * to 1.
4208
 */
4209
static void
4210
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4211
0
{
4212
0
    int i;
4213
0
    xmlNodePtr node;
4214
4215
0
    if ((set == NULL) || (set->nodeNr <= 1))
4216
0
  return;
4217
0
    for (i = 0; i < set->nodeNr - 1; i++) {
4218
0
        node = set->nodeTab[i];
4219
0
        if ((node != NULL) &&
4220
0
            (node->type == XML_NAMESPACE_DECL))
4221
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4222
0
    }
4223
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4224
0
    set->nodeNr = 1;
4225
0
}
4226
4227
/**
4228
 * xmlXPathFreeValueTree:
4229
 * @obj:  the xmlNodeSetPtr to free
4230
 *
4231
 * Free the NodeSet compound and the actual tree, this is different
4232
 * from xmlXPathFreeNodeSet()
4233
 */
4234
static void
4235
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4236
0
    int i;
4237
4238
0
    if (obj == NULL) return;
4239
4240
0
    if (obj->nodeTab != NULL) {
4241
0
  for (i = 0;i < obj->nodeNr;i++) {
4242
0
      if (obj->nodeTab[i] != NULL) {
4243
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4244
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4245
0
    } else {
4246
0
        xmlFreeNodeList(obj->nodeTab[i]);
4247
0
    }
4248
0
      }
4249
0
  }
4250
0
  xmlFree(obj->nodeTab);
4251
0
    }
4252
0
    xmlFree(obj);
4253
0
}
4254
4255
#if defined(DEBUG) || defined(DEBUG_STEP)
4256
/**
4257
 * xmlGenericErrorContextNodeSet:
4258
 * @output:  a FILE * for the output
4259
 * @obj:  the xmlNodeSetPtr to display
4260
 *
4261
 * Quick display of a NodeSet
4262
 */
4263
void
4264
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4265
    int i;
4266
4267
    if (output == NULL) output = xmlGenericErrorContext;
4268
    if (obj == NULL)  {
4269
        fprintf(output, "NodeSet == NULL !\n");
4270
  return;
4271
    }
4272
    if (obj->nodeNr == 0) {
4273
        fprintf(output, "NodeSet is empty\n");
4274
  return;
4275
    }
4276
    if (obj->nodeTab == NULL) {
4277
  fprintf(output, " nodeTab == NULL !\n");
4278
  return;
4279
    }
4280
    for (i = 0; i < obj->nodeNr; i++) {
4281
        if (obj->nodeTab[i] == NULL) {
4282
      fprintf(output, " NULL !\n");
4283
      return;
4284
        }
4285
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4286
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4287
      fprintf(output, " /");
4288
  else if (obj->nodeTab[i]->name == NULL)
4289
      fprintf(output, " noname!");
4290
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4291
    }
4292
    fprintf(output, "\n");
4293
}
4294
#endif
4295
4296
/**
4297
 * xmlXPathNewNodeSet:
4298
 * @val:  the NodePtr value
4299
 *
4300
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4301
 * it with the single Node @val
4302
 *
4303
 * Returns the newly created object.
4304
 */
4305
xmlXPathObjectPtr
4306
0
xmlXPathNewNodeSet(xmlNodePtr val) {
4307
0
    xmlXPathObjectPtr ret;
4308
4309
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4310
0
    if (ret == NULL) {
4311
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4312
0
  return(NULL);
4313
0
    }
4314
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4315
0
    ret->type = XPATH_NODESET;
4316
0
    ret->boolval = 0;
4317
    /* TODO: Check memory error. */
4318
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4319
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4320
#ifdef XP_DEBUG_OBJ_USAGE
4321
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4322
#endif
4323
0
    return(ret);
4324
0
}
4325
4326
/**
4327
 * xmlXPathNewValueTree:
4328
 * @val:  the NodePtr value
4329
 *
4330
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4331
 * it with the tree root @val
4332
 *
4333
 * Returns the newly created object.
4334
 */
4335
xmlXPathObjectPtr
4336
0
xmlXPathNewValueTree(xmlNodePtr val) {
4337
0
    xmlXPathObjectPtr ret;
4338
4339
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4340
0
    if (ret == NULL) {
4341
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4342
0
  return(NULL);
4343
0
    }
4344
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4345
0
    ret->type = XPATH_XSLT_TREE;
4346
0
    ret->boolval = 1;
4347
0
    ret->user = (void *) val;
4348
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4349
#ifdef XP_DEBUG_OBJ_USAGE
4350
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4351
#endif
4352
0
    return(ret);
4353
0
}
4354
4355
/**
4356
 * xmlXPathNewNodeSetList:
4357
 * @val:  an existing NodeSet
4358
 *
4359
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4360
 * it with the Nodeset @val
4361
 *
4362
 * Returns the newly created object.
4363
 */
4364
xmlXPathObjectPtr
4365
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4366
0
{
4367
0
    xmlXPathObjectPtr ret;
4368
0
    int i;
4369
4370
0
    if (val == NULL)
4371
0
        ret = NULL;
4372
0
    else if (val->nodeTab == NULL)
4373
0
        ret = xmlXPathNewNodeSet(NULL);
4374
0
    else {
4375
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4376
0
        if (ret) {
4377
0
            for (i = 1; i < val->nodeNr; ++i) {
4378
                /* TODO: Propagate memory error. */
4379
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4380
0
        < 0) break;
4381
0
      }
4382
0
  }
4383
0
    }
4384
4385
0
    return (ret);
4386
0
}
4387
4388
/**
4389
 * xmlXPathWrapNodeSet:
4390
 * @val:  the NodePtr value
4391
 *
4392
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4393
 *
4394
 * Returns the newly created object.
4395
 */
4396
xmlXPathObjectPtr
4397
0
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4398
0
    xmlXPathObjectPtr ret;
4399
4400
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4401
0
    if (ret == NULL) {
4402
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4403
0
  return(NULL);
4404
0
    }
4405
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4406
0
    ret->type = XPATH_NODESET;
4407
0
    ret->nodesetval = val;
4408
#ifdef XP_DEBUG_OBJ_USAGE
4409
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4410
#endif
4411
0
    return(ret);
4412
0
}
4413
4414
/**
4415
 * xmlXPathFreeNodeSetList:
4416
 * @obj:  an existing NodeSetList object
4417
 *
4418
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4419
 * the list contrary to xmlXPathFreeObject().
4420
 */
4421
void
4422
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4423
0
    if (obj == NULL) return;
4424
#ifdef XP_DEBUG_OBJ_USAGE
4425
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4426
#endif
4427
0
    xmlFree(obj);
4428
0
}
4429
4430
/**
4431
 * xmlXPathDifference:
4432
 * @nodes1:  a node-set
4433
 * @nodes2:  a node-set
4434
 *
4435
 * Implements the EXSLT - Sets difference() function:
4436
 *    node-set set:difference (node-set, node-set)
4437
 *
4438
 * Returns the difference between the two node sets, or nodes1 if
4439
 *         nodes2 is empty
4440
 */
4441
xmlNodeSetPtr
4442
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4443
0
    xmlNodeSetPtr ret;
4444
0
    int i, l1;
4445
0
    xmlNodePtr cur;
4446
4447
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4448
0
  return(nodes1);
4449
4450
    /* TODO: Check memory error. */
4451
0
    ret = xmlXPathNodeSetCreate(NULL);
4452
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4453
0
  return(ret);
4454
4455
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4456
4457
0
    for (i = 0; i < l1; i++) {
4458
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4459
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4460
            /* TODO: Propagate memory error. */
4461
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4462
0
          break;
4463
0
  }
4464
0
    }
4465
0
    return(ret);
4466
0
}
4467
4468
/**
4469
 * xmlXPathIntersection:
4470
 * @nodes1:  a node-set
4471
 * @nodes2:  a node-set
4472
 *
4473
 * Implements the EXSLT - Sets intersection() function:
4474
 *    node-set set:intersection (node-set, node-set)
4475
 *
4476
 * Returns a node set comprising the nodes that are within both the
4477
 *         node sets passed as arguments
4478
 */
4479
xmlNodeSetPtr
4480
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4481
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4482
0
    int i, l1;
4483
0
    xmlNodePtr cur;
4484
4485
0
    if (ret == NULL)
4486
0
        return(ret);
4487
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4488
0
  return(ret);
4489
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4490
0
  return(ret);
4491
4492
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4493
4494
0
    for (i = 0; i < l1; i++) {
4495
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4496
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4497
            /* TODO: Propagate memory error. */
4498
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4499
0
          break;
4500
0
  }
4501
0
    }
4502
0
    return(ret);
4503
0
}
4504
4505
/**
4506
 * xmlXPathDistinctSorted:
4507
 * @nodes:  a node-set, sorted by document order
4508
 *
4509
 * Implements the EXSLT - Sets distinct() function:
4510
 *    node-set set:distinct (node-set)
4511
 *
4512
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4513
 *         it is empty
4514
 */
4515
xmlNodeSetPtr
4516
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4517
0
    xmlNodeSetPtr ret;
4518
0
    xmlHashTablePtr hash;
4519
0
    int i, l;
4520
0
    xmlChar * strval;
4521
0
    xmlNodePtr cur;
4522
4523
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4524
0
  return(nodes);
4525
4526
0
    ret = xmlXPathNodeSetCreate(NULL);
4527
0
    if (ret == NULL)
4528
0
        return(ret);
4529
0
    l = xmlXPathNodeSetGetLength(nodes);
4530
0
    hash = xmlHashCreate (l);
4531
0
    for (i = 0; i < l; i++) {
4532
0
  cur = xmlXPathNodeSetItem(nodes, i);
4533
0
  strval = xmlXPathCastNodeToString(cur);
4534
0
  if (xmlHashLookup(hash, strval) == NULL) {
4535
0
      xmlHashAddEntry(hash, strval, strval);
4536
            /* TODO: Propagate memory error. */
4537
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4538
0
          break;
4539
0
  } else {
4540
0
      xmlFree(strval);
4541
0
  }
4542
0
    }
4543
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4544
0
    return(ret);
4545
0
}
4546
4547
/**
4548
 * xmlXPathDistinct:
4549
 * @nodes:  a node-set
4550
 *
4551
 * Implements the EXSLT - Sets distinct() function:
4552
 *    node-set set:distinct (node-set)
4553
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4554
 * is called with the sorted node-set
4555
 *
4556
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4557
 *         it is empty
4558
 */
4559
xmlNodeSetPtr
4560
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4561
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4562
0
  return(nodes);
4563
4564
0
    xmlXPathNodeSetSort(nodes);
4565
0
    return(xmlXPathDistinctSorted(nodes));
4566
0
}
4567
4568
/**
4569
 * xmlXPathHasSameNodes:
4570
 * @nodes1:  a node-set
4571
 * @nodes2:  a node-set
4572
 *
4573
 * Implements the EXSLT - Sets has-same-nodes function:
4574
 *    boolean set:has-same-node(node-set, node-set)
4575
 *
4576
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4577
 *         otherwise
4578
 */
4579
int
4580
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4581
0
    int i, l;
4582
0
    xmlNodePtr cur;
4583
4584
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4585
0
  xmlXPathNodeSetIsEmpty(nodes2))
4586
0
  return(0);
4587
4588
0
    l = xmlXPathNodeSetGetLength(nodes1);
4589
0
    for (i = 0; i < l; i++) {
4590
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4591
0
  if (xmlXPathNodeSetContains(nodes2, cur))
4592
0
      return(1);
4593
0
    }
4594
0
    return(0);
4595
0
}
4596
4597
/**
4598
 * xmlXPathNodeLeadingSorted:
4599
 * @nodes: a node-set, sorted by document order
4600
 * @node: a node
4601
 *
4602
 * Implements the EXSLT - Sets leading() function:
4603
 *    node-set set:leading (node-set, node-set)
4604
 *
4605
 * Returns the nodes in @nodes that precede @node in document order,
4606
 *         @nodes if @node is NULL or an empty node-set if @nodes
4607
 *         doesn't contain @node
4608
 */
4609
xmlNodeSetPtr
4610
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4611
0
    int i, l;
4612
0
    xmlNodePtr cur;
4613
0
    xmlNodeSetPtr ret;
4614
4615
0
    if (node == NULL)
4616
0
  return(nodes);
4617
4618
0
    ret = xmlXPathNodeSetCreate(NULL);
4619
0
    if (ret == NULL)
4620
0
        return(ret);
4621
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4622
0
  (!xmlXPathNodeSetContains(nodes, node)))
4623
0
  return(ret);
4624
4625
0
    l = xmlXPathNodeSetGetLength(nodes);
4626
0
    for (i = 0; i < l; i++) {
4627
0
  cur = xmlXPathNodeSetItem(nodes, i);
4628
0
  if (cur == node)
4629
0
      break;
4630
        /* TODO: Propagate memory error. */
4631
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4632
0
      break;
4633
0
    }
4634
0
    return(ret);
4635
0
}
4636
4637
/**
4638
 * xmlXPathNodeLeading:
4639
 * @nodes:  a node-set
4640
 * @node:  a node
4641
 *
4642
 * Implements the EXSLT - Sets leading() function:
4643
 *    node-set set:leading (node-set, node-set)
4644
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4645
 * is called.
4646
 *
4647
 * Returns the nodes in @nodes that precede @node in document order,
4648
 *         @nodes if @node is NULL or an empty node-set if @nodes
4649
 *         doesn't contain @node
4650
 */
4651
xmlNodeSetPtr
4652
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4653
0
    xmlXPathNodeSetSort(nodes);
4654
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4655
0
}
4656
4657
/**
4658
 * xmlXPathLeadingSorted:
4659
 * @nodes1:  a node-set, sorted by document order
4660
 * @nodes2:  a node-set, sorted by document order
4661
 *
4662
 * Implements the EXSLT - Sets leading() function:
4663
 *    node-set set:leading (node-set, node-set)
4664
 *
4665
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4666
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4667
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4668
 */
4669
xmlNodeSetPtr
4670
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4671
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4672
0
  return(nodes1);
4673
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4674
0
             xmlXPathNodeSetItem(nodes2, 1)));
4675
0
}
4676
4677
/**
4678
 * xmlXPathLeading:
4679
 * @nodes1:  a node-set
4680
 * @nodes2:  a node-set
4681
 *
4682
 * Implements the EXSLT - Sets leading() function:
4683
 *    node-set set:leading (node-set, node-set)
4684
 * @nodes1 and @nodes2 are sorted by document order, then
4685
 * #exslSetsLeadingSorted is called.
4686
 *
4687
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4688
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4689
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4690
 */
4691
xmlNodeSetPtr
4692
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4693
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4694
0
  return(nodes1);
4695
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4696
0
  return(xmlXPathNodeSetCreate(NULL));
4697
0
    xmlXPathNodeSetSort(nodes1);
4698
0
    xmlXPathNodeSetSort(nodes2);
4699
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4700
0
             xmlXPathNodeSetItem(nodes2, 1)));
4701
0
}
4702
4703
/**
4704
 * xmlXPathNodeTrailingSorted:
4705
 * @nodes: a node-set, sorted by document order
4706
 * @node: a node
4707
 *
4708
 * Implements the EXSLT - Sets trailing() function:
4709
 *    node-set set:trailing (node-set, node-set)
4710
 *
4711
 * Returns the nodes in @nodes that follow @node in document order,
4712
 *         @nodes if @node is NULL or an empty node-set if @nodes
4713
 *         doesn't contain @node
4714
 */
4715
xmlNodeSetPtr
4716
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4717
0
    int i, l;
4718
0
    xmlNodePtr cur;
4719
0
    xmlNodeSetPtr ret;
4720
4721
0
    if (node == NULL)
4722
0
  return(nodes);
4723
4724
0
    ret = xmlXPathNodeSetCreate(NULL);
4725
0
    if (ret == NULL)
4726
0
        return(ret);
4727
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4728
0
  (!xmlXPathNodeSetContains(nodes, node)))
4729
0
  return(ret);
4730
4731
0
    l = xmlXPathNodeSetGetLength(nodes);
4732
0
    for (i = l - 1; i >= 0; i--) {
4733
0
  cur = xmlXPathNodeSetItem(nodes, i);
4734
0
  if (cur == node)
4735
0
      break;
4736
        /* TODO: Propagate memory error. */
4737
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4738
0
      break;
4739
0
    }
4740
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4741
0
    return(ret);
4742
0
}
4743
4744
/**
4745
 * xmlXPathNodeTrailing:
4746
 * @nodes:  a node-set
4747
 * @node:  a node
4748
 *
4749
 * Implements the EXSLT - Sets trailing() function:
4750
 *    node-set set:trailing (node-set, node-set)
4751
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4752
 * is called.
4753
 *
4754
 * Returns the nodes in @nodes that follow @node in document order,
4755
 *         @nodes if @node is NULL or an empty node-set if @nodes
4756
 *         doesn't contain @node
4757
 */
4758
xmlNodeSetPtr
4759
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4760
0
    xmlXPathNodeSetSort(nodes);
4761
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4762
0
}
4763
4764
/**
4765
 * xmlXPathTrailingSorted:
4766
 * @nodes1:  a node-set, sorted by document order
4767
 * @nodes2:  a node-set, sorted by document order
4768
 *
4769
 * Implements the EXSLT - Sets trailing() function:
4770
 *    node-set set:trailing (node-set, node-set)
4771
 *
4772
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4773
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4774
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4775
 */
4776
xmlNodeSetPtr
4777
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4778
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4779
0
  return(nodes1);
4780
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4781
0
              xmlXPathNodeSetItem(nodes2, 0)));
4782
0
}
4783
4784
/**
4785
 * xmlXPathTrailing:
4786
 * @nodes1:  a node-set
4787
 * @nodes2:  a node-set
4788
 *
4789
 * Implements the EXSLT - Sets trailing() function:
4790
 *    node-set set:trailing (node-set, node-set)
4791
 * @nodes1 and @nodes2 are sorted by document order, then
4792
 * #xmlXPathTrailingSorted is called.
4793
 *
4794
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4795
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4796
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4797
 */
4798
xmlNodeSetPtr
4799
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4800
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4801
0
  return(nodes1);
4802
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4803
0
  return(xmlXPathNodeSetCreate(NULL));
4804
0
    xmlXPathNodeSetSort(nodes1);
4805
0
    xmlXPathNodeSetSort(nodes2);
4806
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4807
0
              xmlXPathNodeSetItem(nodes2, 0)));
4808
0
}
4809
4810
/************************************************************************
4811
 *                  *
4812
 *    Routines to handle extra functions      *
4813
 *                  *
4814
 ************************************************************************/
4815
4816
/**
4817
 * xmlXPathRegisterFunc:
4818
 * @ctxt:  the XPath context
4819
 * @name:  the function name
4820
 * @f:  the function implementation or NULL
4821
 *
4822
 * Register a new function. If @f is NULL it unregisters the function
4823
 *
4824
 * Returns 0 in case of success, -1 in case of error
4825
 */
4826
int
4827
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4828
0
         xmlXPathFunction f) {
4829
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4830
0
}
4831
4832
/**
4833
 * xmlXPathRegisterFuncNS:
4834
 * @ctxt:  the XPath context
4835
 * @name:  the function name
4836
 * @ns_uri:  the function namespace URI
4837
 * @f:  the function implementation or NULL
4838
 *
4839
 * Register a new function. If @f is NULL it unregisters the function
4840
 *
4841
 * Returns 0 in case of success, -1 in case of error
4842
 */
4843
int
4844
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4845
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
4846
0
    if (ctxt == NULL)
4847
0
  return(-1);
4848
0
    if (name == NULL)
4849
0
  return(-1);
4850
4851
0
    if (ctxt->funcHash == NULL)
4852
0
  ctxt->funcHash = xmlHashCreate(0);
4853
0
    if (ctxt->funcHash == NULL)
4854
0
  return(-1);
4855
0
    if (f == NULL)
4856
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4857
0
XML_IGNORE_PEDANTIC_WARNINGS
4858
0
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4859
0
XML_POP_WARNINGS
4860
0
}
4861
4862
/**
4863
 * xmlXPathRegisterFuncLookup:
4864
 * @ctxt:  the XPath context
4865
 * @f:  the lookup function
4866
 * @funcCtxt:  the lookup data
4867
 *
4868
 * Registers an external mechanism to do function lookup.
4869
 */
4870
void
4871
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4872
          xmlXPathFuncLookupFunc f,
4873
0
          void *funcCtxt) {
4874
0
    if (ctxt == NULL)
4875
0
  return;
4876
0
    ctxt->funcLookupFunc = f;
4877
0
    ctxt->funcLookupData = funcCtxt;
4878
0
}
4879
4880
/**
4881
 * xmlXPathFunctionLookup:
4882
 * @ctxt:  the XPath context
4883
 * @name:  the function name
4884
 *
4885
 * Search in the Function array of the context for the given
4886
 * function.
4887
 *
4888
 * Returns the xmlXPathFunction or NULL if not found
4889
 */
4890
xmlXPathFunction
4891
0
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4892
0
    if (ctxt == NULL)
4893
0
  return (NULL);
4894
4895
0
    if (ctxt->funcLookupFunc != NULL) {
4896
0
  xmlXPathFunction ret;
4897
0
  xmlXPathFuncLookupFunc f;
4898
4899
0
  f = ctxt->funcLookupFunc;
4900
0
  ret = f(ctxt->funcLookupData, name, NULL);
4901
0
  if (ret != NULL)
4902
0
      return(ret);
4903
0
    }
4904
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4905
0
}
4906
4907
/**
4908
 * xmlXPathFunctionLookupNS:
4909
 * @ctxt:  the XPath context
4910
 * @name:  the function name
4911
 * @ns_uri:  the function namespace URI
4912
 *
4913
 * Search in the Function array of the context for the given
4914
 * function.
4915
 *
4916
 * Returns the xmlXPathFunction or NULL if not found
4917
 */
4918
xmlXPathFunction
4919
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4920
0
       const xmlChar *ns_uri) {
4921
0
    xmlXPathFunction ret;
4922
4923
0
    if (ctxt == NULL)
4924
0
  return(NULL);
4925
0
    if (name == NULL)
4926
0
  return(NULL);
4927
4928
0
    if (ctxt->funcLookupFunc != NULL) {
4929
0
  xmlXPathFuncLookupFunc f;
4930
4931
0
  f = ctxt->funcLookupFunc;
4932
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
4933
0
  if (ret != NULL)
4934
0
      return(ret);
4935
0
    }
4936
4937
0
    if (ctxt->funcHash == NULL)
4938
0
  return(NULL);
4939
4940
0
XML_IGNORE_PEDANTIC_WARNINGS
4941
0
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4942
0
XML_POP_WARNINGS
4943
0
    return(ret);
4944
0
}
4945
4946
/**
4947
 * xmlXPathRegisteredFuncsCleanup:
4948
 * @ctxt:  the XPath context
4949
 *
4950
 * Cleanup the XPath context data associated to registered functions
4951
 */
4952
void
4953
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4954
0
    if (ctxt == NULL)
4955
0
  return;
4956
4957
0
    xmlHashFree(ctxt->funcHash, NULL);
4958
0
    ctxt->funcHash = NULL;
4959
0
}
4960
4961
/************************************************************************
4962
 *                  *
4963
 *      Routines to handle Variables      *
4964
 *                  *
4965
 ************************************************************************/
4966
4967
/**
4968
 * xmlXPathRegisterVariable:
4969
 * @ctxt:  the XPath context
4970
 * @name:  the variable name
4971
 * @value:  the variable value or NULL
4972
 *
4973
 * Register a new variable value. If @value is NULL it unregisters
4974
 * the variable
4975
 *
4976
 * Returns 0 in case of success, -1 in case of error
4977
 */
4978
int
4979
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4980
0
       xmlXPathObjectPtr value) {
4981
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4982
0
}
4983
4984
/**
4985
 * xmlXPathRegisterVariableNS:
4986
 * @ctxt:  the XPath context
4987
 * @name:  the variable name
4988
 * @ns_uri:  the variable namespace URI
4989
 * @value:  the variable value or NULL
4990
 *
4991
 * Register a new variable value. If @value is NULL it unregisters
4992
 * the variable
4993
 *
4994
 * Returns 0 in case of success, -1 in case of error
4995
 */
4996
int
4997
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4998
         const xmlChar *ns_uri,
4999
0
         xmlXPathObjectPtr value) {
5000
0
    if (ctxt == NULL)
5001
0
  return(-1);
5002
0
    if (name == NULL)
5003
0
  return(-1);
5004
5005
0
    if (ctxt->varHash == NULL)
5006
0
  ctxt->varHash = xmlHashCreate(0);
5007
0
    if (ctxt->varHash == NULL)
5008
0
  return(-1);
5009
0
    if (value == NULL)
5010
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5011
0
                             xmlXPathFreeObjectEntry));
5012
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5013
0
             (void *) value, xmlXPathFreeObjectEntry));
5014
0
}
5015
5016
/**
5017
 * xmlXPathRegisterVariableLookup:
5018
 * @ctxt:  the XPath context
5019
 * @f:  the lookup function
5020
 * @data:  the lookup data
5021
 *
5022
 * register an external mechanism to do variable lookup
5023
 */
5024
void
5025
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5026
0
   xmlXPathVariableLookupFunc f, void *data) {
5027
0
    if (ctxt == NULL)
5028
0
  return;
5029
0
    ctxt->varLookupFunc = f;
5030
0
    ctxt->varLookupData = data;
5031
0
}
5032
5033
/**
5034
 * xmlXPathVariableLookup:
5035
 * @ctxt:  the XPath context
5036
 * @name:  the variable name
5037
 *
5038
 * Search in the Variable array of the context for the given
5039
 * variable value.
5040
 *
5041
 * Returns a copy of the value or NULL if not found
5042
 */
5043
xmlXPathObjectPtr
5044
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5045
0
    if (ctxt == NULL)
5046
0
  return(NULL);
5047
5048
0
    if (ctxt->varLookupFunc != NULL) {
5049
0
  xmlXPathObjectPtr ret;
5050
5051
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5052
0
          (ctxt->varLookupData, name, NULL);
5053
0
  return(ret);
5054
0
    }
5055
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5056
0
}
5057
5058
/**
5059
 * xmlXPathVariableLookupNS:
5060
 * @ctxt:  the XPath context
5061
 * @name:  the variable name
5062
 * @ns_uri:  the variable namespace URI
5063
 *
5064
 * Search in the Variable array of the context for the given
5065
 * variable value.
5066
 *
5067
 * Returns the a copy of the value or NULL if not found
5068
 */
5069
xmlXPathObjectPtr
5070
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5071
0
       const xmlChar *ns_uri) {
5072
0
    if (ctxt == NULL)
5073
0
  return(NULL);
5074
5075
0
    if (ctxt->varLookupFunc != NULL) {
5076
0
  xmlXPathObjectPtr ret;
5077
5078
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5079
0
          (ctxt->varLookupData, name, ns_uri);
5080
0
  if (ret != NULL) return(ret);
5081
0
    }
5082
5083
0
    if (ctxt->varHash == NULL)
5084
0
  return(NULL);
5085
0
    if (name == NULL)
5086
0
  return(NULL);
5087
5088
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5089
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5090
0
}
5091
5092
/**
5093
 * xmlXPathRegisteredVariablesCleanup:
5094
 * @ctxt:  the XPath context
5095
 *
5096
 * Cleanup the XPath context data associated to registered variables
5097
 */
5098
void
5099
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5100
0
    if (ctxt == NULL)
5101
0
  return;
5102
5103
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5104
0
    ctxt->varHash = NULL;
5105
0
}
5106
5107
/**
5108
 * xmlXPathRegisterNs:
5109
 * @ctxt:  the XPath context
5110
 * @prefix:  the namespace prefix cannot be NULL or empty string
5111
 * @ns_uri:  the namespace name
5112
 *
5113
 * Register a new namespace. If @ns_uri is NULL it unregisters
5114
 * the namespace
5115
 *
5116
 * Returns 0 in case of success, -1 in case of error
5117
 */
5118
int
5119
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5120
0
         const xmlChar *ns_uri) {
5121
0
    if (ctxt == NULL)
5122
0
  return(-1);
5123
0
    if (prefix == NULL)
5124
0
  return(-1);
5125
0
    if (prefix[0] == 0)
5126
0
  return(-1);
5127
5128
0
    if (ctxt->nsHash == NULL)
5129
0
  ctxt->nsHash = xmlHashCreate(10);
5130
0
    if (ctxt->nsHash == NULL)
5131
0
  return(-1);
5132
0
    if (ns_uri == NULL)
5133
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5134
0
                            xmlHashDefaultDeallocator));
5135
0
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5136
0
            xmlHashDefaultDeallocator));
5137
0
}
5138
5139
/**
5140
 * xmlXPathNsLookup:
5141
 * @ctxt:  the XPath context
5142
 * @prefix:  the namespace prefix value
5143
 *
5144
 * Search in the namespace declaration array of the context for the given
5145
 * namespace name associated to the given prefix
5146
 *
5147
 * Returns the value or NULL if not found
5148
 */
5149
const xmlChar *
5150
0
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5151
0
    if (ctxt == NULL)
5152
0
  return(NULL);
5153
0
    if (prefix == NULL)
5154
0
  return(NULL);
5155
5156
0
#ifdef XML_XML_NAMESPACE
5157
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5158
0
  return(XML_XML_NAMESPACE);
5159
0
#endif
5160
5161
0
    if (ctxt->namespaces != NULL) {
5162
0
  int i;
5163
5164
0
  for (i = 0;i < ctxt->nsNr;i++) {
5165
0
      if ((ctxt->namespaces[i] != NULL) &&
5166
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5167
0
    return(ctxt->namespaces[i]->href);
5168
0
  }
5169
0
    }
5170
5171
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5172
0
}
5173
5174
/**
5175
 * xmlXPathRegisteredNsCleanup:
5176
 * @ctxt:  the XPath context
5177
 *
5178
 * Cleanup the XPath context data associated to registered variables
5179
 */
5180
void
5181
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5182
0
    if (ctxt == NULL)
5183
0
  return;
5184
5185
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5186
0
    ctxt->nsHash = NULL;
5187
0
}
5188
5189
/************************************************************************
5190
 *                  *
5191
 *      Routines to handle Values     *
5192
 *                  *
5193
 ************************************************************************/
5194
5195
/* Allocations are terrible, one needs to optimize all this !!! */
5196
5197
/**
5198
 * xmlXPathNewFloat:
5199
 * @val:  the double value
5200
 *
5201
 * Create a new xmlXPathObjectPtr of type double and of value @val
5202
 *
5203
 * Returns the newly created object.
5204
 */
5205
xmlXPathObjectPtr
5206
0
xmlXPathNewFloat(double val) {
5207
0
    xmlXPathObjectPtr ret;
5208
5209
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5210
0
    if (ret == NULL) {
5211
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5212
0
  return(NULL);
5213
0
    }
5214
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5215
0
    ret->type = XPATH_NUMBER;
5216
0
    ret->floatval = val;
5217
#ifdef XP_DEBUG_OBJ_USAGE
5218
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5219
#endif
5220
0
    return(ret);
5221
0
}
5222
5223
/**
5224
 * xmlXPathNewBoolean:
5225
 * @val:  the boolean value
5226
 *
5227
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5228
 *
5229
 * Returns the newly created object.
5230
 */
5231
xmlXPathObjectPtr
5232
0
xmlXPathNewBoolean(int val) {
5233
0
    xmlXPathObjectPtr ret;
5234
5235
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5236
0
    if (ret == NULL) {
5237
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5238
0
  return(NULL);
5239
0
    }
5240
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5241
0
    ret->type = XPATH_BOOLEAN;
5242
0
    ret->boolval = (val != 0);
5243
#ifdef XP_DEBUG_OBJ_USAGE
5244
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5245
#endif
5246
0
    return(ret);
5247
0
}
5248
5249
/**
5250
 * xmlXPathNewString:
5251
 * @val:  the xmlChar * value
5252
 *
5253
 * Create a new xmlXPathObjectPtr of type string and of value @val
5254
 *
5255
 * Returns the newly created object.
5256
 */
5257
xmlXPathObjectPtr
5258
0
xmlXPathNewString(const xmlChar *val) {
5259
0
    xmlXPathObjectPtr ret;
5260
5261
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5262
0
    if (ret == NULL) {
5263
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5264
0
  return(NULL);
5265
0
    }
5266
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5267
0
    ret->type = XPATH_STRING;
5268
0
    if (val != NULL)
5269
0
  ret->stringval = xmlStrdup(val);
5270
0
    else
5271
0
  ret->stringval = xmlStrdup((const xmlChar *)"");
5272
#ifdef XP_DEBUG_OBJ_USAGE
5273
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5274
#endif
5275
0
    return(ret);
5276
0
}
5277
5278
/**
5279
 * xmlXPathWrapString:
5280
 * @val:  the xmlChar * value
5281
 *
5282
 * Wraps the @val string into an XPath object.
5283
 *
5284
 * Returns the newly created object.
5285
 */
5286
xmlXPathObjectPtr
5287
0
xmlXPathWrapString (xmlChar *val) {
5288
0
    xmlXPathObjectPtr ret;
5289
5290
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5291
0
    if (ret == NULL) {
5292
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5293
0
  return(NULL);
5294
0
    }
5295
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5296
0
    ret->type = XPATH_STRING;
5297
0
    ret->stringval = val;
5298
#ifdef XP_DEBUG_OBJ_USAGE
5299
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5300
#endif
5301
0
    return(ret);
5302
0
}
5303
5304
/**
5305
 * xmlXPathNewCString:
5306
 * @val:  the char * value
5307
 *
5308
 * Create a new xmlXPathObjectPtr of type string and of value @val
5309
 *
5310
 * Returns the newly created object.
5311
 */
5312
xmlXPathObjectPtr
5313
0
xmlXPathNewCString(const char *val) {
5314
0
    xmlXPathObjectPtr ret;
5315
5316
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5317
0
    if (ret == NULL) {
5318
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5319
0
  return(NULL);
5320
0
    }
5321
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5322
0
    ret->type = XPATH_STRING;
5323
0
    ret->stringval = xmlStrdup(BAD_CAST val);
5324
#ifdef XP_DEBUG_OBJ_USAGE
5325
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5326
#endif
5327
0
    return(ret);
5328
0
}
5329
5330
/**
5331
 * xmlXPathWrapCString:
5332
 * @val:  the char * value
5333
 *
5334
 * Wraps a string into an XPath object.
5335
 *
5336
 * Returns the newly created object.
5337
 */
5338
xmlXPathObjectPtr
5339
0
xmlXPathWrapCString (char * val) {
5340
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5341
0
}
5342
5343
/**
5344
 * xmlXPathWrapExternal:
5345
 * @val:  the user data
5346
 *
5347
 * Wraps the @val data into an XPath object.
5348
 *
5349
 * Returns the newly created object.
5350
 */
5351
xmlXPathObjectPtr
5352
0
xmlXPathWrapExternal (void *val) {
5353
0
    xmlXPathObjectPtr ret;
5354
5355
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5356
0
    if (ret == NULL) {
5357
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5358
0
  return(NULL);
5359
0
    }
5360
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5361
0
    ret->type = XPATH_USERS;
5362
0
    ret->user = val;
5363
#ifdef XP_DEBUG_OBJ_USAGE
5364
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5365
#endif
5366
0
    return(ret);
5367
0
}
5368
5369
/**
5370
 * xmlXPathObjectCopy:
5371
 * @val:  the original object
5372
 *
5373
 * allocate a new copy of a given object
5374
 *
5375
 * Returns the newly created object.
5376
 */
5377
xmlXPathObjectPtr
5378
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5379
0
    xmlXPathObjectPtr ret;
5380
5381
0
    if (val == NULL)
5382
0
  return(NULL);
5383
5384
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5385
0
    if (ret == NULL) {
5386
0
        xmlXPathErrMemory(NULL, "copying object\n");
5387
0
  return(NULL);
5388
0
    }
5389
0
    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5390
#ifdef XP_DEBUG_OBJ_USAGE
5391
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5392
#endif
5393
0
    switch (val->type) {
5394
0
  case XPATH_BOOLEAN:
5395
0
  case XPATH_NUMBER:
5396
#ifdef LIBXML_XPTR_LOCS_ENABLED
5397
  case XPATH_POINT:
5398
  case XPATH_RANGE:
5399
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5400
0
      break;
5401
0
  case XPATH_STRING:
5402
0
      ret->stringval = xmlStrdup(val->stringval);
5403
0
      break;
5404
0
  case XPATH_XSLT_TREE:
5405
#if 0
5406
/*
5407
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5408
  this previous handling is no longer correct, and can cause some serious
5409
  problems (ref. bug 145547)
5410
*/
5411
      if ((val->nodesetval != NULL) &&
5412
    (val->nodesetval->nodeTab != NULL)) {
5413
    xmlNodePtr cur, tmp;
5414
    xmlDocPtr top;
5415
5416
    ret->boolval = 1;
5417
    top =  xmlNewDoc(NULL);
5418
    top->name = (char *)
5419
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5420
    ret->user = top;
5421
    if (top != NULL) {
5422
        top->doc = top;
5423
        cur = val->nodesetval->nodeTab[0]->children;
5424
        while (cur != NULL) {
5425
      tmp = xmlDocCopyNode(cur, top, 1);
5426
      xmlAddChild((xmlNodePtr) top, tmp);
5427
      cur = cur->next;
5428
        }
5429
    }
5430
5431
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5432
      } else
5433
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5434
      /* Deallocate the copied tree value */
5435
      break;
5436
#endif
5437
0
  case XPATH_NODESET:
5438
            /* TODO: Check memory error. */
5439
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5440
      /* Do not deallocate the copied tree value */
5441
0
      ret->boolval = 0;
5442
0
      break;
5443
#ifdef LIBXML_XPTR_LOCS_ENABLED
5444
  case XPATH_LOCATIONSET:
5445
  {
5446
      xmlLocationSetPtr loc = val->user;
5447
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5448
      break;
5449
  }
5450
#endif
5451
0
        case XPATH_USERS:
5452
0
      ret->user = val->user;
5453
0
      break;
5454
0
        case XPATH_UNDEFINED:
5455
0
      xmlGenericError(xmlGenericErrorContext,
5456
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5457
0
        val->type);
5458
0
      break;
5459
0
    }
5460
0
    return(ret);
5461
0
}
5462
5463
/**
5464
 * xmlXPathFreeObject:
5465
 * @obj:  the object to free
5466
 *
5467
 * Free up an xmlXPathObjectPtr object.
5468
 */
5469
void
5470
0
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5471
0
    if (obj == NULL) return;
5472
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5473
0
  if (obj->boolval) {
5474
#if 0
5475
      if (obj->user != NULL) {
5476
                xmlXPathFreeNodeSet(obj->nodesetval);
5477
    xmlFreeNodeList((xmlNodePtr) obj->user);
5478
      } else
5479
#endif
5480
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5481
0
      if (obj->nodesetval != NULL)
5482
0
    xmlXPathFreeValueTree(obj->nodesetval);
5483
0
  } else {
5484
0
      if (obj->nodesetval != NULL)
5485
0
    xmlXPathFreeNodeSet(obj->nodesetval);
5486
0
  }
5487
#ifdef LIBXML_XPTR_LOCS_ENABLED
5488
    } else if (obj->type == XPATH_LOCATIONSET) {
5489
  if (obj->user != NULL)
5490
      xmlXPtrFreeLocationSet(obj->user);
5491
#endif
5492
0
    } else if (obj->type == XPATH_STRING) {
5493
0
  if (obj->stringval != NULL)
5494
0
      xmlFree(obj->stringval);
5495
0
    }
5496
#ifdef XP_DEBUG_OBJ_USAGE
5497
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5498
#endif
5499
0
    xmlFree(obj);
5500
0
}
5501
5502
static void
5503
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5504
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5505
0
}
5506
5507
/**
5508
 * xmlXPathReleaseObject:
5509
 * @obj:  the xmlXPathObjectPtr to free or to cache
5510
 *
5511
 * Depending on the state of the cache this frees the given
5512
 * XPath object or stores it in the cache.
5513
 */
5514
static void
5515
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5516
0
{
5517
0
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5518
0
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5519
0
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5520
5521
0
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5522
5523
0
    if (obj == NULL)
5524
0
  return;
5525
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5526
0
   xmlXPathFreeObject(obj);
5527
0
    } else {
5528
0
  xmlXPathContextCachePtr cache =
5529
0
      (xmlXPathContextCachePtr) ctxt->cache;
5530
5531
0
  switch (obj->type) {
5532
0
      case XPATH_NODESET:
5533
0
      case XPATH_XSLT_TREE:
5534
0
    if (obj->nodesetval != NULL) {
5535
0
        if (obj->boolval) {
5536
      /*
5537
      * It looks like the @boolval is used for
5538
      * evaluation if this an XSLT Result Tree Fragment.
5539
      * TODO: Check if this assumption is correct.
5540
      */
5541
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5542
0
      xmlXPathFreeValueTree(obj->nodesetval);
5543
0
      obj->nodesetval = NULL;
5544
0
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5545
0
      (XP_CACHE_WANTS(cache->nodesetObjs,
5546
0
          cache->maxNodeset)))
5547
0
        {
5548
0
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5549
0
      goto obj_cached;
5550
0
        } else {
5551
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5552
0
      obj->nodesetval = NULL;
5553
0
        }
5554
0
    }
5555
0
    break;
5556
0
      case XPATH_STRING:
5557
0
    if (obj->stringval != NULL)
5558
0
        xmlFree(obj->stringval);
5559
5560
0
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5561
0
        XP_CACHE_ADD(cache->stringObjs, obj);
5562
0
        goto obj_cached;
5563
0
    }
5564
0
    break;
5565
0
      case XPATH_BOOLEAN:
5566
0
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5567
0
        XP_CACHE_ADD(cache->booleanObjs, obj);
5568
0
        goto obj_cached;
5569
0
    }
5570
0
    break;
5571
0
      case XPATH_NUMBER:
5572
0
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5573
0
        XP_CACHE_ADD(cache->numberObjs, obj);
5574
0
        goto obj_cached;
5575
0
    }
5576
0
    break;
5577
#ifdef LIBXML_XPTR_LOCS_ENABLED
5578
      case XPATH_LOCATIONSET:
5579
    if (obj->user != NULL) {
5580
        xmlXPtrFreeLocationSet(obj->user);
5581
    }
5582
    goto free_obj;
5583
#endif
5584
0
      default:
5585
0
    goto free_obj;
5586
0
  }
5587
5588
  /*
5589
  * Fallback to adding to the misc-objects slot.
5590
  */
5591
0
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5592
0
      XP_CACHE_ADD(cache->miscObjs, obj);
5593
0
  } else
5594
0
      goto free_obj;
5595
5596
0
obj_cached:
5597
5598
#ifdef XP_DEBUG_OBJ_USAGE
5599
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5600
#endif
5601
5602
0
  if (obj->nodesetval != NULL) {
5603
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
5604
5605
      /*
5606
      * TODO: Due to those nasty ns-nodes, we need to traverse
5607
      *  the list and free the ns-nodes.
5608
      * URGENT TODO: Check if it's actually slowing things down.
5609
      *  Maybe we shouldn't try to preserve the list.
5610
      */
5611
0
      if (tmpset->nodeNr > 1) {
5612
0
    int i;
5613
0
    xmlNodePtr node;
5614
5615
0
    for (i = 0; i < tmpset->nodeNr; i++) {
5616
0
        node = tmpset->nodeTab[i];
5617
0
        if ((node != NULL) &&
5618
0
      (node->type == XML_NAMESPACE_DECL))
5619
0
        {
5620
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5621
0
        }
5622
0
    }
5623
0
      } else if (tmpset->nodeNr == 1) {
5624
0
    if ((tmpset->nodeTab[0] != NULL) &&
5625
0
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5626
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5627
0
      }
5628
0
      tmpset->nodeNr = 0;
5629
0
      memset(obj, 0, sizeof(xmlXPathObject));
5630
0
      obj->nodesetval = tmpset;
5631
0
  } else
5632
0
      memset(obj, 0, sizeof(xmlXPathObject));
5633
5634
0
  return;
5635
5636
0
free_obj:
5637
  /*
5638
  * Cache is full; free the object.
5639
  */
5640
0
  if (obj->nodesetval != NULL)
5641
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5642
#ifdef XP_DEBUG_OBJ_USAGE
5643
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5644
#endif
5645
0
  xmlFree(obj);
5646
0
    }
5647
0
    return;
5648
0
}
5649
5650
5651
/************************************************************************
5652
 *                  *
5653
 *      Type Casting Routines       *
5654
 *                  *
5655
 ************************************************************************/
5656
5657
/**
5658
 * xmlXPathCastBooleanToString:
5659
 * @val:  a boolean
5660
 *
5661
 * Converts a boolean to its string value.
5662
 *
5663
 * Returns a newly allocated string.
5664
 */
5665
xmlChar *
5666
0
xmlXPathCastBooleanToString (int val) {
5667
0
    xmlChar *ret;
5668
0
    if (val)
5669
0
  ret = xmlStrdup((const xmlChar *) "true");
5670
0
    else
5671
0
  ret = xmlStrdup((const xmlChar *) "false");
5672
0
    return(ret);
5673
0
}
5674
5675
/**
5676
 * xmlXPathCastNumberToString:
5677
 * @val:  a number
5678
 *
5679
 * Converts a number to its string value.
5680
 *
5681
 * Returns a newly allocated string.
5682
 */
5683
xmlChar *
5684
0
xmlXPathCastNumberToString (double val) {
5685
0
    xmlChar *ret;
5686
0
    switch (xmlXPathIsInf(val)) {
5687
0
    case 1:
5688
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
5689
0
  break;
5690
0
    case -1:
5691
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5692
0
  break;
5693
0
    default:
5694
0
  if (xmlXPathIsNaN(val)) {
5695
0
      ret = xmlStrdup((const xmlChar *) "NaN");
5696
0
  } else if (val == 0) {
5697
            /* Omit sign for negative zero. */
5698
0
      ret = xmlStrdup((const xmlChar *) "0");
5699
0
  } else {
5700
      /* could be improved */
5701
0
      char buf[100];
5702
0
      xmlXPathFormatNumber(val, buf, 99);
5703
0
      buf[99] = 0;
5704
0
      ret = xmlStrdup((const xmlChar *) buf);
5705
0
  }
5706
0
    }
5707
0
    return(ret);
5708
0
}
5709
5710
/**
5711
 * xmlXPathCastNodeToString:
5712
 * @node:  a node
5713
 *
5714
 * Converts a node to its string value.
5715
 *
5716
 * Returns a newly allocated string.
5717
 */
5718
xmlChar *
5719
0
xmlXPathCastNodeToString (xmlNodePtr node) {
5720
0
xmlChar *ret;
5721
0
    if ((ret = xmlNodeGetContent(node)) == NULL)
5722
0
  ret = xmlStrdup((const xmlChar *) "");
5723
0
    return(ret);
5724
0
}
5725
5726
/**
5727
 * xmlXPathCastNodeSetToString:
5728
 * @ns:  a node-set
5729
 *
5730
 * Converts a node-set to its string value.
5731
 *
5732
 * Returns a newly allocated string.
5733
 */
5734
xmlChar *
5735
0
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5736
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5737
0
  return(xmlStrdup((const xmlChar *) ""));
5738
5739
0
    if (ns->nodeNr > 1)
5740
0
  xmlXPathNodeSetSort(ns);
5741
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5742
0
}
5743
5744
/**
5745
 * xmlXPathCastToString:
5746
 * @val:  an XPath object
5747
 *
5748
 * Converts an existing object to its string() equivalent
5749
 *
5750
 * Returns the allocated string value of the object, NULL in case of error.
5751
 *         It's up to the caller to free the string memory with xmlFree().
5752
 */
5753
xmlChar *
5754
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
5755
0
    xmlChar *ret = NULL;
5756
5757
0
    if (val == NULL)
5758
0
  return(xmlStrdup((const xmlChar *) ""));
5759
0
    switch (val->type) {
5760
0
  case XPATH_UNDEFINED:
5761
#ifdef DEBUG_EXPR
5762
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5763
#endif
5764
0
      ret = xmlStrdup((const xmlChar *) "");
5765
0
      break;
5766
0
        case XPATH_NODESET:
5767
0
        case XPATH_XSLT_TREE:
5768
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5769
0
      break;
5770
0
  case XPATH_STRING:
5771
0
      return(xmlStrdup(val->stringval));
5772
0
        case XPATH_BOOLEAN:
5773
0
      ret = xmlXPathCastBooleanToString(val->boolval);
5774
0
      break;
5775
0
  case XPATH_NUMBER: {
5776
0
      ret = xmlXPathCastNumberToString(val->floatval);
5777
0
      break;
5778
0
  }
5779
0
  case XPATH_USERS:
5780
#ifdef LIBXML_XPTR_LOCS_ENABLED
5781
  case XPATH_POINT:
5782
  case XPATH_RANGE:
5783
  case XPATH_LOCATIONSET:
5784
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5785
0
      TODO
5786
0
      ret = xmlStrdup((const xmlChar *) "");
5787
0
      break;
5788
0
    }
5789
0
    return(ret);
5790
0
}
5791
5792
/**
5793
 * xmlXPathConvertString:
5794
 * @val:  an XPath object
5795
 *
5796
 * Converts an existing object to its string() equivalent
5797
 *
5798
 * Returns the new object, the old one is freed (or the operation
5799
 *         is done directly on @val)
5800
 */
5801
xmlXPathObjectPtr
5802
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
5803
0
    xmlChar *res = NULL;
5804
5805
0
    if (val == NULL)
5806
0
  return(xmlXPathNewCString(""));
5807
5808
0
    switch (val->type) {
5809
0
    case XPATH_UNDEFINED:
5810
#ifdef DEBUG_EXPR
5811
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5812
#endif
5813
0
  break;
5814
0
    case XPATH_NODESET:
5815
0
    case XPATH_XSLT_TREE:
5816
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5817
0
  break;
5818
0
    case XPATH_STRING:
5819
0
  return(val);
5820
0
    case XPATH_BOOLEAN:
5821
0
  res = xmlXPathCastBooleanToString(val->boolval);
5822
0
  break;
5823
0
    case XPATH_NUMBER:
5824
0
  res = xmlXPathCastNumberToString(val->floatval);
5825
0
  break;
5826
0
    case XPATH_USERS:
5827
#ifdef LIBXML_XPTR_LOCS_ENABLED
5828
    case XPATH_POINT:
5829
    case XPATH_RANGE:
5830
    case XPATH_LOCATIONSET:
5831
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5832
0
  TODO;
5833
0
  break;
5834
0
    }
5835
0
    xmlXPathFreeObject(val);
5836
0
    if (res == NULL)
5837
0
  return(xmlXPathNewCString(""));
5838
0
    return(xmlXPathWrapString(res));
5839
0
}
5840
5841
/**
5842
 * xmlXPathCastBooleanToNumber:
5843
 * @val:  a boolean
5844
 *
5845
 * Converts a boolean to its number value
5846
 *
5847
 * Returns the number value
5848
 */
5849
double
5850
0
xmlXPathCastBooleanToNumber(int val) {
5851
0
    if (val)
5852
0
  return(1.0);
5853
0
    return(0.0);
5854
0
}
5855
5856
/**
5857
 * xmlXPathCastStringToNumber:
5858
 * @val:  a string
5859
 *
5860
 * Converts a string to its number value
5861
 *
5862
 * Returns the number value
5863
 */
5864
double
5865
0
xmlXPathCastStringToNumber(const xmlChar * val) {
5866
0
    return(xmlXPathStringEvalNumber(val));
5867
0
}
5868
5869
/**
5870
 * xmlXPathCastNodeToNumber:
5871
 * @node:  a node
5872
 *
5873
 * Converts a node to its number value
5874
 *
5875
 * Returns the number value
5876
 */
5877
double
5878
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5879
0
    xmlChar *strval;
5880
0
    double ret;
5881
5882
0
    if (node == NULL)
5883
0
  return(xmlXPathNAN);
5884
0
    strval = xmlXPathCastNodeToString(node);
5885
0
    if (strval == NULL)
5886
0
  return(xmlXPathNAN);
5887
0
    ret = xmlXPathCastStringToNumber(strval);
5888
0
    xmlFree(strval);
5889
5890
0
    return(ret);
5891
0
}
5892
5893
/**
5894
 * xmlXPathCastNodeSetToNumber:
5895
 * @ns:  a node-set
5896
 *
5897
 * Converts a node-set to its number value
5898
 *
5899
 * Returns the number value
5900
 */
5901
double
5902
0
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5903
0
    xmlChar *str;
5904
0
    double ret;
5905
5906
0
    if (ns == NULL)
5907
0
  return(xmlXPathNAN);
5908
0
    str = xmlXPathCastNodeSetToString(ns);
5909
0
    ret = xmlXPathCastStringToNumber(str);
5910
0
    xmlFree(str);
5911
0
    return(ret);
5912
0
}
5913
5914
/**
5915
 * xmlXPathCastToNumber:
5916
 * @val:  an XPath object
5917
 *
5918
 * Converts an XPath object to its number value
5919
 *
5920
 * Returns the number value
5921
 */
5922
double
5923
0
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5924
0
    double ret = 0.0;
5925
5926
0
    if (val == NULL)
5927
0
  return(xmlXPathNAN);
5928
0
    switch (val->type) {
5929
0
    case XPATH_UNDEFINED:
5930
#ifdef DEBUG_EXPR
5931
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5932
#endif
5933
0
  ret = xmlXPathNAN;
5934
0
  break;
5935
0
    case XPATH_NODESET:
5936
0
    case XPATH_XSLT_TREE:
5937
0
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5938
0
  break;
5939
0
    case XPATH_STRING:
5940
0
  ret = xmlXPathCastStringToNumber(val->stringval);
5941
0
  break;
5942
0
    case XPATH_NUMBER:
5943
0
  ret = val->floatval;
5944
0
  break;
5945
0
    case XPATH_BOOLEAN:
5946
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5947
0
  break;
5948
0
    case XPATH_USERS:
5949
#ifdef LIBXML_XPTR_LOCS_ENABLED
5950
    case XPATH_POINT:
5951
    case XPATH_RANGE:
5952
    case XPATH_LOCATIONSET:
5953
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5954
0
  TODO;
5955
0
  ret = xmlXPathNAN;
5956
0
  break;
5957
0
    }
5958
0
    return(ret);
5959
0
}
5960
5961
/**
5962
 * xmlXPathConvertNumber:
5963
 * @val:  an XPath object
5964
 *
5965
 * Converts an existing object to its number() equivalent
5966
 *
5967
 * Returns the new object, the old one is freed (or the operation
5968
 *         is done directly on @val)
5969
 */
5970
xmlXPathObjectPtr
5971
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5972
0
    xmlXPathObjectPtr ret;
5973
5974
0
    if (val == NULL)
5975
0
  return(xmlXPathNewFloat(0.0));
5976
0
    if (val->type == XPATH_NUMBER)
5977
0
  return(val);
5978
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5979
0
    xmlXPathFreeObject(val);
5980
0
    return(ret);
5981
0
}
5982
5983
/**
5984
 * xmlXPathCastNumberToBoolean:
5985
 * @val:  a number
5986
 *
5987
 * Converts a number to its boolean value
5988
 *
5989
 * Returns the boolean value
5990
 */
5991
int
5992
0
xmlXPathCastNumberToBoolean (double val) {
5993
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
5994
0
   return(0);
5995
0
     return(1);
5996
0
}
5997
5998
/**
5999
 * xmlXPathCastStringToBoolean:
6000
 * @val:  a string
6001
 *
6002
 * Converts a string to its boolean value
6003
 *
6004
 * Returns the boolean value
6005
 */
6006
int
6007
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
6008
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
6009
0
  return(0);
6010
0
    return(1);
6011
0
}
6012
6013
/**
6014
 * xmlXPathCastNodeSetToBoolean:
6015
 * @ns:  a node-set
6016
 *
6017
 * Converts a node-set to its boolean value
6018
 *
6019
 * Returns the boolean value
6020
 */
6021
int
6022
0
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6023
0
    if ((ns == NULL) || (ns->nodeNr == 0))
6024
0
  return(0);
6025
0
    return(1);
6026
0
}
6027
6028
/**
6029
 * xmlXPathCastToBoolean:
6030
 * @val:  an XPath object
6031
 *
6032
 * Converts an XPath object to its boolean value
6033
 *
6034
 * Returns the boolean value
6035
 */
6036
int
6037
0
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6038
0
    int ret = 0;
6039
6040
0
    if (val == NULL)
6041
0
  return(0);
6042
0
    switch (val->type) {
6043
0
    case XPATH_UNDEFINED:
6044
#ifdef DEBUG_EXPR
6045
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6046
#endif
6047
0
  ret = 0;
6048
0
  break;
6049
0
    case XPATH_NODESET:
6050
0
    case XPATH_XSLT_TREE:
6051
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6052
0
  break;
6053
0
    case XPATH_STRING:
6054
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
6055
0
  break;
6056
0
    case XPATH_NUMBER:
6057
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6058
0
  break;
6059
0
    case XPATH_BOOLEAN:
6060
0
  ret = val->boolval;
6061
0
  break;
6062
0
    case XPATH_USERS:
6063
#ifdef LIBXML_XPTR_LOCS_ENABLED
6064
    case XPATH_POINT:
6065
    case XPATH_RANGE:
6066
    case XPATH_LOCATIONSET:
6067
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6068
0
  TODO;
6069
0
  ret = 0;
6070
0
  break;
6071
0
    }
6072
0
    return(ret);
6073
0
}
6074
6075
6076
/**
6077
 * xmlXPathConvertBoolean:
6078
 * @val:  an XPath object
6079
 *
6080
 * Converts an existing object to its boolean() equivalent
6081
 *
6082
 * Returns the new object, the old one is freed (or the operation
6083
 *         is done directly on @val)
6084
 */
6085
xmlXPathObjectPtr
6086
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6087
0
    xmlXPathObjectPtr ret;
6088
6089
0
    if (val == NULL)
6090
0
  return(xmlXPathNewBoolean(0));
6091
0
    if (val->type == XPATH_BOOLEAN)
6092
0
  return(val);
6093
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6094
0
    xmlXPathFreeObject(val);
6095
0
    return(ret);
6096
0
}
6097
6098
/************************************************************************
6099
 *                  *
6100
 *    Routines to handle XPath contexts     *
6101
 *                  *
6102
 ************************************************************************/
6103
6104
/**
6105
 * xmlXPathNewContext:
6106
 * @doc:  the XML document
6107
 *
6108
 * Create a new xmlXPathContext
6109
 *
6110
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6111
 */
6112
xmlXPathContextPtr
6113
0
xmlXPathNewContext(xmlDocPtr doc) {
6114
0
    xmlXPathContextPtr ret;
6115
6116
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6117
0
    if (ret == NULL) {
6118
0
        xmlXPathErrMemory(NULL, "creating context\n");
6119
0
  return(NULL);
6120
0
    }
6121
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6122
0
    ret->doc = doc;
6123
0
    ret->node = NULL;
6124
6125
0
    ret->varHash = NULL;
6126
6127
0
    ret->nb_types = 0;
6128
0
    ret->max_types = 0;
6129
0
    ret->types = NULL;
6130
6131
0
    ret->funcHash = xmlHashCreate(0);
6132
6133
0
    ret->nb_axis = 0;
6134
0
    ret->max_axis = 0;
6135
0
    ret->axis = NULL;
6136
6137
0
    ret->nsHash = NULL;
6138
0
    ret->user = NULL;
6139
6140
0
    ret->contextSize = -1;
6141
0
    ret->proximityPosition = -1;
6142
6143
#ifdef XP_DEFAULT_CACHE_ON
6144
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6145
  xmlXPathFreeContext(ret);
6146
  return(NULL);
6147
    }
6148
#endif
6149
6150
0
    xmlXPathRegisterAllFunctions(ret);
6151
6152
0
    return(ret);
6153
0
}
6154
6155
/**
6156
 * xmlXPathFreeContext:
6157
 * @ctxt:  the context to free
6158
 *
6159
 * Free up an xmlXPathContext
6160
 */
6161
void
6162
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6163
0
    if (ctxt == NULL) return;
6164
6165
0
    if (ctxt->cache != NULL)
6166
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6167
0
    xmlXPathRegisteredNsCleanup(ctxt);
6168
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
6169
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
6170
0
    xmlResetError(&ctxt->lastError);
6171
0
    xmlFree(ctxt);
6172
0
}
6173
6174
/************************************************************************
6175
 *                  *
6176
 *    Routines to handle XPath parser contexts    *
6177
 *                  *
6178
 ************************************************************************/
6179
6180
#define CHECK_CTXT(ctxt)            \
6181
0
    if (ctxt == NULL) {           \
6182
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6183
0
    NULL, NULL, XML_FROM_XPATH,       \
6184
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6185
0
    __FILE__, __LINE__,         \
6186
0
    NULL, NULL, NULL, 0, 0,         \
6187
0
    "NULL context pointer\n");        \
6188
0
  return(NULL);             \
6189
0
    }                  \
6190
6191
#define CHECK_CTXT_NEG(ctxt)            \
6192
0
    if (ctxt == NULL) {           \
6193
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6194
0
    NULL, NULL, XML_FROM_XPATH,       \
6195
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6196
0
    __FILE__, __LINE__,         \
6197
0
    NULL, NULL, NULL, 0, 0,         \
6198
0
    "NULL context pointer\n");        \
6199
0
  return(-1);             \
6200
0
    }                  \
6201
6202
6203
#define CHECK_CONTEXT(ctxt)           \
6204
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6205
        (ctxt->doc->children == NULL)) {        \
6206
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6207
  return(NULL);             \
6208
    }
6209
6210
6211
/**
6212
 * xmlXPathNewParserContext:
6213
 * @str:  the XPath expression
6214
 * @ctxt:  the XPath context
6215
 *
6216
 * Create a new xmlXPathParserContext
6217
 *
6218
 * Returns the xmlXPathParserContext just allocated.
6219
 */
6220
xmlXPathParserContextPtr
6221
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6222
0
    xmlXPathParserContextPtr ret;
6223
6224
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6225
0
    if (ret == NULL) {
6226
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6227
0
  return(NULL);
6228
0
    }
6229
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6230
0
    ret->cur = ret->base = str;
6231
0
    ret->context = ctxt;
6232
6233
0
    ret->comp = xmlXPathNewCompExpr();
6234
0
    if (ret->comp == NULL) {
6235
0
  xmlFree(ret->valueTab);
6236
0
  xmlFree(ret);
6237
0
  return(NULL);
6238
0
    }
6239
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6240
0
        ret->comp->dict = ctxt->dict;
6241
0
  xmlDictReference(ret->comp->dict);
6242
0
    }
6243
6244
0
    return(ret);
6245
0
}
6246
6247
/**
6248
 * xmlXPathCompParserContext:
6249
 * @comp:  the XPath compiled expression
6250
 * @ctxt:  the XPath context
6251
 *
6252
 * Create a new xmlXPathParserContext when processing a compiled expression
6253
 *
6254
 * Returns the xmlXPathParserContext just allocated.
6255
 */
6256
static xmlXPathParserContextPtr
6257
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6258
0
    xmlXPathParserContextPtr ret;
6259
6260
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6261
0
    if (ret == NULL) {
6262
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6263
0
  return(NULL);
6264
0
    }
6265
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6266
6267
    /* Allocate the value stack */
6268
0
    ret->valueTab = (xmlXPathObjectPtr *)
6269
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6270
0
    if (ret->valueTab == NULL) {
6271
0
  xmlFree(ret);
6272
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6273
0
  return(NULL);
6274
0
    }
6275
0
    ret->valueNr = 0;
6276
0
    ret->valueMax = 10;
6277
0
    ret->value = NULL;
6278
0
    ret->valueFrame = 0;
6279
6280
0
    ret->context = ctxt;
6281
0
    ret->comp = comp;
6282
6283
0
    return(ret);
6284
0
}
6285
6286
/**
6287
 * xmlXPathFreeParserContext:
6288
 * @ctxt:  the context to free
6289
 *
6290
 * Free up an xmlXPathParserContext
6291
 */
6292
void
6293
0
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6294
0
    int i;
6295
6296
0
    if (ctxt->valueTab != NULL) {
6297
0
        for (i = 0; i < ctxt->valueNr; i++) {
6298
0
            if (ctxt->context)
6299
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6300
0
            else
6301
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6302
0
        }
6303
0
        xmlFree(ctxt->valueTab);
6304
0
    }
6305
0
    if (ctxt->comp != NULL) {
6306
0
#ifdef XPATH_STREAMING
6307
0
  if (ctxt->comp->stream != NULL) {
6308
0
      xmlFreePatternList(ctxt->comp->stream);
6309
0
      ctxt->comp->stream = NULL;
6310
0
  }
6311
0
#endif
6312
0
  xmlXPathFreeCompExpr(ctxt->comp);
6313
0
    }
6314
0
    xmlFree(ctxt);
6315
0
}
6316
6317
/************************************************************************
6318
 *                  *
6319
 *    The implicit core function library      *
6320
 *                  *
6321
 ************************************************************************/
6322
6323
/**
6324
 * xmlXPathNodeValHash:
6325
 * @node:  a node pointer
6326
 *
6327
 * Function computing the beginning of the string value of the node,
6328
 * used to speed up comparisons
6329
 *
6330
 * Returns an int usable as a hash
6331
 */
6332
static unsigned int
6333
0
xmlXPathNodeValHash(xmlNodePtr node) {
6334
0
    int len = 2;
6335
0
    const xmlChar * string = NULL;
6336
0
    xmlNodePtr tmp = NULL;
6337
0
    unsigned int ret = 0;
6338
6339
0
    if (node == NULL)
6340
0
  return(0);
6341
6342
0
    if (node->type == XML_DOCUMENT_NODE) {
6343
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6344
0
  if (tmp == NULL)
6345
0
      node = node->children;
6346
0
  else
6347
0
      node = tmp;
6348
6349
0
  if (node == NULL)
6350
0
      return(0);
6351
0
    }
6352
6353
0
    switch (node->type) {
6354
0
  case XML_COMMENT_NODE:
6355
0
  case XML_PI_NODE:
6356
0
  case XML_CDATA_SECTION_NODE:
6357
0
  case XML_TEXT_NODE:
6358
0
      string = node->content;
6359
0
      if (string == NULL)
6360
0
    return(0);
6361
0
      if (string[0] == 0)
6362
0
    return(0);
6363
0
      return(((unsigned int) string[0]) +
6364
0
       (((unsigned int) string[1]) << 8));
6365
0
  case XML_NAMESPACE_DECL:
6366
0
      string = ((xmlNsPtr)node)->href;
6367
0
      if (string == NULL)
6368
0
    return(0);
6369
0
      if (string[0] == 0)
6370
0
    return(0);
6371
0
      return(((unsigned int) string[0]) +
6372
0
       (((unsigned int) string[1]) << 8));
6373
0
  case XML_ATTRIBUTE_NODE:
6374
0
      tmp = ((xmlAttrPtr) node)->children;
6375
0
      break;
6376
0
  case XML_ELEMENT_NODE:
6377
0
      tmp = node->children;
6378
0
      break;
6379
0
  default:
6380
0
      return(0);
6381
0
    }
6382
0
    while (tmp != NULL) {
6383
0
  switch (tmp->type) {
6384
0
      case XML_CDATA_SECTION_NODE:
6385
0
      case XML_TEXT_NODE:
6386
0
    string = tmp->content;
6387
0
    break;
6388
0
      default:
6389
0
                string = NULL;
6390
0
    break;
6391
0
  }
6392
0
  if ((string != NULL) && (string[0] != 0)) {
6393
0
      if (len == 1) {
6394
0
    return(ret + (((unsigned int) string[0]) << 8));
6395
0
      }
6396
0
      if (string[1] == 0) {
6397
0
    len = 1;
6398
0
    ret = (unsigned int) string[0];
6399
0
      } else {
6400
0
    return(((unsigned int) string[0]) +
6401
0
           (((unsigned int) string[1]) << 8));
6402
0
      }
6403
0
  }
6404
  /*
6405
   * Skip to next node
6406
   */
6407
0
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6408
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6409
0
    tmp = tmp->children;
6410
0
    continue;
6411
0
      }
6412
0
  }
6413
0
  if (tmp == node)
6414
0
      break;
6415
6416
0
  if (tmp->next != NULL) {
6417
0
      tmp = tmp->next;
6418
0
      continue;
6419
0
  }
6420
6421
0
  do {
6422
0
      tmp = tmp->parent;
6423
0
      if (tmp == NULL)
6424
0
    break;
6425
0
      if (tmp == node) {
6426
0
    tmp = NULL;
6427
0
    break;
6428
0
      }
6429
0
      if (tmp->next != NULL) {
6430
0
    tmp = tmp->next;
6431
0
    break;
6432
0
      }
6433
0
  } while (tmp != NULL);
6434
0
    }
6435
0
    return(ret);
6436
0
}
6437
6438
/**
6439
 * xmlXPathStringHash:
6440
 * @string:  a string
6441
 *
6442
 * Function computing the beginning of the string value of the node,
6443
 * used to speed up comparisons
6444
 *
6445
 * Returns an int usable as a hash
6446
 */
6447
static unsigned int
6448
0
xmlXPathStringHash(const xmlChar * string) {
6449
0
    if (string == NULL)
6450
0
  return((unsigned int) 0);
6451
0
    if (string[0] == 0)
6452
0
  return(0);
6453
0
    return(((unsigned int) string[0]) +
6454
0
     (((unsigned int) string[1]) << 8));
6455
0
}
6456
6457
/**
6458
 * xmlXPathCompareNodeSetFloat:
6459
 * @ctxt:  the XPath Parser context
6460
 * @inf:  less than (1) or greater than (0)
6461
 * @strict:  is the comparison strict
6462
 * @arg:  the node set
6463
 * @f:  the value
6464
 *
6465
 * Implement the compare operation between a nodeset and a number
6466
 *     @ns < @val    (1, 1, ...
6467
 *     @ns <= @val   (1, 0, ...
6468
 *     @ns > @val    (0, 1, ...
6469
 *     @ns >= @val   (0, 0, ...
6470
 *
6471
 * If one object to be compared is a node-set and the other is a number,
6472
 * then the comparison will be true if and only if there is a node in the
6473
 * node-set such that the result of performing the comparison on the number
6474
 * to be compared and on the result of converting the string-value of that
6475
 * node to a number using the number function is true.
6476
 *
6477
 * Returns 0 or 1 depending on the results of the test.
6478
 */
6479
static int
6480
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6481
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6482
0
    int i, ret = 0;
6483
0
    xmlNodeSetPtr ns;
6484
0
    xmlChar *str2;
6485
6486
0
    if ((f == NULL) || (arg == NULL) ||
6487
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6488
0
  xmlXPathReleaseObject(ctxt->context, arg);
6489
0
  xmlXPathReleaseObject(ctxt->context, f);
6490
0
        return(0);
6491
0
    }
6492
0
    ns = arg->nodesetval;
6493
0
    if (ns != NULL) {
6494
0
  for (i = 0;i < ns->nodeNr;i++) {
6495
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6496
0
       if (str2 != NULL) {
6497
0
     valuePush(ctxt,
6498
0
         xmlXPathCacheNewString(ctxt->context, str2));
6499
0
     xmlFree(str2);
6500
0
     xmlXPathNumberFunction(ctxt, 1);
6501
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6502
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6503
0
     if (ret)
6504
0
         break;
6505
0
       }
6506
0
  }
6507
0
    }
6508
0
    xmlXPathReleaseObject(ctxt->context, arg);
6509
0
    xmlXPathReleaseObject(ctxt->context, f);
6510
0
    return(ret);
6511
0
}
6512
6513
/**
6514
 * xmlXPathCompareNodeSetString:
6515
 * @ctxt:  the XPath Parser context
6516
 * @inf:  less than (1) or greater than (0)
6517
 * @strict:  is the comparison strict
6518
 * @arg:  the node set
6519
 * @s:  the value
6520
 *
6521
 * Implement the compare operation between a nodeset and a string
6522
 *     @ns < @val    (1, 1, ...
6523
 *     @ns <= @val   (1, 0, ...
6524
 *     @ns > @val    (0, 1, ...
6525
 *     @ns >= @val   (0, 0, ...
6526
 *
6527
 * If one object to be compared is a node-set and the other is a string,
6528
 * then the comparison will be true if and only if there is a node in
6529
 * the node-set such that the result of performing the comparison on the
6530
 * string-value of the node and the other string is true.
6531
 *
6532
 * Returns 0 or 1 depending on the results of the test.
6533
 */
6534
static int
6535
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6536
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6537
0
    int i, ret = 0;
6538
0
    xmlNodeSetPtr ns;
6539
0
    xmlChar *str2;
6540
6541
0
    if ((s == NULL) || (arg == NULL) ||
6542
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6543
0
  xmlXPathReleaseObject(ctxt->context, arg);
6544
0
  xmlXPathReleaseObject(ctxt->context, s);
6545
0
        return(0);
6546
0
    }
6547
0
    ns = arg->nodesetval;
6548
0
    if (ns != NULL) {
6549
0
  for (i = 0;i < ns->nodeNr;i++) {
6550
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6551
0
       if (str2 != NULL) {
6552
0
     valuePush(ctxt,
6553
0
         xmlXPathCacheNewString(ctxt->context, str2));
6554
0
     xmlFree(str2);
6555
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6556
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6557
0
     if (ret)
6558
0
         break;
6559
0
       }
6560
0
  }
6561
0
    }
6562
0
    xmlXPathReleaseObject(ctxt->context, arg);
6563
0
    xmlXPathReleaseObject(ctxt->context, s);
6564
0
    return(ret);
6565
0
}
6566
6567
/**
6568
 * xmlXPathCompareNodeSets:
6569
 * @inf:  less than (1) or greater than (0)
6570
 * @strict:  is the comparison strict
6571
 * @arg1:  the first node set object
6572
 * @arg2:  the second node set object
6573
 *
6574
 * Implement the compare operation on nodesets:
6575
 *
6576
 * If both objects to be compared are node-sets, then the comparison
6577
 * will be true if and only if there is a node in the first node-set
6578
 * and a node in the second node-set such that the result of performing
6579
 * the comparison on the string-values of the two nodes is true.
6580
 * ....
6581
 * When neither object to be compared is a node-set and the operator
6582
 * is <=, <, >= or >, then the objects are compared by converting both
6583
 * objects to numbers and comparing the numbers according to IEEE 754.
6584
 * ....
6585
 * The number function converts its argument to a number as follows:
6586
 *  - a string that consists of optional whitespace followed by an
6587
 *    optional minus sign followed by a Number followed by whitespace
6588
 *    is converted to the IEEE 754 number that is nearest (according
6589
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6590
 *    represented by the string; any other string is converted to NaN
6591
 *
6592
 * Conclusion all nodes need to be converted first to their string value
6593
 * and then the comparison must be done when possible
6594
 */
6595
static int
6596
xmlXPathCompareNodeSets(int inf, int strict,
6597
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6598
0
    int i, j, init = 0;
6599
0
    double val1;
6600
0
    double *values2;
6601
0
    int ret = 0;
6602
0
    xmlNodeSetPtr ns1;
6603
0
    xmlNodeSetPtr ns2;
6604
6605
0
    if ((arg1 == NULL) ||
6606
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6607
0
  xmlXPathFreeObject(arg2);
6608
0
        return(0);
6609
0
    }
6610
0
    if ((arg2 == NULL) ||
6611
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6612
0
  xmlXPathFreeObject(arg1);
6613
0
  xmlXPathFreeObject(arg2);
6614
0
        return(0);
6615
0
    }
6616
6617
0
    ns1 = arg1->nodesetval;
6618
0
    ns2 = arg2->nodesetval;
6619
6620
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6621
0
  xmlXPathFreeObject(arg1);
6622
0
  xmlXPathFreeObject(arg2);
6623
0
  return(0);
6624
0
    }
6625
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6626
0
  xmlXPathFreeObject(arg1);
6627
0
  xmlXPathFreeObject(arg2);
6628
0
  return(0);
6629
0
    }
6630
6631
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6632
0
    if (values2 == NULL) {
6633
        /* TODO: Propagate memory error. */
6634
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6635
0
  xmlXPathFreeObject(arg1);
6636
0
  xmlXPathFreeObject(arg2);
6637
0
  return(0);
6638
0
    }
6639
0
    for (i = 0;i < ns1->nodeNr;i++) {
6640
0
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6641
0
  if (xmlXPathIsNaN(val1))
6642
0
      continue;
6643
0
  for (j = 0;j < ns2->nodeNr;j++) {
6644
0
      if (init == 0) {
6645
0
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6646
0
      }
6647
0
      if (xmlXPathIsNaN(values2[j]))
6648
0
    continue;
6649
0
      if (inf && strict)
6650
0
    ret = (val1 < values2[j]);
6651
0
      else if (inf && !strict)
6652
0
    ret = (val1 <= values2[j]);
6653
0
      else if (!inf && strict)
6654
0
    ret = (val1 > values2[j]);
6655
0
      else if (!inf && !strict)
6656
0
    ret = (val1 >= values2[j]);
6657
0
      if (ret)
6658
0
    break;
6659
0
  }
6660
0
  if (ret)
6661
0
      break;
6662
0
  init = 1;
6663
0
    }
6664
0
    xmlFree(values2);
6665
0
    xmlXPathFreeObject(arg1);
6666
0
    xmlXPathFreeObject(arg2);
6667
0
    return(ret);
6668
0
}
6669
6670
/**
6671
 * xmlXPathCompareNodeSetValue:
6672
 * @ctxt:  the XPath Parser context
6673
 * @inf:  less than (1) or greater than (0)
6674
 * @strict:  is the comparison strict
6675
 * @arg:  the node set
6676
 * @val:  the value
6677
 *
6678
 * Implement the compare operation between a nodeset and a value
6679
 *     @ns < @val    (1, 1, ...
6680
 *     @ns <= @val   (1, 0, ...
6681
 *     @ns > @val    (0, 1, ...
6682
 *     @ns >= @val   (0, 0, ...
6683
 *
6684
 * If one object to be compared is a node-set and the other is a boolean,
6685
 * then the comparison will be true if and only if the result of performing
6686
 * the comparison on the boolean and on the result of converting
6687
 * the node-set to a boolean using the boolean function is true.
6688
 *
6689
 * Returns 0 or 1 depending on the results of the test.
6690
 */
6691
static int
6692
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6693
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6694
0
    if ((val == NULL) || (arg == NULL) ||
6695
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6696
0
        return(0);
6697
6698
0
    switch(val->type) {
6699
0
        case XPATH_NUMBER:
6700
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6701
0
        case XPATH_NODESET:
6702
0
        case XPATH_XSLT_TREE:
6703
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6704
0
        case XPATH_STRING:
6705
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6706
0
        case XPATH_BOOLEAN:
6707
0
      valuePush(ctxt, arg);
6708
0
      xmlXPathBooleanFunction(ctxt, 1);
6709
0
      valuePush(ctxt, val);
6710
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
6711
0
  default:
6712
0
            xmlGenericError(xmlGenericErrorContext,
6713
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6714
0
                    "and object of type %d\n",
6715
0
                    val->type);
6716
0
            xmlXPathReleaseObject(ctxt->context, arg);
6717
0
            xmlXPathReleaseObject(ctxt->context, val);
6718
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6719
0
    }
6720
0
    return(0);
6721
0
}
6722
6723
/**
6724
 * xmlXPathEqualNodeSetString:
6725
 * @arg:  the nodeset object argument
6726
 * @str:  the string to compare to.
6727
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6728
 *
6729
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6730
 * If one object to be compared is a node-set and the other is a string,
6731
 * then the comparison will be true if and only if there is a node in
6732
 * the node-set such that the result of performing the comparison on the
6733
 * string-value of the node and the other string is true.
6734
 *
6735
 * Returns 0 or 1 depending on the results of the test.
6736
 */
6737
static int
6738
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6739
0
{
6740
0
    int i;
6741
0
    xmlNodeSetPtr ns;
6742
0
    xmlChar *str2;
6743
0
    unsigned int hash;
6744
6745
0
    if ((str == NULL) || (arg == NULL) ||
6746
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6747
0
        return (0);
6748
0
    ns = arg->nodesetval;
6749
    /*
6750
     * A NULL nodeset compared with a string is always false
6751
     * (since there is no node equal, and no node not equal)
6752
     */
6753
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6754
0
        return (0);
6755
0
    hash = xmlXPathStringHash(str);
6756
0
    for (i = 0; i < ns->nodeNr; i++) {
6757
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6758
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6759
0
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6760
0
                xmlFree(str2);
6761
0
    if (neq)
6762
0
        continue;
6763
0
                return (1);
6764
0
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6765
0
    if (neq)
6766
0
        continue;
6767
0
                return (1);
6768
0
            } else if (neq) {
6769
0
    if (str2 != NULL)
6770
0
        xmlFree(str2);
6771
0
    return (1);
6772
0
      }
6773
0
            if (str2 != NULL)
6774
0
                xmlFree(str2);
6775
0
        } else if (neq)
6776
0
      return (1);
6777
0
    }
6778
0
    return (0);
6779
0
}
6780
6781
/**
6782
 * xmlXPathEqualNodeSetFloat:
6783
 * @arg:  the nodeset object argument
6784
 * @f:  the float to compare to
6785
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6786
 *
6787
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6788
 * If one object to be compared is a node-set and the other is a number,
6789
 * then the comparison will be true if and only if there is a node in
6790
 * the node-set such that the result of performing the comparison on the
6791
 * number to be compared and on the result of converting the string-value
6792
 * of that node to a number using the number function is true.
6793
 *
6794
 * Returns 0 or 1 depending on the results of the test.
6795
 */
6796
static int
6797
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6798
0
    xmlXPathObjectPtr arg, double f, int neq) {
6799
0
  int i, ret=0;
6800
0
  xmlNodeSetPtr ns;
6801
0
  xmlChar *str2;
6802
0
  xmlXPathObjectPtr val;
6803
0
  double v;
6804
6805
0
    if ((arg == NULL) ||
6806
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6807
0
        return(0);
6808
6809
0
    ns = arg->nodesetval;
6810
0
    if (ns != NULL) {
6811
0
  for (i=0;i<ns->nodeNr;i++) {
6812
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6813
0
      if (str2 != NULL) {
6814
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6815
0
    xmlFree(str2);
6816
0
    xmlXPathNumberFunction(ctxt, 1);
6817
0
    val = valuePop(ctxt);
6818
0
    v = val->floatval;
6819
0
    xmlXPathReleaseObject(ctxt->context, val);
6820
0
    if (!xmlXPathIsNaN(v)) {
6821
0
        if ((!neq) && (v==f)) {
6822
0
      ret = 1;
6823
0
      break;
6824
0
        } else if ((neq) && (v!=f)) {
6825
0
      ret = 1;
6826
0
      break;
6827
0
        }
6828
0
    } else { /* NaN is unequal to any value */
6829
0
        if (neq)
6830
0
      ret = 1;
6831
0
    }
6832
0
      }
6833
0
  }
6834
0
    }
6835
6836
0
    return(ret);
6837
0
}
6838
6839
6840
/**
6841
 * xmlXPathEqualNodeSets:
6842
 * @arg1:  first nodeset object argument
6843
 * @arg2:  second nodeset object argument
6844
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6845
 *
6846
 * Implement the equal / not equal operation on XPath nodesets:
6847
 * @arg1 == @arg2  or  @arg1 != @arg2
6848
 * If both objects to be compared are node-sets, then the comparison
6849
 * will be true if and only if there is a node in the first node-set and
6850
 * a node in the second node-set such that the result of performing the
6851
 * comparison on the string-values of the two nodes is true.
6852
 *
6853
 * (needless to say, this is a costly operation)
6854
 *
6855
 * Returns 0 or 1 depending on the results of the test.
6856
 */
6857
static int
6858
0
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6859
0
    int i, j;
6860
0
    unsigned int *hashs1;
6861
0
    unsigned int *hashs2;
6862
0
    xmlChar **values1;
6863
0
    xmlChar **values2;
6864
0
    int ret = 0;
6865
0
    xmlNodeSetPtr ns1;
6866
0
    xmlNodeSetPtr ns2;
6867
6868
0
    if ((arg1 == NULL) ||
6869
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6870
0
        return(0);
6871
0
    if ((arg2 == NULL) ||
6872
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6873
0
        return(0);
6874
6875
0
    ns1 = arg1->nodesetval;
6876
0
    ns2 = arg2->nodesetval;
6877
6878
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6879
0
  return(0);
6880
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6881
0
  return(0);
6882
6883
    /*
6884
     * for equal, check if there is a node pertaining to both sets
6885
     */
6886
0
    if (neq == 0)
6887
0
  for (i = 0;i < ns1->nodeNr;i++)
6888
0
      for (j = 0;j < ns2->nodeNr;j++)
6889
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6890
0
        return(1);
6891
6892
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6893
0
    if (values1 == NULL) {
6894
        /* TODO: Propagate memory error. */
6895
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896
0
  return(0);
6897
0
    }
6898
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6899
0
    if (hashs1 == NULL) {
6900
        /* TODO: Propagate memory error. */
6901
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6902
0
  xmlFree(values1);
6903
0
  return(0);
6904
0
    }
6905
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6906
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6907
0
    if (values2 == NULL) {
6908
        /* TODO: Propagate memory error. */
6909
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6910
0
  xmlFree(hashs1);
6911
0
  xmlFree(values1);
6912
0
  return(0);
6913
0
    }
6914
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6915
0
    if (hashs2 == NULL) {
6916
        /* TODO: Propagate memory error. */
6917
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918
0
  xmlFree(hashs1);
6919
0
  xmlFree(values1);
6920
0
  xmlFree(values2);
6921
0
  return(0);
6922
0
    }
6923
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6924
0
    for (i = 0;i < ns1->nodeNr;i++) {
6925
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6926
0
  for (j = 0;j < ns2->nodeNr;j++) {
6927
0
      if (i == 0)
6928
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6929
0
      if (hashs1[i] != hashs2[j]) {
6930
0
    if (neq) {
6931
0
        ret = 1;
6932
0
        break;
6933
0
    }
6934
0
      }
6935
0
      else {
6936
0
    if (values1[i] == NULL)
6937
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6938
0
    if (values2[j] == NULL)
6939
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6940
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6941
0
    if (ret)
6942
0
        break;
6943
0
      }
6944
0
  }
6945
0
  if (ret)
6946
0
      break;
6947
0
    }
6948
0
    for (i = 0;i < ns1->nodeNr;i++)
6949
0
  if (values1[i] != NULL)
6950
0
      xmlFree(values1[i]);
6951
0
    for (j = 0;j < ns2->nodeNr;j++)
6952
0
  if (values2[j] != NULL)
6953
0
      xmlFree(values2[j]);
6954
0
    xmlFree(values1);
6955
0
    xmlFree(values2);
6956
0
    xmlFree(hashs1);
6957
0
    xmlFree(hashs2);
6958
0
    return(ret);
6959
0
}
6960
6961
static int
6962
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6963
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6964
0
    int ret = 0;
6965
    /*
6966
     *At this point we are assured neither arg1 nor arg2
6967
     *is a nodeset, so we can just pick the appropriate routine.
6968
     */
6969
0
    switch (arg1->type) {
6970
0
        case XPATH_UNDEFINED:
6971
#ifdef DEBUG_EXPR
6972
      xmlGenericError(xmlGenericErrorContext,
6973
        "Equal: undefined\n");
6974
#endif
6975
0
      break;
6976
0
        case XPATH_BOOLEAN:
6977
0
      switch (arg2->type) {
6978
0
          case XPATH_UNDEFINED:
6979
#ifdef DEBUG_EXPR
6980
        xmlGenericError(xmlGenericErrorContext,
6981
          "Equal: undefined\n");
6982
#endif
6983
0
        break;
6984
0
    case XPATH_BOOLEAN:
6985
#ifdef DEBUG_EXPR
6986
        xmlGenericError(xmlGenericErrorContext,
6987
          "Equal: %d boolean %d \n",
6988
          arg1->boolval, arg2->boolval);
6989
#endif
6990
0
        ret = (arg1->boolval == arg2->boolval);
6991
0
        break;
6992
0
    case XPATH_NUMBER:
6993
0
        ret = (arg1->boolval ==
6994
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
6995
0
        break;
6996
0
    case XPATH_STRING:
6997
0
        if ((arg2->stringval == NULL) ||
6998
0
      (arg2->stringval[0] == 0)) ret = 0;
6999
0
        else
7000
0
      ret = 1;
7001
0
        ret = (arg1->boolval == ret);
7002
0
        break;
7003
0
    case XPATH_USERS:
7004
#ifdef LIBXML_XPTR_LOCS_ENABLED
7005
    case XPATH_POINT:
7006
    case XPATH_RANGE:
7007
    case XPATH_LOCATIONSET:
7008
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7009
0
        TODO
7010
0
        break;
7011
0
    case XPATH_NODESET:
7012
0
    case XPATH_XSLT_TREE:
7013
0
        break;
7014
0
      }
7015
0
      break;
7016
0
        case XPATH_NUMBER:
7017
0
      switch (arg2->type) {
7018
0
          case XPATH_UNDEFINED:
7019
#ifdef DEBUG_EXPR
7020
        xmlGenericError(xmlGenericErrorContext,
7021
          "Equal: undefined\n");
7022
#endif
7023
0
        break;
7024
0
    case XPATH_BOOLEAN:
7025
0
        ret = (arg2->boolval==
7026
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
7027
0
        break;
7028
0
    case XPATH_STRING:
7029
0
        valuePush(ctxt, arg2);
7030
0
        xmlXPathNumberFunction(ctxt, 1);
7031
0
        arg2 = valuePop(ctxt);
7032
                    /* Falls through. */
7033
0
    case XPATH_NUMBER:
7034
        /* Hand check NaN and Infinity equalities */
7035
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7036
0
          xmlXPathIsNaN(arg2->floatval)) {
7037
0
            ret = 0;
7038
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7039
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
7040
0
          ret = 1;
7041
0
      else
7042
0
          ret = 0;
7043
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7044
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7045
0
          ret = 1;
7046
0
      else
7047
0
          ret = 0;
7048
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7049
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7050
0
          ret = 1;
7051
0
      else
7052
0
          ret = 0;
7053
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7054
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7055
0
          ret = 1;
7056
0
      else
7057
0
          ret = 0;
7058
0
        } else {
7059
0
            ret = (arg1->floatval == arg2->floatval);
7060
0
        }
7061
0
        break;
7062
0
    case XPATH_USERS:
7063
#ifdef LIBXML_XPTR_LOCS_ENABLED
7064
    case XPATH_POINT:
7065
    case XPATH_RANGE:
7066
    case XPATH_LOCATIONSET:
7067
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7068
0
        TODO
7069
0
        break;
7070
0
    case XPATH_NODESET:
7071
0
    case XPATH_XSLT_TREE:
7072
0
        break;
7073
0
      }
7074
0
      break;
7075
0
        case XPATH_STRING:
7076
0
      switch (arg2->type) {
7077
0
          case XPATH_UNDEFINED:
7078
#ifdef DEBUG_EXPR
7079
        xmlGenericError(xmlGenericErrorContext,
7080
          "Equal: undefined\n");
7081
#endif
7082
0
        break;
7083
0
    case XPATH_BOOLEAN:
7084
0
        if ((arg1->stringval == NULL) ||
7085
0
      (arg1->stringval[0] == 0)) ret = 0;
7086
0
        else
7087
0
      ret = 1;
7088
0
        ret = (arg2->boolval == ret);
7089
0
        break;
7090
0
    case XPATH_STRING:
7091
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7092
0
        break;
7093
0
    case XPATH_NUMBER:
7094
0
        valuePush(ctxt, arg1);
7095
0
        xmlXPathNumberFunction(ctxt, 1);
7096
0
        arg1 = valuePop(ctxt);
7097
        /* Hand check NaN and Infinity equalities */
7098
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7099
0
          xmlXPathIsNaN(arg2->floatval)) {
7100
0
            ret = 0;
7101
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7102
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7103
0
          ret = 1;
7104
0
      else
7105
0
          ret = 0;
7106
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7107
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7108
0
          ret = 1;
7109
0
      else
7110
0
          ret = 0;
7111
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7112
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7113
0
          ret = 1;
7114
0
      else
7115
0
          ret = 0;
7116
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7117
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7118
0
          ret = 1;
7119
0
      else
7120
0
          ret = 0;
7121
0
        } else {
7122
0
            ret = (arg1->floatval == arg2->floatval);
7123
0
        }
7124
0
        break;
7125
0
    case XPATH_USERS:
7126
#ifdef LIBXML_XPTR_LOCS_ENABLED
7127
    case XPATH_POINT:
7128
    case XPATH_RANGE:
7129
    case XPATH_LOCATIONSET:
7130
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7131
0
        TODO
7132
0
        break;
7133
0
    case XPATH_NODESET:
7134
0
    case XPATH_XSLT_TREE:
7135
0
        break;
7136
0
      }
7137
0
      break;
7138
0
        case XPATH_USERS:
7139
#ifdef LIBXML_XPTR_LOCS_ENABLED
7140
  case XPATH_POINT:
7141
  case XPATH_RANGE:
7142
  case XPATH_LOCATIONSET:
7143
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7144
0
      TODO
7145
0
      break;
7146
0
  case XPATH_NODESET:
7147
0
  case XPATH_XSLT_TREE:
7148
0
      break;
7149
0
    }
7150
0
    xmlXPathReleaseObject(ctxt->context, arg1);
7151
0
    xmlXPathReleaseObject(ctxt->context, arg2);
7152
0
    return(ret);
7153
0
}
7154
7155
/**
7156
 * xmlXPathEqualValues:
7157
 * @ctxt:  the XPath Parser context
7158
 *
7159
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7160
 *
7161
 * Returns 0 or 1 depending on the results of the test.
7162
 */
7163
int
7164
0
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7165
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
7166
0
    int ret = 0;
7167
7168
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7169
0
    arg2 = valuePop(ctxt);
7170
0
    arg1 = valuePop(ctxt);
7171
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7172
0
  if (arg1 != NULL)
7173
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7174
0
  else
7175
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7176
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7177
0
    }
7178
7179
0
    if (arg1 == arg2) {
7180
#ifdef DEBUG_EXPR
7181
        xmlGenericError(xmlGenericErrorContext,
7182
    "Equal: by pointer\n");
7183
#endif
7184
0
  xmlXPathFreeObject(arg1);
7185
0
        return(1);
7186
0
    }
7187
7188
    /*
7189
     *If either argument is a nodeset, it's a 'special case'
7190
     */
7191
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7192
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7193
  /*
7194
   *Hack it to assure arg1 is the nodeset
7195
   */
7196
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7197
0
    argtmp = arg2;
7198
0
    arg2 = arg1;
7199
0
    arg1 = argtmp;
7200
0
  }
7201
0
  switch (arg2->type) {
7202
0
      case XPATH_UNDEFINED:
7203
#ifdef DEBUG_EXPR
7204
    xmlGenericError(xmlGenericErrorContext,
7205
      "Equal: undefined\n");
7206
#endif
7207
0
    break;
7208
0
      case XPATH_NODESET:
7209
0
      case XPATH_XSLT_TREE:
7210
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7211
0
    break;
7212
0
      case XPATH_BOOLEAN:
7213
0
    if ((arg1->nodesetval == NULL) ||
7214
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7215
0
    else
7216
0
        ret = 1;
7217
0
    ret = (ret == arg2->boolval);
7218
0
    break;
7219
0
      case XPATH_NUMBER:
7220
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7221
0
    break;
7222
0
      case XPATH_STRING:
7223
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7224
0
    break;
7225
0
      case XPATH_USERS:
7226
#ifdef LIBXML_XPTR_LOCS_ENABLED
7227
      case XPATH_POINT:
7228
      case XPATH_RANGE:
7229
      case XPATH_LOCATIONSET:
7230
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7231
0
    TODO
7232
0
    break;
7233
0
  }
7234
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7235
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7236
0
  return(ret);
7237
0
    }
7238
7239
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7240
0
}
7241
7242
/**
7243
 * xmlXPathNotEqualValues:
7244
 * @ctxt:  the XPath Parser context
7245
 *
7246
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7247
 *
7248
 * Returns 0 or 1 depending on the results of the test.
7249
 */
7250
int
7251
0
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7252
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
7253
0
    int ret = 0;
7254
7255
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7256
0
    arg2 = valuePop(ctxt);
7257
0
    arg1 = valuePop(ctxt);
7258
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7259
0
  if (arg1 != NULL)
7260
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7261
0
  else
7262
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7263
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7264
0
    }
7265
7266
0
    if (arg1 == arg2) {
7267
#ifdef DEBUG_EXPR
7268
        xmlGenericError(xmlGenericErrorContext,
7269
    "NotEqual: by pointer\n");
7270
#endif
7271
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7272
0
        return(0);
7273
0
    }
7274
7275
    /*
7276
     *If either argument is a nodeset, it's a 'special case'
7277
     */
7278
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7279
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7280
  /*
7281
   *Hack it to assure arg1 is the nodeset
7282
   */
7283
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7284
0
    argtmp = arg2;
7285
0
    arg2 = arg1;
7286
0
    arg1 = argtmp;
7287
0
  }
7288
0
  switch (arg2->type) {
7289
0
      case XPATH_UNDEFINED:
7290
#ifdef DEBUG_EXPR
7291
    xmlGenericError(xmlGenericErrorContext,
7292
      "NotEqual: undefined\n");
7293
#endif
7294
0
    break;
7295
0
      case XPATH_NODESET:
7296
0
      case XPATH_XSLT_TREE:
7297
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7298
0
    break;
7299
0
      case XPATH_BOOLEAN:
7300
0
    if ((arg1->nodesetval == NULL) ||
7301
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7302
0
    else
7303
0
        ret = 1;
7304
0
    ret = (ret != arg2->boolval);
7305
0
    break;
7306
0
      case XPATH_NUMBER:
7307
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7308
0
    break;
7309
0
      case XPATH_STRING:
7310
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7311
0
    break;
7312
0
      case XPATH_USERS:
7313
#ifdef LIBXML_XPTR_LOCS_ENABLED
7314
      case XPATH_POINT:
7315
      case XPATH_RANGE:
7316
      case XPATH_LOCATIONSET:
7317
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7318
0
    TODO
7319
0
    break;
7320
0
  }
7321
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7322
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7323
0
  return(ret);
7324
0
    }
7325
7326
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7327
0
}
7328
7329
/**
7330
 * xmlXPathCompareValues:
7331
 * @ctxt:  the XPath Parser context
7332
 * @inf:  less than (1) or greater than (0)
7333
 * @strict:  is the comparison strict
7334
 *
7335
 * Implement the compare operation on XPath objects:
7336
 *     @arg1 < @arg2    (1, 1, ...
7337
 *     @arg1 <= @arg2   (1, 0, ...
7338
 *     @arg1 > @arg2    (0, 1, ...
7339
 *     @arg1 >= @arg2   (0, 0, ...
7340
 *
7341
 * When neither object to be compared is a node-set and the operator is
7342
 * <=, <, >=, >, then the objects are compared by converted both objects
7343
 * to numbers and comparing the numbers according to IEEE 754. The <
7344
 * comparison will be true if and only if the first number is less than the
7345
 * second number. The <= comparison will be true if and only if the first
7346
 * number is less than or equal to the second number. The > comparison
7347
 * will be true if and only if the first number is greater than the second
7348
 * number. The >= comparison will be true if and only if the first number
7349
 * is greater than or equal to the second number.
7350
 *
7351
 * Returns 1 if the comparison succeeded, 0 if it failed
7352
 */
7353
int
7354
0
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7355
0
    int ret = 0, arg1i = 0, arg2i = 0;
7356
0
    xmlXPathObjectPtr arg1, arg2;
7357
7358
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7359
0
    arg2 = valuePop(ctxt);
7360
0
    arg1 = valuePop(ctxt);
7361
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7362
0
  if (arg1 != NULL)
7363
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7364
0
  else
7365
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7366
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7367
0
    }
7368
7369
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7370
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7371
  /*
7372
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7373
   * are not freed from within this routine; they will be freed from the
7374
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7375
   */
7376
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7377
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7378
0
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7379
0
  } else {
7380
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7381
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7382
0
                                arg1, arg2);
7383
0
      } else {
7384
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7385
0
                                arg2, arg1);
7386
0
      }
7387
0
  }
7388
0
  return(ret);
7389
0
    }
7390
7391
0
    if (arg1->type != XPATH_NUMBER) {
7392
0
  valuePush(ctxt, arg1);
7393
0
  xmlXPathNumberFunction(ctxt, 1);
7394
0
  arg1 = valuePop(ctxt);
7395
0
    }
7396
0
    if (arg1->type != XPATH_NUMBER) {
7397
0
  xmlXPathFreeObject(arg1);
7398
0
  xmlXPathFreeObject(arg2);
7399
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7400
0
    }
7401
0
    if (arg2->type != XPATH_NUMBER) {
7402
0
  valuePush(ctxt, arg2);
7403
0
  xmlXPathNumberFunction(ctxt, 1);
7404
0
  arg2 = valuePop(ctxt);
7405
0
    }
7406
0
    if (arg2->type != XPATH_NUMBER) {
7407
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7408
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7409
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7410
0
    }
7411
    /*
7412
     * Add tests for infinity and nan
7413
     * => feedback on 3.4 for Inf and NaN
7414
     */
7415
    /* Hand check NaN and Infinity comparisons */
7416
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7417
0
  ret=0;
7418
0
    } else {
7419
0
  arg1i=xmlXPathIsInf(arg1->floatval);
7420
0
  arg2i=xmlXPathIsInf(arg2->floatval);
7421
0
  if (inf && strict) {
7422
0
      if ((arg1i == -1 && arg2i != -1) ||
7423
0
    (arg2i == 1 && arg1i != 1)) {
7424
0
    ret = 1;
7425
0
      } else if (arg1i == 0 && arg2i == 0) {
7426
0
    ret = (arg1->floatval < arg2->floatval);
7427
0
      } else {
7428
0
    ret = 0;
7429
0
      }
7430
0
  }
7431
0
  else if (inf && !strict) {
7432
0
      if (arg1i == -1 || arg2i == 1) {
7433
0
    ret = 1;
7434
0
      } else if (arg1i == 0 && arg2i == 0) {
7435
0
    ret = (arg1->floatval <= arg2->floatval);
7436
0
      } else {
7437
0
    ret = 0;
7438
0
      }
7439
0
  }
7440
0
  else if (!inf && strict) {
7441
0
      if ((arg1i == 1 && arg2i != 1) ||
7442
0
    (arg2i == -1 && arg1i != -1)) {
7443
0
    ret = 1;
7444
0
      } else if (arg1i == 0 && arg2i == 0) {
7445
0
    ret = (arg1->floatval > arg2->floatval);
7446
0
      } else {
7447
0
    ret = 0;
7448
0
      }
7449
0
  }
7450
0
  else if (!inf && !strict) {
7451
0
      if (arg1i == 1 || arg2i == -1) {
7452
0
    ret = 1;
7453
0
      } else if (arg1i == 0 && arg2i == 0) {
7454
0
    ret = (arg1->floatval >= arg2->floatval);
7455
0
      } else {
7456
0
    ret = 0;
7457
0
      }
7458
0
  }
7459
0
    }
7460
0
    xmlXPathReleaseObject(ctxt->context, arg1);
7461
0
    xmlXPathReleaseObject(ctxt->context, arg2);
7462
0
    return(ret);
7463
0
}
7464
7465
/**
7466
 * xmlXPathValueFlipSign:
7467
 * @ctxt:  the XPath Parser context
7468
 *
7469
 * Implement the unary - operation on an XPath object
7470
 * The numeric operators convert their operands to numbers as if
7471
 * by calling the number function.
7472
 */
7473
void
7474
0
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7475
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7476
0
    CAST_TO_NUMBER;
7477
0
    CHECK_TYPE(XPATH_NUMBER);
7478
0
    ctxt->value->floatval = -ctxt->value->floatval;
7479
0
}
7480
7481
/**
7482
 * xmlXPathAddValues:
7483
 * @ctxt:  the XPath Parser context
7484
 *
7485
 * Implement the add operation on XPath objects:
7486
 * The numeric operators convert their operands to numbers as if
7487
 * by calling the number function.
7488
 */
7489
void
7490
0
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7491
0
    xmlXPathObjectPtr arg;
7492
0
    double val;
7493
7494
0
    arg = valuePop(ctxt);
7495
0
    if (arg == NULL)
7496
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7497
0
    val = xmlXPathCastToNumber(arg);
7498
0
    xmlXPathReleaseObject(ctxt->context, arg);
7499
0
    CAST_TO_NUMBER;
7500
0
    CHECK_TYPE(XPATH_NUMBER);
7501
0
    ctxt->value->floatval += val;
7502
0
}
7503
7504
/**
7505
 * xmlXPathSubValues:
7506
 * @ctxt:  the XPath Parser context
7507
 *
7508
 * Implement the subtraction operation on XPath objects:
7509
 * The numeric operators convert their operands to numbers as if
7510
 * by calling the number function.
7511
 */
7512
void
7513
0
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7514
0
    xmlXPathObjectPtr arg;
7515
0
    double val;
7516
7517
0
    arg = valuePop(ctxt);
7518
0
    if (arg == NULL)
7519
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7520
0
    val = xmlXPathCastToNumber(arg);
7521
0
    xmlXPathReleaseObject(ctxt->context, arg);
7522
0
    CAST_TO_NUMBER;
7523
0
    CHECK_TYPE(XPATH_NUMBER);
7524
0
    ctxt->value->floatval -= val;
7525
0
}
7526
7527
/**
7528
 * xmlXPathMultValues:
7529
 * @ctxt:  the XPath Parser context
7530
 *
7531
 * Implement the multiply operation on XPath objects:
7532
 * The numeric operators convert their operands to numbers as if
7533
 * by calling the number function.
7534
 */
7535
void
7536
0
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7537
0
    xmlXPathObjectPtr arg;
7538
0
    double val;
7539
7540
0
    arg = valuePop(ctxt);
7541
0
    if (arg == NULL)
7542
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7543
0
    val = xmlXPathCastToNumber(arg);
7544
0
    xmlXPathReleaseObject(ctxt->context, arg);
7545
0
    CAST_TO_NUMBER;
7546
0
    CHECK_TYPE(XPATH_NUMBER);
7547
0
    ctxt->value->floatval *= val;
7548
0
}
7549
7550
/**
7551
 * xmlXPathDivValues:
7552
 * @ctxt:  the XPath Parser context
7553
 *
7554
 * Implement the div operation on XPath objects @arg1 / @arg2:
7555
 * The numeric operators convert their operands to numbers as if
7556
 * by calling the number function.
7557
 */
7558
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7559
void
7560
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7561
0
    xmlXPathObjectPtr arg;
7562
0
    double val;
7563
7564
0
    arg = valuePop(ctxt);
7565
0
    if (arg == NULL)
7566
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7567
0
    val = xmlXPathCastToNumber(arg);
7568
0
    xmlXPathReleaseObject(ctxt->context, arg);
7569
0
    CAST_TO_NUMBER;
7570
0
    CHECK_TYPE(XPATH_NUMBER);
7571
0
    ctxt->value->floatval /= val;
7572
0
}
7573
7574
/**
7575
 * xmlXPathModValues:
7576
 * @ctxt:  the XPath Parser context
7577
 *
7578
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7579
 * The numeric operators convert their operands to numbers as if
7580
 * by calling the number function.
7581
 */
7582
void
7583
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7584
0
    xmlXPathObjectPtr arg;
7585
0
    double arg1, arg2;
7586
7587
0
    arg = valuePop(ctxt);
7588
0
    if (arg == NULL)
7589
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7590
0
    arg2 = xmlXPathCastToNumber(arg);
7591
0
    xmlXPathReleaseObject(ctxt->context, arg);
7592
0
    CAST_TO_NUMBER;
7593
0
    CHECK_TYPE(XPATH_NUMBER);
7594
0
    arg1 = ctxt->value->floatval;
7595
0
    if (arg2 == 0)
7596
0
  ctxt->value->floatval = xmlXPathNAN;
7597
0
    else {
7598
0
  ctxt->value->floatval = fmod(arg1, arg2);
7599
0
    }
7600
0
}
7601
7602
/************************************************************************
7603
 *                  *
7604
 *    The traversal functions         *
7605
 *                  *
7606
 ************************************************************************/
7607
7608
/*
7609
 * A traversal function enumerates nodes along an axis.
7610
 * Initially it must be called with NULL, and it indicates
7611
 * termination on the axis by returning NULL.
7612
 */
7613
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7614
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7615
7616
/*
7617
 * xmlXPathTraversalFunctionExt:
7618
 * A traversal function enumerates nodes along an axis.
7619
 * Initially it must be called with NULL, and it indicates
7620
 * termination on the axis by returning NULL.
7621
 * The context node of the traversal is specified via @contextNode.
7622
 */
7623
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7624
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7625
7626
/*
7627
 * xmlXPathNodeSetMergeFunction:
7628
 * Used for merging node sets in xmlXPathCollectAndTest().
7629
 */
7630
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7631
        (xmlNodeSetPtr, xmlNodeSetPtr);
7632
7633
7634
/**
7635
 * xmlXPathNextSelf:
7636
 * @ctxt:  the XPath Parser context
7637
 * @cur:  the current node in the traversal
7638
 *
7639
 * Traversal function for the "self" direction
7640
 * The self axis contains just the context node itself
7641
 *
7642
 * Returns the next element following that axis
7643
 */
7644
xmlNodePtr
7645
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7646
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7647
0
    if (cur == NULL)
7648
0
        return(ctxt->context->node);
7649
0
    return(NULL);
7650
0
}
7651
7652
/**
7653
 * xmlXPathNextChild:
7654
 * @ctxt:  the XPath Parser context
7655
 * @cur:  the current node in the traversal
7656
 *
7657
 * Traversal function for the "child" direction
7658
 * The child axis contains the children of the context node in document order.
7659
 *
7660
 * Returns the next element following that axis
7661
 */
7662
xmlNodePtr
7663
0
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7664
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7665
0
    if (cur == NULL) {
7666
0
  if (ctxt->context->node == NULL) return(NULL);
7667
0
  switch (ctxt->context->node->type) {
7668
0
            case XML_ELEMENT_NODE:
7669
0
            case XML_TEXT_NODE:
7670
0
            case XML_CDATA_SECTION_NODE:
7671
0
            case XML_ENTITY_REF_NODE:
7672
0
            case XML_ENTITY_NODE:
7673
0
            case XML_PI_NODE:
7674
0
            case XML_COMMENT_NODE:
7675
0
            case XML_NOTATION_NODE:
7676
0
            case XML_DTD_NODE:
7677
0
    return(ctxt->context->node->children);
7678
0
            case XML_DOCUMENT_NODE:
7679
0
            case XML_DOCUMENT_TYPE_NODE:
7680
0
            case XML_DOCUMENT_FRAG_NODE:
7681
0
            case XML_HTML_DOCUMENT_NODE:
7682
0
    return(((xmlDocPtr) ctxt->context->node)->children);
7683
0
      case XML_ELEMENT_DECL:
7684
0
      case XML_ATTRIBUTE_DECL:
7685
0
      case XML_ENTITY_DECL:
7686
0
            case XML_ATTRIBUTE_NODE:
7687
0
      case XML_NAMESPACE_DECL:
7688
0
      case XML_XINCLUDE_START:
7689
0
      case XML_XINCLUDE_END:
7690
0
    return(NULL);
7691
0
  }
7692
0
  return(NULL);
7693
0
    }
7694
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
7695
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
7696
0
  return(NULL);
7697
0
    return(cur->next);
7698
0
}
7699
7700
/**
7701
 * xmlXPathNextChildElement:
7702
 * @ctxt:  the XPath Parser context
7703
 * @cur:  the current node in the traversal
7704
 *
7705
 * Traversal function for the "child" direction and nodes of type element.
7706
 * The child axis contains the children of the context node in document order.
7707
 *
7708
 * Returns the next element following that axis
7709
 */
7710
static xmlNodePtr
7711
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7712
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713
0
    if (cur == NULL) {
7714
0
  cur = ctxt->context->node;
7715
0
  if (cur == NULL) return(NULL);
7716
  /*
7717
  * Get the first element child.
7718
  */
7719
0
  switch (cur->type) {
7720
0
            case XML_ELEMENT_NODE:
7721
0
      case XML_DOCUMENT_FRAG_NODE:
7722
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7723
0
            case XML_ENTITY_NODE:
7724
0
    cur = cur->children;
7725
0
    if (cur != NULL) {
7726
0
        if (cur->type == XML_ELEMENT_NODE)
7727
0
      return(cur);
7728
0
        do {
7729
0
      cur = cur->next;
7730
0
        } while ((cur != NULL) &&
7731
0
      (cur->type != XML_ELEMENT_NODE));
7732
0
        return(cur);
7733
0
    }
7734
0
    return(NULL);
7735
0
            case XML_DOCUMENT_NODE:
7736
0
            case XML_HTML_DOCUMENT_NODE:
7737
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7738
0
      default:
7739
0
    return(NULL);
7740
0
  }
7741
0
  return(NULL);
7742
0
    }
7743
    /*
7744
    * Get the next sibling element node.
7745
    */
7746
0
    switch (cur->type) {
7747
0
  case XML_ELEMENT_NODE:
7748
0
  case XML_TEXT_NODE:
7749
0
  case XML_ENTITY_REF_NODE:
7750
0
  case XML_ENTITY_NODE:
7751
0
  case XML_CDATA_SECTION_NODE:
7752
0
  case XML_PI_NODE:
7753
0
  case XML_COMMENT_NODE:
7754
0
  case XML_XINCLUDE_END:
7755
0
      break;
7756
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7757
0
  default:
7758
0
      return(NULL);
7759
0
    }
7760
0
    if (cur->next != NULL) {
7761
0
  if (cur->next->type == XML_ELEMENT_NODE)
7762
0
      return(cur->next);
7763
0
  cur = cur->next;
7764
0
  do {
7765
0
      cur = cur->next;
7766
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7767
0
  return(cur);
7768
0
    }
7769
0
    return(NULL);
7770
0
}
7771
7772
#if 0
7773
/**
7774
 * xmlXPathNextDescendantOrSelfElemParent:
7775
 * @ctxt:  the XPath Parser context
7776
 * @cur:  the current node in the traversal
7777
 *
7778
 * Traversal function for the "descendant-or-self" axis.
7779
 * Additionally it returns only nodes which can be parents of
7780
 * element nodes.
7781
 *
7782
 *
7783
 * Returns the next element following that axis
7784
 */
7785
static xmlNodePtr
7786
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7787
               xmlNodePtr contextNode)
7788
{
7789
    if (cur == NULL) {
7790
  if (contextNode == NULL)
7791
      return(NULL);
7792
  switch (contextNode->type) {
7793
      case XML_ELEMENT_NODE:
7794
      case XML_XINCLUDE_START:
7795
      case XML_DOCUMENT_FRAG_NODE:
7796
      case XML_DOCUMENT_NODE:
7797
      case XML_HTML_DOCUMENT_NODE:
7798
    return(contextNode);
7799
      default:
7800
    return(NULL);
7801
  }
7802
  return(NULL);
7803
    } else {
7804
  xmlNodePtr start = cur;
7805
7806
  while (cur != NULL) {
7807
      switch (cur->type) {
7808
    case XML_ELEMENT_NODE:
7809
    /* TODO: OK to have XInclude here? */
7810
    case XML_XINCLUDE_START:
7811
    case XML_DOCUMENT_FRAG_NODE:
7812
        if (cur != start)
7813
      return(cur);
7814
        if (cur->children != NULL) {
7815
      cur = cur->children;
7816
      continue;
7817
        }
7818
        break;
7819
    /* Not sure if we need those here. */
7820
    case XML_DOCUMENT_NODE:
7821
    case XML_HTML_DOCUMENT_NODE:
7822
        if (cur != start)
7823
      return(cur);
7824
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7825
    default:
7826
        break;
7827
      }
7828
7829
next_sibling:
7830
      if ((cur == NULL) || (cur == contextNode))
7831
    return(NULL);
7832
      if (cur->next != NULL) {
7833
    cur = cur->next;
7834
      } else {
7835
    cur = cur->parent;
7836
    goto next_sibling;
7837
      }
7838
  }
7839
    }
7840
    return(NULL);
7841
}
7842
#endif
7843
7844
/**
7845
 * xmlXPathNextDescendant:
7846
 * @ctxt:  the XPath Parser context
7847
 * @cur:  the current node in the traversal
7848
 *
7849
 * Traversal function for the "descendant" direction
7850
 * the descendant axis contains the descendants of the context node in document
7851
 * order; a descendant is a child or a child of a child and so on.
7852
 *
7853
 * Returns the next element following that axis
7854
 */
7855
xmlNodePtr
7856
0
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7857
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7858
0
    if (cur == NULL) {
7859
0
  if (ctxt->context->node == NULL)
7860
0
      return(NULL);
7861
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7862
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7863
0
      return(NULL);
7864
7865
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7866
0
      return(ctxt->context->doc->children);
7867
0
        return(ctxt->context->node->children);
7868
0
    }
7869
7870
0
    if (cur->type == XML_NAMESPACE_DECL)
7871
0
        return(NULL);
7872
0
    if (cur->children != NULL) {
7873
  /*
7874
   * Do not descend on entities declarations
7875
   */
7876
0
  if (cur->children->type != XML_ENTITY_DECL) {
7877
0
      cur = cur->children;
7878
      /*
7879
       * Skip DTDs
7880
       */
7881
0
      if (cur->type != XML_DTD_NODE)
7882
0
    return(cur);
7883
0
  }
7884
0
    }
7885
7886
0
    if (cur == ctxt->context->node) return(NULL);
7887
7888
0
    while (cur->next != NULL) {
7889
0
  cur = cur->next;
7890
0
  if ((cur->type != XML_ENTITY_DECL) &&
7891
0
      (cur->type != XML_DTD_NODE))
7892
0
      return(cur);
7893
0
    }
7894
7895
0
    do {
7896
0
        cur = cur->parent;
7897
0
  if (cur == NULL) break;
7898
0
  if (cur == ctxt->context->node) return(NULL);
7899
0
  if (cur->next != NULL) {
7900
0
      cur = cur->next;
7901
0
      return(cur);
7902
0
  }
7903
0
    } while (cur != NULL);
7904
0
    return(cur);
7905
0
}
7906
7907
/**
7908
 * xmlXPathNextDescendantOrSelf:
7909
 * @ctxt:  the XPath Parser context
7910
 * @cur:  the current node in the traversal
7911
 *
7912
 * Traversal function for the "descendant-or-self" direction
7913
 * the descendant-or-self axis contains the context node and the descendants
7914
 * of the context node in document order; thus the context node is the first
7915
 * node on the axis, and the first child of the context node is the second node
7916
 * on the axis
7917
 *
7918
 * Returns the next element following that axis
7919
 */
7920
xmlNodePtr
7921
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7922
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7923
0
    if (cur == NULL)
7924
0
        return(ctxt->context->node);
7925
7926
0
    if (ctxt->context->node == NULL)
7927
0
        return(NULL);
7928
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7929
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7930
0
        return(NULL);
7931
7932
0
    return(xmlXPathNextDescendant(ctxt, cur));
7933
0
}
7934
7935
/**
7936
 * xmlXPathNextParent:
7937
 * @ctxt:  the XPath Parser context
7938
 * @cur:  the current node in the traversal
7939
 *
7940
 * Traversal function for the "parent" direction
7941
 * The parent axis contains the parent of the context node, if there is one.
7942
 *
7943
 * Returns the next element following that axis
7944
 */
7945
xmlNodePtr
7946
0
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7947
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7948
    /*
7949
     * the parent of an attribute or namespace node is the element
7950
     * to which the attribute or namespace node is attached
7951
     * Namespace handling !!!
7952
     */
7953
0
    if (cur == NULL) {
7954
0
  if (ctxt->context->node == NULL) return(NULL);
7955
0
  switch (ctxt->context->node->type) {
7956
0
            case XML_ELEMENT_NODE:
7957
0
            case XML_TEXT_NODE:
7958
0
            case XML_CDATA_SECTION_NODE:
7959
0
            case XML_ENTITY_REF_NODE:
7960
0
            case XML_ENTITY_NODE:
7961
0
            case XML_PI_NODE:
7962
0
            case XML_COMMENT_NODE:
7963
0
            case XML_NOTATION_NODE:
7964
0
            case XML_DTD_NODE:
7965
0
      case XML_ELEMENT_DECL:
7966
0
      case XML_ATTRIBUTE_DECL:
7967
0
      case XML_XINCLUDE_START:
7968
0
      case XML_XINCLUDE_END:
7969
0
      case XML_ENTITY_DECL:
7970
0
    if (ctxt->context->node->parent == NULL)
7971
0
        return((xmlNodePtr) ctxt->context->doc);
7972
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7973
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
7974
0
         (xmlStrEqual(ctxt->context->node->parent->name,
7975
0
         BAD_CAST "fake node libxslt"))))
7976
0
        return(NULL);
7977
0
    return(ctxt->context->node->parent);
7978
0
            case XML_ATTRIBUTE_NODE: {
7979
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7980
7981
0
    return(att->parent);
7982
0
      }
7983
0
            case XML_DOCUMENT_NODE:
7984
0
            case XML_DOCUMENT_TYPE_NODE:
7985
0
            case XML_DOCUMENT_FRAG_NODE:
7986
0
            case XML_HTML_DOCUMENT_NODE:
7987
0
                return(NULL);
7988
0
      case XML_NAMESPACE_DECL: {
7989
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7990
7991
0
    if ((ns->next != NULL) &&
7992
0
        (ns->next->type != XML_NAMESPACE_DECL))
7993
0
        return((xmlNodePtr) ns->next);
7994
0
                return(NULL);
7995
0
      }
7996
0
  }
7997
0
    }
7998
0
    return(NULL);
7999
0
}
8000
8001
/**
8002
 * xmlXPathNextAncestor:
8003
 * @ctxt:  the XPath Parser context
8004
 * @cur:  the current node in the traversal
8005
 *
8006
 * Traversal function for the "ancestor" direction
8007
 * the ancestor axis contains the ancestors of the context node; the ancestors
8008
 * of the context node consist of the parent of context node and the parent's
8009
 * parent and so on; the nodes are ordered in reverse document order; thus the
8010
 * parent is the first node on the axis, and the parent's parent is the second
8011
 * node on the axis
8012
 *
8013
 * Returns the next element following that axis
8014
 */
8015
xmlNodePtr
8016
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8017
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8018
    /*
8019
     * the parent of an attribute or namespace node is the element
8020
     * to which the attribute or namespace node is attached
8021
     * !!!!!!!!!!!!!
8022
     */
8023
0
    if (cur == NULL) {
8024
0
  if (ctxt->context->node == NULL) return(NULL);
8025
0
  switch (ctxt->context->node->type) {
8026
0
            case XML_ELEMENT_NODE:
8027
0
            case XML_TEXT_NODE:
8028
0
            case XML_CDATA_SECTION_NODE:
8029
0
            case XML_ENTITY_REF_NODE:
8030
0
            case XML_ENTITY_NODE:
8031
0
            case XML_PI_NODE:
8032
0
            case XML_COMMENT_NODE:
8033
0
      case XML_DTD_NODE:
8034
0
      case XML_ELEMENT_DECL:
8035
0
      case XML_ATTRIBUTE_DECL:
8036
0
      case XML_ENTITY_DECL:
8037
0
            case XML_NOTATION_NODE:
8038
0
      case XML_XINCLUDE_START:
8039
0
      case XML_XINCLUDE_END:
8040
0
    if (ctxt->context->node->parent == NULL)
8041
0
        return((xmlNodePtr) ctxt->context->doc);
8042
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8043
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
8044
0
         (xmlStrEqual(ctxt->context->node->parent->name,
8045
0
         BAD_CAST "fake node libxslt"))))
8046
0
        return(NULL);
8047
0
    return(ctxt->context->node->parent);
8048
0
            case XML_ATTRIBUTE_NODE: {
8049
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8050
8051
0
    return(tmp->parent);
8052
0
      }
8053
0
            case XML_DOCUMENT_NODE:
8054
0
            case XML_DOCUMENT_TYPE_NODE:
8055
0
            case XML_DOCUMENT_FRAG_NODE:
8056
0
            case XML_HTML_DOCUMENT_NODE:
8057
0
                return(NULL);
8058
0
      case XML_NAMESPACE_DECL: {
8059
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8060
8061
0
    if ((ns->next != NULL) &&
8062
0
        (ns->next->type != XML_NAMESPACE_DECL))
8063
0
        return((xmlNodePtr) ns->next);
8064
    /* Bad, how did that namespace end up here ? */
8065
0
                return(NULL);
8066
0
      }
8067
0
  }
8068
0
  return(NULL);
8069
0
    }
8070
0
    if (cur == ctxt->context->doc->children)
8071
0
  return((xmlNodePtr) ctxt->context->doc);
8072
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8073
0
  return(NULL);
8074
0
    switch (cur->type) {
8075
0
  case XML_ELEMENT_NODE:
8076
0
  case XML_TEXT_NODE:
8077
0
  case XML_CDATA_SECTION_NODE:
8078
0
  case XML_ENTITY_REF_NODE:
8079
0
  case XML_ENTITY_NODE:
8080
0
  case XML_PI_NODE:
8081
0
  case XML_COMMENT_NODE:
8082
0
  case XML_NOTATION_NODE:
8083
0
  case XML_DTD_NODE:
8084
0
        case XML_ELEMENT_DECL:
8085
0
        case XML_ATTRIBUTE_DECL:
8086
0
        case XML_ENTITY_DECL:
8087
0
  case XML_XINCLUDE_START:
8088
0
  case XML_XINCLUDE_END:
8089
0
      if (cur->parent == NULL)
8090
0
    return(NULL);
8091
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8092
0
    ((cur->parent->name[0] == ' ') ||
8093
0
     (xmlStrEqual(cur->parent->name,
8094
0
            BAD_CAST "fake node libxslt"))))
8095
0
    return(NULL);
8096
0
      return(cur->parent);
8097
0
  case XML_ATTRIBUTE_NODE: {
8098
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8099
8100
0
      return(att->parent);
8101
0
  }
8102
0
  case XML_NAMESPACE_DECL: {
8103
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8104
8105
0
      if ((ns->next != NULL) &&
8106
0
          (ns->next->type != XML_NAMESPACE_DECL))
8107
0
          return((xmlNodePtr) ns->next);
8108
      /* Bad, how did that namespace end up here ? */
8109
0
            return(NULL);
8110
0
  }
8111
0
  case XML_DOCUMENT_NODE:
8112
0
  case XML_DOCUMENT_TYPE_NODE:
8113
0
  case XML_DOCUMENT_FRAG_NODE:
8114
0
  case XML_HTML_DOCUMENT_NODE:
8115
0
      return(NULL);
8116
0
    }
8117
0
    return(NULL);
8118
0
}
8119
8120
/**
8121
 * xmlXPathNextAncestorOrSelf:
8122
 * @ctxt:  the XPath Parser context
8123
 * @cur:  the current node in the traversal
8124
 *
8125
 * Traversal function for the "ancestor-or-self" direction
8126
 * he ancestor-or-self axis contains the context node and ancestors of
8127
 * the context node in reverse document order; thus the context node is
8128
 * the first node on the axis, and the context node's parent the second;
8129
 * parent here is defined the same as with the parent axis.
8130
 *
8131
 * Returns the next element following that axis
8132
 */
8133
xmlNodePtr
8134
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8135
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8136
0
    if (cur == NULL)
8137
0
        return(ctxt->context->node);
8138
0
    return(xmlXPathNextAncestor(ctxt, cur));
8139
0
}
8140
8141
/**
8142
 * xmlXPathNextFollowingSibling:
8143
 * @ctxt:  the XPath Parser context
8144
 * @cur:  the current node in the traversal
8145
 *
8146
 * Traversal function for the "following-sibling" direction
8147
 * The following-sibling axis contains the following siblings of the context
8148
 * node in document order.
8149
 *
8150
 * Returns the next element following that axis
8151
 */
8152
xmlNodePtr
8153
0
xmlXPathNextFollowingSibling(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->next);
8162
0
    return(cur->next);
8163
0
}
8164
8165
/**
8166
 * xmlXPathNextPrecedingSibling:
8167
 * @ctxt:  the XPath Parser context
8168
 * @cur:  the current node in the traversal
8169
 *
8170
 * Traversal function for the "preceding-sibling" direction
8171
 * The preceding-sibling axis contains the preceding siblings of the context
8172
 * node in reverse document order; the first preceding sibling is first on the
8173
 * axis; the sibling preceding that node is the second on the axis and so on.
8174
 *
8175
 * Returns the next element following that axis
8176
 */
8177
xmlNodePtr
8178
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8179
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8180
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8181
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8182
0
  return(NULL);
8183
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8184
0
        return(NULL);
8185
0
    if (cur == NULL)
8186
0
        return(ctxt->context->node->prev);
8187
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8188
0
  cur = cur->prev;
8189
0
  if (cur == NULL)
8190
0
      return(ctxt->context->node->prev);
8191
0
    }
8192
0
    return(cur->prev);
8193
0
}
8194
8195
/**
8196
 * xmlXPathNextFollowing:
8197
 * @ctxt:  the XPath Parser context
8198
 * @cur:  the current node in the traversal
8199
 *
8200
 * Traversal function for the "following" direction
8201
 * The following axis contains all nodes in the same document as the context
8202
 * node that are after the context node in document order, excluding any
8203
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8204
 * are ordered in document order
8205
 *
8206
 * Returns the next element following that axis
8207
 */
8208
xmlNodePtr
8209
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8210
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8211
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8212
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8213
0
        return(cur->children);
8214
8215
0
    if (cur == NULL) {
8216
0
        cur = ctxt->context->node;
8217
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8218
0
            cur = cur->parent;
8219
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8220
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8221
8222
0
            if ((ns->next == NULL) ||
8223
0
                (ns->next->type == XML_NAMESPACE_DECL))
8224
0
                return (NULL);
8225
0
            cur = (xmlNodePtr) ns->next;
8226
0
        }
8227
0
    }
8228
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8229
0
    if (cur->next != NULL) return(cur->next) ;
8230
0
    do {
8231
0
        cur = cur->parent;
8232
0
        if (cur == NULL) break;
8233
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8234
0
        if (cur->next != NULL) return(cur->next);
8235
0
    } while (cur != NULL);
8236
0
    return(cur);
8237
0
}
8238
8239
/*
8240
 * xmlXPathIsAncestor:
8241
 * @ancestor:  the ancestor node
8242
 * @node:  the current node
8243
 *
8244
 * Check that @ancestor is a @node's ancestor
8245
 *
8246
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8247
 */
8248
static int
8249
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8250
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8251
0
    if (node->type == XML_NAMESPACE_DECL)
8252
0
        return(0);
8253
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8254
0
        return(0);
8255
    /* nodes need to be in the same document */
8256
0
    if (ancestor->doc != node->doc) return(0);
8257
    /* avoid searching if ancestor or node is the root node */
8258
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8259
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8260
0
    while (node->parent != NULL) {
8261
0
        if (node->parent == ancestor)
8262
0
            return(1);
8263
0
  node = node->parent;
8264
0
    }
8265
0
    return(0);
8266
0
}
8267
8268
/**
8269
 * xmlXPathNextPreceding:
8270
 * @ctxt:  the XPath Parser context
8271
 * @cur:  the current node in the traversal
8272
 *
8273
 * Traversal function for the "preceding" direction
8274
 * the preceding axis contains all nodes in the same document as the context
8275
 * node that are before the context node in document order, excluding any
8276
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8277
 * ordered in reverse document order
8278
 *
8279
 * Returns the next element following that axis
8280
 */
8281
xmlNodePtr
8282
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8283
0
{
8284
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8285
0
    if (cur == NULL) {
8286
0
        cur = ctxt->context->node;
8287
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8288
0
            cur = cur->parent;
8289
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8290
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8291
8292
0
            if ((ns->next == NULL) ||
8293
0
                (ns->next->type == XML_NAMESPACE_DECL))
8294
0
                return (NULL);
8295
0
            cur = (xmlNodePtr) ns->next;
8296
0
        }
8297
0
    }
8298
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8299
0
  return (NULL);
8300
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8301
0
  cur = cur->prev;
8302
0
    do {
8303
0
        if (cur->prev != NULL) {
8304
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8305
0
            return (cur);
8306
0
        }
8307
8308
0
        cur = cur->parent;
8309
0
        if (cur == NULL)
8310
0
            return (NULL);
8311
0
        if (cur == ctxt->context->doc->children)
8312
0
            return (NULL);
8313
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8314
0
    return (cur);
8315
0
}
8316
8317
/**
8318
 * xmlXPathNextPrecedingInternal:
8319
 * @ctxt:  the XPath Parser context
8320
 * @cur:  the current node in the traversal
8321
 *
8322
 * Traversal function for the "preceding" direction
8323
 * the preceding axis contains all nodes in the same document as the context
8324
 * node that are before the context node in document order, excluding any
8325
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8326
 * ordered in reverse document order
8327
 * This is a faster implementation but internal only since it requires a
8328
 * state kept in the parser context: ctxt->ancestor.
8329
 *
8330
 * Returns the next element following that axis
8331
 */
8332
static xmlNodePtr
8333
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8334
                              xmlNodePtr cur)
8335
0
{
8336
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8337
0
    if (cur == NULL) {
8338
0
        cur = ctxt->context->node;
8339
0
        if (cur == NULL)
8340
0
            return (NULL);
8341
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8342
0
            cur = cur->parent;
8343
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8344
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8345
8346
0
            if ((ns->next == NULL) ||
8347
0
                (ns->next->type == XML_NAMESPACE_DECL))
8348
0
                return (NULL);
8349
0
            cur = (xmlNodePtr) ns->next;
8350
0
        }
8351
0
        ctxt->ancestor = cur->parent;
8352
0
    }
8353
0
    if (cur->type == XML_NAMESPACE_DECL)
8354
0
        return(NULL);
8355
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8356
0
  cur = cur->prev;
8357
0
    while (cur->prev == NULL) {
8358
0
        cur = cur->parent;
8359
0
        if (cur == NULL)
8360
0
            return (NULL);
8361
0
        if (cur == ctxt->context->doc->children)
8362
0
            return (NULL);
8363
0
        if (cur != ctxt->ancestor)
8364
0
            return (cur);
8365
0
        ctxt->ancestor = cur->parent;
8366
0
    }
8367
0
    cur = cur->prev;
8368
0
    while (cur->last != NULL)
8369
0
        cur = cur->last;
8370
0
    return (cur);
8371
0
}
8372
8373
/**
8374
 * xmlXPathNextNamespace:
8375
 * @ctxt:  the XPath Parser context
8376
 * @cur:  the current attribute in the traversal
8377
 *
8378
 * Traversal function for the "namespace" direction
8379
 * the namespace axis contains the namespace nodes of the context node;
8380
 * the order of nodes on this axis is implementation-defined; the axis will
8381
 * be empty unless the context node is an element
8382
 *
8383
 * We keep the XML namespace node at the end of the list.
8384
 *
8385
 * Returns the next element following that axis
8386
 */
8387
xmlNodePtr
8388
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8389
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8390
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8391
0
    if (cur == NULL) {
8392
0
        if (ctxt->context->tmpNsList != NULL)
8393
0
      xmlFree(ctxt->context->tmpNsList);
8394
0
  ctxt->context->tmpNsList =
8395
0
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8396
0
  ctxt->context->tmpNsNr = 0;
8397
0
  if (ctxt->context->tmpNsList != NULL) {
8398
0
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8399
0
    ctxt->context->tmpNsNr++;
8400
0
      }
8401
0
  }
8402
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
8403
0
    }
8404
0
    if (ctxt->context->tmpNsNr > 0) {
8405
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8406
0
    } else {
8407
0
  if (ctxt->context->tmpNsList != NULL)
8408
0
      xmlFree(ctxt->context->tmpNsList);
8409
0
  ctxt->context->tmpNsList = NULL;
8410
0
  return(NULL);
8411
0
    }
8412
0
}
8413
8414
/**
8415
 * xmlXPathNextAttribute:
8416
 * @ctxt:  the XPath Parser context
8417
 * @cur:  the current attribute in the traversal
8418
 *
8419
 * Traversal function for the "attribute" direction
8420
 * TODO: support DTD inherited default attributes
8421
 *
8422
 * Returns the next element following that axis
8423
 */
8424
xmlNodePtr
8425
0
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8426
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8427
0
    if (ctxt->context->node == NULL)
8428
0
  return(NULL);
8429
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8430
0
  return(NULL);
8431
0
    if (cur == NULL) {
8432
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8433
0
      return(NULL);
8434
0
        return((xmlNodePtr)ctxt->context->node->properties);
8435
0
    }
8436
0
    return((xmlNodePtr)cur->next);
8437
0
}
8438
8439
/************************************************************************
8440
 *                  *
8441
 *    NodeTest Functions          *
8442
 *                  *
8443
 ************************************************************************/
8444
8445
#define IS_FUNCTION     200
8446
8447
8448
/************************************************************************
8449
 *                  *
8450
 *    Implicit tree core function library     *
8451
 *                  *
8452
 ************************************************************************/
8453
8454
/**
8455
 * xmlXPathRoot:
8456
 * @ctxt:  the XPath Parser context
8457
 *
8458
 * Initialize the context to the root of the document
8459
 */
8460
void
8461
0
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8462
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
8463
0
  return;
8464
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8465
0
  (xmlNodePtr) ctxt->context->doc));
8466
0
}
8467
8468
/************************************************************************
8469
 *                  *
8470
 *    The explicit core function library      *
8471
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8472
 *                  *
8473
 ************************************************************************/
8474
8475
8476
/**
8477
 * xmlXPathLastFunction:
8478
 * @ctxt:  the XPath Parser context
8479
 * @nargs:  the number of arguments
8480
 *
8481
 * Implement the last() XPath function
8482
 *    number last()
8483
 * The last function returns the number of nodes in the context node list.
8484
 */
8485
void
8486
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8487
0
    CHECK_ARITY(0);
8488
0
    if (ctxt->context->contextSize >= 0) {
8489
0
  valuePush(ctxt,
8490
0
      xmlXPathCacheNewFloat(ctxt->context,
8491
0
    (double) ctxt->context->contextSize));
8492
#ifdef DEBUG_EXPR
8493
  xmlGenericError(xmlGenericErrorContext,
8494
    "last() : %d\n", ctxt->context->contextSize);
8495
#endif
8496
0
    } else {
8497
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8498
0
    }
8499
0
}
8500
8501
/**
8502
 * xmlXPathPositionFunction:
8503
 * @ctxt:  the XPath Parser context
8504
 * @nargs:  the number of arguments
8505
 *
8506
 * Implement the position() XPath function
8507
 *    number position()
8508
 * The position function returns the position of the context node in the
8509
 * context node list. The first position is 1, and so the last position
8510
 * will be equal to last().
8511
 */
8512
void
8513
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8514
0
    CHECK_ARITY(0);
8515
0
    if (ctxt->context->proximityPosition >= 0) {
8516
0
  valuePush(ctxt,
8517
0
        xmlXPathCacheNewFloat(ctxt->context,
8518
0
    (double) ctxt->context->proximityPosition));
8519
#ifdef DEBUG_EXPR
8520
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8521
    ctxt->context->proximityPosition);
8522
#endif
8523
0
    } else {
8524
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8525
0
    }
8526
0
}
8527
8528
/**
8529
 * xmlXPathCountFunction:
8530
 * @ctxt:  the XPath Parser context
8531
 * @nargs:  the number of arguments
8532
 *
8533
 * Implement the count() XPath function
8534
 *    number count(node-set)
8535
 */
8536
void
8537
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8538
0
    xmlXPathObjectPtr cur;
8539
8540
0
    CHECK_ARITY(1);
8541
0
    if ((ctxt->value == NULL) ||
8542
0
  ((ctxt->value->type != XPATH_NODESET) &&
8543
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8544
0
  XP_ERROR(XPATH_INVALID_TYPE);
8545
0
    cur = valuePop(ctxt);
8546
8547
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
8548
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8549
0
    else
8550
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8551
0
      (double) cur->nodesetval->nodeNr));
8552
0
    xmlXPathReleaseObject(ctxt->context, cur);
8553
0
}
8554
8555
/**
8556
 * xmlXPathGetElementsByIds:
8557
 * @doc:  the document
8558
 * @ids:  a whitespace separated list of IDs
8559
 *
8560
 * Selects elements by their unique ID.
8561
 *
8562
 * Returns a node-set of selected elements.
8563
 */
8564
static xmlNodeSetPtr
8565
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8566
0
    xmlNodeSetPtr ret;
8567
0
    const xmlChar *cur = ids;
8568
0
    xmlChar *ID;
8569
0
    xmlAttrPtr attr;
8570
0
    xmlNodePtr elem = NULL;
8571
8572
0
    if (ids == NULL) return(NULL);
8573
8574
0
    ret = xmlXPathNodeSetCreate(NULL);
8575
0
    if (ret == NULL)
8576
0
        return(ret);
8577
8578
0
    while (IS_BLANK_CH(*cur)) cur++;
8579
0
    while (*cur != 0) {
8580
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8581
0
      cur++;
8582
8583
0
        ID = xmlStrndup(ids, cur - ids);
8584
0
  if (ID != NULL) {
8585
      /*
8586
       * We used to check the fact that the value passed
8587
       * was an NCName, but this generated much troubles for
8588
       * me and Aleksey Sanin, people blatantly violated that
8589
       * constraint, like Visa3D spec.
8590
       * if (xmlValidateNCName(ID, 1) == 0)
8591
       */
8592
0
      attr = xmlGetID(doc, ID);
8593
0
      if (attr != NULL) {
8594
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8595
0
        elem = attr->parent;
8596
0
    else if (attr->type == XML_ELEMENT_NODE)
8597
0
        elem = (xmlNodePtr) attr;
8598
0
    else
8599
0
        elem = NULL;
8600
                /* TODO: Check memory error. */
8601
0
    if (elem != NULL)
8602
0
        xmlXPathNodeSetAdd(ret, elem);
8603
0
      }
8604
0
      xmlFree(ID);
8605
0
  }
8606
8607
0
  while (IS_BLANK_CH(*cur)) cur++;
8608
0
  ids = cur;
8609
0
    }
8610
0
    return(ret);
8611
0
}
8612
8613
/**
8614
 * xmlXPathIdFunction:
8615
 * @ctxt:  the XPath Parser context
8616
 * @nargs:  the number of arguments
8617
 *
8618
 * Implement the id() XPath function
8619
 *    node-set id(object)
8620
 * The id function selects elements by their unique ID
8621
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8622
 * then the result is the union of the result of applying id to the
8623
 * string value of each of the nodes in the argument node-set. When the
8624
 * argument to id is of any other type, the argument is converted to a
8625
 * string as if by a call to the string function; the string is split
8626
 * into a whitespace-separated list of tokens (whitespace is any sequence
8627
 * of characters matching the production S); the result is a node-set
8628
 * containing the elements in the same document as the context node that
8629
 * have a unique ID equal to any of the tokens in the list.
8630
 */
8631
void
8632
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8633
0
    xmlChar *tokens;
8634
0
    xmlNodeSetPtr ret;
8635
0
    xmlXPathObjectPtr obj;
8636
8637
0
    CHECK_ARITY(1);
8638
0
    obj = valuePop(ctxt);
8639
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8640
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8641
0
  xmlNodeSetPtr ns;
8642
0
  int i;
8643
8644
        /* TODO: Check memory error. */
8645
0
  ret = xmlXPathNodeSetCreate(NULL);
8646
8647
0
  if (obj->nodesetval != NULL) {
8648
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8649
0
    tokens =
8650
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8651
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8652
                /* TODO: Check memory error. */
8653
0
    ret = xmlXPathNodeSetMerge(ret, ns);
8654
0
    xmlXPathFreeNodeSet(ns);
8655
0
    if (tokens != NULL)
8656
0
        xmlFree(tokens);
8657
0
      }
8658
0
  }
8659
0
  xmlXPathReleaseObject(ctxt->context, obj);
8660
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8661
0
  return;
8662
0
    }
8663
0
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8664
0
    if (obj == NULL) return;
8665
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8666
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8667
0
    xmlXPathReleaseObject(ctxt->context, obj);
8668
0
    return;
8669
0
}
8670
8671
/**
8672
 * xmlXPathLocalNameFunction:
8673
 * @ctxt:  the XPath Parser context
8674
 * @nargs:  the number of arguments
8675
 *
8676
 * Implement the local-name() XPath function
8677
 *    string local-name(node-set?)
8678
 * The local-name function returns a string containing the local part
8679
 * of the name of the node in the argument node-set that is first in
8680
 * document order. If the node-set is empty or the first node has no
8681
 * name, an empty string is returned. If the argument is omitted it
8682
 * defaults to the context node.
8683
 */
8684
void
8685
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8686
0
    xmlXPathObjectPtr cur;
8687
8688
0
    if (ctxt == NULL) return;
8689
8690
0
    if (nargs == 0) {
8691
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8692
0
      ctxt->context->node));
8693
0
  nargs = 1;
8694
0
    }
8695
8696
0
    CHECK_ARITY(1);
8697
0
    if ((ctxt->value == NULL) ||
8698
0
  ((ctxt->value->type != XPATH_NODESET) &&
8699
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8700
0
  XP_ERROR(XPATH_INVALID_TYPE);
8701
0
    cur = valuePop(ctxt);
8702
8703
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8704
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8705
0
    } else {
8706
0
  int i = 0; /* Should be first in document order !!!!! */
8707
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8708
0
  case XML_ELEMENT_NODE:
8709
0
  case XML_ATTRIBUTE_NODE:
8710
0
  case XML_PI_NODE:
8711
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8712
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8713
0
      else
8714
0
    valuePush(ctxt,
8715
0
          xmlXPathCacheNewString(ctxt->context,
8716
0
      cur->nodesetval->nodeTab[i]->name));
8717
0
      break;
8718
0
  case XML_NAMESPACE_DECL:
8719
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8720
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8721
0
      break;
8722
0
  default:
8723
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8724
0
  }
8725
0
    }
8726
0
    xmlXPathReleaseObject(ctxt->context, cur);
8727
0
}
8728
8729
/**
8730
 * xmlXPathNamespaceURIFunction:
8731
 * @ctxt:  the XPath Parser context
8732
 * @nargs:  the number of arguments
8733
 *
8734
 * Implement the namespace-uri() XPath function
8735
 *    string namespace-uri(node-set?)
8736
 * The namespace-uri function returns a string containing the
8737
 * namespace URI of the expanded name of the node in the argument
8738
 * node-set that is first in document order. If the node-set is empty,
8739
 * the first node has no name, or the expanded name has no namespace
8740
 * URI, an empty string is returned. If the argument is omitted it
8741
 * defaults to the context node.
8742
 */
8743
void
8744
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8745
0
    xmlXPathObjectPtr cur;
8746
8747
0
    if (ctxt == NULL) return;
8748
8749
0
    if (nargs == 0) {
8750
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8751
0
      ctxt->context->node));
8752
0
  nargs = 1;
8753
0
    }
8754
0
    CHECK_ARITY(1);
8755
0
    if ((ctxt->value == NULL) ||
8756
0
  ((ctxt->value->type != XPATH_NODESET) &&
8757
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8758
0
  XP_ERROR(XPATH_INVALID_TYPE);
8759
0
    cur = valuePop(ctxt);
8760
8761
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8762
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8763
0
    } else {
8764
0
  int i = 0; /* Should be first in document order !!!!! */
8765
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8766
0
  case XML_ELEMENT_NODE:
8767
0
  case XML_ATTRIBUTE_NODE:
8768
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8769
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8770
0
      else
8771
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8772
0
        cur->nodesetval->nodeTab[i]->ns->href));
8773
0
      break;
8774
0
  default:
8775
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8776
0
  }
8777
0
    }
8778
0
    xmlXPathReleaseObject(ctxt->context, cur);
8779
0
}
8780
8781
/**
8782
 * xmlXPathNameFunction:
8783
 * @ctxt:  the XPath Parser context
8784
 * @nargs:  the number of arguments
8785
 *
8786
 * Implement the name() XPath function
8787
 *    string name(node-set?)
8788
 * The name function returns a string containing a QName representing
8789
 * the name of the node in the argument node-set that is first in document
8790
 * order. The QName must represent the name with respect to the namespace
8791
 * declarations in effect on the node whose name is being represented.
8792
 * Typically, this will be the form in which the name occurred in the XML
8793
 * source. This need not be the case if there are namespace declarations
8794
 * in effect on the node that associate multiple prefixes with the same
8795
 * namespace. However, an implementation may include information about
8796
 * the original prefix in its representation of nodes; in this case, an
8797
 * implementation can ensure that the returned string is always the same
8798
 * as the QName used in the XML source. If the argument it omitted it
8799
 * defaults to the context node.
8800
 * Libxml keep the original prefix so the "real qualified name" used is
8801
 * returned.
8802
 */
8803
static void
8804
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8805
0
{
8806
0
    xmlXPathObjectPtr cur;
8807
8808
0
    if (nargs == 0) {
8809
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8810
0
      ctxt->context->node));
8811
0
        nargs = 1;
8812
0
    }
8813
8814
0
    CHECK_ARITY(1);
8815
0
    if ((ctxt->value == NULL) ||
8816
0
        ((ctxt->value->type != XPATH_NODESET) &&
8817
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
8818
0
        XP_ERROR(XPATH_INVALID_TYPE);
8819
0
    cur = valuePop(ctxt);
8820
8821
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8822
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8823
0
    } else {
8824
0
        int i = 0;              /* Should be first in document order !!!!! */
8825
8826
0
        switch (cur->nodesetval->nodeTab[i]->type) {
8827
0
            case XML_ELEMENT_NODE:
8828
0
            case XML_ATTRIBUTE_NODE:
8829
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8830
0
        valuePush(ctxt,
8831
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8832
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8833
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8834
0
        valuePush(ctxt,
8835
0
            xmlXPathCacheNewString(ctxt->context,
8836
0
          cur->nodesetval->nodeTab[i]->name));
8837
0
    } else {
8838
0
        xmlChar *fullname;
8839
8840
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8841
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8842
0
             NULL, 0);
8843
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8844
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8845
0
        if (fullname == NULL) {
8846
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8847
0
        }
8848
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8849
0
      ctxt->context, fullname));
8850
0
                }
8851
0
                break;
8852
0
            default:
8853
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8854
0
        cur->nodesetval->nodeTab[i]));
8855
0
                xmlXPathLocalNameFunction(ctxt, 1);
8856
0
        }
8857
0
    }
8858
0
    xmlXPathReleaseObject(ctxt->context, cur);
8859
0
}
8860
8861
8862
/**
8863
 * xmlXPathStringFunction:
8864
 * @ctxt:  the XPath Parser context
8865
 * @nargs:  the number of arguments
8866
 *
8867
 * Implement the string() XPath function
8868
 *    string string(object?)
8869
 * The string function converts an object to a string as follows:
8870
 *    - A node-set is converted to a string by returning the value of
8871
 *      the node in the node-set that is first in document order.
8872
 *      If the node-set is empty, an empty string is returned.
8873
 *    - A number is converted to a string as follows
8874
 *      + NaN is converted to the string NaN
8875
 *      + positive zero is converted to the string 0
8876
 *      + negative zero is converted to the string 0
8877
 *      + positive infinity is converted to the string Infinity
8878
 *      + negative infinity is converted to the string -Infinity
8879
 *      + if the number is an integer, the number is represented in
8880
 *        decimal form as a Number with no decimal point and no leading
8881
 *        zeros, preceded by a minus sign (-) if the number is negative
8882
 *      + otherwise, the number is represented in decimal form as a
8883
 *        Number including a decimal point with at least one digit
8884
 *        before the decimal point and at least one digit after the
8885
 *        decimal point, preceded by a minus sign (-) if the number
8886
 *        is negative; there must be no leading zeros before the decimal
8887
 *        point apart possibly from the one required digit immediately
8888
 *        before the decimal point; beyond the one required digit
8889
 *        after the decimal point there must be as many, but only as
8890
 *        many, more digits as are needed to uniquely distinguish the
8891
 *        number from all other IEEE 754 numeric values.
8892
 *    - The boolean false value is converted to the string false.
8893
 *      The boolean true value is converted to the string true.
8894
 *
8895
 * If the argument is omitted, it defaults to a node-set with the
8896
 * context node as its only member.
8897
 */
8898
void
8899
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8900
0
    xmlXPathObjectPtr cur;
8901
8902
0
    if (ctxt == NULL) return;
8903
0
    if (nargs == 0) {
8904
0
    valuePush(ctxt,
8905
0
  xmlXPathCacheWrapString(ctxt->context,
8906
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8907
0
  return;
8908
0
    }
8909
8910
0
    CHECK_ARITY(1);
8911
0
    cur = valuePop(ctxt);
8912
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8913
0
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8914
0
}
8915
8916
/**
8917
 * xmlXPathStringLengthFunction:
8918
 * @ctxt:  the XPath Parser context
8919
 * @nargs:  the number of arguments
8920
 *
8921
 * Implement the string-length() XPath function
8922
 *    number string-length(string?)
8923
 * The string-length returns the number of characters in the string
8924
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8925
 * the context node converted to a string, in other words the value
8926
 * of the context node.
8927
 */
8928
void
8929
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8930
0
    xmlXPathObjectPtr cur;
8931
8932
0
    if (nargs == 0) {
8933
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8934
0
      return;
8935
0
  if (ctxt->context->node == NULL) {
8936
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8937
0
  } else {
8938
0
      xmlChar *content;
8939
8940
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8941
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8942
0
    xmlUTF8Strlen(content)));
8943
0
      xmlFree(content);
8944
0
  }
8945
0
  return;
8946
0
    }
8947
0
    CHECK_ARITY(1);
8948
0
    CAST_TO_STRING;
8949
0
    CHECK_TYPE(XPATH_STRING);
8950
0
    cur = valuePop(ctxt);
8951
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8952
0
  xmlUTF8Strlen(cur->stringval)));
8953
0
    xmlXPathReleaseObject(ctxt->context, cur);
8954
0
}
8955
8956
/**
8957
 * xmlXPathConcatFunction:
8958
 * @ctxt:  the XPath Parser context
8959
 * @nargs:  the number of arguments
8960
 *
8961
 * Implement the concat() XPath function
8962
 *    string concat(string, string, string*)
8963
 * The concat function returns the concatenation of its arguments.
8964
 */
8965
void
8966
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8967
0
    xmlXPathObjectPtr cur, newobj;
8968
0
    xmlChar *tmp;
8969
8970
0
    if (ctxt == NULL) return;
8971
0
    if (nargs < 2) {
8972
0
  CHECK_ARITY(2);
8973
0
    }
8974
8975
0
    CAST_TO_STRING;
8976
0
    cur = valuePop(ctxt);
8977
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8978
0
  xmlXPathReleaseObject(ctxt->context, cur);
8979
0
  return;
8980
0
    }
8981
0
    nargs--;
8982
8983
0
    while (nargs > 0) {
8984
0
  CAST_TO_STRING;
8985
0
  newobj = valuePop(ctxt);
8986
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8987
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8988
0
      xmlXPathReleaseObject(ctxt->context, cur);
8989
0
      XP_ERROR(XPATH_INVALID_TYPE);
8990
0
  }
8991
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8992
0
  newobj->stringval = cur->stringval;
8993
0
  cur->stringval = tmp;
8994
0
  xmlXPathReleaseObject(ctxt->context, newobj);
8995
0
  nargs--;
8996
0
    }
8997
0
    valuePush(ctxt, cur);
8998
0
}
8999
9000
/**
9001
 * xmlXPathContainsFunction:
9002
 * @ctxt:  the XPath Parser context
9003
 * @nargs:  the number of arguments
9004
 *
9005
 * Implement the contains() XPath function
9006
 *    boolean contains(string, string)
9007
 * The contains function returns true if the first argument string
9008
 * contains the second argument string, and otherwise returns false.
9009
 */
9010
void
9011
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9012
0
    xmlXPathObjectPtr hay, needle;
9013
9014
0
    CHECK_ARITY(2);
9015
0
    CAST_TO_STRING;
9016
0
    CHECK_TYPE(XPATH_STRING);
9017
0
    needle = valuePop(ctxt);
9018
0
    CAST_TO_STRING;
9019
0
    hay = valuePop(ctxt);
9020
9021
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9022
0
  xmlXPathReleaseObject(ctxt->context, hay);
9023
0
  xmlXPathReleaseObject(ctxt->context, needle);
9024
0
  XP_ERROR(XPATH_INVALID_TYPE);
9025
0
    }
9026
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9027
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9028
0
    else
9029
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9030
0
    xmlXPathReleaseObject(ctxt->context, hay);
9031
0
    xmlXPathReleaseObject(ctxt->context, needle);
9032
0
}
9033
9034
/**
9035
 * xmlXPathStartsWithFunction:
9036
 * @ctxt:  the XPath Parser context
9037
 * @nargs:  the number of arguments
9038
 *
9039
 * Implement the starts-with() XPath function
9040
 *    boolean starts-with(string, string)
9041
 * The starts-with function returns true if the first argument string
9042
 * starts with the second argument string, and otherwise returns false.
9043
 */
9044
void
9045
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9046
0
    xmlXPathObjectPtr hay, needle;
9047
0
    int n;
9048
9049
0
    CHECK_ARITY(2);
9050
0
    CAST_TO_STRING;
9051
0
    CHECK_TYPE(XPATH_STRING);
9052
0
    needle = valuePop(ctxt);
9053
0
    CAST_TO_STRING;
9054
0
    hay = valuePop(ctxt);
9055
9056
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9057
0
  xmlXPathReleaseObject(ctxt->context, hay);
9058
0
  xmlXPathReleaseObject(ctxt->context, needle);
9059
0
  XP_ERROR(XPATH_INVALID_TYPE);
9060
0
    }
9061
0
    n = xmlStrlen(needle->stringval);
9062
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9063
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9064
0
    else
9065
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9066
0
    xmlXPathReleaseObject(ctxt->context, hay);
9067
0
    xmlXPathReleaseObject(ctxt->context, needle);
9068
0
}
9069
9070
/**
9071
 * xmlXPathSubstringFunction:
9072
 * @ctxt:  the XPath Parser context
9073
 * @nargs:  the number of arguments
9074
 *
9075
 * Implement the substring() XPath function
9076
 *    string substring(string, number, number?)
9077
 * The substring function returns the substring of the first argument
9078
 * starting at the position specified in the second argument with
9079
 * length specified in the third argument. For example,
9080
 * substring("12345",2,3) returns "234". If the third argument is not
9081
 * specified, it returns the substring starting at the position specified
9082
 * in the second argument and continuing to the end of the string. For
9083
 * example, substring("12345",2) returns "2345".  More precisely, each
9084
 * character in the string (see [3.6 Strings]) is considered to have a
9085
 * numeric position: the position of the first character is 1, the position
9086
 * of the second character is 2 and so on. The returned substring contains
9087
 * those characters for which the position of the character is greater than
9088
 * or equal to the second argument and, if the third argument is specified,
9089
 * less than the sum of the second and third arguments; the comparisons
9090
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9091
 *  - substring("12345", 1.5, 2.6) returns "234"
9092
 *  - substring("12345", 0, 3) returns "12"
9093
 *  - substring("12345", 0 div 0, 3) returns ""
9094
 *  - substring("12345", 1, 0 div 0) returns ""
9095
 *  - substring("12345", -42, 1 div 0) returns "12345"
9096
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9097
 */
9098
void
9099
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9100
0
    xmlXPathObjectPtr str, start, len;
9101
0
    double le=0, in;
9102
0
    int i = 1, j = INT_MAX;
9103
9104
0
    if (nargs < 2) {
9105
0
  CHECK_ARITY(2);
9106
0
    }
9107
0
    if (nargs > 3) {
9108
0
  CHECK_ARITY(3);
9109
0
    }
9110
    /*
9111
     * take care of possible last (position) argument
9112
    */
9113
0
    if (nargs == 3) {
9114
0
  CAST_TO_NUMBER;
9115
0
  CHECK_TYPE(XPATH_NUMBER);
9116
0
  len = valuePop(ctxt);
9117
0
  le = len->floatval;
9118
0
  xmlXPathReleaseObject(ctxt->context, len);
9119
0
    }
9120
9121
0
    CAST_TO_NUMBER;
9122
0
    CHECK_TYPE(XPATH_NUMBER);
9123
0
    start = valuePop(ctxt);
9124
0
    in = start->floatval;
9125
0
    xmlXPathReleaseObject(ctxt->context, start);
9126
0
    CAST_TO_STRING;
9127
0
    CHECK_TYPE(XPATH_STRING);
9128
0
    str = valuePop(ctxt);
9129
9130
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9131
0
        i = INT_MAX;
9132
0
    } else if (in >= 1.0) {
9133
0
        i = (int)in;
9134
0
        if (in - floor(in) >= 0.5)
9135
0
            i += 1;
9136
0
    }
9137
9138
0
    if (nargs == 3) {
9139
0
        double rin, rle, end;
9140
9141
0
        rin = floor(in);
9142
0
        if (in - rin >= 0.5)
9143
0
            rin += 1.0;
9144
9145
0
        rle = floor(le);
9146
0
        if (le - rle >= 0.5)
9147
0
            rle += 1.0;
9148
9149
0
        end = rin + rle;
9150
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9151
0
            j = 1;
9152
0
        } else if (end < INT_MAX) {
9153
0
            j = (int)end;
9154
0
        }
9155
0
    }
9156
9157
0
    if (i < j) {
9158
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9159
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9160
0
  xmlFree(ret);
9161
0
    } else {
9162
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9163
0
    }
9164
9165
0
    xmlXPathReleaseObject(ctxt->context, str);
9166
0
}
9167
9168
/**
9169
 * xmlXPathSubstringBeforeFunction:
9170
 * @ctxt:  the XPath Parser context
9171
 * @nargs:  the number of arguments
9172
 *
9173
 * Implement the substring-before() XPath function
9174
 *    string substring-before(string, string)
9175
 * The substring-before function returns the substring of the first
9176
 * argument string that precedes the first occurrence of the second
9177
 * argument string in the first argument string, or the empty string
9178
 * if the first argument string does not contain the second argument
9179
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9180
 */
9181
void
9182
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9183
0
  xmlXPathObjectPtr str;
9184
0
  xmlXPathObjectPtr find;
9185
0
  xmlBufPtr target;
9186
0
  const xmlChar *point;
9187
0
  int offset;
9188
9189
0
  CHECK_ARITY(2);
9190
0
  CAST_TO_STRING;
9191
0
  find = valuePop(ctxt);
9192
0
  CAST_TO_STRING;
9193
0
  str = valuePop(ctxt);
9194
9195
0
  target = xmlBufCreate();
9196
0
  if (target) {
9197
0
    point = xmlStrstr(str->stringval, find->stringval);
9198
0
    if (point) {
9199
0
      offset = (int)(point - str->stringval);
9200
0
      xmlBufAdd(target, str->stringval, offset);
9201
0
    }
9202
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9203
0
  xmlBufContent(target)));
9204
0
    xmlBufFree(target);
9205
0
  }
9206
0
  xmlXPathReleaseObject(ctxt->context, str);
9207
0
  xmlXPathReleaseObject(ctxt->context, find);
9208
0
}
9209
9210
/**
9211
 * xmlXPathSubstringAfterFunction:
9212
 * @ctxt:  the XPath Parser context
9213
 * @nargs:  the number of arguments
9214
 *
9215
 * Implement the substring-after() XPath function
9216
 *    string substring-after(string, string)
9217
 * The substring-after function returns the substring of the first
9218
 * argument string that follows the first occurrence of the second
9219
 * argument string in the first argument string, or the empty stringi
9220
 * if the first argument string does not contain the second argument
9221
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9222
 * and substring-after("1999/04/01","19") returns 99/04/01.
9223
 */
9224
void
9225
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9226
0
  xmlXPathObjectPtr str;
9227
0
  xmlXPathObjectPtr find;
9228
0
  xmlBufPtr target;
9229
0
  const xmlChar *point;
9230
0
  int offset;
9231
9232
0
  CHECK_ARITY(2);
9233
0
  CAST_TO_STRING;
9234
0
  find = valuePop(ctxt);
9235
0
  CAST_TO_STRING;
9236
0
  str = valuePop(ctxt);
9237
9238
0
  target = xmlBufCreate();
9239
0
  if (target) {
9240
0
    point = xmlStrstr(str->stringval, find->stringval);
9241
0
    if (point) {
9242
0
      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9243
0
      xmlBufAdd(target, &str->stringval[offset],
9244
0
       xmlStrlen(str->stringval) - offset);
9245
0
    }
9246
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9247
0
  xmlBufContent(target)));
9248
0
    xmlBufFree(target);
9249
0
  }
9250
0
  xmlXPathReleaseObject(ctxt->context, str);
9251
0
  xmlXPathReleaseObject(ctxt->context, find);
9252
0
}
9253
9254
/**
9255
 * xmlXPathNormalizeFunction:
9256
 * @ctxt:  the XPath Parser context
9257
 * @nargs:  the number of arguments
9258
 *
9259
 * Implement the normalize-space() XPath function
9260
 *    string normalize-space(string?)
9261
 * The normalize-space function returns the argument string with white
9262
 * space normalized by stripping leading and trailing whitespace
9263
 * and replacing sequences of whitespace characters by a single
9264
 * space. Whitespace characters are the same allowed by the S production
9265
 * in XML. If the argument is omitted, it defaults to the context
9266
 * node converted to a string, in other words the value of the context node.
9267
 */
9268
void
9269
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9270
0
    xmlChar *source, *target;
9271
0
    int blank;
9272
9273
0
    if (ctxt == NULL) return;
9274
0
    if (nargs == 0) {
9275
        /* Use current context node */
9276
0
        valuePush(ctxt,
9277
0
            xmlXPathCacheWrapString(ctxt->context,
9278
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9279
0
        nargs = 1;
9280
0
    }
9281
9282
0
    CHECK_ARITY(1);
9283
0
    CAST_TO_STRING;
9284
0
    CHECK_TYPE(XPATH_STRING);
9285
0
    source = ctxt->value->stringval;
9286
0
    if (source == NULL)
9287
0
        return;
9288
0
    target = source;
9289
9290
    /* Skip leading whitespaces */
9291
0
    while (IS_BLANK_CH(*source))
9292
0
        source++;
9293
9294
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9295
0
    blank = 0;
9296
0
    while (*source) {
9297
0
        if (IS_BLANK_CH(*source)) {
9298
0
      blank = 1;
9299
0
        } else {
9300
0
            if (blank) {
9301
0
                *target++ = 0x20;
9302
0
                blank = 0;
9303
0
            }
9304
0
            *target++ = *source;
9305
0
        }
9306
0
        source++;
9307
0
    }
9308
0
    *target = 0;
9309
0
}
9310
9311
/**
9312
 * xmlXPathTranslateFunction:
9313
 * @ctxt:  the XPath Parser context
9314
 * @nargs:  the number of arguments
9315
 *
9316
 * Implement the translate() XPath function
9317
 *    string translate(string, string, string)
9318
 * The translate function returns the first argument string with
9319
 * occurrences of characters in the second argument string replaced
9320
 * by the character at the corresponding position in the third argument
9321
 * string. For example, translate("bar","abc","ABC") returns the string
9322
 * BAr. If there is a character in the second argument string with no
9323
 * character at a corresponding position in the third argument string
9324
 * (because the second argument string is longer than the third argument
9325
 * string), then occurrences of that character in the first argument
9326
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9327
 * returns "AAA". If a character occurs more than once in second
9328
 * argument string, then the first occurrence determines the replacement
9329
 * character. If the third argument string is longer than the second
9330
 * argument string, then excess characters are ignored.
9331
 */
9332
void
9333
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9334
0
    xmlXPathObjectPtr str;
9335
0
    xmlXPathObjectPtr from;
9336
0
    xmlXPathObjectPtr to;
9337
0
    xmlBufPtr target;
9338
0
    int offset, max;
9339
0
    xmlChar ch;
9340
0
    const xmlChar *point;
9341
0
    xmlChar *cptr;
9342
9343
0
    CHECK_ARITY(3);
9344
9345
0
    CAST_TO_STRING;
9346
0
    to = valuePop(ctxt);
9347
0
    CAST_TO_STRING;
9348
0
    from = valuePop(ctxt);
9349
0
    CAST_TO_STRING;
9350
0
    str = valuePop(ctxt);
9351
9352
0
    target = xmlBufCreate();
9353
0
    if (target) {
9354
0
  max = xmlUTF8Strlen(to->stringval);
9355
0
  for (cptr = str->stringval; (ch=*cptr); ) {
9356
0
      offset = xmlUTF8Strloc(from->stringval, cptr);
9357
0
      if (offset >= 0) {
9358
0
    if (offset < max) {
9359
0
        point = xmlUTF8Strpos(to->stringval, offset);
9360
0
        if (point)
9361
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9362
0
    }
9363
0
      } else
9364
0
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9365
9366
      /* Step to next character in input */
9367
0
      cptr++;
9368
0
      if ( ch & 0x80 ) {
9369
    /* if not simple ascii, verify proper format */
9370
0
    if ( (ch & 0xc0) != 0xc0 ) {
9371
0
        xmlGenericError(xmlGenericErrorContext,
9372
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9373
                    /* not asserting an XPath error is probably better */
9374
0
        break;
9375
0
    }
9376
    /* then skip over remaining bytes for this char */
9377
0
    while ( (ch <<= 1) & 0x80 )
9378
0
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9379
0
      xmlGenericError(xmlGenericErrorContext,
9380
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381
                        /* not asserting an XPath error is probably better */
9382
0
      break;
9383
0
        }
9384
0
    if (ch & 0x80) /* must have had error encountered */
9385
0
        break;
9386
0
      }
9387
0
  }
9388
0
    }
9389
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9390
0
  xmlBufContent(target)));
9391
0
    xmlBufFree(target);
9392
0
    xmlXPathReleaseObject(ctxt->context, str);
9393
0
    xmlXPathReleaseObject(ctxt->context, from);
9394
0
    xmlXPathReleaseObject(ctxt->context, to);
9395
0
}
9396
9397
/**
9398
 * xmlXPathBooleanFunction:
9399
 * @ctxt:  the XPath Parser context
9400
 * @nargs:  the number of arguments
9401
 *
9402
 * Implement the boolean() XPath function
9403
 *    boolean boolean(object)
9404
 * The boolean function converts its argument to a boolean as follows:
9405
 *    - a number is true if and only if it is neither positive or
9406
 *      negative zero nor NaN
9407
 *    - a node-set is true if and only if it is non-empty
9408
 *    - a string is true if and only if its length is non-zero
9409
 */
9410
void
9411
0
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9412
0
    xmlXPathObjectPtr cur;
9413
9414
0
    CHECK_ARITY(1);
9415
0
    cur = valuePop(ctxt);
9416
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9417
0
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9418
0
    valuePush(ctxt, cur);
9419
0
}
9420
9421
/**
9422
 * xmlXPathNotFunction:
9423
 * @ctxt:  the XPath Parser context
9424
 * @nargs:  the number of arguments
9425
 *
9426
 * Implement the not() XPath function
9427
 *    boolean not(boolean)
9428
 * The not function returns true if its argument is false,
9429
 * and false otherwise.
9430
 */
9431
void
9432
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9433
0
    CHECK_ARITY(1);
9434
0
    CAST_TO_BOOLEAN;
9435
0
    CHECK_TYPE(XPATH_BOOLEAN);
9436
0
    ctxt->value->boolval = ! ctxt->value->boolval;
9437
0
}
9438
9439
/**
9440
 * xmlXPathTrueFunction:
9441
 * @ctxt:  the XPath Parser context
9442
 * @nargs:  the number of arguments
9443
 *
9444
 * Implement the true() XPath function
9445
 *    boolean true()
9446
 */
9447
void
9448
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9449
0
    CHECK_ARITY(0);
9450
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9451
0
}
9452
9453
/**
9454
 * xmlXPathFalseFunction:
9455
 * @ctxt:  the XPath Parser context
9456
 * @nargs:  the number of arguments
9457
 *
9458
 * Implement the false() XPath function
9459
 *    boolean false()
9460
 */
9461
void
9462
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9463
0
    CHECK_ARITY(0);
9464
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9465
0
}
9466
9467
/**
9468
 * xmlXPathLangFunction:
9469
 * @ctxt:  the XPath Parser context
9470
 * @nargs:  the number of arguments
9471
 *
9472
 * Implement the lang() XPath function
9473
 *    boolean lang(string)
9474
 * The lang function returns true or false depending on whether the
9475
 * language of the context node as specified by xml:lang attributes
9476
 * is the same as or is a sublanguage of the language specified by
9477
 * the argument string. The language of the context node is determined
9478
 * by the value of the xml:lang attribute on the context node, or, if
9479
 * the context node has no xml:lang attribute, by the value of the
9480
 * xml:lang attribute on the nearest ancestor of the context node that
9481
 * has an xml:lang attribute. If there is no such attribute, then lang
9482
 * returns false. If there is such an attribute, then lang returns
9483
 * true if the attribute value is equal to the argument ignoring case,
9484
 * or if there is some suffix starting with - such that the attribute
9485
 * value is equal to the argument ignoring that suffix of the attribute
9486
 * value and ignoring case.
9487
 */
9488
void
9489
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9490
0
    xmlXPathObjectPtr val = NULL;
9491
0
    const xmlChar *theLang = NULL;
9492
0
    const xmlChar *lang;
9493
0
    int ret = 0;
9494
0
    int i;
9495
9496
0
    CHECK_ARITY(1);
9497
0
    CAST_TO_STRING;
9498
0
    CHECK_TYPE(XPATH_STRING);
9499
0
    val = valuePop(ctxt);
9500
0
    lang = val->stringval;
9501
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9502
0
    if ((theLang != NULL) && (lang != NULL)) {
9503
0
        for (i = 0;lang[i] != 0;i++)
9504
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9505
0
          goto not_equal;
9506
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9507
0
      ret = 1;
9508
0
    }
9509
0
not_equal:
9510
0
    if (theLang != NULL)
9511
0
  xmlFree((void *)theLang);
9512
9513
0
    xmlXPathReleaseObject(ctxt->context, val);
9514
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9515
0
}
9516
9517
/**
9518
 * xmlXPathNumberFunction:
9519
 * @ctxt:  the XPath Parser context
9520
 * @nargs:  the number of arguments
9521
 *
9522
 * Implement the number() XPath function
9523
 *    number number(object?)
9524
 */
9525
void
9526
0
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9527
0
    xmlXPathObjectPtr cur;
9528
0
    double res;
9529
9530
0
    if (ctxt == NULL) return;
9531
0
    if (nargs == 0) {
9532
0
  if (ctxt->context->node == NULL) {
9533
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9534
0
  } else {
9535
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9536
9537
0
      res = xmlXPathStringEvalNumber(content);
9538
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9539
0
      xmlFree(content);
9540
0
  }
9541
0
  return;
9542
0
    }
9543
9544
0
    CHECK_ARITY(1);
9545
0
    cur = valuePop(ctxt);
9546
0
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9547
0
}
9548
9549
/**
9550
 * xmlXPathSumFunction:
9551
 * @ctxt:  the XPath Parser context
9552
 * @nargs:  the number of arguments
9553
 *
9554
 * Implement the sum() XPath function
9555
 *    number sum(node-set)
9556
 * The sum function returns the sum of the values of the nodes in
9557
 * the argument node-set.
9558
 */
9559
void
9560
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561
0
    xmlXPathObjectPtr cur;
9562
0
    int i;
9563
0
    double res = 0.0;
9564
9565
0
    CHECK_ARITY(1);
9566
0
    if ((ctxt->value == NULL) ||
9567
0
  ((ctxt->value->type != XPATH_NODESET) &&
9568
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
9569
0
  XP_ERROR(XPATH_INVALID_TYPE);
9570
0
    cur = valuePop(ctxt);
9571
9572
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9573
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9574
0
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9575
0
  }
9576
0
    }
9577
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9578
0
    xmlXPathReleaseObject(ctxt->context, cur);
9579
0
}
9580
9581
/**
9582
 * xmlXPathFloorFunction:
9583
 * @ctxt:  the XPath Parser context
9584
 * @nargs:  the number of arguments
9585
 *
9586
 * Implement the floor() XPath function
9587
 *    number floor(number)
9588
 * The floor function returns the largest (closest to positive infinity)
9589
 * number that is not greater than the argument and that is an integer.
9590
 */
9591
void
9592
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9593
0
    CHECK_ARITY(1);
9594
0
    CAST_TO_NUMBER;
9595
0
    CHECK_TYPE(XPATH_NUMBER);
9596
9597
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9598
0
}
9599
9600
/**
9601
 * xmlXPathCeilingFunction:
9602
 * @ctxt:  the XPath Parser context
9603
 * @nargs:  the number of arguments
9604
 *
9605
 * Implement the ceiling() XPath function
9606
 *    number ceiling(number)
9607
 * The ceiling function returns the smallest (closest to negative infinity)
9608
 * number that is not less than the argument and that is an integer.
9609
 */
9610
void
9611
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9612
0
    CHECK_ARITY(1);
9613
0
    CAST_TO_NUMBER;
9614
0
    CHECK_TYPE(XPATH_NUMBER);
9615
9616
#ifdef _AIX
9617
    /* Work around buggy ceil() function on AIX */
9618
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9619
#else
9620
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9621
0
#endif
9622
0
}
9623
9624
/**
9625
 * xmlXPathRoundFunction:
9626
 * @ctxt:  the XPath Parser context
9627
 * @nargs:  the number of arguments
9628
 *
9629
 * Implement the round() XPath function
9630
 *    number round(number)
9631
 * The round function returns the number that is closest to the
9632
 * argument and that is an integer. If there are two such numbers,
9633
 * then the one that is closest to positive infinity is returned.
9634
 */
9635
void
9636
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9637
0
    double f;
9638
9639
0
    CHECK_ARITY(1);
9640
0
    CAST_TO_NUMBER;
9641
0
    CHECK_TYPE(XPATH_NUMBER);
9642
9643
0
    f = ctxt->value->floatval;
9644
9645
0
    if ((f >= -0.5) && (f < 0.5)) {
9646
        /* Handles negative zero. */
9647
0
        ctxt->value->floatval *= 0.0;
9648
0
    }
9649
0
    else {
9650
0
        double rounded = floor(f);
9651
0
        if (f - rounded >= 0.5)
9652
0
            rounded += 1.0;
9653
0
        ctxt->value->floatval = rounded;
9654
0
    }
9655
0
}
9656
9657
/************************************************************************
9658
 *                  *
9659
 *      The Parser          *
9660
 *                  *
9661
 ************************************************************************/
9662
9663
/*
9664
 * a few forward declarations since we use a recursive call based
9665
 * implementation.
9666
 */
9667
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9668
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9669
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9670
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9671
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9672
                                    int qualified);
9673
9674
/**
9675
 * xmlXPathCurrentChar:
9676
 * @ctxt:  the XPath parser context
9677
 * @cur:  pointer to the beginning of the char
9678
 * @len:  pointer to the length of the char read
9679
 *
9680
 * The current char value, if using UTF-8 this may actually span multiple
9681
 * bytes in the input buffer.
9682
 *
9683
 * Returns the current char value and its length
9684
 */
9685
9686
static int
9687
0
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9688
0
    unsigned char c;
9689
0
    unsigned int val;
9690
0
    const xmlChar *cur;
9691
9692
0
    if (ctxt == NULL)
9693
0
  return(0);
9694
0
    cur = ctxt->cur;
9695
9696
    /*
9697
     * We are supposed to handle UTF8, check it's valid
9698
     * From rfc2044: encoding of the Unicode values on UTF-8:
9699
     *
9700
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9701
     * 0000 0000-0000 007F   0xxxxxxx
9702
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9703
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9704
     *
9705
     * Check for the 0x110000 limit too
9706
     */
9707
0
    c = *cur;
9708
0
    if (c & 0x80) {
9709
0
  if ((cur[1] & 0xc0) != 0x80)
9710
0
      goto encoding_error;
9711
0
  if ((c & 0xe0) == 0xe0) {
9712
9713
0
      if ((cur[2] & 0xc0) != 0x80)
9714
0
    goto encoding_error;
9715
0
      if ((c & 0xf0) == 0xf0) {
9716
0
    if (((c & 0xf8) != 0xf0) ||
9717
0
        ((cur[3] & 0xc0) != 0x80))
9718
0
        goto encoding_error;
9719
    /* 4-byte code */
9720
0
    *len = 4;
9721
0
    val = (cur[0] & 0x7) << 18;
9722
0
    val |= (cur[1] & 0x3f) << 12;
9723
0
    val |= (cur[2] & 0x3f) << 6;
9724
0
    val |= cur[3] & 0x3f;
9725
0
      } else {
9726
        /* 3-byte code */
9727
0
    *len = 3;
9728
0
    val = (cur[0] & 0xf) << 12;
9729
0
    val |= (cur[1] & 0x3f) << 6;
9730
0
    val |= cur[2] & 0x3f;
9731
0
      }
9732
0
  } else {
9733
    /* 2-byte code */
9734
0
      *len = 2;
9735
0
      val = (cur[0] & 0x1f) << 6;
9736
0
      val |= cur[1] & 0x3f;
9737
0
  }
9738
0
  if (!IS_CHAR(val)) {
9739
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9740
0
  }
9741
0
  return(val);
9742
0
    } else {
9743
  /* 1-byte code */
9744
0
  *len = 1;
9745
0
  return((int) *cur);
9746
0
    }
9747
0
encoding_error:
9748
    /*
9749
     * If we detect an UTF8 error that probably means that the
9750
     * input encoding didn't get properly advertised in the
9751
     * declaration header. Report the error and switch the encoding
9752
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9753
     * encoding !)
9754
     */
9755
0
    *len = 0;
9756
0
    XP_ERROR0(XPATH_ENCODING_ERROR);
9757
0
}
9758
9759
/**
9760
 * xmlXPathParseNCName:
9761
 * @ctxt:  the XPath Parser context
9762
 *
9763
 * parse an XML namespace non qualified name.
9764
 *
9765
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9766
 *
9767
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9768
 *                       CombiningChar | Extender
9769
 *
9770
 * Returns the namespace name or NULL
9771
 */
9772
9773
xmlChar *
9774
0
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9775
0
    const xmlChar *in;
9776
0
    xmlChar *ret;
9777
0
    int count = 0;
9778
9779
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9780
    /*
9781
     * Accelerator for simple ASCII names
9782
     */
9783
0
    in = ctxt->cur;
9784
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9785
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9786
0
  (*in == '_')) {
9787
0
  in++;
9788
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9789
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9790
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9791
0
         (*in == '_') || (*in == '.') ||
9792
0
         (*in == '-'))
9793
0
      in++;
9794
0
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9795
0
            (*in == '[') || (*in == ']') || (*in == ':') ||
9796
0
            (*in == '@') || (*in == '*')) {
9797
0
      count = in - ctxt->cur;
9798
0
      if (count == 0)
9799
0
    return(NULL);
9800
0
      ret = xmlStrndup(ctxt->cur, count);
9801
0
      ctxt->cur = in;
9802
0
      return(ret);
9803
0
  }
9804
0
    }
9805
0
    return(xmlXPathParseNameComplex(ctxt, 0));
9806
0
}
9807
9808
9809
/**
9810
 * xmlXPathParseQName:
9811
 * @ctxt:  the XPath Parser context
9812
 * @prefix:  a xmlChar **
9813
 *
9814
 * parse an XML qualified name
9815
 *
9816
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9817
 *
9818
 * [NS 6] Prefix ::= NCName
9819
 *
9820
 * [NS 7] LocalPart ::= NCName
9821
 *
9822
 * Returns the function returns the local part, and prefix is updated
9823
 *   to get the Prefix if any.
9824
 */
9825
9826
static xmlChar *
9827
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9828
0
    xmlChar *ret = NULL;
9829
9830
0
    *prefix = NULL;
9831
0
    ret = xmlXPathParseNCName(ctxt);
9832
0
    if (ret && CUR == ':') {
9833
0
        *prefix = ret;
9834
0
  NEXT;
9835
0
  ret = xmlXPathParseNCName(ctxt);
9836
0
    }
9837
0
    return(ret);
9838
0
}
9839
9840
/**
9841
 * xmlXPathParseName:
9842
 * @ctxt:  the XPath Parser context
9843
 *
9844
 * parse an XML name
9845
 *
9846
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9847
 *                  CombiningChar | Extender
9848
 *
9849
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9850
 *
9851
 * Returns the namespace name or NULL
9852
 */
9853
9854
xmlChar *
9855
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9856
0
    const xmlChar *in;
9857
0
    xmlChar *ret;
9858
0
    size_t count = 0;
9859
9860
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9861
    /*
9862
     * Accelerator for simple ASCII names
9863
     */
9864
0
    in = ctxt->cur;
9865
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9866
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9867
0
  (*in == '_') || (*in == ':')) {
9868
0
  in++;
9869
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9870
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9871
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9872
0
         (*in == '_') || (*in == '-') ||
9873
0
         (*in == ':') || (*in == '.'))
9874
0
      in++;
9875
0
  if ((*in > 0) && (*in < 0x80)) {
9876
0
      count = in - ctxt->cur;
9877
0
            if (count > XML_MAX_NAME_LENGTH) {
9878
0
                ctxt->cur = in;
9879
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9880
0
            }
9881
0
      ret = xmlStrndup(ctxt->cur, count);
9882
0
      ctxt->cur = in;
9883
0
      return(ret);
9884
0
  }
9885
0
    }
9886
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9887
0
}
9888
9889
static xmlChar *
9890
0
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9891
0
    xmlChar buf[XML_MAX_NAMELEN + 5];
9892
0
    int len = 0, l;
9893
0
    int c;
9894
9895
    /*
9896
     * Handler for more complex cases
9897
     */
9898
0
    c = CUR_CHAR(l);
9899
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9900
0
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9901
0
        (c == '*') || /* accelerators */
9902
0
  (!IS_LETTER(c) && (c != '_') &&
9903
0
         ((!qualified) || (c != ':')))) {
9904
0
  return(NULL);
9905
0
    }
9906
9907
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9908
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9909
0
            (c == '.') || (c == '-') ||
9910
0
      (c == '_') || ((qualified) && (c == ':')) ||
9911
0
      (IS_COMBINING(c)) ||
9912
0
      (IS_EXTENDER(c)))) {
9913
0
  COPY_BUF(l,buf,len,c);
9914
0
  NEXTL(l);
9915
0
  c = CUR_CHAR(l);
9916
0
  if (len >= XML_MAX_NAMELEN) {
9917
      /*
9918
       * Okay someone managed to make a huge name, so he's ready to pay
9919
       * for the processing speed.
9920
       */
9921
0
      xmlChar *buffer;
9922
0
      int max = len * 2;
9923
9924
0
            if (len > XML_MAX_NAME_LENGTH) {
9925
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9926
0
            }
9927
0
      buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9928
0
      if (buffer == NULL) {
9929
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9930
0
      }
9931
0
      memcpy(buffer, buf, len);
9932
0
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9933
0
       (c == '.') || (c == '-') ||
9934
0
       (c == '_') || ((qualified) && (c == ':')) ||
9935
0
       (IS_COMBINING(c)) ||
9936
0
       (IS_EXTENDER(c))) {
9937
0
    if (len + 10 > max) {
9938
0
                    xmlChar *tmp;
9939
0
                    if (max > XML_MAX_NAME_LENGTH) {
9940
0
                        xmlFree(buffer);
9941
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9942
0
                    }
9943
0
        max *= 2;
9944
0
        tmp = (xmlChar *) xmlRealloc(buffer,
9945
0
                               max * sizeof(xmlChar));
9946
0
        if (tmp == NULL) {
9947
0
                        xmlFree(buffer);
9948
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9949
0
        }
9950
0
                    buffer = tmp;
9951
0
    }
9952
0
    COPY_BUF(l,buffer,len,c);
9953
0
    NEXTL(l);
9954
0
    c = CUR_CHAR(l);
9955
0
      }
9956
0
      buffer[len] = 0;
9957
0
      return(buffer);
9958
0
  }
9959
0
    }
9960
0
    if (len == 0)
9961
0
  return(NULL);
9962
0
    return(xmlStrndup(buf, len));
9963
0
}
9964
9965
0
#define MAX_FRAC 20
9966
9967
/**
9968
 * xmlXPathStringEvalNumber:
9969
 * @str:  A string to scan
9970
 *
9971
 *  [30a]  Float  ::= Number ('e' Digits?)?
9972
 *
9973
 *  [30]   Number ::=   Digits ('.' Digits?)?
9974
 *                    | '.' Digits
9975
 *  [31]   Digits ::=   [0-9]+
9976
 *
9977
 * Compile a Number in the string
9978
 * In complement of the Number expression, this function also handles
9979
 * negative values : '-' Number.
9980
 *
9981
 * Returns the double value.
9982
 */
9983
double
9984
0
xmlXPathStringEvalNumber(const xmlChar *str) {
9985
0
    const xmlChar *cur = str;
9986
0
    double ret;
9987
0
    int ok = 0;
9988
0
    int isneg = 0;
9989
0
    int exponent = 0;
9990
0
    int is_exponent_negative = 0;
9991
0
#ifdef __GNUC__
9992
0
    unsigned long tmp = 0;
9993
0
    double temp;
9994
0
#endif
9995
0
    if (cur == NULL) return(0);
9996
0
    while (IS_BLANK_CH(*cur)) cur++;
9997
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9998
0
        return(xmlXPathNAN);
9999
0
    }
10000
0
    if (*cur == '-') {
10001
0
  isneg = 1;
10002
0
  cur++;
10003
0
    }
10004
10005
0
#ifdef __GNUC__
10006
    /*
10007
     * tmp/temp is a workaround against a gcc compiler bug
10008
     * http://veillard.com/gcc.bug
10009
     */
10010
0
    ret = 0;
10011
0
    while ((*cur >= '0') && (*cur <= '9')) {
10012
0
  ret = ret * 10;
10013
0
  tmp = (*cur - '0');
10014
0
  ok = 1;
10015
0
  cur++;
10016
0
  temp = (double) tmp;
10017
0
  ret = ret + temp;
10018
0
    }
10019
#else
10020
    ret = 0;
10021
    while ((*cur >= '0') && (*cur <= '9')) {
10022
  ret = ret * 10 + (*cur - '0');
10023
  ok = 1;
10024
  cur++;
10025
    }
10026
#endif
10027
10028
0
    if (*cur == '.') {
10029
0
  int v, frac = 0, max;
10030
0
  double fraction = 0;
10031
10032
0
        cur++;
10033
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10034
0
      return(xmlXPathNAN);
10035
0
  }
10036
0
        while (*cur == '0') {
10037
0
      frac = frac + 1;
10038
0
      cur++;
10039
0
        }
10040
0
        max = frac + MAX_FRAC;
10041
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10042
0
      v = (*cur - '0');
10043
0
      fraction = fraction * 10 + v;
10044
0
      frac = frac + 1;
10045
0
      cur++;
10046
0
  }
10047
0
  fraction /= pow(10.0, frac);
10048
0
  ret = ret + fraction;
10049
0
  while ((*cur >= '0') && (*cur <= '9'))
10050
0
      cur++;
10051
0
    }
10052
0
    if ((*cur == 'e') || (*cur == 'E')) {
10053
0
      cur++;
10054
0
      if (*cur == '-') {
10055
0
  is_exponent_negative = 1;
10056
0
  cur++;
10057
0
      } else if (*cur == '+') {
10058
0
        cur++;
10059
0
      }
10060
0
      while ((*cur >= '0') && (*cur <= '9')) {
10061
0
        if (exponent < 1000000)
10062
0
    exponent = exponent * 10 + (*cur - '0');
10063
0
  cur++;
10064
0
      }
10065
0
    }
10066
0
    while (IS_BLANK_CH(*cur)) cur++;
10067
0
    if (*cur != 0) return(xmlXPathNAN);
10068
0
    if (isneg) ret = -ret;
10069
0
    if (is_exponent_negative) exponent = -exponent;
10070
0
    ret *= pow(10.0, (double)exponent);
10071
0
    return(ret);
10072
0
}
10073
10074
/**
10075
 * xmlXPathCompNumber:
10076
 * @ctxt:  the XPath Parser context
10077
 *
10078
 *  [30]   Number ::=   Digits ('.' Digits?)?
10079
 *                    | '.' Digits
10080
 *  [31]   Digits ::=   [0-9]+
10081
 *
10082
 * Compile a Number, then push it on the stack
10083
 *
10084
 */
10085
static void
10086
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10087
0
{
10088
0
    double ret = 0.0;
10089
0
    int ok = 0;
10090
0
    int exponent = 0;
10091
0
    int is_exponent_negative = 0;
10092
0
    xmlXPathObjectPtr num;
10093
0
#ifdef __GNUC__
10094
0
    unsigned long tmp = 0;
10095
0
    double temp;
10096
0
#endif
10097
10098
0
    CHECK_ERROR;
10099
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10100
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10101
0
    }
10102
0
#ifdef __GNUC__
10103
    /*
10104
     * tmp/temp is a workaround against a gcc compiler bug
10105
     * http://veillard.com/gcc.bug
10106
     */
10107
0
    ret = 0;
10108
0
    while ((CUR >= '0') && (CUR <= '9')) {
10109
0
  ret = ret * 10;
10110
0
  tmp = (CUR - '0');
10111
0
        ok = 1;
10112
0
        NEXT;
10113
0
  temp = (double) tmp;
10114
0
  ret = ret + temp;
10115
0
    }
10116
#else
10117
    ret = 0;
10118
    while ((CUR >= '0') && (CUR <= '9')) {
10119
  ret = ret * 10 + (CUR - '0');
10120
  ok = 1;
10121
  NEXT;
10122
    }
10123
#endif
10124
0
    if (CUR == '.') {
10125
0
  int v, frac = 0, max;
10126
0
  double fraction = 0;
10127
10128
0
        NEXT;
10129
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10130
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10131
0
        }
10132
0
        while (CUR == '0') {
10133
0
            frac = frac + 1;
10134
0
            NEXT;
10135
0
        }
10136
0
        max = frac + MAX_FRAC;
10137
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10138
0
      v = (CUR - '0');
10139
0
      fraction = fraction * 10 + v;
10140
0
      frac = frac + 1;
10141
0
            NEXT;
10142
0
        }
10143
0
        fraction /= pow(10.0, frac);
10144
0
        ret = ret + fraction;
10145
0
        while ((CUR >= '0') && (CUR <= '9'))
10146
0
            NEXT;
10147
0
    }
10148
0
    if ((CUR == 'e') || (CUR == 'E')) {
10149
0
        NEXT;
10150
0
        if (CUR == '-') {
10151
0
            is_exponent_negative = 1;
10152
0
            NEXT;
10153
0
        } else if (CUR == '+') {
10154
0
      NEXT;
10155
0
  }
10156
0
        while ((CUR >= '0') && (CUR <= '9')) {
10157
0
            if (exponent < 1000000)
10158
0
                exponent = exponent * 10 + (CUR - '0');
10159
0
            NEXT;
10160
0
        }
10161
0
        if (is_exponent_negative)
10162
0
            exponent = -exponent;
10163
0
        ret *= pow(10.0, (double) exponent);
10164
0
    }
10165
0
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10166
0
    if (num == NULL) {
10167
0
  ctxt->error = XPATH_MEMORY_ERROR;
10168
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10169
0
                              NULL) == -1) {
10170
0
        xmlXPathReleaseObject(ctxt->context, num);
10171
0
    }
10172
0
}
10173
10174
/**
10175
 * xmlXPathParseLiteral:
10176
 * @ctxt:  the XPath Parser context
10177
 *
10178
 * Parse a Literal
10179
 *
10180
 *  [29]   Literal ::=   '"' [^"]* '"'
10181
 *                    | "'" [^']* "'"
10182
 *
10183
 * Returns the value found or NULL in case of error
10184
 */
10185
static xmlChar *
10186
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10187
0
    const xmlChar *q;
10188
0
    xmlChar *ret = NULL;
10189
10190
0
    if (CUR == '"') {
10191
0
        NEXT;
10192
0
  q = CUR_PTR;
10193
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10194
0
      NEXT;
10195
0
  if (!IS_CHAR_CH(CUR)) {
10196
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10197
0
  } else {
10198
0
      ret = xmlStrndup(q, CUR_PTR - q);
10199
0
      NEXT;
10200
0
        }
10201
0
    } else if (CUR == '\'') {
10202
0
        NEXT;
10203
0
  q = CUR_PTR;
10204
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10205
0
      NEXT;
10206
0
  if (!IS_CHAR_CH(CUR)) {
10207
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10208
0
  } else {
10209
0
      ret = xmlStrndup(q, CUR_PTR - q);
10210
0
      NEXT;
10211
0
        }
10212
0
    } else {
10213
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10214
0
    }
10215
0
    return(ret);
10216
0
}
10217
10218
/**
10219
 * xmlXPathCompLiteral:
10220
 * @ctxt:  the XPath Parser context
10221
 *
10222
 * Parse a Literal and push it on the stack.
10223
 *
10224
 *  [29]   Literal ::=   '"' [^"]* '"'
10225
 *                    | "'" [^']* "'"
10226
 *
10227
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10228
 */
10229
static void
10230
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10231
0
    const xmlChar *q;
10232
0
    xmlChar *ret = NULL;
10233
0
    xmlXPathObjectPtr lit;
10234
10235
0
    if (CUR == '"') {
10236
0
        NEXT;
10237
0
  q = CUR_PTR;
10238
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10239
0
      NEXT;
10240
0
  if (!IS_CHAR_CH(CUR)) {
10241
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10242
0
  } else {
10243
0
      ret = xmlStrndup(q, CUR_PTR - q);
10244
0
      NEXT;
10245
0
        }
10246
0
    } else if (CUR == '\'') {
10247
0
        NEXT;
10248
0
  q = CUR_PTR;
10249
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10250
0
      NEXT;
10251
0
  if (!IS_CHAR_CH(CUR)) {
10252
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10253
0
  } else {
10254
0
      ret = xmlStrndup(q, CUR_PTR - q);
10255
0
      NEXT;
10256
0
        }
10257
0
    } else {
10258
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10259
0
    }
10260
0
    if (ret == NULL) return;
10261
0
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10262
0
    if (lit == NULL) {
10263
0
  ctxt->error = XPATH_MEMORY_ERROR;
10264
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10265
0
                              NULL) == -1) {
10266
0
        xmlXPathReleaseObject(ctxt->context, lit);
10267
0
    }
10268
0
    xmlFree(ret);
10269
0
}
10270
10271
/**
10272
 * xmlXPathCompVariableReference:
10273
 * @ctxt:  the XPath Parser context
10274
 *
10275
 * Parse a VariableReference, evaluate it and push it on the stack.
10276
 *
10277
 * The variable bindings consist of a mapping from variable names
10278
 * to variable values. The value of a variable is an object, which can be
10279
 * of any of the types that are possible for the value of an expression,
10280
 * and may also be of additional types not specified here.
10281
 *
10282
 * Early evaluation is possible since:
10283
 * The variable bindings [...] used to evaluate a subexpression are
10284
 * always the same as those used to evaluate the containing expression.
10285
 *
10286
 *  [36]   VariableReference ::=   '$' QName
10287
 */
10288
static void
10289
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10290
0
    xmlChar *name;
10291
0
    xmlChar *prefix;
10292
10293
0
    SKIP_BLANKS;
10294
0
    if (CUR != '$') {
10295
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10296
0
    }
10297
0
    NEXT;
10298
0
    name = xmlXPathParseQName(ctxt, &prefix);
10299
0
    if (name == NULL) {
10300
0
        xmlFree(prefix);
10301
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10302
0
    }
10303
0
    ctxt->comp->last = -1;
10304
0
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10305
0
        xmlFree(prefix);
10306
0
        xmlFree(name);
10307
0
    }
10308
0
    SKIP_BLANKS;
10309
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10310
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10311
0
    }
10312
0
}
10313
10314
/**
10315
 * xmlXPathIsNodeType:
10316
 * @name:  a name string
10317
 *
10318
 * Is the name given a NodeType one.
10319
 *
10320
 *  [38]   NodeType ::=   'comment'
10321
 *                    | 'text'
10322
 *                    | 'processing-instruction'
10323
 *                    | 'node'
10324
 *
10325
 * Returns 1 if true 0 otherwise
10326
 */
10327
int
10328
0
xmlXPathIsNodeType(const xmlChar *name) {
10329
0
    if (name == NULL)
10330
0
  return(0);
10331
10332
0
    if (xmlStrEqual(name, BAD_CAST "node"))
10333
0
  return(1);
10334
0
    if (xmlStrEqual(name, BAD_CAST "text"))
10335
0
  return(1);
10336
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
10337
0
  return(1);
10338
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10339
0
  return(1);
10340
0
    return(0);
10341
0
}
10342
10343
/**
10344
 * xmlXPathCompFunctionCall:
10345
 * @ctxt:  the XPath Parser context
10346
 *
10347
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10348
 *  [17]   Argument ::=   Expr
10349
 *
10350
 * Compile a function call, the evaluation of all arguments are
10351
 * pushed on the stack
10352
 */
10353
static void
10354
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10355
0
    xmlChar *name;
10356
0
    xmlChar *prefix;
10357
0
    int nbargs = 0;
10358
0
    int sort = 1;
10359
10360
0
    name = xmlXPathParseQName(ctxt, &prefix);
10361
0
    if (name == NULL) {
10362
0
  xmlFree(prefix);
10363
0
  XP_ERROR(XPATH_EXPR_ERROR);
10364
0
    }
10365
0
    SKIP_BLANKS;
10366
#ifdef DEBUG_EXPR
10367
    if (prefix == NULL)
10368
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10369
      name);
10370
    else
10371
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10372
      prefix, name);
10373
#endif
10374
10375
0
    if (CUR != '(') {
10376
0
  xmlFree(name);
10377
0
  xmlFree(prefix);
10378
0
  XP_ERROR(XPATH_EXPR_ERROR);
10379
0
    }
10380
0
    NEXT;
10381
0
    SKIP_BLANKS;
10382
10383
    /*
10384
    * Optimization for count(): we don't need the node-set to be sorted.
10385
    */
10386
0
    if ((prefix == NULL) && (name[0] == 'c') &&
10387
0
  xmlStrEqual(name, BAD_CAST "count"))
10388
0
    {
10389
0
  sort = 0;
10390
0
    }
10391
0
    ctxt->comp->last = -1;
10392
0
    if (CUR != ')') {
10393
0
  while (CUR != 0) {
10394
0
      int op1 = ctxt->comp->last;
10395
0
      ctxt->comp->last = -1;
10396
0
      xmlXPathCompileExpr(ctxt, sort);
10397
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10398
0
    xmlFree(name);
10399
0
    xmlFree(prefix);
10400
0
    return;
10401
0
      }
10402
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10403
0
      nbargs++;
10404
0
      if (CUR == ')') break;
10405
0
      if (CUR != ',') {
10406
0
    xmlFree(name);
10407
0
    xmlFree(prefix);
10408
0
    XP_ERROR(XPATH_EXPR_ERROR);
10409
0
      }
10410
0
      NEXT;
10411
0
      SKIP_BLANKS;
10412
0
  }
10413
0
    }
10414
0
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10415
0
        xmlFree(prefix);
10416
0
        xmlFree(name);
10417
0
    }
10418
0
    NEXT;
10419
0
    SKIP_BLANKS;
10420
0
}
10421
10422
/**
10423
 * xmlXPathCompPrimaryExpr:
10424
 * @ctxt:  the XPath Parser context
10425
 *
10426
 *  [15]   PrimaryExpr ::=   VariableReference
10427
 *                | '(' Expr ')'
10428
 *                | Literal
10429
 *                | Number
10430
 *                | FunctionCall
10431
 *
10432
 * Compile a primary expression.
10433
 */
10434
static void
10435
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10436
0
    SKIP_BLANKS;
10437
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10438
0
    else if (CUR == '(') {
10439
0
  NEXT;
10440
0
  SKIP_BLANKS;
10441
0
  xmlXPathCompileExpr(ctxt, 1);
10442
0
  CHECK_ERROR;
10443
0
  if (CUR != ')') {
10444
0
      XP_ERROR(XPATH_EXPR_ERROR);
10445
0
  }
10446
0
  NEXT;
10447
0
  SKIP_BLANKS;
10448
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10449
0
  xmlXPathCompNumber(ctxt);
10450
0
    } else if ((CUR == '\'') || (CUR == '"')) {
10451
0
  xmlXPathCompLiteral(ctxt);
10452
0
    } else {
10453
0
  xmlXPathCompFunctionCall(ctxt);
10454
0
    }
10455
0
    SKIP_BLANKS;
10456
0
}
10457
10458
/**
10459
 * xmlXPathCompFilterExpr:
10460
 * @ctxt:  the XPath Parser context
10461
 *
10462
 *  [20]   FilterExpr ::=   PrimaryExpr
10463
 *               | FilterExpr Predicate
10464
 *
10465
 * Compile a filter expression.
10466
 * Square brackets are used to filter expressions in the same way that
10467
 * they are used in location paths. It is an error if the expression to
10468
 * be filtered does not evaluate to a node-set. The context node list
10469
 * used for evaluating the expression in square brackets is the node-set
10470
 * to be filtered listed in document order.
10471
 */
10472
10473
static void
10474
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10475
0
    xmlXPathCompPrimaryExpr(ctxt);
10476
0
    CHECK_ERROR;
10477
0
    SKIP_BLANKS;
10478
10479
0
    while (CUR == '[') {
10480
0
  xmlXPathCompPredicate(ctxt, 1);
10481
0
  SKIP_BLANKS;
10482
0
    }
10483
10484
10485
0
}
10486
10487
/**
10488
 * xmlXPathScanName:
10489
 * @ctxt:  the XPath Parser context
10490
 *
10491
 * Trickery: parse an XML name but without consuming the input flow
10492
 * Needed to avoid insanity in the parser state.
10493
 *
10494
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10495
 *                  CombiningChar | Extender
10496
 *
10497
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10498
 *
10499
 * [6] Names ::= Name (S Name)*
10500
 *
10501
 * Returns the Name parsed or NULL
10502
 */
10503
10504
static xmlChar *
10505
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10506
0
    int l;
10507
0
    int c;
10508
0
    const xmlChar *cur;
10509
0
    xmlChar *ret;
10510
10511
0
    cur = ctxt->cur;
10512
10513
0
    c = CUR_CHAR(l);
10514
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10515
0
  (!IS_LETTER(c) && (c != '_') &&
10516
0
         (c != ':'))) {
10517
0
  return(NULL);
10518
0
    }
10519
10520
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10521
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10522
0
            (c == '.') || (c == '-') ||
10523
0
      (c == '_') || (c == ':') ||
10524
0
      (IS_COMBINING(c)) ||
10525
0
      (IS_EXTENDER(c)))) {
10526
0
  NEXTL(l);
10527
0
  c = CUR_CHAR(l);
10528
0
    }
10529
0
    ret = xmlStrndup(cur, ctxt->cur - cur);
10530
0
    ctxt->cur = cur;
10531
0
    return(ret);
10532
0
}
10533
10534
/**
10535
 * xmlXPathCompPathExpr:
10536
 * @ctxt:  the XPath Parser context
10537
 *
10538
 *  [19]   PathExpr ::=   LocationPath
10539
 *               | FilterExpr
10540
 *               | FilterExpr '/' RelativeLocationPath
10541
 *               | FilterExpr '//' RelativeLocationPath
10542
 *
10543
 * Compile a path expression.
10544
 * The / operator and // operators combine an arbitrary expression
10545
 * and a relative location path. It is an error if the expression
10546
 * does not evaluate to a node-set.
10547
 * The / operator does composition in the same way as when / is
10548
 * used in a location path. As in location paths, // is short for
10549
 * /descendant-or-self::node()/.
10550
 */
10551
10552
static void
10553
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10554
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
10555
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10556
10557
0
    SKIP_BLANKS;
10558
0
    if ((CUR == '$') || (CUR == '(') ||
10559
0
  (IS_ASCII_DIGIT(CUR)) ||
10560
0
        (CUR == '\'') || (CUR == '"') ||
10561
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10562
0
  lc = 0;
10563
0
    } else if (CUR == '*') {
10564
  /* relative or absolute location path */
10565
0
  lc = 1;
10566
0
    } else if (CUR == '/') {
10567
  /* relative or absolute location path */
10568
0
  lc = 1;
10569
0
    } else if (CUR == '@') {
10570
  /* relative abbreviated attribute location path */
10571
0
  lc = 1;
10572
0
    } else if (CUR == '.') {
10573
  /* relative abbreviated attribute location path */
10574
0
  lc = 1;
10575
0
    } else {
10576
  /*
10577
   * Problem is finding if we have a name here whether it's:
10578
   *   - a nodetype
10579
   *   - a function call in which case it's followed by '('
10580
   *   - an axis in which case it's followed by ':'
10581
   *   - a element name
10582
   * We do an a priori analysis here rather than having to
10583
   * maintain parsed token content through the recursive function
10584
   * calls. This looks uglier but makes the code easier to
10585
   * read/write/debug.
10586
   */
10587
0
  SKIP_BLANKS;
10588
0
  name = xmlXPathScanName(ctxt);
10589
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10590
#ifdef DEBUG_STEP
10591
      xmlGenericError(xmlGenericErrorContext,
10592
        "PathExpr: Axis\n");
10593
#endif
10594
0
      lc = 1;
10595
0
      xmlFree(name);
10596
0
  } else if (name != NULL) {
10597
0
      int len =xmlStrlen(name);
10598
10599
10600
0
      while (NXT(len) != 0) {
10601
0
    if (NXT(len) == '/') {
10602
        /* element name */
10603
#ifdef DEBUG_STEP
10604
        xmlGenericError(xmlGenericErrorContext,
10605
          "PathExpr: AbbrRelLocation\n");
10606
#endif
10607
0
        lc = 1;
10608
0
        break;
10609
0
    } else if (IS_BLANK_CH(NXT(len))) {
10610
        /* ignore blanks */
10611
0
        ;
10612
0
    } else if (NXT(len) == ':') {
10613
#ifdef DEBUG_STEP
10614
        xmlGenericError(xmlGenericErrorContext,
10615
          "PathExpr: AbbrRelLocation\n");
10616
#endif
10617
0
        lc = 1;
10618
0
        break;
10619
0
    } else if ((NXT(len) == '(')) {
10620
        /* Node Type or Function */
10621
0
        if (xmlXPathIsNodeType(name)) {
10622
#ifdef DEBUG_STEP
10623
            xmlGenericError(xmlGenericErrorContext,
10624
        "PathExpr: Type search\n");
10625
#endif
10626
0
      lc = 1;
10627
#ifdef LIBXML_XPTR_LOCS_ENABLED
10628
                    } else if (ctxt->xptr &&
10629
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10630
                        lc = 1;
10631
#endif
10632
0
        } else {
10633
#ifdef DEBUG_STEP
10634
            xmlGenericError(xmlGenericErrorContext,
10635
        "PathExpr: function call\n");
10636
#endif
10637
0
      lc = 0;
10638
0
        }
10639
0
                    break;
10640
0
    } else if ((NXT(len) == '[')) {
10641
        /* element name */
10642
#ifdef DEBUG_STEP
10643
        xmlGenericError(xmlGenericErrorContext,
10644
          "PathExpr: AbbrRelLocation\n");
10645
#endif
10646
0
        lc = 1;
10647
0
        break;
10648
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10649
0
         (NXT(len) == '=')) {
10650
0
        lc = 1;
10651
0
        break;
10652
0
    } else {
10653
0
        lc = 1;
10654
0
        break;
10655
0
    }
10656
0
    len++;
10657
0
      }
10658
0
      if (NXT(len) == 0) {
10659
#ifdef DEBUG_STEP
10660
    xmlGenericError(xmlGenericErrorContext,
10661
      "PathExpr: AbbrRelLocation\n");
10662
#endif
10663
    /* element name */
10664
0
    lc = 1;
10665
0
      }
10666
0
      xmlFree(name);
10667
0
  } else {
10668
      /* make sure all cases are covered explicitly */
10669
0
      XP_ERROR(XPATH_EXPR_ERROR);
10670
0
  }
10671
0
    }
10672
10673
0
    if (lc) {
10674
0
  if (CUR == '/') {
10675
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10676
0
  } else {
10677
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10678
0
  }
10679
0
  xmlXPathCompLocationPath(ctxt);
10680
0
    } else {
10681
0
  xmlXPathCompFilterExpr(ctxt);
10682
0
  CHECK_ERROR;
10683
0
  if ((CUR == '/') && (NXT(1) == '/')) {
10684
0
      SKIP(2);
10685
0
      SKIP_BLANKS;
10686
10687
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10688
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10689
10690
0
      xmlXPathCompRelativeLocationPath(ctxt);
10691
0
  } else if (CUR == '/') {
10692
0
      xmlXPathCompRelativeLocationPath(ctxt);
10693
0
  }
10694
0
    }
10695
0
    SKIP_BLANKS;
10696
0
}
10697
10698
/**
10699
 * xmlXPathCompUnionExpr:
10700
 * @ctxt:  the XPath Parser context
10701
 *
10702
 *  [18]   UnionExpr ::=   PathExpr
10703
 *               | UnionExpr '|' PathExpr
10704
 *
10705
 * Compile an union expression.
10706
 */
10707
10708
static void
10709
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10710
0
    xmlXPathCompPathExpr(ctxt);
10711
0
    CHECK_ERROR;
10712
0
    SKIP_BLANKS;
10713
0
    while (CUR == '|') {
10714
0
  int op1 = ctxt->comp->last;
10715
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10716
10717
0
  NEXT;
10718
0
  SKIP_BLANKS;
10719
0
  xmlXPathCompPathExpr(ctxt);
10720
10721
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10722
10723
0
  SKIP_BLANKS;
10724
0
    }
10725
0
}
10726
10727
/**
10728
 * xmlXPathCompUnaryExpr:
10729
 * @ctxt:  the XPath Parser context
10730
 *
10731
 *  [27]   UnaryExpr ::=   UnionExpr
10732
 *                   | '-' UnaryExpr
10733
 *
10734
 * Compile an unary expression.
10735
 */
10736
10737
static void
10738
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10739
0
    int minus = 0;
10740
0
    int found = 0;
10741
10742
0
    SKIP_BLANKS;
10743
0
    while (CUR == '-') {
10744
0
        minus = 1 - minus;
10745
0
  found = 1;
10746
0
  NEXT;
10747
0
  SKIP_BLANKS;
10748
0
    }
10749
10750
0
    xmlXPathCompUnionExpr(ctxt);
10751
0
    CHECK_ERROR;
10752
0
    if (found) {
10753
0
  if (minus)
10754
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10755
0
  else
10756
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10757
0
    }
10758
0
}
10759
10760
/**
10761
 * xmlXPathCompMultiplicativeExpr:
10762
 * @ctxt:  the XPath Parser context
10763
 *
10764
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10765
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10766
 *                   | MultiplicativeExpr 'div' UnaryExpr
10767
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10768
 *  [34]   MultiplyOperator ::=   '*'
10769
 *
10770
 * Compile an Additive expression.
10771
 */
10772
10773
static void
10774
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10775
0
    xmlXPathCompUnaryExpr(ctxt);
10776
0
    CHECK_ERROR;
10777
0
    SKIP_BLANKS;
10778
0
    while ((CUR == '*') ||
10779
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10780
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10781
0
  int op = -1;
10782
0
  int op1 = ctxt->comp->last;
10783
10784
0
        if (CUR == '*') {
10785
0
      op = 0;
10786
0
      NEXT;
10787
0
  } else if (CUR == 'd') {
10788
0
      op = 1;
10789
0
      SKIP(3);
10790
0
  } else if (CUR == 'm') {
10791
0
      op = 2;
10792
0
      SKIP(3);
10793
0
  }
10794
0
  SKIP_BLANKS;
10795
0
        xmlXPathCompUnaryExpr(ctxt);
10796
0
  CHECK_ERROR;
10797
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10798
0
  SKIP_BLANKS;
10799
0
    }
10800
0
}
10801
10802
/**
10803
 * xmlXPathCompAdditiveExpr:
10804
 * @ctxt:  the XPath Parser context
10805
 *
10806
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10807
 *                   | AdditiveExpr '+' MultiplicativeExpr
10808
 *                   | AdditiveExpr '-' MultiplicativeExpr
10809
 *
10810
 * Compile an Additive expression.
10811
 */
10812
10813
static void
10814
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10815
10816
0
    xmlXPathCompMultiplicativeExpr(ctxt);
10817
0
    CHECK_ERROR;
10818
0
    SKIP_BLANKS;
10819
0
    while ((CUR == '+') || (CUR == '-')) {
10820
0
  int plus;
10821
0
  int op1 = ctxt->comp->last;
10822
10823
0
        if (CUR == '+') plus = 1;
10824
0
  else plus = 0;
10825
0
  NEXT;
10826
0
  SKIP_BLANKS;
10827
0
        xmlXPathCompMultiplicativeExpr(ctxt);
10828
0
  CHECK_ERROR;
10829
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10830
0
  SKIP_BLANKS;
10831
0
    }
10832
0
}
10833
10834
/**
10835
 * xmlXPathCompRelationalExpr:
10836
 * @ctxt:  the XPath Parser context
10837
 *
10838
 *  [24]   RelationalExpr ::=   AdditiveExpr
10839
 *                 | RelationalExpr '<' AdditiveExpr
10840
 *                 | RelationalExpr '>' AdditiveExpr
10841
 *                 | RelationalExpr '<=' AdditiveExpr
10842
 *                 | RelationalExpr '>=' AdditiveExpr
10843
 *
10844
 *  A <= B > C is allowed ? Answer from James, yes with
10845
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10846
 *  which is basically what got implemented.
10847
 *
10848
 * Compile a Relational expression, then push the result
10849
 * on the stack
10850
 */
10851
10852
static void
10853
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10854
0
    xmlXPathCompAdditiveExpr(ctxt);
10855
0
    CHECK_ERROR;
10856
0
    SKIP_BLANKS;
10857
0
    while ((CUR == '<') || (CUR == '>')) {
10858
0
  int inf, strict;
10859
0
  int op1 = ctxt->comp->last;
10860
10861
0
        if (CUR == '<') inf = 1;
10862
0
  else inf = 0;
10863
0
  if (NXT(1) == '=') strict = 0;
10864
0
  else strict = 1;
10865
0
  NEXT;
10866
0
  if (!strict) NEXT;
10867
0
  SKIP_BLANKS;
10868
0
        xmlXPathCompAdditiveExpr(ctxt);
10869
0
  CHECK_ERROR;
10870
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10871
0
  SKIP_BLANKS;
10872
0
    }
10873
0
}
10874
10875
/**
10876
 * xmlXPathCompEqualityExpr:
10877
 * @ctxt:  the XPath Parser context
10878
 *
10879
 *  [23]   EqualityExpr ::=   RelationalExpr
10880
 *                 | EqualityExpr '=' RelationalExpr
10881
 *                 | EqualityExpr '!=' RelationalExpr
10882
 *
10883
 *  A != B != C is allowed ? Answer from James, yes with
10884
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10885
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10886
 *  which is basically what got implemented.
10887
 *
10888
 * Compile an Equality expression.
10889
 *
10890
 */
10891
static void
10892
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10893
0
    xmlXPathCompRelationalExpr(ctxt);
10894
0
    CHECK_ERROR;
10895
0
    SKIP_BLANKS;
10896
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10897
0
  int eq;
10898
0
  int op1 = ctxt->comp->last;
10899
10900
0
        if (CUR == '=') eq = 1;
10901
0
  else eq = 0;
10902
0
  NEXT;
10903
0
  if (!eq) NEXT;
10904
0
  SKIP_BLANKS;
10905
0
        xmlXPathCompRelationalExpr(ctxt);
10906
0
  CHECK_ERROR;
10907
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10908
0
  SKIP_BLANKS;
10909
0
    }
10910
0
}
10911
10912
/**
10913
 * xmlXPathCompAndExpr:
10914
 * @ctxt:  the XPath Parser context
10915
 *
10916
 *  [22]   AndExpr ::=   EqualityExpr
10917
 *                 | AndExpr 'and' EqualityExpr
10918
 *
10919
 * Compile an AND expression.
10920
 *
10921
 */
10922
static void
10923
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10924
0
    xmlXPathCompEqualityExpr(ctxt);
10925
0
    CHECK_ERROR;
10926
0
    SKIP_BLANKS;
10927
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10928
0
  int op1 = ctxt->comp->last;
10929
0
        SKIP(3);
10930
0
  SKIP_BLANKS;
10931
0
        xmlXPathCompEqualityExpr(ctxt);
10932
0
  CHECK_ERROR;
10933
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10934
0
  SKIP_BLANKS;
10935
0
    }
10936
0
}
10937
10938
/**
10939
 * xmlXPathCompileExpr:
10940
 * @ctxt:  the XPath Parser context
10941
 *
10942
 *  [14]   Expr ::=   OrExpr
10943
 *  [21]   OrExpr ::=   AndExpr
10944
 *                 | OrExpr 'or' AndExpr
10945
 *
10946
 * Parse and compile an expression
10947
 */
10948
static void
10949
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10950
0
    xmlXPathContextPtr xpctxt = ctxt->context;
10951
10952
0
    if (xpctxt != NULL) {
10953
0
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10954
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10955
        /*
10956
         * Parsing a single '(' pushes about 10 functions on the call stack
10957
         * before recursing!
10958
         */
10959
0
        xpctxt->depth += 10;
10960
0
    }
10961
10962
0
    xmlXPathCompAndExpr(ctxt);
10963
0
    CHECK_ERROR;
10964
0
    SKIP_BLANKS;
10965
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10966
0
  int op1 = ctxt->comp->last;
10967
0
        SKIP(2);
10968
0
  SKIP_BLANKS;
10969
0
        xmlXPathCompAndExpr(ctxt);
10970
0
  CHECK_ERROR;
10971
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10972
0
  SKIP_BLANKS;
10973
0
    }
10974
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10975
  /* more ops could be optimized too */
10976
  /*
10977
  * This is the main place to eliminate sorting for
10978
  * operations which don't require a sorted node-set.
10979
  * E.g. count().
10980
  */
10981
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10982
0
    }
10983
10984
0
    if (xpctxt != NULL)
10985
0
        xpctxt->depth -= 10;
10986
0
}
10987
10988
/**
10989
 * xmlXPathCompPredicate:
10990
 * @ctxt:  the XPath Parser context
10991
 * @filter:  act as a filter
10992
 *
10993
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10994
 *  [9]   PredicateExpr ::=   Expr
10995
 *
10996
 * Compile a predicate expression
10997
 */
10998
static void
10999
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11000
0
    int op1 = ctxt->comp->last;
11001
11002
0
    SKIP_BLANKS;
11003
0
    if (CUR != '[') {
11004
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11005
0
    }
11006
0
    NEXT;
11007
0
    SKIP_BLANKS;
11008
11009
0
    ctxt->comp->last = -1;
11010
    /*
11011
    * This call to xmlXPathCompileExpr() will deactivate sorting
11012
    * of the predicate result.
11013
    * TODO: Sorting is still activated for filters, since I'm not
11014
    *  sure if needed. Normally sorting should not be needed, since
11015
    *  a filter can only diminish the number of items in a sequence,
11016
    *  but won't change its order; so if the initial sequence is sorted,
11017
    *  subsequent sorting is not needed.
11018
    */
11019
0
    if (! filter)
11020
0
  xmlXPathCompileExpr(ctxt, 0);
11021
0
    else
11022
0
  xmlXPathCompileExpr(ctxt, 1);
11023
0
    CHECK_ERROR;
11024
11025
0
    if (CUR != ']') {
11026
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11027
0
    }
11028
11029
0
    if (filter)
11030
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11031
0
    else
11032
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11033
11034
0
    NEXT;
11035
0
    SKIP_BLANKS;
11036
0
}
11037
11038
/**
11039
 * xmlXPathCompNodeTest:
11040
 * @ctxt:  the XPath Parser context
11041
 * @test:  pointer to a xmlXPathTestVal
11042
 * @type:  pointer to a xmlXPathTypeVal
11043
 * @prefix:  placeholder for a possible name prefix
11044
 *
11045
 * [7] NodeTest ::=   NameTest
11046
 *        | NodeType '(' ')'
11047
 *        | 'processing-instruction' '(' Literal ')'
11048
 *
11049
 * [37] NameTest ::=  '*'
11050
 *        | NCName ':' '*'
11051
 *        | QName
11052
 * [38] NodeType ::= 'comment'
11053
 *       | 'text'
11054
 *       | 'processing-instruction'
11055
 *       | 'node'
11056
 *
11057
 * Returns the name found and updates @test, @type and @prefix appropriately
11058
 */
11059
static xmlChar *
11060
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11061
               xmlXPathTypeVal *type, xmlChar **prefix,
11062
0
         xmlChar *name) {
11063
0
    int blanks;
11064
11065
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11066
0
  STRANGE;
11067
0
  return(NULL);
11068
0
    }
11069
0
    *type = (xmlXPathTypeVal) 0;
11070
0
    *test = (xmlXPathTestVal) 0;
11071
0
    *prefix = NULL;
11072
0
    SKIP_BLANKS;
11073
11074
0
    if ((name == NULL) && (CUR == '*')) {
11075
  /*
11076
   * All elements
11077
   */
11078
0
  NEXT;
11079
0
  *test = NODE_TEST_ALL;
11080
0
  return(NULL);
11081
0
    }
11082
11083
0
    if (name == NULL)
11084
0
  name = xmlXPathParseNCName(ctxt);
11085
0
    if (name == NULL) {
11086
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11087
0
    }
11088
11089
0
    blanks = IS_BLANK_CH(CUR);
11090
0
    SKIP_BLANKS;
11091
0
    if (CUR == '(') {
11092
0
  NEXT;
11093
  /*
11094
   * NodeType or PI search
11095
   */
11096
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
11097
0
      *type = NODE_TYPE_COMMENT;
11098
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
11099
0
      *type = NODE_TYPE_NODE;
11100
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11101
0
      *type = NODE_TYPE_PI;
11102
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
11103
0
      *type = NODE_TYPE_TEXT;
11104
0
  else {
11105
0
      if (name != NULL)
11106
0
    xmlFree(name);
11107
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11108
0
  }
11109
11110
0
  *test = NODE_TEST_TYPE;
11111
11112
0
  SKIP_BLANKS;
11113
0
  if (*type == NODE_TYPE_PI) {
11114
      /*
11115
       * Specific case: search a PI by name.
11116
       */
11117
0
      if (name != NULL)
11118
0
    xmlFree(name);
11119
0
      name = NULL;
11120
0
      if (CUR != ')') {
11121
0
    name = xmlXPathParseLiteral(ctxt);
11122
0
                if (name == NULL) {
11123
0
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11124
0
                }
11125
0
    *test = NODE_TEST_PI;
11126
0
    SKIP_BLANKS;
11127
0
      }
11128
0
  }
11129
0
  if (CUR != ')') {
11130
0
      if (name != NULL)
11131
0
    xmlFree(name);
11132
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11133
0
  }
11134
0
  NEXT;
11135
0
  return(name);
11136
0
    }
11137
0
    *test = NODE_TEST_NAME;
11138
0
    if ((!blanks) && (CUR == ':')) {
11139
0
  NEXT;
11140
11141
  /*
11142
   * Since currently the parser context don't have a
11143
   * namespace list associated:
11144
   * The namespace name for this prefix can be computed
11145
   * only at evaluation time. The compilation is done
11146
   * outside of any context.
11147
   */
11148
#if 0
11149
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11150
  if (name != NULL)
11151
      xmlFree(name);
11152
  if (*prefix == NULL) {
11153
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11154
  }
11155
#else
11156
0
  *prefix = name;
11157
0
#endif
11158
11159
0
  if (CUR == '*') {
11160
      /*
11161
       * All elements
11162
       */
11163
0
      NEXT;
11164
0
      *test = NODE_TEST_ALL;
11165
0
      return(NULL);
11166
0
  }
11167
11168
0
  name = xmlXPathParseNCName(ctxt);
11169
0
  if (name == NULL) {
11170
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11171
0
  }
11172
0
    }
11173
0
    return(name);
11174
0
}
11175
11176
/**
11177
 * xmlXPathIsAxisName:
11178
 * @name:  a preparsed name token
11179
 *
11180
 * [6] AxisName ::=   'ancestor'
11181
 *                  | 'ancestor-or-self'
11182
 *                  | 'attribute'
11183
 *                  | 'child'
11184
 *                  | 'descendant'
11185
 *                  | 'descendant-or-self'
11186
 *                  | 'following'
11187
 *                  | 'following-sibling'
11188
 *                  | 'namespace'
11189
 *                  | 'parent'
11190
 *                  | 'preceding'
11191
 *                  | 'preceding-sibling'
11192
 *                  | 'self'
11193
 *
11194
 * Returns the axis or 0
11195
 */
11196
static xmlXPathAxisVal
11197
0
xmlXPathIsAxisName(const xmlChar *name) {
11198
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11199
0
    switch (name[0]) {
11200
0
  case 'a':
11201
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11202
0
    ret = AXIS_ANCESTOR;
11203
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11204
0
    ret = AXIS_ANCESTOR_OR_SELF;
11205
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11206
0
    ret = AXIS_ATTRIBUTE;
11207
0
      break;
11208
0
  case 'c':
11209
0
      if (xmlStrEqual(name, BAD_CAST "child"))
11210
0
    ret = AXIS_CHILD;
11211
0
      break;
11212
0
  case 'd':
11213
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11214
0
    ret = AXIS_DESCENDANT;
11215
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11216
0
    ret = AXIS_DESCENDANT_OR_SELF;
11217
0
      break;
11218
0
  case 'f':
11219
0
      if (xmlStrEqual(name, BAD_CAST "following"))
11220
0
    ret = AXIS_FOLLOWING;
11221
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11222
0
    ret = AXIS_FOLLOWING_SIBLING;
11223
0
      break;
11224
0
  case 'n':
11225
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11226
0
    ret = AXIS_NAMESPACE;
11227
0
      break;
11228
0
  case 'p':
11229
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
11230
0
    ret = AXIS_PARENT;
11231
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11232
0
    ret = AXIS_PRECEDING;
11233
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11234
0
    ret = AXIS_PRECEDING_SIBLING;
11235
0
      break;
11236
0
  case 's':
11237
0
      if (xmlStrEqual(name, BAD_CAST "self"))
11238
0
    ret = AXIS_SELF;
11239
0
      break;
11240
0
    }
11241
0
    return(ret);
11242
0
}
11243
11244
/**
11245
 * xmlXPathCompStep:
11246
 * @ctxt:  the XPath Parser context
11247
 *
11248
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11249
 *                  | AbbreviatedStep
11250
 *
11251
 * [12] AbbreviatedStep ::=   '.' | '..'
11252
 *
11253
 * [5] AxisSpecifier ::= AxisName '::'
11254
 *                  | AbbreviatedAxisSpecifier
11255
 *
11256
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11257
 *
11258
 * Modified for XPtr range support as:
11259
 *
11260
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11261
 *                     | AbbreviatedStep
11262
 *                     | 'range-to' '(' Expr ')' Predicate*
11263
 *
11264
 * Compile one step in a Location Path
11265
 * A location step of . is short for self::node(). This is
11266
 * particularly useful in conjunction with //. For example, the
11267
 * location path .//para is short for
11268
 * self::node()/descendant-or-self::node()/child::para
11269
 * and so will select all para descendant elements of the context
11270
 * node.
11271
 * Similarly, a location step of .. is short for parent::node().
11272
 * For example, ../title is short for parent::node()/child::title
11273
 * and so will select the title children of the parent of the context
11274
 * node.
11275
 */
11276
static void
11277
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11278
#ifdef LIBXML_XPTR_LOCS_ENABLED
11279
    int rangeto = 0;
11280
    int op2 = -1;
11281
#endif
11282
11283
0
    SKIP_BLANKS;
11284
0
    if ((CUR == '.') && (NXT(1) == '.')) {
11285
0
  SKIP(2);
11286
0
  SKIP_BLANKS;
11287
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11288
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11289
0
    } else if (CUR == '.') {
11290
0
  NEXT;
11291
0
  SKIP_BLANKS;
11292
0
    } else {
11293
0
  xmlChar *name = NULL;
11294
0
  xmlChar *prefix = NULL;
11295
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11296
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11297
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11298
0
  int op1;
11299
11300
  /*
11301
   * The modification needed for XPointer change to the production
11302
   */
11303
#ifdef LIBXML_XPTR_LOCS_ENABLED
11304
  if (ctxt->xptr) {
11305
      name = xmlXPathParseNCName(ctxt);
11306
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11307
                op2 = ctxt->comp->last;
11308
    xmlFree(name);
11309
    SKIP_BLANKS;
11310
    if (CUR != '(') {
11311
        XP_ERROR(XPATH_EXPR_ERROR);
11312
    }
11313
    NEXT;
11314
    SKIP_BLANKS;
11315
11316
    xmlXPathCompileExpr(ctxt, 1);
11317
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11318
    CHECK_ERROR;
11319
11320
    SKIP_BLANKS;
11321
    if (CUR != ')') {
11322
        XP_ERROR(XPATH_EXPR_ERROR);
11323
    }
11324
    NEXT;
11325
    rangeto = 1;
11326
    goto eval_predicates;
11327
      }
11328
  }
11329
#endif
11330
0
  if (CUR == '*') {
11331
0
      axis = AXIS_CHILD;
11332
0
  } else {
11333
0
      if (name == NULL)
11334
0
    name = xmlXPathParseNCName(ctxt);
11335
0
      if (name != NULL) {
11336
0
    axis = xmlXPathIsAxisName(name);
11337
0
    if (axis != 0) {
11338
0
        SKIP_BLANKS;
11339
0
        if ((CUR == ':') && (NXT(1) == ':')) {
11340
0
      SKIP(2);
11341
0
      xmlFree(name);
11342
0
      name = NULL;
11343
0
        } else {
11344
      /* an element name can conflict with an axis one :-\ */
11345
0
      axis = AXIS_CHILD;
11346
0
        }
11347
0
    } else {
11348
0
        axis = AXIS_CHILD;
11349
0
    }
11350
0
      } else if (CUR == '@') {
11351
0
    NEXT;
11352
0
    axis = AXIS_ATTRIBUTE;
11353
0
      } else {
11354
0
    axis = AXIS_CHILD;
11355
0
      }
11356
0
  }
11357
11358
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11359
0
            xmlFree(name);
11360
0
            return;
11361
0
        }
11362
11363
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11364
0
  if (test == 0)
11365
0
      return;
11366
11367
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11368
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11369
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11370
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11371
0
      }
11372
0
  }
11373
#ifdef DEBUG_STEP
11374
  xmlGenericError(xmlGenericErrorContext,
11375
    "Basis : computing new set\n");
11376
#endif
11377
11378
#ifdef DEBUG_STEP
11379
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11380
  if (ctxt->value == NULL)
11381
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11382
  else if (ctxt->value->nodesetval == NULL)
11383
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11384
  else
11385
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11386
#endif
11387
11388
#ifdef LIBXML_XPTR_LOCS_ENABLED
11389
eval_predicates:
11390
#endif
11391
0
  op1 = ctxt->comp->last;
11392
0
  ctxt->comp->last = -1;
11393
11394
0
  SKIP_BLANKS;
11395
0
  while (CUR == '[') {
11396
0
      xmlXPathCompPredicate(ctxt, 0);
11397
0
  }
11398
11399
#ifdef LIBXML_XPTR_LOCS_ENABLED
11400
  if (rangeto) {
11401
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11402
  } else
11403
#endif
11404
0
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11405
0
                           test, type, (void *)prefix, (void *)name) == -1) {
11406
0
            xmlFree(prefix);
11407
0
            xmlFree(name);
11408
0
        }
11409
0
    }
11410
#ifdef DEBUG_STEP
11411
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11412
    if (ctxt->value == NULL)
11413
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11414
    else if (ctxt->value->nodesetval == NULL)
11415
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11416
    else
11417
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11418
    ctxt->value->nodesetval);
11419
#endif
11420
0
}
11421
11422
/**
11423
 * xmlXPathCompRelativeLocationPath:
11424
 * @ctxt:  the XPath Parser context
11425
 *
11426
 *  [3]   RelativeLocationPath ::=   Step
11427
 *                     | RelativeLocationPath '/' Step
11428
 *                     | AbbreviatedRelativeLocationPath
11429
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11430
 *
11431
 * Compile a relative location path.
11432
 */
11433
static void
11434
xmlXPathCompRelativeLocationPath
11435
0
(xmlXPathParserContextPtr ctxt) {
11436
0
    SKIP_BLANKS;
11437
0
    if ((CUR == '/') && (NXT(1) == '/')) {
11438
0
  SKIP(2);
11439
0
  SKIP_BLANKS;
11440
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11441
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11442
0
    } else if (CUR == '/') {
11443
0
      NEXT;
11444
0
  SKIP_BLANKS;
11445
0
    }
11446
0
    xmlXPathCompStep(ctxt);
11447
0
    CHECK_ERROR;
11448
0
    SKIP_BLANKS;
11449
0
    while (CUR == '/') {
11450
0
  if ((CUR == '/') && (NXT(1) == '/')) {
11451
0
      SKIP(2);
11452
0
      SKIP_BLANKS;
11453
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11454
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11455
0
      xmlXPathCompStep(ctxt);
11456
0
  } else if (CUR == '/') {
11457
0
      NEXT;
11458
0
      SKIP_BLANKS;
11459
0
      xmlXPathCompStep(ctxt);
11460
0
  }
11461
0
  SKIP_BLANKS;
11462
0
    }
11463
0
}
11464
11465
/**
11466
 * xmlXPathCompLocationPath:
11467
 * @ctxt:  the XPath Parser context
11468
 *
11469
 *  [1]   LocationPath ::=   RelativeLocationPath
11470
 *                     | AbsoluteLocationPath
11471
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11472
 *                     | AbbreviatedAbsoluteLocationPath
11473
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11474
 *                           '//' RelativeLocationPath
11475
 *
11476
 * Compile a location path
11477
 *
11478
 * // is short for /descendant-or-self::node()/. For example,
11479
 * //para is short for /descendant-or-self::node()/child::para and
11480
 * so will select any para element in the document (even a para element
11481
 * that is a document element will be selected by //para since the
11482
 * document element node is a child of the root node); div//para is
11483
 * short for div/descendant-or-self::node()/child::para and so will
11484
 * select all para descendants of div children.
11485
 */
11486
static void
11487
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11488
0
    SKIP_BLANKS;
11489
0
    if (CUR != '/') {
11490
0
        xmlXPathCompRelativeLocationPath(ctxt);
11491
0
    } else {
11492
0
  while (CUR == '/') {
11493
0
      if ((CUR == '/') && (NXT(1) == '/')) {
11494
0
    SKIP(2);
11495
0
    SKIP_BLANKS;
11496
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11497
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11498
0
    xmlXPathCompRelativeLocationPath(ctxt);
11499
0
      } else if (CUR == '/') {
11500
0
    NEXT;
11501
0
    SKIP_BLANKS;
11502
0
    if ((CUR != 0 ) &&
11503
0
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11504
0
         (CUR == '@') || (CUR == '*')))
11505
0
        xmlXPathCompRelativeLocationPath(ctxt);
11506
0
      }
11507
0
      CHECK_ERROR;
11508
0
  }
11509
0
    }
11510
0
}
11511
11512
/************************************************************************
11513
 *                  *
11514
 *    XPath precompiled expression evaluation     *
11515
 *                  *
11516
 ************************************************************************/
11517
11518
static int
11519
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11520
11521
#ifdef DEBUG_STEP
11522
static void
11523
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11524
        int nbNodes)
11525
{
11526
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11527
    switch (op->value) {
11528
        case AXIS_ANCESTOR:
11529
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11530
            break;
11531
        case AXIS_ANCESTOR_OR_SELF:
11532
            xmlGenericError(xmlGenericErrorContext,
11533
                            "axis 'ancestors-or-self' ");
11534
            break;
11535
        case AXIS_ATTRIBUTE:
11536
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11537
            break;
11538
        case AXIS_CHILD:
11539
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11540
            break;
11541
        case AXIS_DESCENDANT:
11542
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11543
            break;
11544
        case AXIS_DESCENDANT_OR_SELF:
11545
            xmlGenericError(xmlGenericErrorContext,
11546
                            "axis 'descendant-or-self' ");
11547
            break;
11548
        case AXIS_FOLLOWING:
11549
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11550
            break;
11551
        case AXIS_FOLLOWING_SIBLING:
11552
            xmlGenericError(xmlGenericErrorContext,
11553
                            "axis 'following-siblings' ");
11554
            break;
11555
        case AXIS_NAMESPACE:
11556
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11557
            break;
11558
        case AXIS_PARENT:
11559
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11560
            break;
11561
        case AXIS_PRECEDING:
11562
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11563
            break;
11564
        case AXIS_PRECEDING_SIBLING:
11565
            xmlGenericError(xmlGenericErrorContext,
11566
                            "axis 'preceding-sibling' ");
11567
            break;
11568
        case AXIS_SELF:
11569
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11570
            break;
11571
    }
11572
    xmlGenericError(xmlGenericErrorContext,
11573
  " context contains %d nodes\n", nbNodes);
11574
    switch (op->value2) {
11575
        case NODE_TEST_NONE:
11576
            xmlGenericError(xmlGenericErrorContext,
11577
                            "           searching for none !!!\n");
11578
            break;
11579
        case NODE_TEST_TYPE:
11580
            xmlGenericError(xmlGenericErrorContext,
11581
                            "           searching for type %d\n", op->value3);
11582
            break;
11583
        case NODE_TEST_PI:
11584
            xmlGenericError(xmlGenericErrorContext,
11585
                            "           searching for PI !!!\n");
11586
            break;
11587
        case NODE_TEST_ALL:
11588
            xmlGenericError(xmlGenericErrorContext,
11589
                            "           searching for *\n");
11590
            break;
11591
        case NODE_TEST_NS:
11592
            xmlGenericError(xmlGenericErrorContext,
11593
                            "           searching for namespace %s\n",
11594
                            op->value5);
11595
            break;
11596
        case NODE_TEST_NAME:
11597
            xmlGenericError(xmlGenericErrorContext,
11598
                            "           searching for name %s\n", op->value5);
11599
            if (op->value4)
11600
                xmlGenericError(xmlGenericErrorContext,
11601
                                "           with namespace %s\n", op->value4);
11602
            break;
11603
    }
11604
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11605
}
11606
#endif /* DEBUG_STEP */
11607
11608
/**
11609
 * xmlXPathNodeSetFilter:
11610
 * @ctxt:  the XPath Parser context
11611
 * @set: the node set to filter
11612
 * @filterOpIndex: the index of the predicate/filter op
11613
 * @minPos: minimum position in the filtered set (1-based)
11614
 * @maxPos: maximum position in the filtered set (1-based)
11615
 * @hasNsNodes: true if the node set may contain namespace nodes
11616
 *
11617
 * Filter a node set, keeping only nodes for which the predicate expression
11618
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11619
 * filtered result.
11620
 */
11621
static void
11622
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11623
          xmlNodeSetPtr set,
11624
          int filterOpIndex,
11625
                      int minPos, int maxPos,
11626
          int hasNsNodes)
11627
0
{
11628
0
    xmlXPathContextPtr xpctxt;
11629
0
    xmlNodePtr oldnode;
11630
0
    xmlDocPtr olddoc;
11631
0
    xmlXPathStepOpPtr filterOp;
11632
0
    int oldcs, oldpp;
11633
0
    int i, j, pos;
11634
11635
0
    if ((set == NULL) || (set->nodeNr == 0))
11636
0
        return;
11637
11638
    /*
11639
    * Check if the node set contains a sufficient number of nodes for
11640
    * the requested range.
11641
    */
11642
0
    if (set->nodeNr < minPos) {
11643
0
        xmlXPathNodeSetClear(set, hasNsNodes);
11644
0
        return;
11645
0
    }
11646
11647
0
    xpctxt = ctxt->context;
11648
0
    oldnode = xpctxt->node;
11649
0
    olddoc = xpctxt->doc;
11650
0
    oldcs = xpctxt->contextSize;
11651
0
    oldpp = xpctxt->proximityPosition;
11652
0
    filterOp = &ctxt->comp->steps[filterOpIndex];
11653
11654
0
    xpctxt->contextSize = set->nodeNr;
11655
11656
0
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11657
0
        xmlNodePtr node = set->nodeTab[i];
11658
0
        int res;
11659
11660
0
        xpctxt->node = node;
11661
0
        xpctxt->proximityPosition = i + 1;
11662
11663
        /*
11664
        * Also set the xpath document in case things like
11665
        * key() are evaluated in the predicate.
11666
        *
11667
        * TODO: Get real doc for namespace nodes.
11668
        */
11669
0
        if ((node->type != XML_NAMESPACE_DECL) &&
11670
0
            (node->doc != NULL))
11671
0
            xpctxt->doc = node->doc;
11672
11673
0
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11674
11675
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
11676
0
            break;
11677
0
        if (res < 0) {
11678
            /* Shouldn't happen */
11679
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11680
0
            break;
11681
0
        }
11682
11683
0
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11684
0
            if (i != j) {
11685
0
                set->nodeTab[j] = node;
11686
0
                set->nodeTab[i] = NULL;
11687
0
            }
11688
11689
0
            j += 1;
11690
0
        } else {
11691
            /* Remove the entry from the initial node set. */
11692
0
            set->nodeTab[i] = NULL;
11693
0
            if (node->type == XML_NAMESPACE_DECL)
11694
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11695
0
        }
11696
11697
0
        if (res != 0) {
11698
0
            if (pos == maxPos) {
11699
0
                i += 1;
11700
0
                break;
11701
0
            }
11702
11703
0
            pos += 1;
11704
0
        }
11705
0
    }
11706
11707
    /* Free remaining nodes. */
11708
0
    if (hasNsNodes) {
11709
0
        for (; i < set->nodeNr; i++) {
11710
0
            xmlNodePtr node = set->nodeTab[i];
11711
0
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11712
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11713
0
        }
11714
0
    }
11715
11716
0
    set->nodeNr = j;
11717
11718
    /* If too many elements were removed, shrink table to preserve memory. */
11719
0
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11720
0
        (set->nodeNr < set->nodeMax / 2)) {
11721
0
        xmlNodePtr *tmp;
11722
0
        int nodeMax = set->nodeNr;
11723
11724
0
        if (nodeMax < XML_NODESET_DEFAULT)
11725
0
            nodeMax = XML_NODESET_DEFAULT;
11726
0
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11727
0
                nodeMax * sizeof(xmlNodePtr));
11728
0
        if (tmp == NULL) {
11729
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11730
0
        } else {
11731
0
            set->nodeTab = tmp;
11732
0
            set->nodeMax = nodeMax;
11733
0
        }
11734
0
    }
11735
11736
0
    xpctxt->node = oldnode;
11737
0
    xpctxt->doc = olddoc;
11738
0
    xpctxt->contextSize = oldcs;
11739
0
    xpctxt->proximityPosition = oldpp;
11740
0
}
11741
11742
#ifdef LIBXML_XPTR_LOCS_ENABLED
11743
/**
11744
 * xmlXPathLocationSetFilter:
11745
 * @ctxt:  the XPath Parser context
11746
 * @locset: the location set to filter
11747
 * @filterOpIndex: the index of the predicate/filter op
11748
 * @minPos: minimum position in the filtered set (1-based)
11749
 * @maxPos: maximum position in the filtered set (1-based)
11750
 *
11751
 * Filter a location set, keeping only nodes for which the predicate
11752
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11753
 * in the filtered result.
11754
 */
11755
static void
11756
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11757
              xmlLocationSetPtr locset,
11758
              int filterOpIndex,
11759
                          int minPos, int maxPos)
11760
{
11761
    xmlXPathContextPtr xpctxt;
11762
    xmlNodePtr oldnode;
11763
    xmlDocPtr olddoc;
11764
    xmlXPathStepOpPtr filterOp;
11765
    int oldcs, oldpp;
11766
    int i, j, pos;
11767
11768
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11769
        return;
11770
11771
    xpctxt = ctxt->context;
11772
    oldnode = xpctxt->node;
11773
    olddoc = xpctxt->doc;
11774
    oldcs = xpctxt->contextSize;
11775
    oldpp = xpctxt->proximityPosition;
11776
    filterOp = &ctxt->comp->steps[filterOpIndex];
11777
11778
    xpctxt->contextSize = locset->locNr;
11779
11780
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11781
        xmlNodePtr contextNode = locset->locTab[i]->user;
11782
        int res;
11783
11784
        xpctxt->node = contextNode;
11785
        xpctxt->proximityPosition = i + 1;
11786
11787
        /*
11788
        * Also set the xpath document in case things like
11789
        * key() are evaluated in the predicate.
11790
        *
11791
        * TODO: Get real doc for namespace nodes.
11792
        */
11793
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11794
            (contextNode->doc != NULL))
11795
            xpctxt->doc = contextNode->doc;
11796
11797
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11798
11799
        if (ctxt->error != XPATH_EXPRESSION_OK)
11800
            break;
11801
        if (res < 0) {
11802
            /* Shouldn't happen */
11803
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11804
            break;
11805
        }
11806
11807
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11808
            if (i != j) {
11809
                locset->locTab[j] = locset->locTab[i];
11810
                locset->locTab[i] = NULL;
11811
            }
11812
11813
            j += 1;
11814
        } else {
11815
            /* Remove the entry from the initial location set. */
11816
            xmlXPathFreeObject(locset->locTab[i]);
11817
            locset->locTab[i] = NULL;
11818
        }
11819
11820
        if (res != 0) {
11821
            if (pos == maxPos) {
11822
                i += 1;
11823
                break;
11824
            }
11825
11826
            pos += 1;
11827
        }
11828
    }
11829
11830
    /* Free remaining nodes. */
11831
    for (; i < locset->locNr; i++)
11832
        xmlXPathFreeObject(locset->locTab[i]);
11833
11834
    locset->locNr = j;
11835
11836
    /* If too many elements were removed, shrink table to preserve memory. */
11837
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11838
        (locset->locNr < locset->locMax / 2)) {
11839
        xmlXPathObjectPtr *tmp;
11840
        int locMax = locset->locNr;
11841
11842
        if (locMax < XML_NODESET_DEFAULT)
11843
            locMax = XML_NODESET_DEFAULT;
11844
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11845
                locMax * sizeof(xmlXPathObjectPtr));
11846
        if (tmp == NULL) {
11847
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11848
        } else {
11849
            locset->locTab = tmp;
11850
            locset->locMax = locMax;
11851
        }
11852
    }
11853
11854
    xpctxt->node = oldnode;
11855
    xpctxt->doc = olddoc;
11856
    xpctxt->contextSize = oldcs;
11857
    xpctxt->proximityPosition = oldpp;
11858
}
11859
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11860
11861
/**
11862
 * xmlXPathCompOpEvalPredicate:
11863
 * @ctxt:  the XPath Parser context
11864
 * @op: the predicate op
11865
 * @set: the node set to filter
11866
 * @minPos: minimum position in the filtered set (1-based)
11867
 * @maxPos: maximum position in the filtered set (1-based)
11868
 * @hasNsNodes: true if the node set may contain namespace nodes
11869
 *
11870
 * Filter a node set, keeping only nodes for which the sequence of predicate
11871
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11872
 * in the filtered result.
11873
 */
11874
static void
11875
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11876
          xmlXPathStepOpPtr op,
11877
          xmlNodeSetPtr set,
11878
                            int minPos, int maxPos,
11879
          int hasNsNodes)
11880
0
{
11881
0
    if (op->ch1 != -1) {
11882
0
  xmlXPathCompExprPtr comp = ctxt->comp;
11883
  /*
11884
  * Process inner predicates first.
11885
  */
11886
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11887
0
            xmlGenericError(xmlGenericErrorContext,
11888
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11889
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11890
0
  }
11891
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11892
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11893
0
        ctxt->context->depth += 1;
11894
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11895
0
                                    1, set->nodeNr, hasNsNodes);
11896
0
        ctxt->context->depth -= 1;
11897
0
  CHECK_ERROR;
11898
0
    }
11899
11900
0
    if (op->ch2 != -1)
11901
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11902
0
}
11903
11904
static int
11905
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11906
          xmlXPathStepOpPtr op,
11907
          int *maxPos)
11908
0
{
11909
11910
0
    xmlXPathStepOpPtr exprOp;
11911
11912
    /*
11913
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11914
    */
11915
11916
    /*
11917
    * If not -1, then ch1 will point to:
11918
    * 1) For predicates (XPATH_OP_PREDICATE):
11919
    *    - an inner predicate operator
11920
    * 2) For filters (XPATH_OP_FILTER):
11921
    *    - an inner filter operator OR
11922
    *    - an expression selecting the node set.
11923
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11924
    */
11925
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11926
0
  return(0);
11927
11928
0
    if (op->ch2 != -1) {
11929
0
  exprOp = &ctxt->comp->steps[op->ch2];
11930
0
    } else
11931
0
  return(0);
11932
11933
0
    if ((exprOp != NULL) &&
11934
0
  (exprOp->op == XPATH_OP_VALUE) &&
11935
0
  (exprOp->value4 != NULL) &&
11936
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11937
0
    {
11938
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11939
11940
  /*
11941
  * We have a "[n]" predicate here.
11942
  * TODO: Unfortunately this simplistic test here is not
11943
  * able to detect a position() predicate in compound
11944
  * expressions like "[@attr = 'a" and position() = 1],
11945
  * and even not the usage of position() in
11946
  * "[position() = 1]"; thus - obviously - a position-range,
11947
  * like it "[position() < 5]", is also not detected.
11948
  * Maybe we could rewrite the AST to ease the optimization.
11949
  */
11950
11951
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11952
0
      *maxPos = (int) floatval;
11953
0
            if (floatval == (double) *maxPos)
11954
0
                return(1);
11955
0
        }
11956
0
    }
11957
0
    return(0);
11958
0
}
11959
11960
static int
11961
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11962
                           xmlXPathStepOpPtr op,
11963
         xmlNodePtr * first, xmlNodePtr * last,
11964
         int toBool)
11965
0
{
11966
11967
0
#define XP_TEST_HIT \
11968
0
    if (hasAxisRange != 0) { \
11969
0
  if (++pos == maxPos) { \
11970
0
      if (addNode(seq, cur) < 0) \
11971
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11972
0
      goto axis_range_end; } \
11973
0
    } else { \
11974
0
  if (addNode(seq, cur) < 0) \
11975
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11976
0
  if (breakOnFirstHit) goto first_hit; }
11977
11978
0
#define XP_TEST_HIT_NS \
11979
0
    if (hasAxisRange != 0) { \
11980
0
  if (++pos == maxPos) { \
11981
0
      hasNsNodes = 1; \
11982
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11983
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11984
0
  goto axis_range_end; } \
11985
0
    } else { \
11986
0
  hasNsNodes = 1; \
11987
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11988
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11989
0
  if (breakOnFirstHit) goto first_hit; }
11990
11991
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11992
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11993
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11994
0
    const xmlChar *prefix = op->value4;
11995
0
    const xmlChar *name = op->value5;
11996
0
    const xmlChar *URI = NULL;
11997
11998
#ifdef DEBUG_STEP
11999
    int nbMatches = 0, prevMatches = 0;
12000
#endif
12001
0
    int total = 0, hasNsNodes = 0;
12002
    /* The popped object holding the context nodes */
12003
0
    xmlXPathObjectPtr obj;
12004
    /* The set of context nodes for the node tests */
12005
0
    xmlNodeSetPtr contextSeq;
12006
0
    int contextIdx;
12007
0
    xmlNodePtr contextNode;
12008
    /* The final resulting node set wrt to all context nodes */
12009
0
    xmlNodeSetPtr outSeq;
12010
    /*
12011
    * The temporary resulting node set wrt 1 context node.
12012
    * Used to feed predicate evaluation.
12013
    */
12014
0
    xmlNodeSetPtr seq;
12015
0
    xmlNodePtr cur;
12016
    /* First predicate operator */
12017
0
    xmlXPathStepOpPtr predOp;
12018
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12019
0
    int hasPredicateRange, hasAxisRange, pos;
12020
0
    int breakOnFirstHit;
12021
12022
0
    xmlXPathTraversalFunction next = NULL;
12023
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12024
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
12025
0
    xmlNodePtr oldContextNode;
12026
0
    xmlXPathContextPtr xpctxt = ctxt->context;
12027
12028
12029
0
    CHECK_TYPE0(XPATH_NODESET);
12030
0
    obj = valuePop(ctxt);
12031
    /*
12032
    * Setup namespaces.
12033
    */
12034
0
    if (prefix != NULL) {
12035
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
12036
0
        if (URI == NULL) {
12037
0
      xmlXPathReleaseObject(xpctxt, obj);
12038
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12039
0
  }
12040
0
    }
12041
    /*
12042
    * Setup axis.
12043
    *
12044
    * MAYBE FUTURE TODO: merging optimizations:
12045
    * - If the nodes to be traversed wrt to the initial nodes and
12046
    *   the current axis cannot overlap, then we could avoid searching
12047
    *   for duplicates during the merge.
12048
    *   But the question is how/when to evaluate if they cannot overlap.
12049
    *   Example: if we know that for two initial nodes, the one is
12050
    *   not in the ancestor-or-self axis of the other, then we could safely
12051
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12052
    *   the descendant-or-self axis.
12053
    */
12054
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12055
0
    switch (axis) {
12056
0
        case AXIS_ANCESTOR:
12057
0
            first = NULL;
12058
0
            next = xmlXPathNextAncestor;
12059
0
            break;
12060
0
        case AXIS_ANCESTOR_OR_SELF:
12061
0
            first = NULL;
12062
0
            next = xmlXPathNextAncestorOrSelf;
12063
0
            break;
12064
0
        case AXIS_ATTRIBUTE:
12065
0
            first = NULL;
12066
0
      last = NULL;
12067
0
            next = xmlXPathNextAttribute;
12068
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12069
0
            break;
12070
0
        case AXIS_CHILD:
12071
0
      last = NULL;
12072
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12073
0
    (type == NODE_TYPE_NODE))
12074
0
      {
12075
    /*
12076
    * Optimization if an element node type is 'element'.
12077
    */
12078
0
    next = xmlXPathNextChildElement;
12079
0
      } else
12080
0
    next = xmlXPathNextChild;
12081
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12082
0
            break;
12083
0
        case AXIS_DESCENDANT:
12084
0
      last = NULL;
12085
0
            next = xmlXPathNextDescendant;
12086
0
            break;
12087
0
        case AXIS_DESCENDANT_OR_SELF:
12088
0
      last = NULL;
12089
0
            next = xmlXPathNextDescendantOrSelf;
12090
0
            break;
12091
0
        case AXIS_FOLLOWING:
12092
0
      last = NULL;
12093
0
            next = xmlXPathNextFollowing;
12094
0
            break;
12095
0
        case AXIS_FOLLOWING_SIBLING:
12096
0
      last = NULL;
12097
0
            next = xmlXPathNextFollowingSibling;
12098
0
            break;
12099
0
        case AXIS_NAMESPACE:
12100
0
            first = NULL;
12101
0
      last = NULL;
12102
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12103
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12104
0
            break;
12105
0
        case AXIS_PARENT:
12106
0
            first = NULL;
12107
0
            next = xmlXPathNextParent;
12108
0
            break;
12109
0
        case AXIS_PRECEDING:
12110
0
            first = NULL;
12111
0
            next = xmlXPathNextPrecedingInternal;
12112
0
            break;
12113
0
        case AXIS_PRECEDING_SIBLING:
12114
0
            first = NULL;
12115
0
            next = xmlXPathNextPrecedingSibling;
12116
0
            break;
12117
0
        case AXIS_SELF:
12118
0
            first = NULL;
12119
0
      last = NULL;
12120
0
            next = xmlXPathNextSelf;
12121
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12122
0
            break;
12123
0
    }
12124
12125
#ifdef DEBUG_STEP
12126
    xmlXPathDebugDumpStepAxis(op,
12127
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12128
#endif
12129
12130
0
    if (next == NULL) {
12131
0
  xmlXPathReleaseObject(xpctxt, obj);
12132
0
        return(0);
12133
0
    }
12134
0
    contextSeq = obj->nodesetval;
12135
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12136
0
  xmlXPathReleaseObject(xpctxt, obj);
12137
0
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12138
0
        return(0);
12139
0
    }
12140
    /*
12141
    * Predicate optimization ---------------------------------------------
12142
    * If this step has a last predicate, which contains a position(),
12143
    * then we'll optimize (although not exactly "position()", but only
12144
    * the  short-hand form, i.e., "[n]".
12145
    *
12146
    * Example - expression "/foo[parent::bar][1]":
12147
    *
12148
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12149
    *   ROOT                               -- op->ch1
12150
    *   PREDICATE                          -- op->ch2 (predOp)
12151
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12152
    *       SORT
12153
    *         COLLECT  'parent' 'name' 'node' bar
12154
    *           NODE
12155
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12156
    *
12157
    */
12158
0
    maxPos = 0;
12159
0
    predOp = NULL;
12160
0
    hasPredicateRange = 0;
12161
0
    hasAxisRange = 0;
12162
0
    if (op->ch2 != -1) {
12163
  /*
12164
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12165
  */
12166
0
  predOp = &ctxt->comp->steps[op->ch2];
12167
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12168
0
      if (predOp->ch1 != -1) {
12169
    /*
12170
    * Use the next inner predicate operator.
12171
    */
12172
0
    predOp = &ctxt->comp->steps[predOp->ch1];
12173
0
    hasPredicateRange = 1;
12174
0
      } else {
12175
    /*
12176
    * There's no other predicate than the [n] predicate.
12177
    */
12178
0
    predOp = NULL;
12179
0
    hasAxisRange = 1;
12180
0
      }
12181
0
  }
12182
0
    }
12183
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12184
    /*
12185
    * Axis traversal -----------------------------------------------------
12186
    */
12187
    /*
12188
     * 2.3 Node Tests
12189
     *  - For the attribute axis, the principal node type is attribute.
12190
     *  - For the namespace axis, the principal node type is namespace.
12191
     *  - For other axes, the principal node type is element.
12192
     *
12193
     * A node test * is true for any node of the
12194
     * principal node type. For example, child::* will
12195
     * select all element children of the context node
12196
     */
12197
0
    oldContextNode = xpctxt->node;
12198
0
    addNode = xmlXPathNodeSetAddUnique;
12199
0
    outSeq = NULL;
12200
0
    seq = NULL;
12201
0
    contextNode = NULL;
12202
0
    contextIdx = 0;
12203
12204
12205
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12206
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12207
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12208
12209
0
  if (seq == NULL) {
12210
0
      seq = xmlXPathNodeSetCreate(NULL);
12211
0
      if (seq == NULL) {
12212
                /* TODO: Propagate memory error. */
12213
0
    total = 0;
12214
0
    goto error;
12215
0
      }
12216
0
  }
12217
  /*
12218
  * Traverse the axis and test the nodes.
12219
  */
12220
0
  pos = 0;
12221
0
  cur = NULL;
12222
0
  hasNsNodes = 0;
12223
0
        do {
12224
0
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12225
0
                goto error;
12226
12227
0
            cur = next(ctxt, cur);
12228
0
            if (cur == NULL)
12229
0
                break;
12230
12231
      /*
12232
      * QUESTION TODO: What does the "first" and "last" stuff do?
12233
      */
12234
0
            if ((first != NULL) && (*first != NULL)) {
12235
0
    if (*first == cur)
12236
0
        break;
12237
0
    if (((total % 256) == 0) &&
12238
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12239
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12240
#else
12241
        (xmlXPathCmpNodes(*first, cur) >= 0))
12242
#endif
12243
0
    {
12244
0
        break;
12245
0
    }
12246
0
      }
12247
0
      if ((last != NULL) && (*last != NULL)) {
12248
0
    if (*last == cur)
12249
0
        break;
12250
0
    if (((total % 256) == 0) &&
12251
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12252
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12253
#else
12254
        (xmlXPathCmpNodes(cur, *last) >= 0))
12255
#endif
12256
0
    {
12257
0
        break;
12258
0
    }
12259
0
      }
12260
12261
0
            total++;
12262
12263
#ifdef DEBUG_STEP
12264
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12265
#endif
12266
12267
0
      switch (test) {
12268
0
                case NODE_TEST_NONE:
12269
0
        total = 0;
12270
0
                    STRANGE
12271
0
        goto error;
12272
0
                case NODE_TEST_TYPE:
12273
0
        if (type == NODE_TYPE_NODE) {
12274
0
      switch (cur->type) {
12275
0
          case XML_DOCUMENT_NODE:
12276
0
          case XML_HTML_DOCUMENT_NODE:
12277
0
          case XML_ELEMENT_NODE:
12278
0
          case XML_ATTRIBUTE_NODE:
12279
0
          case XML_PI_NODE:
12280
0
          case XML_COMMENT_NODE:
12281
0
          case XML_CDATA_SECTION_NODE:
12282
0
          case XML_TEXT_NODE:
12283
0
        XP_TEST_HIT
12284
0
        break;
12285
0
          case XML_NAMESPACE_DECL: {
12286
0
        if (axis == AXIS_NAMESPACE) {
12287
0
            XP_TEST_HIT_NS
12288
0
        } else {
12289
0
                              hasNsNodes = 1;
12290
0
            XP_TEST_HIT
12291
0
        }
12292
0
        break;
12293
0
                            }
12294
0
          default:
12295
0
        break;
12296
0
      }
12297
0
        } else if (cur->type == (xmlElementType) type) {
12298
0
      if (cur->type == XML_NAMESPACE_DECL)
12299
0
          XP_TEST_HIT_NS
12300
0
      else
12301
0
          XP_TEST_HIT
12302
0
        } else if ((type == NODE_TYPE_TEXT) &&
12303
0
       (cur->type == XML_CDATA_SECTION_NODE))
12304
0
        {
12305
0
      XP_TEST_HIT
12306
0
        }
12307
0
        break;
12308
0
                case NODE_TEST_PI:
12309
0
                    if ((cur->type == XML_PI_NODE) &&
12310
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12311
0
        {
12312
0
      XP_TEST_HIT
12313
0
                    }
12314
0
                    break;
12315
0
                case NODE_TEST_ALL:
12316
0
                    if (axis == AXIS_ATTRIBUTE) {
12317
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
12318
0
      {
12319
0
                            if (prefix == NULL)
12320
0
          {
12321
0
        XP_TEST_HIT
12322
0
                            } else if ((cur->ns != NULL) &&
12323
0
        (xmlStrEqual(URI, cur->ns->href)))
12324
0
          {
12325
0
        XP_TEST_HIT
12326
0
                            }
12327
0
                        }
12328
0
                    } else if (axis == AXIS_NAMESPACE) {
12329
0
                        if (cur->type == XML_NAMESPACE_DECL)
12330
0
      {
12331
0
          XP_TEST_HIT_NS
12332
0
                        }
12333
0
                    } else {
12334
0
                        if (cur->type == XML_ELEMENT_NODE) {
12335
0
                            if (prefix == NULL)
12336
0
          {
12337
0
        XP_TEST_HIT
12338
12339
0
                            } else if ((cur->ns != NULL) &&
12340
0
        (xmlStrEqual(URI, cur->ns->href)))
12341
0
          {
12342
0
        XP_TEST_HIT
12343
0
                            }
12344
0
                        }
12345
0
                    }
12346
0
                    break;
12347
0
                case NODE_TEST_NS:{
12348
0
                        TODO;
12349
0
                        break;
12350
0
                    }
12351
0
                case NODE_TEST_NAME:
12352
0
                    if (axis == AXIS_ATTRIBUTE) {
12353
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
12354
0
          break;
12355
0
        } else if (axis == AXIS_NAMESPACE) {
12356
0
                        if (cur->type != XML_NAMESPACE_DECL)
12357
0
          break;
12358
0
        } else {
12359
0
            if (cur->type != XML_ELEMENT_NODE)
12360
0
          break;
12361
0
        }
12362
0
                    switch (cur->type) {
12363
0
                        case XML_ELEMENT_NODE:
12364
0
                            if (xmlStrEqual(name, cur->name)) {
12365
0
                                if (prefix == NULL) {
12366
0
                                    if (cur->ns == NULL)
12367
0
            {
12368
0
          XP_TEST_HIT
12369
0
                                    }
12370
0
                                } else {
12371
0
                                    if ((cur->ns != NULL) &&
12372
0
                                        (xmlStrEqual(URI, cur->ns->href)))
12373
0
            {
12374
0
          XP_TEST_HIT
12375
0
                                    }
12376
0
                                }
12377
0
                            }
12378
0
                            break;
12379
0
                        case XML_ATTRIBUTE_NODE:{
12380
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12381
12382
0
                                if (xmlStrEqual(name, attr->name)) {
12383
0
                                    if (prefix == NULL) {
12384
0
                                        if ((attr->ns == NULL) ||
12385
0
                                            (attr->ns->prefix == NULL))
12386
0
          {
12387
0
              XP_TEST_HIT
12388
0
                                        }
12389
0
                                    } else {
12390
0
                                        if ((attr->ns != NULL) &&
12391
0
                                            (xmlStrEqual(URI,
12392
0
                attr->ns->href)))
12393
0
          {
12394
0
              XP_TEST_HIT
12395
0
                                        }
12396
0
                                    }
12397
0
                                }
12398
0
                                break;
12399
0
                            }
12400
0
                        case XML_NAMESPACE_DECL:
12401
0
                            if (cur->type == XML_NAMESPACE_DECL) {
12402
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
12403
12404
0
                                if ((ns->prefix != NULL) && (name != NULL)
12405
0
                                    && (xmlStrEqual(ns->prefix, name)))
12406
0
        {
12407
0
            XP_TEST_HIT_NS
12408
0
                                }
12409
0
                            }
12410
0
                            break;
12411
0
                        default:
12412
0
                            break;
12413
0
                    }
12414
0
                    break;
12415
0
      } /* switch(test) */
12416
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12417
12418
0
  goto apply_predicates;
12419
12420
0
axis_range_end: /* ----------------------------------------------------- */
12421
  /*
12422
  * We have a "/foo[n]", and position() = n was reached.
12423
  * Note that we can have as well "/foo/::parent::foo[1]", so
12424
  * a duplicate-aware merge is still needed.
12425
  * Merge with the result.
12426
  */
12427
0
  if (outSeq == NULL) {
12428
0
      outSeq = seq;
12429
0
      seq = NULL;
12430
0
  } else
12431
            /* TODO: Check memory error. */
12432
0
      outSeq = mergeAndClear(outSeq, seq);
12433
  /*
12434
  * Break if only a true/false result was requested.
12435
  */
12436
0
  if (toBool)
12437
0
      break;
12438
0
  continue;
12439
12440
0
first_hit: /* ---------------------------------------------------------- */
12441
  /*
12442
  * Break if only a true/false result was requested and
12443
  * no predicates existed and a node test succeeded.
12444
  */
12445
0
  if (outSeq == NULL) {
12446
0
      outSeq = seq;
12447
0
      seq = NULL;
12448
0
  } else
12449
            /* TODO: Check memory error. */
12450
0
      outSeq = mergeAndClear(outSeq, seq);
12451
0
  break;
12452
12453
#ifdef DEBUG_STEP
12454
  if (seq != NULL)
12455
      nbMatches += seq->nodeNr;
12456
#endif
12457
12458
0
apply_predicates: /* --------------------------------------------------- */
12459
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
12460
0
      goto error;
12461
12462
        /*
12463
  * Apply predicates.
12464
  */
12465
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12466
      /*
12467
      * E.g. when we have a "/foo[some expression][n]".
12468
      */
12469
      /*
12470
      * QUESTION TODO: The old predicate evaluation took into
12471
      *  account location-sets.
12472
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12473
      *  Do we expect such a set here?
12474
      *  All what I learned now from the evaluation semantics
12475
      *  does not indicate that a location-set will be processed
12476
      *  here, so this looks OK.
12477
      */
12478
      /*
12479
      * Iterate over all predicates, starting with the outermost
12480
      * predicate.
12481
      * TODO: Problem: we cannot execute the inner predicates first
12482
      *  since we cannot go back *up* the operator tree!
12483
      *  Options we have:
12484
      *  1) Use of recursive functions (like is it currently done
12485
      *     via xmlXPathCompOpEval())
12486
      *  2) Add a predicate evaluation information stack to the
12487
      *     context struct
12488
      *  3) Change the way the operators are linked; we need a
12489
      *     "parent" field on xmlXPathStepOp
12490
      *
12491
      * For the moment, I'll try to solve this with a recursive
12492
      * function: xmlXPathCompOpEvalPredicate().
12493
      */
12494
0
      if (hasPredicateRange != 0)
12495
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12496
0
              hasNsNodes);
12497
0
      else
12498
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12499
0
              hasNsNodes);
12500
12501
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12502
0
    total = 0;
12503
0
    goto error;
12504
0
      }
12505
0
        }
12506
12507
0
        if (seq->nodeNr > 0) {
12508
      /*
12509
      * Add to result set.
12510
      */
12511
0
      if (outSeq == NULL) {
12512
0
    outSeq = seq;
12513
0
    seq = NULL;
12514
0
      } else {
12515
                /* TODO: Check memory error. */
12516
0
    outSeq = mergeAndClear(outSeq, seq);
12517
0
      }
12518
12519
0
            if (toBool)
12520
0
                break;
12521
0
  }
12522
0
    }
12523
12524
0
error:
12525
0
    if ((obj->boolval) && (obj->user != NULL)) {
12526
  /*
12527
  * QUESTION TODO: What does this do and why?
12528
  * TODO: Do we have to do this also for the "error"
12529
  * cleanup further down?
12530
  */
12531
0
  ctxt->value->boolval = 1;
12532
0
  ctxt->value->user = obj->user;
12533
0
  obj->user = NULL;
12534
0
  obj->boolval = 0;
12535
0
    }
12536
0
    xmlXPathReleaseObject(xpctxt, obj);
12537
12538
    /*
12539
    * Ensure we return at least an empty set.
12540
    */
12541
0
    if (outSeq == NULL) {
12542
0
  if ((seq != NULL) && (seq->nodeNr == 0))
12543
0
      outSeq = seq;
12544
0
  else
12545
            /* TODO: Check memory error. */
12546
0
      outSeq = xmlXPathNodeSetCreate(NULL);
12547
0
    }
12548
0
    if ((seq != NULL) && (seq != outSeq)) {
12549
0
   xmlXPathFreeNodeSet(seq);
12550
0
    }
12551
    /*
12552
    * Hand over the result. Better to push the set also in
12553
    * case of errors.
12554
    */
12555
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12556
    /*
12557
    * Reset the context node.
12558
    */
12559
0
    xpctxt->node = oldContextNode;
12560
    /*
12561
    * When traversing the namespace axis in "toBool" mode, it's
12562
    * possible that tmpNsList wasn't freed.
12563
    */
12564
0
    if (xpctxt->tmpNsList != NULL) {
12565
0
        xmlFree(xpctxt->tmpNsList);
12566
0
        xpctxt->tmpNsList = NULL;
12567
0
    }
12568
12569
#ifdef DEBUG_STEP
12570
    xmlGenericError(xmlGenericErrorContext,
12571
  "\nExamined %d nodes, found %d nodes at that step\n",
12572
  total, nbMatches);
12573
#endif
12574
12575
0
    return(total);
12576
0
}
12577
12578
static int
12579
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12580
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12581
12582
/**
12583
 * xmlXPathCompOpEvalFirst:
12584
 * @ctxt:  the XPath parser context with the compiled expression
12585
 * @op:  an XPath compiled operation
12586
 * @first:  the first elem found so far
12587
 *
12588
 * Evaluate the Precompiled XPath operation searching only the first
12589
 * element in document order
12590
 *
12591
 * Returns the number of examined objects.
12592
 */
12593
static int
12594
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12595
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12596
0
{
12597
0
    int total = 0, cur;
12598
0
    xmlXPathCompExprPtr comp;
12599
0
    xmlXPathObjectPtr arg1, arg2;
12600
12601
0
    CHECK_ERROR0;
12602
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12603
0
        return(0);
12604
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12605
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12606
0
    ctxt->context->depth += 1;
12607
0
    comp = ctxt->comp;
12608
0
    switch (op->op) {
12609
0
        case XPATH_OP_END:
12610
0
            break;
12611
0
        case XPATH_OP_UNION:
12612
0
            total =
12613
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12614
0
                                        first);
12615
0
      CHECK_ERROR0;
12616
0
            if ((ctxt->value != NULL)
12617
0
                && (ctxt->value->type == XPATH_NODESET)
12618
0
                && (ctxt->value->nodesetval != NULL)
12619
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12620
                /*
12621
                 * limit tree traversing to first node in the result
12622
                 */
12623
    /*
12624
    * OPTIMIZE TODO: This implicitly sorts
12625
    *  the result, even if not needed. E.g. if the argument
12626
    *  of the count() function, no sorting is needed.
12627
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12628
    *  already sorted?
12629
    */
12630
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12631
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12632
0
                *first = ctxt->value->nodesetval->nodeTab[0];
12633
0
            }
12634
0
            cur =
12635
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12636
0
                                        first);
12637
0
      CHECK_ERROR0;
12638
12639
0
            arg2 = valuePop(ctxt);
12640
0
            arg1 = valuePop(ctxt);
12641
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12642
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12643
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12644
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12645
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12646
0
            }
12647
0
            if ((ctxt->context->opLimit != 0) &&
12648
0
                (((arg1->nodesetval != NULL) &&
12649
0
                  (xmlXPathCheckOpLimit(ctxt,
12650
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12651
0
                 ((arg2->nodesetval != NULL) &&
12652
0
                  (xmlXPathCheckOpLimit(ctxt,
12653
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12654
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12655
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12656
0
                break;
12657
0
            }
12658
12659
            /* TODO: Check memory error. */
12660
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12661
0
                                                    arg2->nodesetval);
12662
0
            valuePush(ctxt, arg1);
12663
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12664
            /* optimizer */
12665
0
      if (total > cur)
12666
0
    xmlXPathCompSwap(op);
12667
0
            total += cur;
12668
0
            break;
12669
0
        case XPATH_OP_ROOT:
12670
0
            xmlXPathRoot(ctxt);
12671
0
            break;
12672
0
        case XPATH_OP_NODE:
12673
0
            if (op->ch1 != -1)
12674
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12675
0
      CHECK_ERROR0;
12676
0
            if (op->ch2 != -1)
12677
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12678
0
      CHECK_ERROR0;
12679
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12680
0
    ctxt->context->node));
12681
0
            break;
12682
0
        case XPATH_OP_COLLECT:{
12683
0
                if (op->ch1 == -1)
12684
0
                    break;
12685
12686
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12687
0
    CHECK_ERROR0;
12688
12689
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12690
0
                break;
12691
0
            }
12692
0
        case XPATH_OP_VALUE:
12693
0
            valuePush(ctxt,
12694
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12695
0
      (xmlXPathObjectPtr) op->value4));
12696
0
            break;
12697
0
        case XPATH_OP_SORT:
12698
0
            if (op->ch1 != -1)
12699
0
                total +=
12700
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12701
0
                                            first);
12702
0
      CHECK_ERROR0;
12703
0
            if ((ctxt->value != NULL)
12704
0
                && (ctxt->value->type == XPATH_NODESET)
12705
0
                && (ctxt->value->nodesetval != NULL)
12706
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12707
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12708
0
            break;
12709
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12710
0
  case XPATH_OP_FILTER:
12711
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12712
0
            break;
12713
0
#endif
12714
0
        default:
12715
0
            total += xmlXPathCompOpEval(ctxt, op);
12716
0
            break;
12717
0
    }
12718
12719
0
    ctxt->context->depth -= 1;
12720
0
    return(total);
12721
0
}
12722
12723
/**
12724
 * xmlXPathCompOpEvalLast:
12725
 * @ctxt:  the XPath parser context with the compiled expression
12726
 * @op:  an XPath compiled operation
12727
 * @last:  the last elem found so far
12728
 *
12729
 * Evaluate the Precompiled XPath operation searching only the last
12730
 * element in document order
12731
 *
12732
 * Returns the number of nodes traversed
12733
 */
12734
static int
12735
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12736
                       xmlNodePtr * last)
12737
0
{
12738
0
    int total = 0, cur;
12739
0
    xmlXPathCompExprPtr comp;
12740
0
    xmlXPathObjectPtr arg1, arg2;
12741
12742
0
    CHECK_ERROR0;
12743
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12744
0
        return(0);
12745
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12746
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12747
0
    ctxt->context->depth += 1;
12748
0
    comp = ctxt->comp;
12749
0
    switch (op->op) {
12750
0
        case XPATH_OP_END:
12751
0
            break;
12752
0
        case XPATH_OP_UNION:
12753
0
            total =
12754
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12755
0
      CHECK_ERROR0;
12756
0
            if ((ctxt->value != NULL)
12757
0
                && (ctxt->value->type == XPATH_NODESET)
12758
0
                && (ctxt->value->nodesetval != NULL)
12759
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12760
                /*
12761
                 * limit tree traversing to first node in the result
12762
                 */
12763
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12764
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12765
0
                *last =
12766
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12767
0
                                                     nodesetval->nodeNr -
12768
0
                                                     1];
12769
0
            }
12770
0
            cur =
12771
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12772
0
      CHECK_ERROR0;
12773
0
            if ((ctxt->value != NULL)
12774
0
                && (ctxt->value->type == XPATH_NODESET)
12775
0
                && (ctxt->value->nodesetval != NULL)
12776
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12777
0
            }
12778
12779
0
            arg2 = valuePop(ctxt);
12780
0
            arg1 = valuePop(ctxt);
12781
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12782
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12783
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12784
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12785
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12786
0
            }
12787
0
            if ((ctxt->context->opLimit != 0) &&
12788
0
                (((arg1->nodesetval != NULL) &&
12789
0
                  (xmlXPathCheckOpLimit(ctxt,
12790
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12791
0
                 ((arg2->nodesetval != NULL) &&
12792
0
                  (xmlXPathCheckOpLimit(ctxt,
12793
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12794
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12795
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12796
0
                break;
12797
0
            }
12798
12799
            /* TODO: Check memory error. */
12800
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12801
0
                                                    arg2->nodesetval);
12802
0
            valuePush(ctxt, arg1);
12803
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12804
            /* optimizer */
12805
0
      if (total > cur)
12806
0
    xmlXPathCompSwap(op);
12807
0
            total += cur;
12808
0
            break;
12809
0
        case XPATH_OP_ROOT:
12810
0
            xmlXPathRoot(ctxt);
12811
0
            break;
12812
0
        case XPATH_OP_NODE:
12813
0
            if (op->ch1 != -1)
12814
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12815
0
      CHECK_ERROR0;
12816
0
            if (op->ch2 != -1)
12817
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12818
0
      CHECK_ERROR0;
12819
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12820
0
    ctxt->context->node));
12821
0
            break;
12822
0
        case XPATH_OP_COLLECT:{
12823
0
                if (op->ch1 == -1)
12824
0
                    break;
12825
12826
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12827
0
    CHECK_ERROR0;
12828
12829
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12830
0
                break;
12831
0
            }
12832
0
        case XPATH_OP_VALUE:
12833
0
            valuePush(ctxt,
12834
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12835
0
      (xmlXPathObjectPtr) op->value4));
12836
0
            break;
12837
0
        case XPATH_OP_SORT:
12838
0
            if (op->ch1 != -1)
12839
0
                total +=
12840
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12841
0
                                           last);
12842
0
      CHECK_ERROR0;
12843
0
            if ((ctxt->value != NULL)
12844
0
                && (ctxt->value->type == XPATH_NODESET)
12845
0
                && (ctxt->value->nodesetval != NULL)
12846
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12847
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12848
0
            break;
12849
0
        default:
12850
0
            total += xmlXPathCompOpEval(ctxt, op);
12851
0
            break;
12852
0
    }
12853
12854
0
    ctxt->context->depth -= 1;
12855
0
    return (total);
12856
0
}
12857
12858
#ifdef XP_OPTIMIZED_FILTER_FIRST
12859
static int
12860
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12861
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12862
0
{
12863
0
    int total = 0;
12864
0
    xmlXPathCompExprPtr comp;
12865
0
    xmlNodeSetPtr set;
12866
12867
0
    CHECK_ERROR0;
12868
0
    comp = ctxt->comp;
12869
    /*
12870
    * Optimization for ()[last()] selection i.e. the last elem
12871
    */
12872
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12873
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12874
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12875
0
  int f = comp->steps[op->ch2].ch1;
12876
12877
0
  if ((f != -1) &&
12878
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12879
0
      (comp->steps[f].value5 == NULL) &&
12880
0
      (comp->steps[f].value == 0) &&
12881
0
      (comp->steps[f].value4 != NULL) &&
12882
0
      (xmlStrEqual
12883
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
12884
0
      xmlNodePtr last = NULL;
12885
12886
0
      total +=
12887
0
    xmlXPathCompOpEvalLast(ctxt,
12888
0
        &comp->steps[op->ch1],
12889
0
        &last);
12890
0
      CHECK_ERROR0;
12891
      /*
12892
      * The nodeset should be in document order,
12893
      * Keep only the last value
12894
      */
12895
0
      if ((ctxt->value != NULL) &&
12896
0
    (ctxt->value->type == XPATH_NODESET) &&
12897
0
    (ctxt->value->nodesetval != NULL) &&
12898
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12899
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
12900
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12901
0
    *first = *(ctxt->value->nodesetval->nodeTab);
12902
0
      }
12903
0
      return (total);
12904
0
  }
12905
0
    }
12906
12907
0
    if (op->ch1 != -1)
12908
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12909
0
    CHECK_ERROR0;
12910
0
    if (op->ch2 == -1)
12911
0
  return (total);
12912
0
    if (ctxt->value == NULL)
12913
0
  return (total);
12914
12915
#ifdef LIBXML_XPTR_LOCS_ENABLED
12916
    /*
12917
    * Hum are we filtering the result of an XPointer expression
12918
    */
12919
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12920
        xmlLocationSetPtr locset = ctxt->value->user;
12921
12922
        if (locset != NULL) {
12923
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12924
            if (locset->locNr > 0)
12925
                *first = (xmlNodePtr) locset->locTab[0]->user;
12926
        }
12927
12928
  return (total);
12929
    }
12930
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12931
12932
0
    CHECK_TYPE0(XPATH_NODESET);
12933
0
    set = ctxt->value->nodesetval;
12934
0
    if (set != NULL) {
12935
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12936
0
        if (set->nodeNr > 0)
12937
0
            *first = set->nodeTab[0];
12938
0
    }
12939
12940
0
    return (total);
12941
0
}
12942
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12943
12944
/**
12945
 * xmlXPathCompOpEval:
12946
 * @ctxt:  the XPath parser context with the compiled expression
12947
 * @op:  an XPath compiled operation
12948
 *
12949
 * Evaluate the Precompiled XPath operation
12950
 * Returns the number of nodes traversed
12951
 */
12952
static int
12953
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12954
0
{
12955
0
    int total = 0;
12956
0
    int equal, ret;
12957
0
    xmlXPathCompExprPtr comp;
12958
0
    xmlXPathObjectPtr arg1, arg2;
12959
12960
0
    CHECK_ERROR0;
12961
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12962
0
        return(0);
12963
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12964
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12965
0
    ctxt->context->depth += 1;
12966
0
    comp = ctxt->comp;
12967
0
    switch (op->op) {
12968
0
        case XPATH_OP_END:
12969
0
            break;
12970
0
        case XPATH_OP_AND:
12971
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12972
0
      CHECK_ERROR0;
12973
0
            xmlXPathBooleanFunction(ctxt, 1);
12974
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12975
0
                break;
12976
0
            arg2 = valuePop(ctxt);
12977
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12978
0
      if (ctxt->error) {
12979
0
    xmlXPathFreeObject(arg2);
12980
0
    break;
12981
0
      }
12982
0
            xmlXPathBooleanFunction(ctxt, 1);
12983
0
            if (ctxt->value != NULL)
12984
0
                ctxt->value->boolval &= arg2->boolval;
12985
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12986
0
            break;
12987
0
        case XPATH_OP_OR:
12988
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12989
0
      CHECK_ERROR0;
12990
0
            xmlXPathBooleanFunction(ctxt, 1);
12991
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12992
0
                break;
12993
0
            arg2 = valuePop(ctxt);
12994
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12995
0
      if (ctxt->error) {
12996
0
    xmlXPathFreeObject(arg2);
12997
0
    break;
12998
0
      }
12999
0
            xmlXPathBooleanFunction(ctxt, 1);
13000
0
            if (ctxt->value != NULL)
13001
0
                ctxt->value->boolval |= arg2->boolval;
13002
0
      xmlXPathReleaseObject(ctxt->context, arg2);
13003
0
            break;
13004
0
        case XPATH_OP_EQUAL:
13005
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13006
0
      CHECK_ERROR0;
13007
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13008
0
      CHECK_ERROR0;
13009
0
      if (op->value)
13010
0
    equal = xmlXPathEqualValues(ctxt);
13011
0
      else
13012
0
    equal = xmlXPathNotEqualValues(ctxt);
13013
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13014
0
            break;
13015
0
        case XPATH_OP_CMP:
13016
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13017
0
      CHECK_ERROR0;
13018
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13019
0
      CHECK_ERROR0;
13020
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13021
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13022
0
            break;
13023
0
        case XPATH_OP_PLUS:
13024
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13025
0
      CHECK_ERROR0;
13026
0
            if (op->ch2 != -1) {
13027
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13028
0
      }
13029
0
      CHECK_ERROR0;
13030
0
            if (op->value == 0)
13031
0
                xmlXPathSubValues(ctxt);
13032
0
            else if (op->value == 1)
13033
0
                xmlXPathAddValues(ctxt);
13034
0
            else if (op->value == 2)
13035
0
                xmlXPathValueFlipSign(ctxt);
13036
0
            else if (op->value == 3) {
13037
0
                CAST_TO_NUMBER;
13038
0
                CHECK_TYPE0(XPATH_NUMBER);
13039
0
            }
13040
0
            break;
13041
0
        case XPATH_OP_MULT:
13042
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13043
0
      CHECK_ERROR0;
13044
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13045
0
      CHECK_ERROR0;
13046
0
            if (op->value == 0)
13047
0
                xmlXPathMultValues(ctxt);
13048
0
            else if (op->value == 1)
13049
0
                xmlXPathDivValues(ctxt);
13050
0
            else if (op->value == 2)
13051
0
                xmlXPathModValues(ctxt);
13052
0
            break;
13053
0
        case XPATH_OP_UNION:
13054
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13055
0
      CHECK_ERROR0;
13056
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13057
0
      CHECK_ERROR0;
13058
13059
0
            arg2 = valuePop(ctxt);
13060
0
            arg1 = valuePop(ctxt);
13061
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13062
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13063
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13064
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13065
0
                XP_ERROR0(XPATH_INVALID_TYPE);
13066
0
            }
13067
0
            if ((ctxt->context->opLimit != 0) &&
13068
0
                (((arg1->nodesetval != NULL) &&
13069
0
                  (xmlXPathCheckOpLimit(ctxt,
13070
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
13071
0
                 ((arg2->nodesetval != NULL) &&
13072
0
                  (xmlXPathCheckOpLimit(ctxt,
13073
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
13074
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13075
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13076
0
                break;
13077
0
            }
13078
13079
0
      if ((arg1->nodesetval == NULL) ||
13080
0
    ((arg2->nodesetval != NULL) &&
13081
0
     (arg2->nodesetval->nodeNr != 0)))
13082
0
      {
13083
                /* TODO: Check memory error. */
13084
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13085
0
              arg2->nodesetval);
13086
0
      }
13087
13088
0
            valuePush(ctxt, arg1);
13089
0
      xmlXPathReleaseObject(ctxt->context, arg2);
13090
0
            break;
13091
0
        case XPATH_OP_ROOT:
13092
0
            xmlXPathRoot(ctxt);
13093
0
            break;
13094
0
        case XPATH_OP_NODE:
13095
0
            if (op->ch1 != -1)
13096
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13097
0
      CHECK_ERROR0;
13098
0
            if (op->ch2 != -1)
13099
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13100
0
      CHECK_ERROR0;
13101
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13102
0
    ctxt->context->node));
13103
0
            break;
13104
0
        case XPATH_OP_COLLECT:{
13105
0
                if (op->ch1 == -1)
13106
0
                    break;
13107
13108
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13109
0
    CHECK_ERROR0;
13110
13111
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13112
0
                break;
13113
0
            }
13114
0
        case XPATH_OP_VALUE:
13115
0
            valuePush(ctxt,
13116
0
                      xmlXPathCacheObjectCopy(ctxt->context,
13117
0
      (xmlXPathObjectPtr) op->value4));
13118
0
            break;
13119
0
        case XPATH_OP_VARIABLE:{
13120
0
    xmlXPathObjectPtr val;
13121
13122
0
                if (op->ch1 != -1)
13123
0
                    total +=
13124
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13125
0
                if (op->value5 == NULL) {
13126
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13127
0
        if (val == NULL)
13128
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13129
0
                    valuePush(ctxt, val);
13130
0
    } else {
13131
0
                    const xmlChar *URI;
13132
13133
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13134
0
                    if (URI == NULL) {
13135
0
                        xmlGenericError(xmlGenericErrorContext,
13136
0
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13137
0
                                    (char *) op->value4, (char *)op->value5);
13138
0
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13139
0
                        break;
13140
0
                    }
13141
0
        val = xmlXPathVariableLookupNS(ctxt->context,
13142
0
                                                       op->value4, URI);
13143
0
        if (val == NULL)
13144
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13145
0
                    valuePush(ctxt, val);
13146
0
                }
13147
0
                break;
13148
0
            }
13149
0
        case XPATH_OP_FUNCTION:{
13150
0
                xmlXPathFunction func;
13151
0
                const xmlChar *oldFunc, *oldFuncURI;
13152
0
    int i;
13153
0
                int frame;
13154
13155
0
                frame = xmlXPathSetFrame(ctxt);
13156
0
                if (op->ch1 != -1) {
13157
0
                    total +=
13158
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13159
0
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13160
0
                        xmlXPathPopFrame(ctxt, frame);
13161
0
                        break;
13162
0
                    }
13163
0
                }
13164
0
    if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13165
0
        xmlGenericError(xmlGenericErrorContext,
13166
0
          "xmlXPathCompOpEval: parameter error\n");
13167
0
        ctxt->error = XPATH_INVALID_OPERAND;
13168
0
                    xmlXPathPopFrame(ctxt, frame);
13169
0
        break;
13170
0
    }
13171
0
    for (i = 0; i < op->value; i++) {
13172
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13173
0
      xmlGenericError(xmlGenericErrorContext,
13174
0
        "xmlXPathCompOpEval: parameter error\n");
13175
0
      ctxt->error = XPATH_INVALID_OPERAND;
13176
0
                        xmlXPathPopFrame(ctxt, frame);
13177
0
      break;
13178
0
        }
13179
0
                }
13180
0
                if (op->cache != NULL)
13181
0
                    func = op->cache;
13182
0
                else {
13183
0
                    const xmlChar *URI = NULL;
13184
13185
0
                    if (op->value5 == NULL)
13186
0
                        func =
13187
0
                            xmlXPathFunctionLookup(ctxt->context,
13188
0
                                                   op->value4);
13189
0
                    else {
13190
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13191
0
                        if (URI == NULL) {
13192
0
                            xmlGenericError(xmlGenericErrorContext,
13193
0
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13194
0
                                    (char *)op->value4, (char *)op->value5);
13195
0
                            xmlXPathPopFrame(ctxt, frame);
13196
0
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13197
0
                            break;
13198
0
                        }
13199
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13200
0
                                                        op->value4, URI);
13201
0
                    }
13202
0
                    if (func == NULL) {
13203
0
                        xmlGenericError(xmlGenericErrorContext,
13204
0
                                "xmlXPathCompOpEval: function %s not found\n",
13205
0
                                        (char *)op->value4);
13206
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13207
0
                    }
13208
0
                    op->cache = func;
13209
0
                    op->cacheURI = (void *) URI;
13210
0
                }
13211
0
                oldFunc = ctxt->context->function;
13212
0
                oldFuncURI = ctxt->context->functionURI;
13213
0
                ctxt->context->function = op->value4;
13214
0
                ctxt->context->functionURI = op->cacheURI;
13215
0
                func(ctxt, op->value);
13216
0
                ctxt->context->function = oldFunc;
13217
0
                ctxt->context->functionURI = oldFuncURI;
13218
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13219
0
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13220
0
                    XP_ERROR0(XPATH_STACK_ERROR);
13221
0
                xmlXPathPopFrame(ctxt, frame);
13222
0
                break;
13223
0
            }
13224
0
        case XPATH_OP_ARG:
13225
0
            if (op->ch1 != -1) {
13226
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13227
0
          CHECK_ERROR0;
13228
0
            }
13229
0
            if (op->ch2 != -1) {
13230
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13231
0
          CHECK_ERROR0;
13232
0
      }
13233
0
            break;
13234
0
        case XPATH_OP_PREDICATE:
13235
0
        case XPATH_OP_FILTER:{
13236
0
                xmlNodeSetPtr set;
13237
13238
                /*
13239
                 * Optimization for ()[1] selection i.e. the first elem
13240
                 */
13241
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13242
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
13243
        /*
13244
        * FILTER TODO: Can we assume that the inner processing
13245
        *  will result in an ordered list if we have an
13246
        *  XPATH_OP_FILTER?
13247
        *  What about an additional field or flag on
13248
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13249
        *  to assume anything, so it would be more robust and
13250
        *  easier to optimize.
13251
        */
13252
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13253
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13254
#else
13255
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13256
#endif
13257
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13258
0
                    xmlXPathObjectPtr val;
13259
13260
0
                    val = comp->steps[op->ch2].value4;
13261
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13262
0
                        (val->floatval == 1.0)) {
13263
0
                        xmlNodePtr first = NULL;
13264
13265
0
                        total +=
13266
0
                            xmlXPathCompOpEvalFirst(ctxt,
13267
0
                                                    &comp->steps[op->ch1],
13268
0
                                                    &first);
13269
0
      CHECK_ERROR0;
13270
                        /*
13271
                         * The nodeset should be in document order,
13272
                         * Keep only the first value
13273
                         */
13274
0
                        if ((ctxt->value != NULL) &&
13275
0
                            (ctxt->value->type == XPATH_NODESET) &&
13276
0
                            (ctxt->value->nodesetval != NULL) &&
13277
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13278
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13279
0
                                                        1, 1);
13280
0
                        break;
13281
0
                    }
13282
0
                }
13283
                /*
13284
                 * Optimization for ()[last()] selection i.e. the last elem
13285
                 */
13286
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13287
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13288
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13289
0
                    int f = comp->steps[op->ch2].ch1;
13290
13291
0
                    if ((f != -1) &&
13292
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13293
0
                        (comp->steps[f].value5 == NULL) &&
13294
0
                        (comp->steps[f].value == 0) &&
13295
0
                        (comp->steps[f].value4 != NULL) &&
13296
0
                        (xmlStrEqual
13297
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13298
0
                        xmlNodePtr last = NULL;
13299
13300
0
                        total +=
13301
0
                            xmlXPathCompOpEvalLast(ctxt,
13302
0
                                                   &comp->steps[op->ch1],
13303
0
                                                   &last);
13304
0
      CHECK_ERROR0;
13305
                        /*
13306
                         * The nodeset should be in document order,
13307
                         * Keep only the last value
13308
                         */
13309
0
                        if ((ctxt->value != NULL) &&
13310
0
                            (ctxt->value->type == XPATH_NODESET) &&
13311
0
                            (ctxt->value->nodesetval != NULL) &&
13312
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13313
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13314
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13315
0
                        break;
13316
0
                    }
13317
0
                }
13318
    /*
13319
    * Process inner predicates first.
13320
    * Example "index[parent::book][1]":
13321
    * ...
13322
    *   PREDICATE   <-- we are here "[1]"
13323
    *     PREDICATE <-- process "[parent::book]" first
13324
    *       SORT
13325
    *         COLLECT  'parent' 'name' 'node' book
13326
    *           NODE
13327
    *     ELEM Object is a number : 1
13328
    */
13329
0
                if (op->ch1 != -1)
13330
0
                    total +=
13331
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13332
0
    CHECK_ERROR0;
13333
0
                if (op->ch2 == -1)
13334
0
                    break;
13335
0
                if (ctxt->value == NULL)
13336
0
                    break;
13337
13338
#ifdef LIBXML_XPTR_LOCS_ENABLED
13339
                /*
13340
                 * Hum are we filtering the result of an XPointer expression
13341
                 */
13342
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13343
                    xmlLocationSetPtr locset = ctxt->value->user;
13344
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13345
                                              1, locset->locNr);
13346
                    break;
13347
                }
13348
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13349
13350
0
                CHECK_TYPE0(XPATH_NODESET);
13351
0
                set = ctxt->value->nodesetval;
13352
0
                if (set != NULL)
13353
0
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13354
0
                                          1, set->nodeNr, 1);
13355
0
                break;
13356
0
            }
13357
0
        case XPATH_OP_SORT:
13358
0
            if (op->ch1 != -1)
13359
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13360
0
      CHECK_ERROR0;
13361
0
            if ((ctxt->value != NULL) &&
13362
0
                (ctxt->value->type == XPATH_NODESET) &&
13363
0
                (ctxt->value->nodesetval != NULL) &&
13364
0
    (ctxt->value->nodesetval->nodeNr > 1))
13365
0
      {
13366
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13367
0
      }
13368
0
            break;
13369
#ifdef LIBXML_XPTR_LOCS_ENABLED
13370
        case XPATH_OP_RANGETO:{
13371
                xmlXPathObjectPtr range;
13372
                xmlXPathObjectPtr res, obj;
13373
                xmlXPathObjectPtr tmp;
13374
                xmlLocationSetPtr newlocset = NULL;
13375
        xmlLocationSetPtr oldlocset;
13376
                xmlNodeSetPtr oldset;
13377
                xmlNodePtr oldnode = ctxt->context->node;
13378
                int oldcs = ctxt->context->contextSize;
13379
                int oldpp = ctxt->context->proximityPosition;
13380
                int i, j;
13381
13382
                if (op->ch1 != -1) {
13383
                    total +=
13384
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13385
                    CHECK_ERROR0;
13386
                }
13387
                if (ctxt->value == NULL) {
13388
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13389
                }
13390
                if (op->ch2 == -1)
13391
                    break;
13392
13393
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13394
                    /*
13395
                     * Extract the old locset, and then evaluate the result of the
13396
                     * expression for all the element in the locset. use it to grow
13397
                     * up a new locset.
13398
                     */
13399
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13400
13401
                    if ((ctxt->value->user == NULL) ||
13402
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13403
                        break;
13404
13405
                    obj = valuePop(ctxt);
13406
                    oldlocset = obj->user;
13407
13408
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13409
13410
                    for (i = 0; i < oldlocset->locNr; i++) {
13411
                        /*
13412
                         * Run the evaluation with a node list made of a
13413
                         * single item in the nodelocset.
13414
                         */
13415
                        ctxt->context->node = oldlocset->locTab[i]->user;
13416
                        ctxt->context->contextSize = oldlocset->locNr;
13417
                        ctxt->context->proximityPosition = i + 1;
13418
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13419
          ctxt->context->node);
13420
                        valuePush(ctxt, tmp);
13421
13422
                        if (op->ch2 != -1)
13423
                            total +=
13424
                                xmlXPathCompOpEval(ctxt,
13425
                                                   &comp->steps[op->ch2]);
13426
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13427
                            xmlXPtrFreeLocationSet(newlocset);
13428
                            goto rangeto_error;
13429
      }
13430
13431
                        res = valuePop(ctxt);
13432
      if (res->type == XPATH_LOCATIONSET) {
13433
          xmlLocationSetPtr rloc =
13434
              (xmlLocationSetPtr)res->user;
13435
          for (j=0; j<rloc->locNr; j++) {
13436
              range = xmlXPtrNewRange(
13437
          oldlocset->locTab[i]->user,
13438
          oldlocset->locTab[i]->index,
13439
          rloc->locTab[j]->user2,
13440
          rloc->locTab[j]->index2);
13441
        if (range != NULL) {
13442
            xmlXPtrLocationSetAdd(newlocset, range);
13443
        }
13444
          }
13445
      } else {
13446
          range = xmlXPtrNewRangeNodeObject(
13447
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13448
                            if (range != NULL) {
13449
                                xmlXPtrLocationSetAdd(newlocset,range);
13450
          }
13451
                        }
13452
13453
                        /*
13454
                         * Cleanup
13455
                         */
13456
                        if (res != NULL) {
13457
          xmlXPathReleaseObject(ctxt->context, res);
13458
      }
13459
                        if (ctxt->value == tmp) {
13460
                            res = valuePop(ctxt);
13461
          xmlXPathReleaseObject(ctxt->context, res);
13462
                        }
13463
                    }
13464
    } else {  /* Not a location set */
13465
                    CHECK_TYPE0(XPATH_NODESET);
13466
                    obj = valuePop(ctxt);
13467
                    oldset = obj->nodesetval;
13468
13469
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13470
13471
                    if (oldset != NULL) {
13472
                        for (i = 0; i < oldset->nodeNr; i++) {
13473
                            /*
13474
                             * Run the evaluation with a node list made of a single item
13475
                             * in the nodeset.
13476
                             */
13477
                            ctxt->context->node = oldset->nodeTab[i];
13478
          /*
13479
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13480
          */
13481
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13482
        ctxt->context->node);
13483
                            valuePush(ctxt, tmp);
13484
13485
                            if (op->ch2 != -1)
13486
                                total +=
13487
                                    xmlXPathCompOpEval(ctxt,
13488
                                                   &comp->steps[op->ch2]);
13489
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13490
                                xmlXPtrFreeLocationSet(newlocset);
13491
                                goto rangeto_error;
13492
          }
13493
13494
                            res = valuePop(ctxt);
13495
                            range =
13496
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13497
                                                      res);
13498
                            if (range != NULL) {
13499
                                xmlXPtrLocationSetAdd(newlocset, range);
13500
                            }
13501
13502
                            /*
13503
                             * Cleanup
13504
                             */
13505
                            if (res != NULL) {
13506
        xmlXPathReleaseObject(ctxt->context, res);
13507
          }
13508
                            if (ctxt->value == tmp) {
13509
                                res = valuePop(ctxt);
13510
        xmlXPathReleaseObject(ctxt->context, res);
13511
                            }
13512
                        }
13513
                    }
13514
                }
13515
13516
                /*
13517
                 * The result is used as the new evaluation set.
13518
                 */
13519
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13520
rangeto_error:
13521
    xmlXPathReleaseObject(ctxt->context, obj);
13522
                ctxt->context->node = oldnode;
13523
                ctxt->context->contextSize = oldcs;
13524
                ctxt->context->proximityPosition = oldpp;
13525
                break;
13526
            }
13527
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13528
0
        default:
13529
0
            xmlGenericError(xmlGenericErrorContext,
13530
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13531
0
            ctxt->error = XPATH_INVALID_OPERAND;
13532
0
            break;
13533
0
    }
13534
13535
0
    ctxt->context->depth -= 1;
13536
0
    return (total);
13537
0
}
13538
13539
/**
13540
 * xmlXPathCompOpEvalToBoolean:
13541
 * @ctxt:  the XPath parser context
13542
 *
13543
 * Evaluates if the expression evaluates to true.
13544
 *
13545
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13546
 */
13547
static int
13548
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13549
          xmlXPathStepOpPtr op,
13550
          int isPredicate)
13551
0
{
13552
0
    xmlXPathObjectPtr resObj = NULL;
13553
13554
0
start:
13555
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13556
0
        return(0);
13557
    /* comp = ctxt->comp; */
13558
0
    switch (op->op) {
13559
0
        case XPATH_OP_END:
13560
0
            return (0);
13561
0
  case XPATH_OP_VALUE:
13562
0
      resObj = (xmlXPathObjectPtr) op->value4;
13563
0
      if (isPredicate)
13564
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13565
0
      return(xmlXPathCastToBoolean(resObj));
13566
0
  case XPATH_OP_SORT:
13567
      /*
13568
      * We don't need sorting for boolean results. Skip this one.
13569
      */
13570
0
            if (op->ch1 != -1) {
13571
0
    op = &ctxt->comp->steps[op->ch1];
13572
0
    goto start;
13573
0
      }
13574
0
      return(0);
13575
0
  case XPATH_OP_COLLECT:
13576
0
      if (op->ch1 == -1)
13577
0
    return(0);
13578
13579
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13580
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13581
0
    return(-1);
13582
13583
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13584
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13585
0
    return(-1);
13586
13587
0
      resObj = valuePop(ctxt);
13588
0
      if (resObj == NULL)
13589
0
    return(-1);
13590
0
      break;
13591
0
  default:
13592
      /*
13593
      * Fallback to call xmlXPathCompOpEval().
13594
      */
13595
0
      xmlXPathCompOpEval(ctxt, op);
13596
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13597
0
    return(-1);
13598
13599
0
      resObj = valuePop(ctxt);
13600
0
      if (resObj == NULL)
13601
0
    return(-1);
13602
0
      break;
13603
0
    }
13604
13605
0
    if (resObj) {
13606
0
  int res;
13607
13608
0
  if (resObj->type == XPATH_BOOLEAN) {
13609
0
      res = resObj->boolval;
13610
0
  } else if (isPredicate) {
13611
      /*
13612
      * For predicates a result of type "number" is handled
13613
      * differently:
13614
      * SPEC XPath 1.0:
13615
      * "If the result is a number, the result will be converted
13616
      *  to true if the number is equal to the context position
13617
      *  and will be converted to false otherwise;"
13618
      */
13619
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13620
0
  } else {
13621
0
      res = xmlXPathCastToBoolean(resObj);
13622
0
  }
13623
0
  xmlXPathReleaseObject(ctxt->context, resObj);
13624
0
  return(res);
13625
0
    }
13626
13627
0
    return(0);
13628
0
}
13629
13630
#ifdef XPATH_STREAMING
13631
/**
13632
 * xmlXPathRunStreamEval:
13633
 * @ctxt:  the XPath parser context with the compiled expression
13634
 *
13635
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13636
 */
13637
static int
13638
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13639
          xmlXPathObjectPtr *resultSeq, int toBool)
13640
0
{
13641
0
    int max_depth, min_depth;
13642
0
    int from_root;
13643
0
    int ret, depth;
13644
0
    int eval_all_nodes;
13645
0
    xmlNodePtr cur = NULL, limit = NULL;
13646
0
    xmlStreamCtxtPtr patstream = NULL;
13647
13648
0
    int nb_nodes = 0;
13649
13650
0
    if ((ctxt == NULL) || (comp == NULL))
13651
0
        return(-1);
13652
0
    max_depth = xmlPatternMaxDepth(comp);
13653
0
    if (max_depth == -1)
13654
0
        return(-1);
13655
0
    if (max_depth == -2)
13656
0
        max_depth = 10000;
13657
0
    min_depth = xmlPatternMinDepth(comp);
13658
0
    if (min_depth == -1)
13659
0
        return(-1);
13660
0
    from_root = xmlPatternFromRoot(comp);
13661
0
    if (from_root < 0)
13662
0
        return(-1);
13663
#if 0
13664
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13665
#endif
13666
13667
0
    if (! toBool) {
13668
0
  if (resultSeq == NULL)
13669
0
      return(-1);
13670
0
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13671
0
  if (*resultSeq == NULL)
13672
0
      return(-1);
13673
0
    }
13674
13675
    /*
13676
     * handle the special cases of "/" amd "." being matched
13677
     */
13678
0
    if (min_depth == 0) {
13679
0
  if (from_root) {
13680
      /* Select "/" */
13681
0
      if (toBool)
13682
0
    return(1);
13683
            /* TODO: Check memory error. */
13684
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13685
0
                         (xmlNodePtr) ctxt->doc);
13686
0
  } else {
13687
      /* Select "self::node()" */
13688
0
      if (toBool)
13689
0
    return(1);
13690
            /* TODO: Check memory error. */
13691
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13692
0
  }
13693
0
    }
13694
0
    if (max_depth == 0) {
13695
0
  return(0);
13696
0
    }
13697
13698
0
    if (from_root) {
13699
0
        cur = (xmlNodePtr)ctxt->doc;
13700
0
    } else if (ctxt->node != NULL) {
13701
0
        switch (ctxt->node->type) {
13702
0
            case XML_ELEMENT_NODE:
13703
0
            case XML_DOCUMENT_NODE:
13704
0
            case XML_DOCUMENT_FRAG_NODE:
13705
0
            case XML_HTML_DOCUMENT_NODE:
13706
0
          cur = ctxt->node;
13707
0
    break;
13708
0
            case XML_ATTRIBUTE_NODE:
13709
0
            case XML_TEXT_NODE:
13710
0
            case XML_CDATA_SECTION_NODE:
13711
0
            case XML_ENTITY_REF_NODE:
13712
0
            case XML_ENTITY_NODE:
13713
0
            case XML_PI_NODE:
13714
0
            case XML_COMMENT_NODE:
13715
0
            case XML_NOTATION_NODE:
13716
0
            case XML_DTD_NODE:
13717
0
            case XML_DOCUMENT_TYPE_NODE:
13718
0
            case XML_ELEMENT_DECL:
13719
0
            case XML_ATTRIBUTE_DECL:
13720
0
            case XML_ENTITY_DECL:
13721
0
            case XML_NAMESPACE_DECL:
13722
0
            case XML_XINCLUDE_START:
13723
0
            case XML_XINCLUDE_END:
13724
0
    break;
13725
0
  }
13726
0
  limit = cur;
13727
0
    }
13728
0
    if (cur == NULL) {
13729
0
        return(0);
13730
0
    }
13731
13732
0
    patstream = xmlPatternGetStreamCtxt(comp);
13733
0
    if (patstream == NULL) {
13734
  /*
13735
  * QUESTION TODO: Is this an error?
13736
  */
13737
0
  return(0);
13738
0
    }
13739
13740
0
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13741
13742
0
    if (from_root) {
13743
0
  ret = xmlStreamPush(patstream, NULL, NULL);
13744
0
  if (ret < 0) {
13745
0
  } else if (ret == 1) {
13746
0
      if (toBool)
13747
0
    goto return_1;
13748
            /* TODO: Check memory error. */
13749
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13750
0
  }
13751
0
    }
13752
0
    depth = 0;
13753
0
    goto scan_children;
13754
0
next_node:
13755
0
    do {
13756
0
        if (ctxt->opLimit != 0) {
13757
0
            if (ctxt->opCount >= ctxt->opLimit) {
13758
0
                xmlGenericError(xmlGenericErrorContext,
13759
0
                        "XPath operation limit exceeded\n");
13760
0
                xmlFreeStreamCtxt(patstream);
13761
0
                return(-1);
13762
0
            }
13763
0
            ctxt->opCount++;
13764
0
        }
13765
13766
0
        nb_nodes++;
13767
13768
0
  switch (cur->type) {
13769
0
      case XML_ELEMENT_NODE:
13770
0
      case XML_TEXT_NODE:
13771
0
      case XML_CDATA_SECTION_NODE:
13772
0
      case XML_COMMENT_NODE:
13773
0
      case XML_PI_NODE:
13774
0
    if (cur->type == XML_ELEMENT_NODE) {
13775
0
        ret = xmlStreamPush(patstream, cur->name,
13776
0
        (cur->ns ? cur->ns->href : NULL));
13777
0
    } else if (eval_all_nodes)
13778
0
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13779
0
    else
13780
0
        break;
13781
13782
0
    if (ret < 0) {
13783
        /* NOP. */
13784
0
    } else if (ret == 1) {
13785
0
        if (toBool)
13786
0
      goto return_1;
13787
0
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13788
0
            < 0) {
13789
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13790
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13791
0
        }
13792
0
    }
13793
0
    if ((cur->children == NULL) || (depth >= max_depth)) {
13794
0
        ret = xmlStreamPop(patstream);
13795
0
        while (cur->next != NULL) {
13796
0
      cur = cur->next;
13797
0
      if ((cur->type != XML_ENTITY_DECL) &&
13798
0
          (cur->type != XML_DTD_NODE))
13799
0
          goto next_node;
13800
0
        }
13801
0
    }
13802
0
      default:
13803
0
    break;
13804
0
  }
13805
13806
0
scan_children:
13807
0
  if (cur->type == XML_NAMESPACE_DECL) break;
13808
0
  if ((cur->children != NULL) && (depth < max_depth)) {
13809
      /*
13810
       * Do not descend on entities declarations
13811
       */
13812
0
      if (cur->children->type != XML_ENTITY_DECL) {
13813
0
    cur = cur->children;
13814
0
    depth++;
13815
    /*
13816
     * Skip DTDs
13817
     */
13818
0
    if (cur->type != XML_DTD_NODE)
13819
0
        continue;
13820
0
      }
13821
0
  }
13822
13823
0
  if (cur == limit)
13824
0
      break;
13825
13826
0
  while (cur->next != NULL) {
13827
0
      cur = cur->next;
13828
0
      if ((cur->type != XML_ENTITY_DECL) &&
13829
0
    (cur->type != XML_DTD_NODE))
13830
0
    goto next_node;
13831
0
  }
13832
13833
0
  do {
13834
0
      cur = cur->parent;
13835
0
      depth--;
13836
0
      if ((cur == NULL) || (cur == limit) ||
13837
0
                (cur->type == XML_DOCUMENT_NODE))
13838
0
          goto done;
13839
0
      if (cur->type == XML_ELEMENT_NODE) {
13840
0
    ret = xmlStreamPop(patstream);
13841
0
      } else if ((eval_all_nodes) &&
13842
0
    ((cur->type == XML_TEXT_NODE) ||
13843
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13844
0
     (cur->type == XML_COMMENT_NODE) ||
13845
0
     (cur->type == XML_PI_NODE)))
13846
0
      {
13847
0
    ret = xmlStreamPop(patstream);
13848
0
      }
13849
0
      if (cur->next != NULL) {
13850
0
    cur = cur->next;
13851
0
    break;
13852
0
      }
13853
0
  } while (cur != NULL);
13854
13855
0
    } while ((cur != NULL) && (depth >= 0));
13856
13857
0
done:
13858
13859
#if 0
13860
    printf("stream eval: checked %d nodes selected %d\n",
13861
           nb_nodes, retObj->nodesetval->nodeNr);
13862
#endif
13863
13864
0
    if (patstream)
13865
0
  xmlFreeStreamCtxt(patstream);
13866
0
    return(0);
13867
13868
0
return_1:
13869
0
    if (patstream)
13870
0
  xmlFreeStreamCtxt(patstream);
13871
0
    return(1);
13872
0
}
13873
#endif /* XPATH_STREAMING */
13874
13875
/**
13876
 * xmlXPathRunEval:
13877
 * @ctxt:  the XPath parser context with the compiled expression
13878
 * @toBool:  evaluate to a boolean result
13879
 *
13880
 * Evaluate the Precompiled XPath expression in the given context.
13881
 */
13882
static int
13883
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13884
0
{
13885
0
    xmlXPathCompExprPtr comp;
13886
0
    int oldDepth;
13887
13888
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13889
0
  return(-1);
13890
13891
0
    if (ctxt->valueTab == NULL) {
13892
  /* Allocate the value stack */
13893
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
13894
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13895
0
  if (ctxt->valueTab == NULL) {
13896
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13897
0
      return(-1);
13898
0
  }
13899
0
  ctxt->valueNr = 0;
13900
0
  ctxt->valueMax = 10;
13901
0
  ctxt->value = NULL;
13902
0
        ctxt->valueFrame = 0;
13903
0
    }
13904
0
#ifdef XPATH_STREAMING
13905
0
    if (ctxt->comp->stream) {
13906
0
  int res;
13907
13908
0
  if (toBool) {
13909
      /*
13910
      * Evaluation to boolean result.
13911
      */
13912
0
      res = xmlXPathRunStreamEval(ctxt->context,
13913
0
    ctxt->comp->stream, NULL, 1);
13914
0
      if (res != -1)
13915
0
    return(res);
13916
0
  } else {
13917
0
      xmlXPathObjectPtr resObj = NULL;
13918
13919
      /*
13920
      * Evaluation to a sequence.
13921
      */
13922
0
      res = xmlXPathRunStreamEval(ctxt->context,
13923
0
    ctxt->comp->stream, &resObj, 0);
13924
13925
0
      if ((res != -1) && (resObj != NULL)) {
13926
0
    valuePush(ctxt, resObj);
13927
0
    return(0);
13928
0
      }
13929
0
      if (resObj != NULL)
13930
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13931
0
  }
13932
  /*
13933
  * QUESTION TODO: This falls back to normal XPath evaluation
13934
  * if res == -1. Is this intended?
13935
  */
13936
0
    }
13937
0
#endif
13938
0
    comp = ctxt->comp;
13939
0
    if (comp->last < 0) {
13940
0
  xmlGenericError(xmlGenericErrorContext,
13941
0
      "xmlXPathRunEval: last is less than zero\n");
13942
0
  return(-1);
13943
0
    }
13944
0
    oldDepth = ctxt->context->depth;
13945
0
    if (toBool)
13946
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13947
0
      &comp->steps[comp->last], 0));
13948
0
    else
13949
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13950
0
    ctxt->context->depth = oldDepth;
13951
13952
0
    return(0);
13953
0
}
13954
13955
/************************************************************************
13956
 *                  *
13957
 *      Public interfaces       *
13958
 *                  *
13959
 ************************************************************************/
13960
13961
/**
13962
 * xmlXPathEvalPredicate:
13963
 * @ctxt:  the XPath context
13964
 * @res:  the Predicate Expression evaluation result
13965
 *
13966
 * Evaluate a predicate result for the current node.
13967
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13968
 * the result to a boolean. If the result is a number, the result will
13969
 * be converted to true if the number is equal to the position of the
13970
 * context node in the context node list (as returned by the position
13971
 * function) and will be converted to false otherwise; if the result
13972
 * is not a number, then the result will be converted as if by a call
13973
 * to the boolean function.
13974
 *
13975
 * Returns 1 if predicate is true, 0 otherwise
13976
 */
13977
int
13978
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13979
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13980
0
    switch (res->type) {
13981
0
        case XPATH_BOOLEAN:
13982
0
      return(res->boolval);
13983
0
        case XPATH_NUMBER:
13984
0
      return(res->floatval == ctxt->proximityPosition);
13985
0
        case XPATH_NODESET:
13986
0
        case XPATH_XSLT_TREE:
13987
0
      if (res->nodesetval == NULL)
13988
0
    return(0);
13989
0
      return(res->nodesetval->nodeNr != 0);
13990
0
        case XPATH_STRING:
13991
0
      return((res->stringval != NULL) &&
13992
0
             (xmlStrlen(res->stringval) != 0));
13993
0
        default:
13994
0
      STRANGE
13995
0
    }
13996
0
    return(0);
13997
0
}
13998
13999
/**
14000
 * xmlXPathEvaluatePredicateResult:
14001
 * @ctxt:  the XPath Parser context
14002
 * @res:  the Predicate Expression evaluation result
14003
 *
14004
 * Evaluate a predicate result for the current node.
14005
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14006
 * the result to a boolean. If the result is a number, the result will
14007
 * be converted to true if the number is equal to the position of the
14008
 * context node in the context node list (as returned by the position
14009
 * function) and will be converted to false otherwise; if the result
14010
 * is not a number, then the result will be converted as if by a call
14011
 * to the boolean function.
14012
 *
14013
 * Returns 1 if predicate is true, 0 otherwise
14014
 */
14015
int
14016
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14017
0
                                xmlXPathObjectPtr res) {
14018
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
14019
0
    switch (res->type) {
14020
0
        case XPATH_BOOLEAN:
14021
0
      return(res->boolval);
14022
0
        case XPATH_NUMBER:
14023
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14024
      return((res->floatval == ctxt->context->proximityPosition) &&
14025
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14026
#else
14027
0
      return(res->floatval == ctxt->context->proximityPosition);
14028
0
#endif
14029
0
        case XPATH_NODESET:
14030
0
        case XPATH_XSLT_TREE:
14031
0
      if (res->nodesetval == NULL)
14032
0
    return(0);
14033
0
      return(res->nodesetval->nodeNr != 0);
14034
0
        case XPATH_STRING:
14035
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14036
#ifdef LIBXML_XPTR_LOCS_ENABLED
14037
  case XPATH_LOCATIONSET:{
14038
      xmlLocationSetPtr ptr = res->user;
14039
      if (ptr == NULL)
14040
          return(0);
14041
      return (ptr->locNr != 0);
14042
      }
14043
#endif
14044
0
        default:
14045
0
      STRANGE
14046
0
    }
14047
0
    return(0);
14048
0
}
14049
14050
#ifdef XPATH_STREAMING
14051
/**
14052
 * xmlXPathTryStreamCompile:
14053
 * @ctxt: an XPath context
14054
 * @str:  the XPath expression
14055
 *
14056
 * Try to compile the XPath expression as a streamable subset.
14057
 *
14058
 * Returns the compiled expression or NULL if failed to compile.
14059
 */
14060
static xmlXPathCompExprPtr
14061
0
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14062
    /*
14063
     * Optimization: use streaming patterns when the XPath expression can
14064
     * be compiled to a stream lookup
14065
     */
14066
0
    xmlPatternPtr stream;
14067
0
    xmlXPathCompExprPtr comp;
14068
0
    xmlDictPtr dict = NULL;
14069
0
    const xmlChar **namespaces = NULL;
14070
0
    xmlNsPtr ns;
14071
0
    int i, j;
14072
14073
0
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14074
0
        (!xmlStrchr(str, '@'))) {
14075
0
  const xmlChar *tmp;
14076
14077
  /*
14078
   * We don't try to handle expressions using the verbose axis
14079
   * specifiers ("::"), just the simplified form at this point.
14080
   * Additionally, if there is no list of namespaces available and
14081
   *  there's a ":" in the expression, indicating a prefixed QName,
14082
   *  then we won't try to compile either. xmlPatterncompile() needs
14083
   *  to have a list of namespaces at compilation time in order to
14084
   *  compile prefixed name tests.
14085
   */
14086
0
  tmp = xmlStrchr(str, ':');
14087
0
  if ((tmp != NULL) &&
14088
0
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14089
0
      return(NULL);
14090
14091
0
  if (ctxt != NULL) {
14092
0
      dict = ctxt->dict;
14093
0
      if (ctxt->nsNr > 0) {
14094
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14095
0
    if (namespaces == NULL) {
14096
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14097
0
        return(NULL);
14098
0
    }
14099
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14100
0
        ns = ctxt->namespaces[j];
14101
0
        namespaces[i++] = ns->href;
14102
0
        namespaces[i++] = ns->prefix;
14103
0
    }
14104
0
    namespaces[i++] = NULL;
14105
0
    namespaces[i] = NULL;
14106
0
      }
14107
0
  }
14108
14109
0
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14110
0
  if (namespaces != NULL) {
14111
0
      xmlFree((xmlChar **)namespaces);
14112
0
  }
14113
0
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14114
0
      comp = xmlXPathNewCompExpr();
14115
0
      if (comp == NULL) {
14116
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14117
0
    return(NULL);
14118
0
      }
14119
0
      comp->stream = stream;
14120
0
      comp->dict = dict;
14121
0
      if (comp->dict)
14122
0
    xmlDictReference(comp->dict);
14123
0
      return(comp);
14124
0
  }
14125
0
  xmlFreePattern(stream);
14126
0
    }
14127
0
    return(NULL);
14128
0
}
14129
#endif /* XPATH_STREAMING */
14130
14131
static void
14132
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14133
                           xmlXPathStepOpPtr op)
14134
0
{
14135
0
    xmlXPathCompExprPtr comp = pctxt->comp;
14136
0
    xmlXPathContextPtr ctxt;
14137
14138
    /*
14139
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14140
    * internal representation.
14141
    */
14142
14143
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14144
0
        (op->ch1 != -1) &&
14145
0
        (op->ch2 == -1 /* no predicate */))
14146
0
    {
14147
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14148
14149
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14150
0
            ((xmlXPathAxisVal) prevop->value ==
14151
0
                AXIS_DESCENDANT_OR_SELF) &&
14152
0
            (prevop->ch2 == -1) &&
14153
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14154
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14155
0
        {
14156
            /*
14157
            * This is a "descendant-or-self::node()" without predicates.
14158
            * Try to eliminate it.
14159
            */
14160
14161
0
            switch ((xmlXPathAxisVal) op->value) {
14162
0
                case AXIS_CHILD:
14163
0
                case AXIS_DESCENDANT:
14164
                    /*
14165
                    * Convert "descendant-or-self::node()/child::" or
14166
                    * "descendant-or-self::node()/descendant::" to
14167
                    * "descendant::"
14168
                    */
14169
0
                    op->ch1   = prevop->ch1;
14170
0
                    op->value = AXIS_DESCENDANT;
14171
0
                    break;
14172
0
                case AXIS_SELF:
14173
0
                case AXIS_DESCENDANT_OR_SELF:
14174
                    /*
14175
                    * Convert "descendant-or-self::node()/self::" or
14176
                    * "descendant-or-self::node()/descendant-or-self::" to
14177
                    * to "descendant-or-self::"
14178
                    */
14179
0
                    op->ch1   = prevop->ch1;
14180
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
14181
0
                    break;
14182
0
                default:
14183
0
                    break;
14184
0
            }
14185
0
  }
14186
0
    }
14187
14188
    /* OP_VALUE has invalid ch1. */
14189
0
    if (op->op == XPATH_OP_VALUE)
14190
0
        return;
14191
14192
    /* Recurse */
14193
0
    ctxt = pctxt->context;
14194
0
    if (ctxt != NULL) {
14195
0
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14196
0
            return;
14197
0
        ctxt->depth += 1;
14198
0
    }
14199
0
    if (op->ch1 != -1)
14200
0
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14201
0
    if (op->ch2 != -1)
14202
0
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14203
0
    if (ctxt != NULL)
14204
0
        ctxt->depth -= 1;
14205
0
}
14206
14207
/**
14208
 * xmlXPathCtxtCompile:
14209
 * @ctxt: an XPath context
14210
 * @str:  the XPath expression
14211
 *
14212
 * Compile an XPath expression
14213
 *
14214
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14215
 *         the caller has to free the object.
14216
 */
14217
xmlXPathCompExprPtr
14218
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14219
0
    xmlXPathParserContextPtr pctxt;
14220
0
    xmlXPathCompExprPtr comp;
14221
0
    int oldDepth = 0;
14222
14223
0
#ifdef XPATH_STREAMING
14224
0
    comp = xmlXPathTryStreamCompile(ctxt, str);
14225
0
    if (comp != NULL)
14226
0
        return(comp);
14227
0
#endif
14228
14229
0
    xmlInitParser();
14230
14231
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
14232
0
    if (pctxt == NULL)
14233
0
        return NULL;
14234
0
    if (ctxt != NULL)
14235
0
        oldDepth = ctxt->depth;
14236
0
    xmlXPathCompileExpr(pctxt, 1);
14237
0
    if (ctxt != NULL)
14238
0
        ctxt->depth = oldDepth;
14239
14240
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
14241
0
    {
14242
0
        xmlXPathFreeParserContext(pctxt);
14243
0
        return(NULL);
14244
0
    }
14245
14246
0
    if (*pctxt->cur != 0) {
14247
  /*
14248
   * aleksey: in some cases this line prints *second* error message
14249
   * (see bug #78858) and probably this should be fixed.
14250
   * However, we are not sure that all error messages are printed
14251
   * out in other places. It's not critical so we leave it as-is for now
14252
   */
14253
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14254
0
  comp = NULL;
14255
0
    } else {
14256
0
  comp = pctxt->comp;
14257
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14258
0
            if (ctxt != NULL)
14259
0
                oldDepth = ctxt->depth;
14260
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14261
0
            if (ctxt != NULL)
14262
0
                ctxt->depth = oldDepth;
14263
0
  }
14264
0
  pctxt->comp = NULL;
14265
0
    }
14266
0
    xmlXPathFreeParserContext(pctxt);
14267
14268
0
    if (comp != NULL) {
14269
0
  comp->expr = xmlStrdup(str);
14270
#ifdef DEBUG_EVAL_COUNTS
14271
  comp->string = xmlStrdup(str);
14272
  comp->nb = 0;
14273
#endif
14274
0
    }
14275
0
    return(comp);
14276
0
}
14277
14278
/**
14279
 * xmlXPathCompile:
14280
 * @str:  the XPath expression
14281
 *
14282
 * Compile an XPath expression
14283
 *
14284
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14285
 *         the caller has to free the object.
14286
 */
14287
xmlXPathCompExprPtr
14288
0
xmlXPathCompile(const xmlChar *str) {
14289
0
    return(xmlXPathCtxtCompile(NULL, str));
14290
0
}
14291
14292
/**
14293
 * xmlXPathCompiledEvalInternal:
14294
 * @comp:  the compiled XPath expression
14295
 * @ctxt:  the XPath context
14296
 * @resObj: the resulting XPath object or NULL
14297
 * @toBool: 1 if only a boolean result is requested
14298
 *
14299
 * Evaluate the Precompiled XPath expression in the given context.
14300
 * The caller has to free @resObj.
14301
 *
14302
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14303
 *         the caller has to free the object.
14304
 */
14305
static int
14306
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14307
           xmlXPathContextPtr ctxt,
14308
           xmlXPathObjectPtr *resObjPtr,
14309
           int toBool)
14310
0
{
14311
0
    xmlXPathParserContextPtr pctxt;
14312
0
    xmlXPathObjectPtr resObj;
14313
#ifndef LIBXML_THREAD_ENABLED
14314
    static int reentance = 0;
14315
#endif
14316
0
    int res;
14317
14318
0
    CHECK_CTXT_NEG(ctxt)
14319
14320
0
    if (comp == NULL)
14321
0
  return(-1);
14322
0
    xmlInitParser();
14323
14324
#ifndef LIBXML_THREAD_ENABLED
14325
    reentance++;
14326
    if (reentance > 1)
14327
  xmlXPathDisableOptimizer = 1;
14328
#endif
14329
14330
#ifdef DEBUG_EVAL_COUNTS
14331
    comp->nb++;
14332
    if ((comp->string != NULL) && (comp->nb > 100)) {
14333
  fprintf(stderr, "100 x %s\n", comp->string);
14334
  comp->nb = 0;
14335
    }
14336
#endif
14337
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14338
0
    res = xmlXPathRunEval(pctxt, toBool);
14339
14340
0
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14341
0
        resObj = NULL;
14342
0
    } else {
14343
0
        resObj = valuePop(pctxt);
14344
0
        if (resObj == NULL) {
14345
0
            if (!toBool)
14346
0
                xmlGenericError(xmlGenericErrorContext,
14347
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14348
0
        } else if (pctxt->valueNr > 0) {
14349
0
            xmlGenericError(xmlGenericErrorContext,
14350
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14351
0
                pctxt->valueNr);
14352
0
        }
14353
0
    }
14354
14355
0
    if (resObjPtr)
14356
0
        *resObjPtr = resObj;
14357
0
    else
14358
0
        xmlXPathReleaseObject(ctxt, resObj);
14359
14360
0
    pctxt->comp = NULL;
14361
0
    xmlXPathFreeParserContext(pctxt);
14362
#ifndef LIBXML_THREAD_ENABLED
14363
    reentance--;
14364
#endif
14365
14366
0
    return(res);
14367
0
}
14368
14369
/**
14370
 * xmlXPathCompiledEval:
14371
 * @comp:  the compiled XPath expression
14372
 * @ctx:  the XPath context
14373
 *
14374
 * Evaluate the Precompiled XPath expression in the given context.
14375
 *
14376
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14377
 *         the caller has to free the object.
14378
 */
14379
xmlXPathObjectPtr
14380
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14381
0
{
14382
0
    xmlXPathObjectPtr res = NULL;
14383
14384
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14385
0
    return(res);
14386
0
}
14387
14388
/**
14389
 * xmlXPathCompiledEvalToBoolean:
14390
 * @comp:  the compiled XPath expression
14391
 * @ctxt:  the XPath context
14392
 *
14393
 * Applies the XPath boolean() function on the result of the given
14394
 * compiled expression.
14395
 *
14396
 * Returns 1 if the expression evaluated to true, 0 if to false and
14397
 *         -1 in API and internal errors.
14398
 */
14399
int
14400
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14401
            xmlXPathContextPtr ctxt)
14402
0
{
14403
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14404
0
}
14405
14406
/**
14407
 * xmlXPathEvalExpr:
14408
 * @ctxt:  the XPath Parser context
14409
 *
14410
 * Parse and evaluate an XPath expression in the given context,
14411
 * then push the result on the context stack
14412
 */
14413
void
14414
0
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14415
0
#ifdef XPATH_STREAMING
14416
0
    xmlXPathCompExprPtr comp;
14417
0
#endif
14418
0
    int oldDepth = 0;
14419
14420
0
    if (ctxt == NULL) return;
14421
14422
0
#ifdef XPATH_STREAMING
14423
0
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14424
0
    if (comp != NULL) {
14425
0
        if (ctxt->comp != NULL)
14426
0
      xmlXPathFreeCompExpr(ctxt->comp);
14427
0
        ctxt->comp = comp;
14428
0
    } else
14429
0
#endif
14430
0
    {
14431
0
        if (ctxt->context != NULL)
14432
0
            oldDepth = ctxt->context->depth;
14433
0
  xmlXPathCompileExpr(ctxt, 1);
14434
0
        if (ctxt->context != NULL)
14435
0
            ctxt->context->depth = oldDepth;
14436
0
        CHECK_ERROR;
14437
14438
        /* Check for trailing characters. */
14439
0
        if (*ctxt->cur != 0)
14440
0
            XP_ERROR(XPATH_EXPR_ERROR);
14441
14442
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14443
0
            if (ctxt->context != NULL)
14444
0
                oldDepth = ctxt->context->depth;
14445
0
      xmlXPathOptimizeExpression(ctxt,
14446
0
    &ctxt->comp->steps[ctxt->comp->last]);
14447
0
            if (ctxt->context != NULL)
14448
0
                ctxt->context->depth = oldDepth;
14449
0
        }
14450
0
    }
14451
14452
0
    xmlXPathRunEval(ctxt, 0);
14453
0
}
14454
14455
/**
14456
 * xmlXPathEval:
14457
 * @str:  the XPath expression
14458
 * @ctx:  the XPath context
14459
 *
14460
 * Evaluate the XPath Location Path in the given context.
14461
 *
14462
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14463
 *         the caller has to free the object.
14464
 */
14465
xmlXPathObjectPtr
14466
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14467
0
    xmlXPathParserContextPtr ctxt;
14468
0
    xmlXPathObjectPtr res;
14469
14470
0
    CHECK_CTXT(ctx)
14471
14472
0
    xmlInitParser();
14473
14474
0
    ctxt = xmlXPathNewParserContext(str, ctx);
14475
0
    if (ctxt == NULL)
14476
0
        return NULL;
14477
0
    xmlXPathEvalExpr(ctxt);
14478
14479
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14480
0
  res = NULL;
14481
0
    } else {
14482
0
  res = valuePop(ctxt);
14483
0
        if (res == NULL) {
14484
0
            xmlGenericError(xmlGenericErrorContext,
14485
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14486
0
        } else if (ctxt->valueNr > 0) {
14487
0
            xmlGenericError(xmlGenericErrorContext,
14488
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14489
0
                ctxt->valueNr);
14490
0
        }
14491
0
    }
14492
14493
0
    xmlXPathFreeParserContext(ctxt);
14494
0
    return(res);
14495
0
}
14496
14497
/**
14498
 * xmlXPathSetContextNode:
14499
 * @node: the node to to use as the context node
14500
 * @ctx:  the XPath context
14501
 *
14502
 * Sets 'node' as the context node. The node must be in the same
14503
 * document as that associated with the context.
14504
 *
14505
 * Returns -1 in case of error or 0 if successful
14506
 */
14507
int
14508
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14509
0
    if ((node == NULL) || (ctx == NULL))
14510
0
        return(-1);
14511
14512
0
    if (node->doc == ctx->doc) {
14513
0
        ctx->node = node;
14514
0
  return(0);
14515
0
    }
14516
0
    return(-1);
14517
0
}
14518
14519
/**
14520
 * xmlXPathNodeEval:
14521
 * @node: the node to to use as the context node
14522
 * @str:  the XPath expression
14523
 * @ctx:  the XPath context
14524
 *
14525
 * Evaluate the XPath Location Path in the given context. The node 'node'
14526
 * is set as the context node. The context node is not restored.
14527
 *
14528
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14529
 *         the caller has to free the object.
14530
 */
14531
xmlXPathObjectPtr
14532
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14533
0
    if (str == NULL)
14534
0
        return(NULL);
14535
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14536
0
        return(NULL);
14537
0
    return(xmlXPathEval(str, ctx));
14538
0
}
14539
14540
/**
14541
 * xmlXPathEvalExpression:
14542
 * @str:  the XPath expression
14543
 * @ctxt:  the XPath context
14544
 *
14545
 * Alias for xmlXPathEval().
14546
 *
14547
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14548
 *         the caller has to free the object.
14549
 */
14550
xmlXPathObjectPtr
14551
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14552
0
    return(xmlXPathEval(str, ctxt));
14553
0
}
14554
14555
/************************************************************************
14556
 *                  *
14557
 *  Extra functions not pertaining to the XPath spec    *
14558
 *                  *
14559
 ************************************************************************/
14560
/**
14561
 * xmlXPathEscapeUriFunction:
14562
 * @ctxt:  the XPath Parser context
14563
 * @nargs:  the number of arguments
14564
 *
14565
 * Implement the escape-uri() XPath function
14566
 *    string escape-uri(string $str, bool $escape-reserved)
14567
 *
14568
 * This function applies the URI escaping rules defined in section 2 of [RFC
14569
 * 2396] to the string supplied as $uri-part, which typically represents all
14570
 * or part of a URI. The effect of the function is to replace any special
14571
 * character in the string by an escape sequence of the form %xx%yy...,
14572
 * where xxyy... is the hexadecimal representation of the octets used to
14573
 * represent the character in UTF-8.
14574
 *
14575
 * The set of characters that are escaped depends on the setting of the
14576
 * boolean argument $escape-reserved.
14577
 *
14578
 * If $escape-reserved is true, all characters are escaped other than lower
14579
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14580
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14581
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14582
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14583
 * A-F).
14584
 *
14585
 * If $escape-reserved is false, the behavior differs in that characters
14586
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14587
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14588
 *
14589
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14590
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14591
 * compared using string comparison functions, this function must always use
14592
 * the upper-case letters A-F.
14593
 *
14594
 * Generally, $escape-reserved should be set to true when escaping a string
14595
 * that is to form a single part of a URI, and to false when escaping an
14596
 * entire URI or URI reference.
14597
 *
14598
 * In the case of non-ascii characters, the string is encoded according to
14599
 * utf-8 and then converted according to RFC 2396.
14600
 *
14601
 * Examples
14602
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14603
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14604
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14605
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14606
 *
14607
 */
14608
static void
14609
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14610
0
    xmlXPathObjectPtr str;
14611
0
    int escape_reserved;
14612
0
    xmlBufPtr target;
14613
0
    xmlChar *cptr;
14614
0
    xmlChar escape[4];
14615
14616
0
    CHECK_ARITY(2);
14617
14618
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14619
14620
0
    CAST_TO_STRING;
14621
0
    str = valuePop(ctxt);
14622
14623
0
    target = xmlBufCreate();
14624
14625
0
    escape[0] = '%';
14626
0
    escape[3] = 0;
14627
14628
0
    if (target) {
14629
0
  for (cptr = str->stringval; *cptr; cptr++) {
14630
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14631
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14632
0
    (*cptr >= '0' && *cptr <= '9') ||
14633
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14634
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14635
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14636
0
    (*cptr == '%' &&
14637
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14638
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14639
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14640
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14641
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14642
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14643
0
    (!escape_reserved &&
14644
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14645
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14646
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14647
0
      *cptr == ','))) {
14648
0
    xmlBufAdd(target, cptr, 1);
14649
0
      } else {
14650
0
    if ((*cptr >> 4) < 10)
14651
0
        escape[1] = '0' + (*cptr >> 4);
14652
0
    else
14653
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14654
0
    if ((*cptr & 0xF) < 10)
14655
0
        escape[2] = '0' + (*cptr & 0xF);
14656
0
    else
14657
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14658
14659
0
    xmlBufAdd(target, &escape[0], 3);
14660
0
      }
14661
0
  }
14662
0
    }
14663
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14664
0
  xmlBufContent(target)));
14665
0
    xmlBufFree(target);
14666
0
    xmlXPathReleaseObject(ctxt->context, str);
14667
0
}
14668
14669
/**
14670
 * xmlXPathRegisterAllFunctions:
14671
 * @ctxt:  the XPath context
14672
 *
14673
 * Registers all default XPath functions in this context
14674
 */
14675
void
14676
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14677
0
{
14678
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14679
0
                         xmlXPathBooleanFunction);
14680
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14681
0
                         xmlXPathCeilingFunction);
14682
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14683
0
                         xmlXPathCountFunction);
14684
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14685
0
                         xmlXPathConcatFunction);
14686
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14687
0
                         xmlXPathContainsFunction);
14688
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14689
0
                         xmlXPathIdFunction);
14690
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14691
0
                         xmlXPathFalseFunction);
14692
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14693
0
                         xmlXPathFloorFunction);
14694
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14695
0
                         xmlXPathLastFunction);
14696
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14697
0
                         xmlXPathLangFunction);
14698
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14699
0
                         xmlXPathLocalNameFunction);
14700
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14701
0
                         xmlXPathNotFunction);
14702
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14703
0
                         xmlXPathNameFunction);
14704
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14705
0
                         xmlXPathNamespaceURIFunction);
14706
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14707
0
                         xmlXPathNormalizeFunction);
14708
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14709
0
                         xmlXPathNumberFunction);
14710
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14711
0
                         xmlXPathPositionFunction);
14712
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14713
0
                         xmlXPathRoundFunction);
14714
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14715
0
                         xmlXPathStringFunction);
14716
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14717
0
                         xmlXPathStringLengthFunction);
14718
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14719
0
                         xmlXPathStartsWithFunction);
14720
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14721
0
                         xmlXPathSubstringFunction);
14722
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14723
0
                         xmlXPathSubstringBeforeFunction);
14724
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14725
0
                         xmlXPathSubstringAfterFunction);
14726
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14727
0
                         xmlXPathSumFunction);
14728
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14729
0
                         xmlXPathTrueFunction);
14730
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14731
0
                         xmlXPathTranslateFunction);
14732
14733
0
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14734
0
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14735
0
                         xmlXPathEscapeUriFunction);
14736
0
}
14737
14738
#endif /* LIBXML_XPATH_ENABLED */