Coverage Report

Created: 2022-06-08 06:16

/src/libxml2/xpath.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xpath.c: XML Path Language implementation
3
 *          XPath is a language for addressing parts of an XML document,
4
 *          designed to be used by both XSLT and XPointer
5
 *
6
 * Reference: W3C Recommendation 16 November 1999
7
 *     http://www.w3.org/TR/1999/REC-xpath-19991116
8
 * Public reference:
9
 *     http://www.w3.org/TR/xpath
10
 *
11
 * See Copyright for the status of this software
12
 *
13
 * Author: daniel@veillard.com
14
 *
15
 */
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/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
    /* MSVC doesn't allow division by zero in constant expressions. */
494
1
    double zero = 0.0;
495
1
    xmlXPathNAN = 0.0 / zero;
496
1
    xmlXPathPINF = 1.0 / zero;
497
1
    xmlXPathNINF = -xmlXPathPINF;
498
1
}
499
500
/**
501
 * xmlXPathIsNaN:
502
 * @val:  a double value
503
 *
504
 * Returns 1 if the value is a NaN, 0 otherwise
505
 */
506
int
507
0
xmlXPathIsNaN(double val) {
508
0
#ifdef isnan
509
0
    return isnan(val);
510
#else
511
    return !(val == val);
512
#endif
513
0
}
514
515
/**
516
 * xmlXPathIsInf:
517
 * @val:  a double value
518
 *
519
 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
520
 */
521
int
522
0
xmlXPathIsInf(double val) {
523
0
#ifdef isinf
524
0
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
525
#else
526
    if (val >= xmlXPathPINF)
527
        return 1;
528
    if (val <= -xmlXPathPINF)
529
        return -1;
530
    return 0;
531
#endif
532
0
}
533
534
#endif /* SCHEMAS or XPATH */
535
536
#ifdef LIBXML_XPATH_ENABLED
537
538
/*
539
 * TODO: when compatibility allows remove all "fake node libxslt" strings
540
 *       the test should just be name[0] = ' '
541
 */
542
#ifdef DEBUG_XPATH_EXPRESSION
543
#define DEBUG_STEP
544
#define DEBUG_EXPR
545
#define DEBUG_EVAL_COUNTS
546
#endif
547
548
static xmlNs xmlXPathXMLNamespaceStruct = {
549
    NULL,
550
    XML_NAMESPACE_DECL,
551
    XML_XML_NAMESPACE,
552
    BAD_CAST "xml",
553
    NULL,
554
    NULL
555
};
556
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
557
#ifndef LIBXML_THREAD_ENABLED
558
/*
559
 * Optimizer is disabled only when threaded apps are detected while
560
 * the library ain't compiled for thread safety.
561
 */
562
static int xmlXPathDisableOptimizer = 0;
563
#endif
564
565
/************************************************************************
566
 *                  *
567
 *      Error handling routines       *
568
 *                  *
569
 ************************************************************************/
570
571
/**
572
 * XP_ERRORNULL:
573
 * @X:  the error code
574
 *
575
 * Macro to raise an XPath error and return NULL.
576
 */
577
#define XP_ERRORNULL(X)             \
578
0
    { xmlXPathErr(ctxt, X); return(NULL); }
579
580
/*
581
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
582
 */
583
static const char* const xmlXPathErrorMessages[] = {
584
    "Ok\n",
585
    "Number encoding\n",
586
    "Unfinished literal\n",
587
    "Start of literal\n",
588
    "Expected $ for variable reference\n",
589
    "Undefined variable\n",
590
    "Invalid predicate\n",
591
    "Invalid expression\n",
592
    "Missing closing curly brace\n",
593
    "Unregistered function\n",
594
    "Invalid operand\n",
595
    "Invalid type\n",
596
    "Invalid number of arguments\n",
597
    "Invalid context size\n",
598
    "Invalid context position\n",
599
    "Memory allocation error\n",
600
    "Syntax error\n",
601
    "Resource error\n",
602
    "Sub resource error\n",
603
    "Undefined namespace prefix\n",
604
    "Encoding error\n",
605
    "Char out of XML range\n",
606
    "Invalid or incomplete context\n",
607
    "Stack usage error\n",
608
    "Forbidden variable\n",
609
    "Operation limit exceeded\n",
610
    "Recursion limit exceeded\n",
611
    "?? Unknown error ??\n" /* Must be last in the list! */
612
};
613
0
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
614
0
       sizeof(xmlXPathErrorMessages[0])) - 1)
615
/**
616
 * xmlXPathErrMemory:
617
 * @ctxt:  an XPath context
618
 * @extra:  extra information
619
 *
620
 * Handle a redefinition of attribute error
621
 */
622
static void
623
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
624
0
{
625
0
    if (ctxt != NULL) {
626
0
        xmlResetError(&ctxt->lastError);
627
0
        if (extra) {
628
0
            xmlChar buf[200];
629
630
0
            xmlStrPrintf(buf, 200,
631
0
                         "Memory allocation failed : %s\n",
632
0
                         extra);
633
0
            ctxt->lastError.message = (char *) xmlStrdup(buf);
634
0
        } else {
635
0
            ctxt->lastError.message = (char *)
636
0
         xmlStrdup(BAD_CAST "Memory allocation failed\n");
637
0
        }
638
0
        ctxt->lastError.domain = XML_FROM_XPATH;
639
0
        ctxt->lastError.code = XML_ERR_NO_MEMORY;
640
0
  if (ctxt->error != NULL)
641
0
      ctxt->error(ctxt->userData, &ctxt->lastError);
642
0
    } else {
643
0
        if (extra)
644
0
            __xmlRaiseError(NULL, NULL, NULL,
645
0
                            NULL, NULL, XML_FROM_XPATH,
646
0
                            XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
647
0
                            extra, NULL, NULL, 0, 0,
648
0
                            "Memory allocation failed : %s\n", extra);
649
0
        else
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
                            NULL, NULL, NULL, 0, 0,
654
0
                            "Memory allocation failed\n");
655
0
    }
656
0
}
657
658
/**
659
 * xmlXPathPErrMemory:
660
 * @ctxt:  an XPath parser context
661
 * @extra:  extra information
662
 *
663
 * Handle a redefinition of attribute error
664
 */
665
static void
666
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
667
0
{
668
0
    if (ctxt == NULL)
669
0
  xmlXPathErrMemory(NULL, extra);
670
0
    else {
671
0
  ctxt->error = XPATH_MEMORY_ERROR;
672
0
  xmlXPathErrMemory(ctxt->context, extra);
673
0
    }
674
0
}
675
676
/**
677
 * xmlXPathErr:
678
 * @ctxt:  a XPath parser context
679
 * @error:  the error code
680
 *
681
 * Handle an XPath error
682
 */
683
void
684
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
685
0
{
686
0
    if ((error < 0) || (error > MAXERRNO))
687
0
  error = MAXERRNO;
688
0
    if (ctxt == NULL) {
689
0
  __xmlRaiseError(NULL, NULL, NULL,
690
0
      NULL, NULL, XML_FROM_XPATH,
691
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
692
0
      XML_ERR_ERROR, NULL, 0,
693
0
      NULL, NULL, NULL, 0, 0,
694
0
      "%s", xmlXPathErrorMessages[error]);
695
0
  return;
696
0
    }
697
0
    ctxt->error = error;
698
0
    if (ctxt->context == NULL) {
699
0
  __xmlRaiseError(NULL, NULL, NULL,
700
0
      NULL, NULL, XML_FROM_XPATH,
701
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
702
0
      XML_ERR_ERROR, NULL, 0,
703
0
      (const char *) ctxt->base, NULL, NULL,
704
0
      ctxt->cur - ctxt->base, 0,
705
0
      "%s", xmlXPathErrorMessages[error]);
706
0
  return;
707
0
    }
708
709
    /* cleanup current last error */
710
0
    xmlResetError(&ctxt->context->lastError);
711
712
0
    ctxt->context->lastError.domain = XML_FROM_XPATH;
713
0
    ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
714
0
                           XPATH_EXPRESSION_OK;
715
0
    ctxt->context->lastError.level = XML_ERR_ERROR;
716
0
    ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
717
0
    ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
718
0
    ctxt->context->lastError.node = ctxt->context->debugNode;
719
0
    if (ctxt->context->error != NULL) {
720
0
  ctxt->context->error(ctxt->context->userData,
721
0
                       &ctxt->context->lastError);
722
0
    } else {
723
0
  __xmlRaiseError(NULL, NULL, NULL,
724
0
      NULL, ctxt->context->debugNode, XML_FROM_XPATH,
725
0
      error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
726
0
      XML_ERR_ERROR, NULL, 0,
727
0
      (const char *) ctxt->base, NULL, NULL,
728
0
      ctxt->cur - ctxt->base, 0,
729
0
      "%s", xmlXPathErrorMessages[error]);
730
0
    }
731
732
0
}
733
734
/**
735
 * xmlXPatherror:
736
 * @ctxt:  the XPath Parser context
737
 * @file:  the file name
738
 * @line:  the line number
739
 * @no:  the error number
740
 *
741
 * Formats an error message.
742
 */
743
void
744
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
745
0
              int line ATTRIBUTE_UNUSED, int no) {
746
0
    xmlXPathErr(ctxt, no);
747
0
}
748
749
/**
750
 * xmlXPathCheckOpLimit:
751
 * @ctxt:  the XPath Parser context
752
 * @opCount:  the number of operations to be added
753
 *
754
 * Adds opCount to the running total of operations and returns -1 if the
755
 * operation limit is exceeded. Returns 0 otherwise.
756
 */
757
static int
758
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
759
0
    xmlXPathContextPtr xpctxt = ctxt->context;
760
761
0
    if ((opCount > xpctxt->opLimit) ||
762
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
763
0
        xpctxt->opCount = xpctxt->opLimit;
764
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
765
0
        return(-1);
766
0
    }
767
768
0
    xpctxt->opCount += opCount;
769
0
    return(0);
770
0
}
771
772
#define OP_LIMIT_EXCEEDED(ctxt, n) \
773
0
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
774
775
/************************************************************************
776
 *                  *
777
 *      Utilities         *
778
 *                  *
779
 ************************************************************************/
780
781
/**
782
 * xsltPointerList:
783
 *
784
 * Pointer-list for various purposes.
785
 */
786
typedef struct _xmlPointerList xmlPointerList;
787
typedef xmlPointerList *xmlPointerListPtr;
788
struct _xmlPointerList {
789
    void **items;
790
    int number;
791
    int size;
792
};
793
/*
794
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
795
* and here, we should make the functions public.
796
*/
797
static int
798
xmlPointerListAddSize(xmlPointerListPtr list,
799
           void *item,
800
           int initialSize)
801
0
{
802
0
    if (list->items == NULL) {
803
0
  if (initialSize <= 0)
804
0
      initialSize = 1;
805
0
  list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
806
0
  if (list->items == NULL) {
807
0
      xmlXPathErrMemory(NULL,
808
0
    "xmlPointerListCreate: allocating item\n");
809
0
      return(-1);
810
0
  }
811
0
  list->number = 0;
812
0
  list->size = initialSize;
813
0
    } else if (list->size <= list->number) {
814
0
        if (list->size > 50000000) {
815
0
      xmlXPathErrMemory(NULL,
816
0
    "xmlPointerListAddSize: re-allocating item\n");
817
0
            return(-1);
818
0
        }
819
0
  list->size *= 2;
820
0
  list->items = (void **) xmlRealloc(list->items,
821
0
      list->size * sizeof(void *));
822
0
  if (list->items == NULL) {
823
0
      xmlXPathErrMemory(NULL,
824
0
    "xmlPointerListAddSize: re-allocating item\n");
825
0
      list->size = 0;
826
0
      return(-1);
827
0
  }
828
0
    }
829
0
    list->items[list->number++] = item;
830
0
    return(0);
831
0
}
832
833
/**
834
 * xsltPointerListCreate:
835
 *
836
 * Creates an xsltPointerList structure.
837
 *
838
 * Returns a xsltPointerList structure or NULL in case of an error.
839
 */
840
static xmlPointerListPtr
841
xmlPointerListCreate(int initialSize)
842
0
{
843
0
    xmlPointerListPtr ret;
844
845
0
    ret = xmlMalloc(sizeof(xmlPointerList));
846
0
    if (ret == NULL) {
847
0
  xmlXPathErrMemory(NULL,
848
0
      "xmlPointerListCreate: allocating item\n");
849
0
  return (NULL);
850
0
    }
851
0
    memset(ret, 0, sizeof(xmlPointerList));
852
0
    if (initialSize > 0) {
853
0
  xmlPointerListAddSize(ret, NULL, initialSize);
854
0
  ret->number = 0;
855
0
    }
856
0
    return (ret);
857
0
}
858
859
/**
860
 * xsltPointerListFree:
861
 *
862
 * Frees the xsltPointerList structure. This does not free
863
 * the content of the list.
864
 */
865
static void
866
xmlPointerListFree(xmlPointerListPtr list)
867
0
{
868
0
    if (list == NULL)
869
0
  return;
870
0
    if (list->items != NULL)
871
0
  xmlFree(list->items);
872
0
    xmlFree(list);
873
0
}
874
875
/************************************************************************
876
 *                  *
877
 *      Parser Types          *
878
 *                  *
879
 ************************************************************************/
880
881
/*
882
 * Types are private:
883
 */
884
885
typedef enum {
886
    XPATH_OP_END=0,
887
    XPATH_OP_AND,
888
    XPATH_OP_OR,
889
    XPATH_OP_EQUAL,
890
    XPATH_OP_CMP,
891
    XPATH_OP_PLUS,
892
    XPATH_OP_MULT,
893
    XPATH_OP_UNION,
894
    XPATH_OP_ROOT,
895
    XPATH_OP_NODE,
896
    XPATH_OP_COLLECT,
897
    XPATH_OP_VALUE, /* 11 */
898
    XPATH_OP_VARIABLE,
899
    XPATH_OP_FUNCTION,
900
    XPATH_OP_ARG,
901
    XPATH_OP_PREDICATE,
902
    XPATH_OP_FILTER, /* 16 */
903
    XPATH_OP_SORT /* 17 */
904
#ifdef LIBXML_XPTR_LOCS_ENABLED
905
    ,XPATH_OP_RANGETO
906
#endif
907
} xmlXPathOp;
908
909
typedef enum {
910
    AXIS_ANCESTOR = 1,
911
    AXIS_ANCESTOR_OR_SELF,
912
    AXIS_ATTRIBUTE,
913
    AXIS_CHILD,
914
    AXIS_DESCENDANT,
915
    AXIS_DESCENDANT_OR_SELF,
916
    AXIS_FOLLOWING,
917
    AXIS_FOLLOWING_SIBLING,
918
    AXIS_NAMESPACE,
919
    AXIS_PARENT,
920
    AXIS_PRECEDING,
921
    AXIS_PRECEDING_SIBLING,
922
    AXIS_SELF
923
} xmlXPathAxisVal;
924
925
typedef enum {
926
    NODE_TEST_NONE = 0,
927
    NODE_TEST_TYPE = 1,
928
    NODE_TEST_PI = 2,
929
    NODE_TEST_ALL = 3,
930
    NODE_TEST_NS = 4,
931
    NODE_TEST_NAME = 5
932
} xmlXPathTestVal;
933
934
typedef enum {
935
    NODE_TYPE_NODE = 0,
936
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
937
    NODE_TYPE_TEXT = XML_TEXT_NODE,
938
    NODE_TYPE_PI = XML_PI_NODE
939
} xmlXPathTypeVal;
940
941
typedef struct _xmlXPathStepOp xmlXPathStepOp;
942
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
943
struct _xmlXPathStepOp {
944
    xmlXPathOp op;    /* The identifier of the operation */
945
    int ch1;      /* First child */
946
    int ch2;      /* Second child */
947
    int value;
948
    int value2;
949
    int value3;
950
    void *value4;
951
    void *value5;
952
    xmlXPathFunction cache;
953
    void *cacheURI;
954
};
955
956
struct _xmlXPathCompExpr {
957
    int nbStep;     /* Number of steps in this expression */
958
    int maxStep;    /* Maximum number of steps allocated */
959
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
960
    int last;     /* index of last step in expression */
961
    xmlChar *expr;    /* the expression being computed */
962
    xmlDictPtr dict;    /* the dictionary to use if any */
963
#ifdef DEBUG_EVAL_COUNTS
964
    int nb;
965
    xmlChar *string;
966
#endif
967
#ifdef XPATH_STREAMING
968
    xmlPatternPtr stream;
969
#endif
970
};
971
972
/************************************************************************
973
 *                  *
974
 *      Forward declarations        *
975
 *                  *
976
 ************************************************************************/
977
static void
978
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
979
static void
980
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
981
static int
982
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
983
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
984
static int
985
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
986
          xmlXPathStepOpPtr op,
987
          int isPredicate);
988
static void
989
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
990
991
/************************************************************************
992
 *                  *
993
 *      Parser Type functions       *
994
 *                  *
995
 ************************************************************************/
996
997
/**
998
 * xmlXPathNewCompExpr:
999
 *
1000
 * Create a new Xpath component
1001
 *
1002
 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1003
 */
1004
static xmlXPathCompExprPtr
1005
0
xmlXPathNewCompExpr(void) {
1006
0
    xmlXPathCompExprPtr cur;
1007
1008
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1009
0
    if (cur == NULL) {
1010
0
        xmlXPathErrMemory(NULL, "allocating component\n");
1011
0
  return(NULL);
1012
0
    }
1013
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
1014
0
    cur->maxStep = 10;
1015
0
    cur->nbStep = 0;
1016
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1017
0
                                     sizeof(xmlXPathStepOp));
1018
0
    if (cur->steps == NULL) {
1019
0
        xmlXPathErrMemory(NULL, "allocating steps\n");
1020
0
  xmlFree(cur);
1021
0
  return(NULL);
1022
0
    }
1023
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1024
0
    cur->last = -1;
1025
#ifdef DEBUG_EVAL_COUNTS
1026
    cur->nb = 0;
1027
#endif
1028
0
    return(cur);
1029
0
}
1030
1031
/**
1032
 * xmlXPathFreeCompExpr:
1033
 * @comp:  an XPATH comp
1034
 *
1035
 * Free up the memory allocated by @comp
1036
 */
1037
void
1038
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1039
0
{
1040
0
    xmlXPathStepOpPtr op;
1041
0
    int i;
1042
1043
0
    if (comp == NULL)
1044
0
        return;
1045
0
    if (comp->dict == NULL) {
1046
0
  for (i = 0; i < comp->nbStep; i++) {
1047
0
      op = &comp->steps[i];
1048
0
      if (op->value4 != NULL) {
1049
0
    if (op->op == XPATH_OP_VALUE)
1050
0
        xmlXPathFreeObject(op->value4);
1051
0
    else
1052
0
        xmlFree(op->value4);
1053
0
      }
1054
0
      if (op->value5 != NULL)
1055
0
    xmlFree(op->value5);
1056
0
  }
1057
0
    } else {
1058
0
  for (i = 0; i < comp->nbStep; i++) {
1059
0
      op = &comp->steps[i];
1060
0
      if (op->value4 != NULL) {
1061
0
    if (op->op == XPATH_OP_VALUE)
1062
0
        xmlXPathFreeObject(op->value4);
1063
0
      }
1064
0
  }
1065
0
        xmlDictFree(comp->dict);
1066
0
    }
1067
0
    if (comp->steps != NULL) {
1068
0
        xmlFree(comp->steps);
1069
0
    }
1070
#ifdef DEBUG_EVAL_COUNTS
1071
    if (comp->string != NULL) {
1072
        xmlFree(comp->string);
1073
    }
1074
#endif
1075
0
#ifdef XPATH_STREAMING
1076
0
    if (comp->stream != NULL) {
1077
0
        xmlFreePatternList(comp->stream);
1078
0
    }
1079
0
#endif
1080
0
    if (comp->expr != NULL) {
1081
0
        xmlFree(comp->expr);
1082
0
    }
1083
1084
0
    xmlFree(comp);
1085
0
}
1086
1087
/**
1088
 * xmlXPathCompExprAdd:
1089
 * @comp:  the compiled expression
1090
 * @ch1: first child index
1091
 * @ch2: second child index
1092
 * @op:  an op
1093
 * @value:  the first int value
1094
 * @value2:  the second int value
1095
 * @value3:  the third int value
1096
 * @value4:  the first string value
1097
 * @value5:  the second string value
1098
 *
1099
 * Add a step to an XPath Compiled Expression
1100
 *
1101
 * Returns -1 in case of failure, the index otherwise
1102
 */
1103
static int
1104
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1105
   xmlXPathOp op, int value,
1106
0
   int value2, int value3, void *value4, void *value5) {
1107
0
    xmlXPathCompExprPtr comp = ctxt->comp;
1108
0
    if (comp->nbStep >= comp->maxStep) {
1109
0
  xmlXPathStepOp *real;
1110
1111
0
        if (comp->maxStep >= XPATH_MAX_STEPS) {
1112
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1113
0
      return(-1);
1114
0
        }
1115
0
  comp->maxStep *= 2;
1116
0
  real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1117
0
                          comp->maxStep * sizeof(xmlXPathStepOp));
1118
0
  if (real == NULL) {
1119
0
      comp->maxStep /= 2;
1120
0
      xmlXPathPErrMemory(ctxt, "adding step\n");
1121
0
      return(-1);
1122
0
  }
1123
0
  comp->steps = real;
1124
0
    }
1125
0
    comp->last = comp->nbStep;
1126
0
    comp->steps[comp->nbStep].ch1 = ch1;
1127
0
    comp->steps[comp->nbStep].ch2 = ch2;
1128
0
    comp->steps[comp->nbStep].op = op;
1129
0
    comp->steps[comp->nbStep].value = value;
1130
0
    comp->steps[comp->nbStep].value2 = value2;
1131
0
    comp->steps[comp->nbStep].value3 = value3;
1132
0
    if ((comp->dict != NULL) &&
1133
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1134
0
   (op == XPATH_OP_COLLECT))) {
1135
0
        if (value4 != NULL) {
1136
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1137
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1138
0
      xmlFree(value4);
1139
0
  } else
1140
0
      comp->steps[comp->nbStep].value4 = NULL;
1141
0
        if (value5 != NULL) {
1142
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1143
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1144
0
      xmlFree(value5);
1145
0
  } else
1146
0
      comp->steps[comp->nbStep].value5 = NULL;
1147
0
    } else {
1148
0
  comp->steps[comp->nbStep].value4 = value4;
1149
0
  comp->steps[comp->nbStep].value5 = value5;
1150
0
    }
1151
0
    comp->steps[comp->nbStep].cache = NULL;
1152
0
    return(comp->nbStep++);
1153
0
}
1154
1155
/**
1156
 * xmlXPathCompSwap:
1157
 * @comp:  the compiled expression
1158
 * @op: operation index
1159
 *
1160
 * Swaps 2 operations in the compiled expression
1161
 */
1162
static void
1163
0
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1164
0
    int tmp;
1165
1166
#ifndef LIBXML_THREAD_ENABLED
1167
    /*
1168
     * Since this manipulates possibly shared variables, this is
1169
     * disabled if one detects that the library is used in a multithreaded
1170
     * application
1171
     */
1172
    if (xmlXPathDisableOptimizer)
1173
  return;
1174
#endif
1175
1176
0
    tmp = op->ch1;
1177
0
    op->ch1 = op->ch2;
1178
0
    op->ch2 = tmp;
1179
0
}
1180
1181
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1182
0
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1183
0
                  (op), (val), (val2), (val3), (val4), (val5))
1184
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1185
0
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1186
0
                  (op), (val), (val2), (val3), (val4), (val5))
1187
1188
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1189
0
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1190
1191
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1192
0
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1193
1194
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1195
0
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1196
0
      (val), (val2), 0 ,NULL ,NULL)
1197
1198
/************************************************************************
1199
 *                  *
1200
 *    XPath object cache structures       *
1201
 *                  *
1202
 ************************************************************************/
1203
1204
/* #define XP_DEFAULT_CACHE_ON */
1205
1206
0
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1207
1208
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1209
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1210
struct _xmlXPathContextCache {
1211
    xmlPointerListPtr nodesetObjs;  /* contains xmlXPathObjectPtr */
1212
    xmlPointerListPtr stringObjs;   /* contains xmlXPathObjectPtr */
1213
    xmlPointerListPtr booleanObjs;  /* contains xmlXPathObjectPtr */
1214
    xmlPointerListPtr numberObjs;   /* contains xmlXPathObjectPtr */
1215
    xmlPointerListPtr miscObjs;     /* contains xmlXPathObjectPtr */
1216
    int maxNodeset;
1217
    int maxString;
1218
    int maxBoolean;
1219
    int maxNumber;
1220
    int maxMisc;
1221
#ifdef XP_DEBUG_OBJ_USAGE
1222
    int dbgCachedAll;
1223
    int dbgCachedNodeset;
1224
    int dbgCachedString;
1225
    int dbgCachedBool;
1226
    int dbgCachedNumber;
1227
    int dbgCachedPoint;
1228
    int dbgCachedRange;
1229
    int dbgCachedLocset;
1230
    int dbgCachedUsers;
1231
    int dbgCachedXSLTTree;
1232
    int dbgCachedUndefined;
1233
1234
1235
    int dbgReusedAll;
1236
    int dbgReusedNodeset;
1237
    int dbgReusedString;
1238
    int dbgReusedBool;
1239
    int dbgReusedNumber;
1240
    int dbgReusedPoint;
1241
    int dbgReusedRange;
1242
    int dbgReusedLocset;
1243
    int dbgReusedUsers;
1244
    int dbgReusedXSLTTree;
1245
    int dbgReusedUndefined;
1246
1247
#endif
1248
};
1249
1250
/************************************************************************
1251
 *                  *
1252
 *    Debugging related functions       *
1253
 *                  *
1254
 ************************************************************************/
1255
1256
#define STRANGE             \
1257
0
    xmlGenericError(xmlGenericErrorContext,       \
1258
0
      "Internal error at %s:%d\n",        \
1259
0
            __FILE__, __LINE__);
1260
1261
#ifdef LIBXML_DEBUG_ENABLED
1262
static void
1263
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1264
0
    int i;
1265
0
    char shift[100];
1266
1267
0
    for (i = 0;((i < depth) && (i < 25));i++)
1268
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1269
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1270
0
    if (cur == NULL) {
1271
0
  fprintf(output, "%s", shift);
1272
0
  fprintf(output, "Node is NULL !\n");
1273
0
  return;
1274
1275
0
    }
1276
1277
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1278
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1279
0
  fprintf(output, "%s", shift);
1280
0
  fprintf(output, " /\n");
1281
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1282
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1283
0
    else
1284
0
  xmlDebugDumpOneNode(output, cur, depth);
1285
0
}
1286
static void
1287
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1288
0
    xmlNodePtr tmp;
1289
0
    int i;
1290
0
    char shift[100];
1291
1292
0
    for (i = 0;((i < depth) && (i < 25));i++)
1293
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1294
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1295
0
    if (cur == NULL) {
1296
0
  fprintf(output, "%s", shift);
1297
0
  fprintf(output, "Node is NULL !\n");
1298
0
  return;
1299
1300
0
    }
1301
1302
0
    while (cur != NULL) {
1303
0
  tmp = cur;
1304
0
  cur = cur->next;
1305
0
  xmlDebugDumpOneNode(output, tmp, depth);
1306
0
    }
1307
0
}
1308
1309
static void
1310
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1311
0
    int i;
1312
0
    char shift[100];
1313
1314
0
    for (i = 0;((i < depth) && (i < 25));i++)
1315
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1316
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1317
1318
0
    if (cur == NULL) {
1319
0
  fprintf(output, "%s", shift);
1320
0
  fprintf(output, "NodeSet is NULL !\n");
1321
0
  return;
1322
1323
0
    }
1324
1325
0
    if (cur != NULL) {
1326
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1327
0
  for (i = 0;i < cur->nodeNr;i++) {
1328
0
      fprintf(output, "%s", shift);
1329
0
      fprintf(output, "%d", i + 1);
1330
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1331
0
  }
1332
0
    }
1333
0
}
1334
1335
static void
1336
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1337
0
    int i;
1338
0
    char shift[100];
1339
1340
0
    for (i = 0;((i < depth) && (i < 25));i++)
1341
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1342
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1343
1344
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1345
0
  fprintf(output, "%s", shift);
1346
0
  fprintf(output, "Value Tree is NULL !\n");
1347
0
  return;
1348
1349
0
    }
1350
1351
0
    fprintf(output, "%s", shift);
1352
0
    fprintf(output, "%d", i + 1);
1353
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1354
0
}
1355
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1356
static void
1357
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1358
    int i;
1359
    char shift[100];
1360
1361
    for (i = 0;((i < depth) && (i < 25));i++)
1362
        shift[2 * i] = shift[2 * i + 1] = ' ';
1363
    shift[2 * i] = shift[2 * i + 1] = 0;
1364
1365
    if (cur == NULL) {
1366
  fprintf(output, "%s", shift);
1367
  fprintf(output, "LocationSet is NULL !\n");
1368
  return;
1369
1370
    }
1371
1372
    for (i = 0;i < cur->locNr;i++) {
1373
  fprintf(output, "%s", shift);
1374
        fprintf(output, "%d : ", i + 1);
1375
  xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1376
    }
1377
}
1378
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1379
1380
/**
1381
 * xmlXPathDebugDumpObject:
1382
 * @output:  the FILE * to dump the output
1383
 * @cur:  the object to inspect
1384
 * @depth:  indentation level
1385
 *
1386
 * Dump the content of the object for debugging purposes
1387
 */
1388
void
1389
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1390
0
    int i;
1391
0
    char shift[100];
1392
1393
0
    if (output == NULL) return;
1394
1395
0
    for (i = 0;((i < depth) && (i < 25));i++)
1396
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1397
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1398
1399
1400
0
    fprintf(output, "%s", shift);
1401
1402
0
    if (cur == NULL) {
1403
0
        fprintf(output, "Object is empty (NULL)\n");
1404
0
  return;
1405
0
    }
1406
0
    switch(cur->type) {
1407
0
        case XPATH_UNDEFINED:
1408
0
      fprintf(output, "Object is uninitialized\n");
1409
0
      break;
1410
0
        case XPATH_NODESET:
1411
0
      fprintf(output, "Object is a Node Set :\n");
1412
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1413
0
      break;
1414
0
  case XPATH_XSLT_TREE:
1415
0
      fprintf(output, "Object is an XSLT value tree :\n");
1416
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1417
0
      break;
1418
0
        case XPATH_BOOLEAN:
1419
0
      fprintf(output, "Object is a Boolean : ");
1420
0
      if (cur->boolval) fprintf(output, "true\n");
1421
0
      else fprintf(output, "false\n");
1422
0
      break;
1423
0
        case XPATH_NUMBER:
1424
0
      switch (xmlXPathIsInf(cur->floatval)) {
1425
0
      case 1:
1426
0
    fprintf(output, "Object is a number : Infinity\n");
1427
0
    break;
1428
0
      case -1:
1429
0
    fprintf(output, "Object is a number : -Infinity\n");
1430
0
    break;
1431
0
      default:
1432
0
    if (xmlXPathIsNaN(cur->floatval)) {
1433
0
        fprintf(output, "Object is a number : NaN\n");
1434
0
    } else if (cur->floatval == 0) {
1435
                    /* Omit sign for negative zero. */
1436
0
        fprintf(output, "Object is a number : 0\n");
1437
0
    } else {
1438
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1439
0
    }
1440
0
      }
1441
0
      break;
1442
0
        case XPATH_STRING:
1443
0
      fprintf(output, "Object is a string : ");
1444
0
      xmlDebugDumpString(output, cur->stringval);
1445
0
      fprintf(output, "\n");
1446
0
      break;
1447
#ifdef LIBXML_XPTR_LOCS_ENABLED
1448
  case XPATH_POINT:
1449
      fprintf(output, "Object is a point : index %d in node", cur->index);
1450
      xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1451
      fprintf(output, "\n");
1452
      break;
1453
  case XPATH_RANGE:
1454
      if ((cur->user2 == NULL) ||
1455
    ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1456
    fprintf(output, "Object is a collapsed range :\n");
1457
    fprintf(output, "%s", shift);
1458
    if (cur->index >= 0)
1459
        fprintf(output, "index %d in ", cur->index);
1460
    fprintf(output, "node\n");
1461
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1462
                    depth + 1);
1463
      } else  {
1464
    fprintf(output, "Object is a range :\n");
1465
    fprintf(output, "%s", shift);
1466
    fprintf(output, "From ");
1467
    if (cur->index >= 0)
1468
        fprintf(output, "index %d in ", cur->index);
1469
    fprintf(output, "node\n");
1470
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1471
                    depth + 1);
1472
    fprintf(output, "%s", shift);
1473
    fprintf(output, "To ");
1474
    if (cur->index2 >= 0)
1475
        fprintf(output, "index %d in ", cur->index2);
1476
    fprintf(output, "node\n");
1477
    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1478
                    depth + 1);
1479
    fprintf(output, "\n");
1480
      }
1481
      break;
1482
  case XPATH_LOCATIONSET:
1483
      fprintf(output, "Object is a Location Set:\n");
1484
      xmlXPathDebugDumpLocationSet(output,
1485
        (xmlLocationSetPtr) cur->user, depth);
1486
      break;
1487
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1488
0
  case XPATH_USERS:
1489
0
      fprintf(output, "Object is user defined\n");
1490
0
      break;
1491
0
    }
1492
0
}
1493
1494
static void
1495
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1496
0
                       xmlXPathStepOpPtr op, int depth) {
1497
0
    int i;
1498
0
    char shift[100];
1499
1500
0
    for (i = 0;((i < depth) && (i < 25));i++)
1501
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1502
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1503
1504
0
    fprintf(output, "%s", shift);
1505
0
    if (op == NULL) {
1506
0
  fprintf(output, "Step is NULL\n");
1507
0
  return;
1508
0
    }
1509
0
    switch (op->op) {
1510
0
        case XPATH_OP_END:
1511
0
      fprintf(output, "END"); break;
1512
0
        case XPATH_OP_AND:
1513
0
      fprintf(output, "AND"); break;
1514
0
        case XPATH_OP_OR:
1515
0
      fprintf(output, "OR"); break;
1516
0
        case XPATH_OP_EQUAL:
1517
0
       if (op->value)
1518
0
     fprintf(output, "EQUAL =");
1519
0
       else
1520
0
     fprintf(output, "EQUAL !=");
1521
0
       break;
1522
0
        case XPATH_OP_CMP:
1523
0
       if (op->value)
1524
0
     fprintf(output, "CMP <");
1525
0
       else
1526
0
     fprintf(output, "CMP >");
1527
0
       if (!op->value2)
1528
0
     fprintf(output, "=");
1529
0
       break;
1530
0
        case XPATH_OP_PLUS:
1531
0
       if (op->value == 0)
1532
0
     fprintf(output, "PLUS -");
1533
0
       else if (op->value == 1)
1534
0
     fprintf(output, "PLUS +");
1535
0
       else if (op->value == 2)
1536
0
     fprintf(output, "PLUS unary -");
1537
0
       else if (op->value == 3)
1538
0
     fprintf(output, "PLUS unary - -");
1539
0
       break;
1540
0
        case XPATH_OP_MULT:
1541
0
       if (op->value == 0)
1542
0
     fprintf(output, "MULT *");
1543
0
       else if (op->value == 1)
1544
0
     fprintf(output, "MULT div");
1545
0
       else
1546
0
     fprintf(output, "MULT mod");
1547
0
       break;
1548
0
        case XPATH_OP_UNION:
1549
0
       fprintf(output, "UNION"); break;
1550
0
        case XPATH_OP_ROOT:
1551
0
       fprintf(output, "ROOT"); break;
1552
0
        case XPATH_OP_NODE:
1553
0
       fprintf(output, "NODE"); break;
1554
0
        case XPATH_OP_SORT:
1555
0
       fprintf(output, "SORT"); break;
1556
0
        case XPATH_OP_COLLECT: {
1557
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1558
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1559
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1560
0
      const xmlChar *prefix = op->value4;
1561
0
      const xmlChar *name = op->value5;
1562
1563
0
      fprintf(output, "COLLECT ");
1564
0
      switch (axis) {
1565
0
    case AXIS_ANCESTOR:
1566
0
        fprintf(output, " 'ancestors' "); break;
1567
0
    case AXIS_ANCESTOR_OR_SELF:
1568
0
        fprintf(output, " 'ancestors-or-self' "); break;
1569
0
    case AXIS_ATTRIBUTE:
1570
0
        fprintf(output, " 'attributes' "); break;
1571
0
    case AXIS_CHILD:
1572
0
        fprintf(output, " 'child' "); break;
1573
0
    case AXIS_DESCENDANT:
1574
0
        fprintf(output, " 'descendant' "); break;
1575
0
    case AXIS_DESCENDANT_OR_SELF:
1576
0
        fprintf(output, " 'descendant-or-self' "); break;
1577
0
    case AXIS_FOLLOWING:
1578
0
        fprintf(output, " 'following' "); break;
1579
0
    case AXIS_FOLLOWING_SIBLING:
1580
0
        fprintf(output, " 'following-siblings' "); break;
1581
0
    case AXIS_NAMESPACE:
1582
0
        fprintf(output, " 'namespace' "); break;
1583
0
    case AXIS_PARENT:
1584
0
        fprintf(output, " 'parent' "); break;
1585
0
    case AXIS_PRECEDING:
1586
0
        fprintf(output, " 'preceding' "); break;
1587
0
    case AXIS_PRECEDING_SIBLING:
1588
0
        fprintf(output, " 'preceding-sibling' "); break;
1589
0
    case AXIS_SELF:
1590
0
        fprintf(output, " 'self' "); break;
1591
0
      }
1592
0
      switch (test) {
1593
0
                case NODE_TEST_NONE:
1594
0
        fprintf(output, "'none' "); break;
1595
0
                case NODE_TEST_TYPE:
1596
0
        fprintf(output, "'type' "); break;
1597
0
                case NODE_TEST_PI:
1598
0
        fprintf(output, "'PI' "); break;
1599
0
                case NODE_TEST_ALL:
1600
0
        fprintf(output, "'all' "); break;
1601
0
                case NODE_TEST_NS:
1602
0
        fprintf(output, "'namespace' "); break;
1603
0
                case NODE_TEST_NAME:
1604
0
        fprintf(output, "'name' "); break;
1605
0
      }
1606
0
      switch (type) {
1607
0
                case NODE_TYPE_NODE:
1608
0
        fprintf(output, "'node' "); break;
1609
0
                case NODE_TYPE_COMMENT:
1610
0
        fprintf(output, "'comment' "); break;
1611
0
                case NODE_TYPE_TEXT:
1612
0
        fprintf(output, "'text' "); break;
1613
0
                case NODE_TYPE_PI:
1614
0
        fprintf(output, "'PI' "); break;
1615
0
      }
1616
0
      if (prefix != NULL)
1617
0
    fprintf(output, "%s:", prefix);
1618
0
      if (name != NULL)
1619
0
    fprintf(output, "%s", (const char *) name);
1620
0
      break;
1621
1622
0
        }
1623
0
  case XPATH_OP_VALUE: {
1624
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1625
1626
0
      fprintf(output, "ELEM ");
1627
0
      xmlXPathDebugDumpObject(output, object, 0);
1628
0
      goto finish;
1629
0
  }
1630
0
  case XPATH_OP_VARIABLE: {
1631
0
      const xmlChar *prefix = op->value5;
1632
0
      const xmlChar *name = op->value4;
1633
1634
0
      if (prefix != NULL)
1635
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1636
0
      else
1637
0
    fprintf(output, "VARIABLE %s", name);
1638
0
      break;
1639
0
  }
1640
0
  case XPATH_OP_FUNCTION: {
1641
0
      int nbargs = op->value;
1642
0
      const xmlChar *prefix = op->value5;
1643
0
      const xmlChar *name = op->value4;
1644
1645
0
      if (prefix != NULL)
1646
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1647
0
      prefix, name, nbargs);
1648
0
      else
1649
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1650
0
      break;
1651
0
  }
1652
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1653
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1654
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1655
#ifdef LIBXML_XPTR_LOCS_ENABLED
1656
        case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1657
#endif
1658
0
  default:
1659
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1660
0
    }
1661
0
    fprintf(output, "\n");
1662
0
finish:
1663
0
    if (op->ch1 >= 0)
1664
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1665
0
    if (op->ch2 >= 0)
1666
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1667
0
}
1668
1669
/**
1670
 * xmlXPathDebugDumpCompExpr:
1671
 * @output:  the FILE * for the output
1672
 * @comp:  the precompiled XPath expression
1673
 * @depth:  the indentation level.
1674
 *
1675
 * Dumps the tree of the compiled XPath expression.
1676
 */
1677
void
1678
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1679
0
                    int depth) {
1680
0
    int i;
1681
0
    char shift[100];
1682
1683
0
    if ((output == NULL) || (comp == NULL)) return;
1684
1685
0
    for (i = 0;((i < depth) && (i < 25));i++)
1686
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1687
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1688
1689
0
    fprintf(output, "%s", shift);
1690
1691
0
#ifdef XPATH_STREAMING
1692
0
    if (comp->stream) {
1693
0
        fprintf(output, "Streaming Expression\n");
1694
0
    } else
1695
0
#endif
1696
0
    {
1697
0
        fprintf(output, "Compiled Expression : %d elements\n",
1698
0
                comp->nbStep);
1699
0
        i = comp->last;
1700
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1701
0
    }
1702
0
}
1703
1704
#ifdef XP_DEBUG_OBJ_USAGE
1705
1706
/*
1707
* XPath object usage related debugging variables.
1708
*/
1709
static int xmlXPathDebugObjCounterUndefined = 0;
1710
static int xmlXPathDebugObjCounterNodeset = 0;
1711
static int xmlXPathDebugObjCounterBool = 0;
1712
static int xmlXPathDebugObjCounterNumber = 0;
1713
static int xmlXPathDebugObjCounterString = 0;
1714
static int xmlXPathDebugObjCounterPoint = 0;
1715
static int xmlXPathDebugObjCounterRange = 0;
1716
static int xmlXPathDebugObjCounterLocset = 0;
1717
static int xmlXPathDebugObjCounterUsers = 0;
1718
static int xmlXPathDebugObjCounterXSLTTree = 0;
1719
static int xmlXPathDebugObjCounterAll = 0;
1720
1721
static int xmlXPathDebugObjTotalUndefined = 0;
1722
static int xmlXPathDebugObjTotalNodeset = 0;
1723
static int xmlXPathDebugObjTotalBool = 0;
1724
static int xmlXPathDebugObjTotalNumber = 0;
1725
static int xmlXPathDebugObjTotalString = 0;
1726
static int xmlXPathDebugObjTotalPoint = 0;
1727
static int xmlXPathDebugObjTotalRange = 0;
1728
static int xmlXPathDebugObjTotalLocset = 0;
1729
static int xmlXPathDebugObjTotalUsers = 0;
1730
static int xmlXPathDebugObjTotalXSLTTree = 0;
1731
static int xmlXPathDebugObjTotalAll = 0;
1732
1733
static int xmlXPathDebugObjMaxUndefined = 0;
1734
static int xmlXPathDebugObjMaxNodeset = 0;
1735
static int xmlXPathDebugObjMaxBool = 0;
1736
static int xmlXPathDebugObjMaxNumber = 0;
1737
static int xmlXPathDebugObjMaxString = 0;
1738
static int xmlXPathDebugObjMaxPoint = 0;
1739
static int xmlXPathDebugObjMaxRange = 0;
1740
static int xmlXPathDebugObjMaxLocset = 0;
1741
static int xmlXPathDebugObjMaxUsers = 0;
1742
static int xmlXPathDebugObjMaxXSLTTree = 0;
1743
static int xmlXPathDebugObjMaxAll = 0;
1744
1745
static void
1746
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1747
{
1748
    if (ctxt != NULL) {
1749
  if (ctxt->cache != NULL) {
1750
      xmlXPathContextCachePtr cache =
1751
    (xmlXPathContextCachePtr) ctxt->cache;
1752
1753
      cache->dbgCachedAll = 0;
1754
      cache->dbgCachedNodeset = 0;
1755
      cache->dbgCachedString = 0;
1756
      cache->dbgCachedBool = 0;
1757
      cache->dbgCachedNumber = 0;
1758
      cache->dbgCachedPoint = 0;
1759
      cache->dbgCachedRange = 0;
1760
      cache->dbgCachedLocset = 0;
1761
      cache->dbgCachedUsers = 0;
1762
      cache->dbgCachedXSLTTree = 0;
1763
      cache->dbgCachedUndefined = 0;
1764
1765
      cache->dbgReusedAll = 0;
1766
      cache->dbgReusedNodeset = 0;
1767
      cache->dbgReusedString = 0;
1768
      cache->dbgReusedBool = 0;
1769
      cache->dbgReusedNumber = 0;
1770
      cache->dbgReusedPoint = 0;
1771
      cache->dbgReusedRange = 0;
1772
      cache->dbgReusedLocset = 0;
1773
      cache->dbgReusedUsers = 0;
1774
      cache->dbgReusedXSLTTree = 0;
1775
      cache->dbgReusedUndefined = 0;
1776
  }
1777
    }
1778
1779
    xmlXPathDebugObjCounterUndefined = 0;
1780
    xmlXPathDebugObjCounterNodeset = 0;
1781
    xmlXPathDebugObjCounterBool = 0;
1782
    xmlXPathDebugObjCounterNumber = 0;
1783
    xmlXPathDebugObjCounterString = 0;
1784
    xmlXPathDebugObjCounterPoint = 0;
1785
    xmlXPathDebugObjCounterRange = 0;
1786
    xmlXPathDebugObjCounterLocset = 0;
1787
    xmlXPathDebugObjCounterUsers = 0;
1788
    xmlXPathDebugObjCounterXSLTTree = 0;
1789
    xmlXPathDebugObjCounterAll = 0;
1790
1791
    xmlXPathDebugObjTotalUndefined = 0;
1792
    xmlXPathDebugObjTotalNodeset = 0;
1793
    xmlXPathDebugObjTotalBool = 0;
1794
    xmlXPathDebugObjTotalNumber = 0;
1795
    xmlXPathDebugObjTotalString = 0;
1796
    xmlXPathDebugObjTotalPoint = 0;
1797
    xmlXPathDebugObjTotalRange = 0;
1798
    xmlXPathDebugObjTotalLocset = 0;
1799
    xmlXPathDebugObjTotalUsers = 0;
1800
    xmlXPathDebugObjTotalXSLTTree = 0;
1801
    xmlXPathDebugObjTotalAll = 0;
1802
1803
    xmlXPathDebugObjMaxUndefined = 0;
1804
    xmlXPathDebugObjMaxNodeset = 0;
1805
    xmlXPathDebugObjMaxBool = 0;
1806
    xmlXPathDebugObjMaxNumber = 0;
1807
    xmlXPathDebugObjMaxString = 0;
1808
    xmlXPathDebugObjMaxPoint = 0;
1809
    xmlXPathDebugObjMaxRange = 0;
1810
    xmlXPathDebugObjMaxLocset = 0;
1811
    xmlXPathDebugObjMaxUsers = 0;
1812
    xmlXPathDebugObjMaxXSLTTree = 0;
1813
    xmlXPathDebugObjMaxAll = 0;
1814
1815
}
1816
1817
static void
1818
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1819
            xmlXPathObjectType objType)
1820
{
1821
    int isCached = 0;
1822
1823
    if (ctxt != NULL) {
1824
  if (ctxt->cache != NULL) {
1825
      xmlXPathContextCachePtr cache =
1826
    (xmlXPathContextCachePtr) ctxt->cache;
1827
1828
      isCached = 1;
1829
1830
      cache->dbgReusedAll++;
1831
      switch (objType) {
1832
    case XPATH_UNDEFINED:
1833
        cache->dbgReusedUndefined++;
1834
        break;
1835
    case XPATH_NODESET:
1836
        cache->dbgReusedNodeset++;
1837
        break;
1838
    case XPATH_BOOLEAN:
1839
        cache->dbgReusedBool++;
1840
        break;
1841
    case XPATH_NUMBER:
1842
        cache->dbgReusedNumber++;
1843
        break;
1844
    case XPATH_STRING:
1845
        cache->dbgReusedString++;
1846
        break;
1847
#ifdef LIBXML_XPTR_LOCS_ENABLED
1848
    case XPATH_POINT:
1849
        cache->dbgReusedPoint++;
1850
        break;
1851
    case XPATH_RANGE:
1852
        cache->dbgReusedRange++;
1853
        break;
1854
    case XPATH_LOCATIONSET:
1855
        cache->dbgReusedLocset++;
1856
        break;
1857
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1858
    case XPATH_USERS:
1859
        cache->dbgReusedUsers++;
1860
        break;
1861
    case XPATH_XSLT_TREE:
1862
        cache->dbgReusedXSLTTree++;
1863
        break;
1864
    default:
1865
        break;
1866
      }
1867
  }
1868
    }
1869
1870
    switch (objType) {
1871
  case XPATH_UNDEFINED:
1872
      if (! isCached)
1873
    xmlXPathDebugObjTotalUndefined++;
1874
      xmlXPathDebugObjCounterUndefined++;
1875
      if (xmlXPathDebugObjCounterUndefined >
1876
    xmlXPathDebugObjMaxUndefined)
1877
    xmlXPathDebugObjMaxUndefined =
1878
        xmlXPathDebugObjCounterUndefined;
1879
      break;
1880
  case XPATH_NODESET:
1881
      if (! isCached)
1882
    xmlXPathDebugObjTotalNodeset++;
1883
      xmlXPathDebugObjCounterNodeset++;
1884
      if (xmlXPathDebugObjCounterNodeset >
1885
    xmlXPathDebugObjMaxNodeset)
1886
    xmlXPathDebugObjMaxNodeset =
1887
        xmlXPathDebugObjCounterNodeset;
1888
      break;
1889
  case XPATH_BOOLEAN:
1890
      if (! isCached)
1891
    xmlXPathDebugObjTotalBool++;
1892
      xmlXPathDebugObjCounterBool++;
1893
      if (xmlXPathDebugObjCounterBool >
1894
    xmlXPathDebugObjMaxBool)
1895
    xmlXPathDebugObjMaxBool =
1896
        xmlXPathDebugObjCounterBool;
1897
      break;
1898
  case XPATH_NUMBER:
1899
      if (! isCached)
1900
    xmlXPathDebugObjTotalNumber++;
1901
      xmlXPathDebugObjCounterNumber++;
1902
      if (xmlXPathDebugObjCounterNumber >
1903
    xmlXPathDebugObjMaxNumber)
1904
    xmlXPathDebugObjMaxNumber =
1905
        xmlXPathDebugObjCounterNumber;
1906
      break;
1907
  case XPATH_STRING:
1908
      if (! isCached)
1909
    xmlXPathDebugObjTotalString++;
1910
      xmlXPathDebugObjCounterString++;
1911
      if (xmlXPathDebugObjCounterString >
1912
    xmlXPathDebugObjMaxString)
1913
    xmlXPathDebugObjMaxString =
1914
        xmlXPathDebugObjCounterString;
1915
      break;
1916
#ifdef LIBXML_XPTR_LOCS_ENABLED
1917
  case XPATH_POINT:
1918
      if (! isCached)
1919
    xmlXPathDebugObjTotalPoint++;
1920
      xmlXPathDebugObjCounterPoint++;
1921
      if (xmlXPathDebugObjCounterPoint >
1922
    xmlXPathDebugObjMaxPoint)
1923
    xmlXPathDebugObjMaxPoint =
1924
        xmlXPathDebugObjCounterPoint;
1925
      break;
1926
  case XPATH_RANGE:
1927
      if (! isCached)
1928
    xmlXPathDebugObjTotalRange++;
1929
      xmlXPathDebugObjCounterRange++;
1930
      if (xmlXPathDebugObjCounterRange >
1931
    xmlXPathDebugObjMaxRange)
1932
    xmlXPathDebugObjMaxRange =
1933
        xmlXPathDebugObjCounterRange;
1934
      break;
1935
  case XPATH_LOCATIONSET:
1936
      if (! isCached)
1937
    xmlXPathDebugObjTotalLocset++;
1938
      xmlXPathDebugObjCounterLocset++;
1939
      if (xmlXPathDebugObjCounterLocset >
1940
    xmlXPathDebugObjMaxLocset)
1941
    xmlXPathDebugObjMaxLocset =
1942
        xmlXPathDebugObjCounterLocset;
1943
      break;
1944
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1945
  case XPATH_USERS:
1946
      if (! isCached)
1947
    xmlXPathDebugObjTotalUsers++;
1948
      xmlXPathDebugObjCounterUsers++;
1949
      if (xmlXPathDebugObjCounterUsers >
1950
    xmlXPathDebugObjMaxUsers)
1951
    xmlXPathDebugObjMaxUsers =
1952
        xmlXPathDebugObjCounterUsers;
1953
      break;
1954
  case XPATH_XSLT_TREE:
1955
      if (! isCached)
1956
    xmlXPathDebugObjTotalXSLTTree++;
1957
      xmlXPathDebugObjCounterXSLTTree++;
1958
      if (xmlXPathDebugObjCounterXSLTTree >
1959
    xmlXPathDebugObjMaxXSLTTree)
1960
    xmlXPathDebugObjMaxXSLTTree =
1961
        xmlXPathDebugObjCounterXSLTTree;
1962
      break;
1963
  default:
1964
      break;
1965
    }
1966
    if (! isCached)
1967
  xmlXPathDebugObjTotalAll++;
1968
    xmlXPathDebugObjCounterAll++;
1969
    if (xmlXPathDebugObjCounterAll >
1970
  xmlXPathDebugObjMaxAll)
1971
  xmlXPathDebugObjMaxAll =
1972
      xmlXPathDebugObjCounterAll;
1973
}
1974
1975
static void
1976
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1977
            xmlXPathObjectType objType)
1978
{
1979
    int isCached = 0;
1980
1981
    if (ctxt != NULL) {
1982
  if (ctxt->cache != NULL) {
1983
      xmlXPathContextCachePtr cache =
1984
    (xmlXPathContextCachePtr) ctxt->cache;
1985
1986
      isCached = 1;
1987
1988
      cache->dbgCachedAll++;
1989
      switch (objType) {
1990
    case XPATH_UNDEFINED:
1991
        cache->dbgCachedUndefined++;
1992
        break;
1993
    case XPATH_NODESET:
1994
        cache->dbgCachedNodeset++;
1995
        break;
1996
    case XPATH_BOOLEAN:
1997
        cache->dbgCachedBool++;
1998
        break;
1999
    case XPATH_NUMBER:
2000
        cache->dbgCachedNumber++;
2001
        break;
2002
    case XPATH_STRING:
2003
        cache->dbgCachedString++;
2004
        break;
2005
#ifdef LIBXML_XPTR_LOCS_ENABLED
2006
    case XPATH_POINT:
2007
        cache->dbgCachedPoint++;
2008
        break;
2009
    case XPATH_RANGE:
2010
        cache->dbgCachedRange++;
2011
        break;
2012
    case XPATH_LOCATIONSET:
2013
        cache->dbgCachedLocset++;
2014
        break;
2015
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2016
    case XPATH_USERS:
2017
        cache->dbgCachedUsers++;
2018
        break;
2019
    case XPATH_XSLT_TREE:
2020
        cache->dbgCachedXSLTTree++;
2021
        break;
2022
    default:
2023
        break;
2024
      }
2025
2026
  }
2027
    }
2028
    switch (objType) {
2029
  case XPATH_UNDEFINED:
2030
      xmlXPathDebugObjCounterUndefined--;
2031
      break;
2032
  case XPATH_NODESET:
2033
      xmlXPathDebugObjCounterNodeset--;
2034
      break;
2035
  case XPATH_BOOLEAN:
2036
      xmlXPathDebugObjCounterBool--;
2037
      break;
2038
  case XPATH_NUMBER:
2039
      xmlXPathDebugObjCounterNumber--;
2040
      break;
2041
  case XPATH_STRING:
2042
      xmlXPathDebugObjCounterString--;
2043
      break;
2044
#ifdef LIBXML_XPTR_LOCS_ENABLED
2045
  case XPATH_POINT:
2046
      xmlXPathDebugObjCounterPoint--;
2047
      break;
2048
  case XPATH_RANGE:
2049
      xmlXPathDebugObjCounterRange--;
2050
      break;
2051
  case XPATH_LOCATIONSET:
2052
      xmlXPathDebugObjCounterLocset--;
2053
      break;
2054
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2055
  case XPATH_USERS:
2056
      xmlXPathDebugObjCounterUsers--;
2057
      break;
2058
  case XPATH_XSLT_TREE:
2059
      xmlXPathDebugObjCounterXSLTTree--;
2060
      break;
2061
  default:
2062
      break;
2063
    }
2064
    xmlXPathDebugObjCounterAll--;
2065
}
2066
2067
static void
2068
xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2069
{
2070
    int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2071
  reqXSLTTree, reqUndefined;
2072
    int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2073
  caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2074
    int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2075
  reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2076
    int leftObjs = xmlXPathDebugObjCounterAll;
2077
2078
    reqAll = xmlXPathDebugObjTotalAll;
2079
    reqNodeset = xmlXPathDebugObjTotalNodeset;
2080
    reqString = xmlXPathDebugObjTotalString;
2081
    reqBool = xmlXPathDebugObjTotalBool;
2082
    reqNumber = xmlXPathDebugObjTotalNumber;
2083
    reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2084
    reqUndefined = xmlXPathDebugObjTotalUndefined;
2085
2086
    printf("# XPath object usage:\n");
2087
2088
    if (ctxt != NULL) {
2089
  if (ctxt->cache != NULL) {
2090
      xmlXPathContextCachePtr cache =
2091
    (xmlXPathContextCachePtr) ctxt->cache;
2092
2093
      reAll = cache->dbgReusedAll;
2094
      reqAll += reAll;
2095
      reNodeset = cache->dbgReusedNodeset;
2096
      reqNodeset += reNodeset;
2097
      reString = cache->dbgReusedString;
2098
      reqString += reString;
2099
      reBool = cache->dbgReusedBool;
2100
      reqBool += reBool;
2101
      reNumber = cache->dbgReusedNumber;
2102
      reqNumber += reNumber;
2103
      reXSLTTree = cache->dbgReusedXSLTTree;
2104
      reqXSLTTree += reXSLTTree;
2105
      reUndefined = cache->dbgReusedUndefined;
2106
      reqUndefined += reUndefined;
2107
2108
      caAll = cache->dbgCachedAll;
2109
      caBool = cache->dbgCachedBool;
2110
      caNodeset = cache->dbgCachedNodeset;
2111
      caString = cache->dbgCachedString;
2112
      caNumber = cache->dbgCachedNumber;
2113
      caXSLTTree = cache->dbgCachedXSLTTree;
2114
      caUndefined = cache->dbgCachedUndefined;
2115
2116
      if (cache->nodesetObjs)
2117
    leftObjs -= cache->nodesetObjs->number;
2118
      if (cache->stringObjs)
2119
    leftObjs -= cache->stringObjs->number;
2120
      if (cache->booleanObjs)
2121
    leftObjs -= cache->booleanObjs->number;
2122
      if (cache->numberObjs)
2123
    leftObjs -= cache->numberObjs->number;
2124
      if (cache->miscObjs)
2125
    leftObjs -= cache->miscObjs->number;
2126
  }
2127
    }
2128
2129
    printf("# all\n");
2130
    printf("#   total  : %d\n", reqAll);
2131
    printf("#   left  : %d\n", leftObjs);
2132
    printf("#   created: %d\n", xmlXPathDebugObjTotalAll);
2133
    printf("#   reused : %d\n", reAll);
2134
    printf("#   max    : %d\n", xmlXPathDebugObjMaxAll);
2135
2136
    printf("# node-sets\n");
2137
    printf("#   total  : %d\n", reqNodeset);
2138
    printf("#   created: %d\n", xmlXPathDebugObjTotalNodeset);
2139
    printf("#   reused : %d\n", reNodeset);
2140
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNodeset);
2141
2142
    printf("# strings\n");
2143
    printf("#   total  : %d\n", reqString);
2144
    printf("#   created: %d\n", xmlXPathDebugObjTotalString);
2145
    printf("#   reused : %d\n", reString);
2146
    printf("#   max    : %d\n", xmlXPathDebugObjMaxString);
2147
2148
    printf("# booleans\n");
2149
    printf("#   total  : %d\n", reqBool);
2150
    printf("#   created: %d\n", xmlXPathDebugObjTotalBool);
2151
    printf("#   reused : %d\n", reBool);
2152
    printf("#   max    : %d\n", xmlXPathDebugObjMaxBool);
2153
2154
    printf("# numbers\n");
2155
    printf("#   total  : %d\n", reqNumber);
2156
    printf("#   created: %d\n", xmlXPathDebugObjTotalNumber);
2157
    printf("#   reused : %d\n", reNumber);
2158
    printf("#   max    : %d\n", xmlXPathDebugObjMaxNumber);
2159
2160
    printf("# XSLT result tree fragments\n");
2161
    printf("#   total  : %d\n", reqXSLTTree);
2162
    printf("#   created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2163
    printf("#   reused : %d\n", reXSLTTree);
2164
    printf("#   max    : %d\n", xmlXPathDebugObjMaxXSLTTree);
2165
2166
    printf("# undefined\n");
2167
    printf("#   total  : %d\n", reqUndefined);
2168
    printf("#   created: %d\n", xmlXPathDebugObjTotalUndefined);
2169
    printf("#   reused : %d\n", reUndefined);
2170
    printf("#   max    : %d\n", xmlXPathDebugObjMaxUndefined);
2171
2172
}
2173
2174
#endif /* XP_DEBUG_OBJ_USAGE */
2175
2176
#endif /* LIBXML_DEBUG_ENABLED */
2177
2178
/************************************************************************
2179
 *                  *
2180
 *      XPath object caching        *
2181
 *                  *
2182
 ************************************************************************/
2183
2184
/**
2185
 * xmlXPathNewCache:
2186
 *
2187
 * Create a new object cache
2188
 *
2189
 * Returns the xmlXPathCache just allocated.
2190
 */
2191
static xmlXPathContextCachePtr
2192
xmlXPathNewCache(void)
2193
0
{
2194
0
    xmlXPathContextCachePtr ret;
2195
2196
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2197
0
    if (ret == NULL) {
2198
0
        xmlXPathErrMemory(NULL, "creating object cache\n");
2199
0
  return(NULL);
2200
0
    }
2201
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2202
0
    ret->maxNodeset = 100;
2203
0
    ret->maxString = 100;
2204
0
    ret->maxBoolean = 100;
2205
0
    ret->maxNumber = 100;
2206
0
    ret->maxMisc = 100;
2207
0
    return(ret);
2208
0
}
2209
2210
static void
2211
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2212
0
{
2213
0
    int i;
2214
0
    xmlXPathObjectPtr obj;
2215
2216
0
    if (list == NULL)
2217
0
  return;
2218
2219
0
    for (i = 0; i < list->number; i++) {
2220
0
  obj = list->items[i];
2221
  /*
2222
  * Note that it is already assured that we don't need to
2223
  * look out for namespace nodes in the node-set.
2224
  */
2225
0
  if (obj->nodesetval != NULL) {
2226
0
      if (obj->nodesetval->nodeTab != NULL)
2227
0
    xmlFree(obj->nodesetval->nodeTab);
2228
0
      xmlFree(obj->nodesetval);
2229
0
  }
2230
0
  xmlFree(obj);
2231
#ifdef XP_DEBUG_OBJ_USAGE
2232
  xmlXPathDebugObjCounterAll--;
2233
#endif
2234
0
    }
2235
0
    xmlPointerListFree(list);
2236
0
}
2237
2238
static void
2239
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2240
0
{
2241
0
    if (cache == NULL)
2242
0
  return;
2243
0
    if (cache->nodesetObjs)
2244
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2245
0
    if (cache->stringObjs)
2246
0
  xmlXPathCacheFreeObjectList(cache->stringObjs);
2247
0
    if (cache->booleanObjs)
2248
0
  xmlXPathCacheFreeObjectList(cache->booleanObjs);
2249
0
    if (cache->numberObjs)
2250
0
  xmlXPathCacheFreeObjectList(cache->numberObjs);
2251
0
    if (cache->miscObjs)
2252
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
2253
0
    xmlFree(cache);
2254
0
}
2255
2256
/**
2257
 * xmlXPathContextSetCache:
2258
 *
2259
 * @ctxt:  the XPath context
2260
 * @active: enables/disables (creates/frees) the cache
2261
 * @value: a value with semantics dependent on @options
2262
 * @options: options (currently only the value 0 is used)
2263
 *
2264
 * Creates/frees an object cache on the XPath context.
2265
 * If activates XPath objects (xmlXPathObject) will be cached internally
2266
 * to be reused.
2267
 * @options:
2268
 *   0: This will set the XPath object caching:
2269
 *      @value:
2270
 *        This will set the maximum number of XPath objects
2271
 *        to be cached per slot
2272
 *        There are 5 slots for: node-set, string, number, boolean, and
2273
 *        misc objects. Use <0 for the default number (100).
2274
 *   Other values for @options have currently no effect.
2275
 *
2276
 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2277
 */
2278
int
2279
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2280
      int active,
2281
      int value,
2282
      int options)
2283
0
{
2284
0
    if (ctxt == NULL)
2285
0
  return(-1);
2286
0
    if (active) {
2287
0
  xmlXPathContextCachePtr cache;
2288
2289
0
  if (ctxt->cache == NULL) {
2290
0
      ctxt->cache = xmlXPathNewCache();
2291
0
      if (ctxt->cache == NULL)
2292
0
    return(-1);
2293
0
  }
2294
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
2295
0
  if (options == 0) {
2296
0
      if (value < 0)
2297
0
    value = 100;
2298
0
      cache->maxNodeset = value;
2299
0
      cache->maxString = value;
2300
0
      cache->maxNumber = value;
2301
0
      cache->maxBoolean = value;
2302
0
      cache->maxMisc = value;
2303
0
  }
2304
0
    } else if (ctxt->cache != NULL) {
2305
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2306
0
  ctxt->cache = NULL;
2307
0
    }
2308
0
    return(0);
2309
0
}
2310
2311
/**
2312
 * xmlXPathCacheWrapNodeSet:
2313
 * @ctxt: the XPath context
2314
 * @val:  the NodePtr value
2315
 *
2316
 * This is the cached version of xmlXPathWrapNodeSet().
2317
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2318
 *
2319
 * Returns the created or reused object.
2320
 */
2321
static xmlXPathObjectPtr
2322
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2323
0
{
2324
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2325
0
  xmlXPathContextCachePtr cache =
2326
0
      (xmlXPathContextCachePtr) ctxt->cache;
2327
2328
0
  if ((cache->miscObjs != NULL) &&
2329
0
      (cache->miscObjs->number != 0))
2330
0
  {
2331
0
      xmlXPathObjectPtr ret;
2332
2333
0
      ret = (xmlXPathObjectPtr)
2334
0
    cache->miscObjs->items[--cache->miscObjs->number];
2335
0
      ret->type = XPATH_NODESET;
2336
0
      ret->nodesetval = val;
2337
#ifdef XP_DEBUG_OBJ_USAGE
2338
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2339
#endif
2340
0
      return(ret);
2341
0
  }
2342
0
    }
2343
2344
0
    return(xmlXPathWrapNodeSet(val));
2345
2346
0
}
2347
2348
/**
2349
 * xmlXPathCacheWrapString:
2350
 * @ctxt: the XPath context
2351
 * @val:  the xmlChar * value
2352
 *
2353
 * This is the cached version of xmlXPathWrapString().
2354
 * Wraps the @val string into an XPath object.
2355
 *
2356
 * Returns the created or reused object.
2357
 */
2358
static xmlXPathObjectPtr
2359
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2360
0
{
2361
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2362
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2363
2364
0
  if ((cache->stringObjs != NULL) &&
2365
0
      (cache->stringObjs->number != 0))
2366
0
  {
2367
2368
0
      xmlXPathObjectPtr ret;
2369
2370
0
      ret = (xmlXPathObjectPtr)
2371
0
    cache->stringObjs->items[--cache->stringObjs->number];
2372
0
      ret->type = XPATH_STRING;
2373
0
      ret->stringval = val;
2374
#ifdef XP_DEBUG_OBJ_USAGE
2375
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2376
#endif
2377
0
      return(ret);
2378
0
  } else if ((cache->miscObjs != NULL) &&
2379
0
      (cache->miscObjs->number != 0))
2380
0
  {
2381
0
      xmlXPathObjectPtr ret;
2382
      /*
2383
      * Fallback to misc-cache.
2384
      */
2385
0
      ret = (xmlXPathObjectPtr)
2386
0
    cache->miscObjs->items[--cache->miscObjs->number];
2387
2388
0
      ret->type = XPATH_STRING;
2389
0
      ret->stringval = val;
2390
#ifdef XP_DEBUG_OBJ_USAGE
2391
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2392
#endif
2393
0
      return(ret);
2394
0
  }
2395
0
    }
2396
0
    return(xmlXPathWrapString(val));
2397
0
}
2398
2399
/**
2400
 * xmlXPathCacheNewNodeSet:
2401
 * @ctxt: the XPath context
2402
 * @val:  the NodePtr value
2403
 *
2404
 * This is the cached version of xmlXPathNewNodeSet().
2405
 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2406
 * it with the single Node @val
2407
 *
2408
 * Returns the created or reused object.
2409
 */
2410
static xmlXPathObjectPtr
2411
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2412
0
{
2413
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2414
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2415
2416
0
  if ((cache->nodesetObjs != NULL) &&
2417
0
      (cache->nodesetObjs->number != 0))
2418
0
  {
2419
0
      xmlXPathObjectPtr ret;
2420
      /*
2421
      * Use the nodeset-cache.
2422
      */
2423
0
      ret = (xmlXPathObjectPtr)
2424
0
    cache->nodesetObjs->items[--cache->nodesetObjs->number];
2425
0
      ret->type = XPATH_NODESET;
2426
0
      ret->boolval = 0;
2427
0
      if (val) {
2428
0
    if ((ret->nodesetval->nodeMax == 0) ||
2429
0
        (val->type == XML_NAMESPACE_DECL))
2430
0
    {
2431
                    /* TODO: Check memory error. */
2432
0
        xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2433
0
    } else {
2434
0
        ret->nodesetval->nodeTab[0] = val;
2435
0
        ret->nodesetval->nodeNr = 1;
2436
0
    }
2437
0
      }
2438
#ifdef XP_DEBUG_OBJ_USAGE
2439
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2440
#endif
2441
0
      return(ret);
2442
0
  } else if ((cache->miscObjs != NULL) &&
2443
0
      (cache->miscObjs->number != 0))
2444
0
  {
2445
0
      xmlXPathObjectPtr ret;
2446
      /*
2447
      * Fallback to misc-cache.
2448
      */
2449
2450
0
      ret = (xmlXPathObjectPtr)
2451
0
    cache->miscObjs->items[--cache->miscObjs->number];
2452
2453
0
      ret->type = XPATH_NODESET;
2454
0
      ret->boolval = 0;
2455
0
      ret->nodesetval = xmlXPathNodeSetCreate(val);
2456
0
      if (ret->nodesetval == NULL) {
2457
0
    ctxt->lastError.domain = XML_FROM_XPATH;
2458
0
    ctxt->lastError.code = XML_ERR_NO_MEMORY;
2459
0
    return(NULL);
2460
0
      }
2461
#ifdef XP_DEBUG_OBJ_USAGE
2462
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2463
#endif
2464
0
      return(ret);
2465
0
  }
2466
0
    }
2467
0
    return(xmlXPathNewNodeSet(val));
2468
0
}
2469
2470
/**
2471
 * xmlXPathCacheNewCString:
2472
 * @ctxt: the XPath context
2473
 * @val:  the char * value
2474
 *
2475
 * This is the cached version of xmlXPathNewCString().
2476
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2477
 *
2478
 * Returns the created or reused object.
2479
 */
2480
static xmlXPathObjectPtr
2481
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2482
0
{
2483
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2484
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2485
2486
0
  if ((cache->stringObjs != NULL) &&
2487
0
      (cache->stringObjs->number != 0))
2488
0
  {
2489
0
      xmlXPathObjectPtr ret;
2490
2491
0
      ret = (xmlXPathObjectPtr)
2492
0
    cache->stringObjs->items[--cache->stringObjs->number];
2493
2494
0
      ret->type = XPATH_STRING;
2495
0
      ret->stringval = xmlStrdup(BAD_CAST val);
2496
#ifdef XP_DEBUG_OBJ_USAGE
2497
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2498
#endif
2499
0
      return(ret);
2500
0
  } else if ((cache->miscObjs != NULL) &&
2501
0
      (cache->miscObjs->number != 0))
2502
0
  {
2503
0
      xmlXPathObjectPtr ret;
2504
2505
0
      ret = (xmlXPathObjectPtr)
2506
0
    cache->miscObjs->items[--cache->miscObjs->number];
2507
2508
0
      ret->type = XPATH_STRING;
2509
0
      ret->stringval = xmlStrdup(BAD_CAST val);
2510
#ifdef XP_DEBUG_OBJ_USAGE
2511
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2512
#endif
2513
0
      return(ret);
2514
0
  }
2515
0
    }
2516
0
    return(xmlXPathNewCString(val));
2517
0
}
2518
2519
/**
2520
 * xmlXPathCacheNewString:
2521
 * @ctxt: the XPath context
2522
 * @val:  the xmlChar * value
2523
 *
2524
 * This is the cached version of xmlXPathNewString().
2525
 * Acquire an xmlXPathObjectPtr of type string and of value @val
2526
 *
2527
 * Returns the created or reused object.
2528
 */
2529
static xmlXPathObjectPtr
2530
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2531
0
{
2532
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2533
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2534
2535
0
  if ((cache->stringObjs != NULL) &&
2536
0
      (cache->stringObjs->number != 0))
2537
0
  {
2538
0
      xmlXPathObjectPtr ret;
2539
2540
0
      ret = (xmlXPathObjectPtr)
2541
0
    cache->stringObjs->items[--cache->stringObjs->number];
2542
0
      ret->type = XPATH_STRING;
2543
0
      if (val != NULL)
2544
0
    ret->stringval = xmlStrdup(val);
2545
0
      else
2546
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2547
#ifdef XP_DEBUG_OBJ_USAGE
2548
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2549
#endif
2550
0
      return(ret);
2551
0
  } else if ((cache->miscObjs != NULL) &&
2552
0
      (cache->miscObjs->number != 0))
2553
0
  {
2554
0
      xmlXPathObjectPtr ret;
2555
2556
0
      ret = (xmlXPathObjectPtr)
2557
0
    cache->miscObjs->items[--cache->miscObjs->number];
2558
2559
0
      ret->type = XPATH_STRING;
2560
0
      if (val != NULL)
2561
0
    ret->stringval = xmlStrdup(val);
2562
0
      else
2563
0
    ret->stringval = xmlStrdup((const xmlChar *)"");
2564
#ifdef XP_DEBUG_OBJ_USAGE
2565
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2566
#endif
2567
0
      return(ret);
2568
0
  }
2569
0
    }
2570
0
    return(xmlXPathNewString(val));
2571
0
}
2572
2573
/**
2574
 * xmlXPathCacheNewBoolean:
2575
 * @ctxt: the XPath context
2576
 * @val:  the boolean value
2577
 *
2578
 * This is the cached version of xmlXPathNewBoolean().
2579
 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2580
 *
2581
 * Returns the created or reused object.
2582
 */
2583
static xmlXPathObjectPtr
2584
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2585
0
{
2586
0
    if ((ctxt != NULL) && (ctxt->cache)) {
2587
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2588
2589
0
  if ((cache->booleanObjs != NULL) &&
2590
0
      (cache->booleanObjs->number != 0))
2591
0
  {
2592
0
      xmlXPathObjectPtr ret;
2593
2594
0
      ret = (xmlXPathObjectPtr)
2595
0
    cache->booleanObjs->items[--cache->booleanObjs->number];
2596
0
      ret->type = XPATH_BOOLEAN;
2597
0
      ret->boolval = (val != 0);
2598
#ifdef XP_DEBUG_OBJ_USAGE
2599
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2600
#endif
2601
0
      return(ret);
2602
0
  } else if ((cache->miscObjs != NULL) &&
2603
0
      (cache->miscObjs->number != 0))
2604
0
  {
2605
0
      xmlXPathObjectPtr ret;
2606
2607
0
      ret = (xmlXPathObjectPtr)
2608
0
    cache->miscObjs->items[--cache->miscObjs->number];
2609
2610
0
      ret->type = XPATH_BOOLEAN;
2611
0
      ret->boolval = (val != 0);
2612
#ifdef XP_DEBUG_OBJ_USAGE
2613
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2614
#endif
2615
0
      return(ret);
2616
0
  }
2617
0
    }
2618
0
    return(xmlXPathNewBoolean(val));
2619
0
}
2620
2621
/**
2622
 * xmlXPathCacheNewFloat:
2623
 * @ctxt: the XPath context
2624
 * @val:  the double value
2625
 *
2626
 * This is the cached version of xmlXPathNewFloat().
2627
 * Acquires an xmlXPathObjectPtr of type double and of value @val
2628
 *
2629
 * Returns the created or reused object.
2630
 */
2631
static xmlXPathObjectPtr
2632
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2633
0
{
2634
0
     if ((ctxt != NULL) && (ctxt->cache)) {
2635
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2636
2637
0
  if ((cache->numberObjs != NULL) &&
2638
0
      (cache->numberObjs->number != 0))
2639
0
  {
2640
0
      xmlXPathObjectPtr ret;
2641
2642
0
      ret = (xmlXPathObjectPtr)
2643
0
    cache->numberObjs->items[--cache->numberObjs->number];
2644
0
      ret->type = XPATH_NUMBER;
2645
0
      ret->floatval = val;
2646
#ifdef XP_DEBUG_OBJ_USAGE
2647
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2648
#endif
2649
0
      return(ret);
2650
0
  } else if ((cache->miscObjs != NULL) &&
2651
0
      (cache->miscObjs->number != 0))
2652
0
  {
2653
0
      xmlXPathObjectPtr ret;
2654
2655
0
      ret = (xmlXPathObjectPtr)
2656
0
    cache->miscObjs->items[--cache->miscObjs->number];
2657
2658
0
      ret->type = XPATH_NUMBER;
2659
0
      ret->floatval = val;
2660
#ifdef XP_DEBUG_OBJ_USAGE
2661
      xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2662
#endif
2663
0
      return(ret);
2664
0
  }
2665
0
    }
2666
0
    return(xmlXPathNewFloat(val));
2667
0
}
2668
2669
/**
2670
 * xmlXPathCacheConvertString:
2671
 * @ctxt: the XPath context
2672
 * @val:  an XPath object
2673
 *
2674
 * This is the cached version of xmlXPathConvertString().
2675
 * Converts an existing object to its string() equivalent
2676
 *
2677
 * Returns a created or reused object, the old one is freed (cached)
2678
 *         (or the operation is done directly on @val)
2679
 */
2680
2681
static xmlXPathObjectPtr
2682
0
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2683
0
    xmlChar *res = NULL;
2684
2685
0
    if (val == NULL)
2686
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2687
2688
0
    switch (val->type) {
2689
0
    case XPATH_UNDEFINED:
2690
#ifdef DEBUG_EXPR
2691
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2692
#endif
2693
0
  break;
2694
0
    case XPATH_NODESET:
2695
0
    case XPATH_XSLT_TREE:
2696
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
2697
0
  break;
2698
0
    case XPATH_STRING:
2699
0
  return(val);
2700
0
    case XPATH_BOOLEAN:
2701
0
  res = xmlXPathCastBooleanToString(val->boolval);
2702
0
  break;
2703
0
    case XPATH_NUMBER:
2704
0
  res = xmlXPathCastNumberToString(val->floatval);
2705
0
  break;
2706
0
    case XPATH_USERS:
2707
#ifdef LIBXML_XPTR_LOCS_ENABLED
2708
    case XPATH_POINT:
2709
    case XPATH_RANGE:
2710
    case XPATH_LOCATIONSET:
2711
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2712
0
  TODO;
2713
0
  break;
2714
0
    }
2715
0
    xmlXPathReleaseObject(ctxt, val);
2716
0
    if (res == NULL)
2717
0
  return(xmlXPathCacheNewCString(ctxt, ""));
2718
0
    return(xmlXPathCacheWrapString(ctxt, res));
2719
0
}
2720
2721
/**
2722
 * xmlXPathCacheObjectCopy:
2723
 * @ctxt: the XPath context
2724
 * @val:  the original object
2725
 *
2726
 * This is the cached version of xmlXPathObjectCopy().
2727
 * Acquire a copy of a given object
2728
 *
2729
 * Returns a created or reused created object.
2730
 */
2731
static xmlXPathObjectPtr
2732
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2733
0
{
2734
0
    if (val == NULL)
2735
0
  return(NULL);
2736
2737
0
    if (XP_HAS_CACHE(ctxt)) {
2738
0
  switch (val->type) {
2739
0
      case XPATH_NODESET:
2740
0
    return(xmlXPathCacheWrapNodeSet(ctxt,
2741
0
        xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2742
0
      case XPATH_STRING:
2743
0
    return(xmlXPathCacheNewString(ctxt, val->stringval));
2744
0
      case XPATH_BOOLEAN:
2745
0
    return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2746
0
      case XPATH_NUMBER:
2747
0
    return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2748
0
      default:
2749
0
    break;
2750
0
  }
2751
0
    }
2752
0
    return(xmlXPathObjectCopy(val));
2753
0
}
2754
2755
/**
2756
 * xmlXPathCacheConvertBoolean:
2757
 * @ctxt: the XPath context
2758
 * @val:  an XPath object
2759
 *
2760
 * This is the cached version of xmlXPathConvertBoolean().
2761
 * Converts an existing object to its boolean() equivalent
2762
 *
2763
 * Returns a created or reused object, the old one is freed (or the operation
2764
 *         is done directly on @val)
2765
 */
2766
static xmlXPathObjectPtr
2767
0
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2768
0
    xmlXPathObjectPtr ret;
2769
2770
0
    if (val == NULL)
2771
0
  return(xmlXPathCacheNewBoolean(ctxt, 0));
2772
0
    if (val->type == XPATH_BOOLEAN)
2773
0
  return(val);
2774
0
    ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2775
0
    xmlXPathReleaseObject(ctxt, val);
2776
0
    return(ret);
2777
0
}
2778
2779
/**
2780
 * xmlXPathCacheConvertNumber:
2781
 * @ctxt: the XPath context
2782
 * @val:  an XPath object
2783
 *
2784
 * This is the cached version of xmlXPathConvertNumber().
2785
 * Converts an existing object to its number() equivalent
2786
 *
2787
 * Returns a created or reused object, the old one is freed (or the operation
2788
 *         is done directly on @val)
2789
 */
2790
static xmlXPathObjectPtr
2791
0
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2792
0
    xmlXPathObjectPtr ret;
2793
2794
0
    if (val == NULL)
2795
0
  return(xmlXPathCacheNewFloat(ctxt, 0.0));
2796
0
    if (val->type == XPATH_NUMBER)
2797
0
  return(val);
2798
0
    ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2799
0
    xmlXPathReleaseObject(ctxt, val);
2800
0
    return(ret);
2801
0
}
2802
2803
/************************************************************************
2804
 *                  *
2805
 *    Parser stacks related functions and macros    *
2806
 *                  *
2807
 ************************************************************************/
2808
2809
/**
2810
 * xmlXPathSetFrame:
2811
 * @ctxt: an XPath parser context
2812
 *
2813
 * Set the callee evaluation frame
2814
 *
2815
 * Returns the previous frame value to be restored once done
2816
 */
2817
static int
2818
0
xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2819
0
    int ret;
2820
2821
0
    if (ctxt == NULL)
2822
0
        return(0);
2823
0
    ret = ctxt->valueFrame;
2824
0
    ctxt->valueFrame = ctxt->valueNr;
2825
0
    return(ret);
2826
0
}
2827
2828
/**
2829
 * xmlXPathPopFrame:
2830
 * @ctxt: an XPath parser context
2831
 * @frame: the previous frame value
2832
 *
2833
 * Remove the callee evaluation frame
2834
 */
2835
static void
2836
0
xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2837
0
    if (ctxt == NULL)
2838
0
        return;
2839
0
    if (ctxt->valueNr < ctxt->valueFrame) {
2840
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2841
0
    }
2842
0
    ctxt->valueFrame = frame;
2843
0
}
2844
2845
/**
2846
 * valuePop:
2847
 * @ctxt: an XPath evaluation context
2848
 *
2849
 * Pops the top XPath object from the value stack
2850
 *
2851
 * Returns the XPath object just removed
2852
 */
2853
xmlXPathObjectPtr
2854
valuePop(xmlXPathParserContextPtr ctxt)
2855
0
{
2856
0
    xmlXPathObjectPtr ret;
2857
2858
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2859
0
        return (NULL);
2860
2861
0
    if (ctxt->valueNr <= ctxt->valueFrame) {
2862
0
        xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2863
0
        return (NULL);
2864
0
    }
2865
2866
0
    ctxt->valueNr--;
2867
0
    if (ctxt->valueNr > 0)
2868
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2869
0
    else
2870
0
        ctxt->value = NULL;
2871
0
    ret = ctxt->valueTab[ctxt->valueNr];
2872
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
2873
0
    return (ret);
2874
0
}
2875
/**
2876
 * valuePush:
2877
 * @ctxt:  an XPath evaluation context
2878
 * @value:  the XPath object
2879
 *
2880
 * Pushes a new XPath object on top of the value stack. If value is NULL,
2881
 * a memory error is recorded in the parser context.
2882
 *
2883
 * Returns the number of items on the value stack, or -1 in case of error.
2884
 */
2885
int
2886
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2887
0
{
2888
0
    if (ctxt == NULL) return(-1);
2889
0
    if (value == NULL) {
2890
        /*
2891
         * A NULL value typically indicates that a memory allocation failed,
2892
         * so we set ctxt->error here to propagate the error.
2893
         */
2894
0
  ctxt->error = XPATH_MEMORY_ERROR;
2895
0
        return(-1);
2896
0
    }
2897
0
    if (ctxt->valueNr >= ctxt->valueMax) {
2898
0
        xmlXPathObjectPtr *tmp;
2899
2900
0
        if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2901
0
            xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2902
0
            return (-1);
2903
0
        }
2904
0
        tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2905
0
                                             2 * ctxt->valueMax *
2906
0
                                             sizeof(ctxt->valueTab[0]));
2907
0
        if (tmp == NULL) {
2908
0
            xmlXPathPErrMemory(ctxt, "pushing value\n");
2909
0
            return (-1);
2910
0
        }
2911
0
        ctxt->valueMax *= 2;
2912
0
  ctxt->valueTab = tmp;
2913
0
    }
2914
0
    ctxt->valueTab[ctxt->valueNr] = value;
2915
0
    ctxt->value = value;
2916
0
    return (ctxt->valueNr++);
2917
0
}
2918
2919
/**
2920
 * xmlXPathPopBoolean:
2921
 * @ctxt:  an XPath parser context
2922
 *
2923
 * Pops a boolean from the stack, handling conversion if needed.
2924
 * Check error with #xmlXPathCheckError.
2925
 *
2926
 * Returns the boolean
2927
 */
2928
int
2929
0
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2930
0
    xmlXPathObjectPtr obj;
2931
0
    int ret;
2932
2933
0
    obj = valuePop(ctxt);
2934
0
    if (obj == NULL) {
2935
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2936
0
  return(0);
2937
0
    }
2938
0
    if (obj->type != XPATH_BOOLEAN)
2939
0
  ret = xmlXPathCastToBoolean(obj);
2940
0
    else
2941
0
        ret = obj->boolval;
2942
0
    xmlXPathReleaseObject(ctxt->context, obj);
2943
0
    return(ret);
2944
0
}
2945
2946
/**
2947
 * xmlXPathPopNumber:
2948
 * @ctxt:  an XPath parser context
2949
 *
2950
 * Pops a number from the stack, handling conversion if needed.
2951
 * Check error with #xmlXPathCheckError.
2952
 *
2953
 * Returns the number
2954
 */
2955
double
2956
0
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2957
0
    xmlXPathObjectPtr obj;
2958
0
    double ret;
2959
2960
0
    obj = valuePop(ctxt);
2961
0
    if (obj == NULL) {
2962
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2963
0
  return(0);
2964
0
    }
2965
0
    if (obj->type != XPATH_NUMBER)
2966
0
  ret = xmlXPathCastToNumber(obj);
2967
0
    else
2968
0
        ret = obj->floatval;
2969
0
    xmlXPathReleaseObject(ctxt->context, obj);
2970
0
    return(ret);
2971
0
}
2972
2973
/**
2974
 * xmlXPathPopString:
2975
 * @ctxt:  an XPath parser context
2976
 *
2977
 * Pops a string from the stack, handling conversion if needed.
2978
 * Check error with #xmlXPathCheckError.
2979
 *
2980
 * Returns the string
2981
 */
2982
xmlChar *
2983
0
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2984
0
    xmlXPathObjectPtr obj;
2985
0
    xmlChar * ret;
2986
2987
0
    obj = valuePop(ctxt);
2988
0
    if (obj == NULL) {
2989
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2990
0
  return(NULL);
2991
0
    }
2992
0
    ret = xmlXPathCastToString(obj);  /* this does required strdup */
2993
    /* TODO: needs refactoring somewhere else */
2994
0
    if (obj->stringval == ret)
2995
0
  obj->stringval = NULL;
2996
0
    xmlXPathReleaseObject(ctxt->context, obj);
2997
0
    return(ret);
2998
0
}
2999
3000
/**
3001
 * xmlXPathPopNodeSet:
3002
 * @ctxt:  an XPath parser context
3003
 *
3004
 * Pops a node-set from the stack, handling conversion if needed.
3005
 * Check error with #xmlXPathCheckError.
3006
 *
3007
 * Returns the node-set
3008
 */
3009
xmlNodeSetPtr
3010
0
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
3011
0
    xmlXPathObjectPtr obj;
3012
0
    xmlNodeSetPtr ret;
3013
3014
0
    if (ctxt == NULL) return(NULL);
3015
0
    if (ctxt->value == NULL) {
3016
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3017
0
  return(NULL);
3018
0
    }
3019
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
3020
0
  xmlXPathSetTypeError(ctxt);
3021
0
  return(NULL);
3022
0
    }
3023
0
    obj = valuePop(ctxt);
3024
0
    ret = obj->nodesetval;
3025
#if 0
3026
    /* to fix memory leak of not clearing obj->user */
3027
    if (obj->boolval && obj->user != NULL)
3028
        xmlFreeNodeList((xmlNodePtr) obj->user);
3029
#endif
3030
0
    obj->nodesetval = NULL;
3031
0
    xmlXPathReleaseObject(ctxt->context, obj);
3032
0
    return(ret);
3033
0
}
3034
3035
/**
3036
 * xmlXPathPopExternal:
3037
 * @ctxt:  an XPath parser context
3038
 *
3039
 * Pops an external object from the stack, handling conversion if needed.
3040
 * Check error with #xmlXPathCheckError.
3041
 *
3042
 * Returns the object
3043
 */
3044
void *
3045
0
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3046
0
    xmlXPathObjectPtr obj;
3047
0
    void * ret;
3048
3049
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
3050
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3051
0
  return(NULL);
3052
0
    }
3053
0
    if (ctxt->value->type != XPATH_USERS) {
3054
0
  xmlXPathSetTypeError(ctxt);
3055
0
  return(NULL);
3056
0
    }
3057
0
    obj = valuePop(ctxt);
3058
0
    ret = obj->user;
3059
0
    obj->user = NULL;
3060
0
    xmlXPathReleaseObject(ctxt->context, obj);
3061
0
    return(ret);
3062
0
}
3063
3064
/*
3065
 * Macros for accessing the content. Those should be used only by the parser,
3066
 * and not exported.
3067
 *
3068
 * Dirty macros, i.e. one need to make assumption on the context to use them
3069
 *
3070
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
3071
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
3072
 *           in ISO-Latin or UTF-8.
3073
 *           This should be used internally by the parser
3074
 *           only to compare to ASCII values otherwise it would break when
3075
 *           running with UTF-8 encoding.
3076
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
3077
 *           to compare on ASCII based substring.
3078
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3079
 *           strings within the parser.
3080
 *   CURRENT Returns the current char value, with the full decoding of
3081
 *           UTF-8 if we are using this mode. It returns an int.
3082
 *   NEXT    Skip to the next character, this does the proper decoding
3083
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
3084
 *           It returns the pointer to the current xmlChar.
3085
 */
3086
3087
0
#define CUR (*ctxt->cur)
3088
0
#define SKIP(val) ctxt->cur += (val)
3089
0
#define NXT(val) ctxt->cur[(val)]
3090
0
#define CUR_PTR ctxt->cur
3091
0
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3092
3093
#define COPY_BUF(l,b,i,v)                                              \
3094
0
    if (l == 1) b[i++] = (xmlChar) v;                                  \
3095
0
    else i += xmlCopyChar(l,&b[i],v)
3096
3097
0
#define NEXTL(l)  ctxt->cur += l
3098
3099
#define SKIP_BLANKS             \
3100
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3101
3102
#define CURRENT (*ctxt->cur)
3103
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
3104
3105
3106
#ifndef DBL_DIG
3107
#define DBL_DIG 16
3108
#endif
3109
#ifndef DBL_EPSILON
3110
#define DBL_EPSILON 1E-9
3111
#endif
3112
3113
0
#define UPPER_DOUBLE 1E9
3114
0
#define LOWER_DOUBLE 1E-5
3115
#define LOWER_DOUBLE_EXP 5
3116
3117
#define INTEGER_DIGITS DBL_DIG
3118
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3119
0
#define EXPONENT_DIGITS (3 + 2)
3120
3121
/**
3122
 * xmlXPathFormatNumber:
3123
 * @number:     number to format
3124
 * @buffer:     output buffer
3125
 * @buffersize: size of output buffer
3126
 *
3127
 * Convert the number into a string representation.
3128
 */
3129
static void
3130
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3131
0
{
3132
0
    switch (xmlXPathIsInf(number)) {
3133
0
    case 1:
3134
0
  if (buffersize > (int)sizeof("Infinity"))
3135
0
      snprintf(buffer, buffersize, "Infinity");
3136
0
  break;
3137
0
    case -1:
3138
0
  if (buffersize > (int)sizeof("-Infinity"))
3139
0
      snprintf(buffer, buffersize, "-Infinity");
3140
0
  break;
3141
0
    default:
3142
0
  if (xmlXPathIsNaN(number)) {
3143
0
      if (buffersize > (int)sizeof("NaN"))
3144
0
    snprintf(buffer, buffersize, "NaN");
3145
0
  } else if (number == 0) {
3146
            /* Omit sign for negative zero. */
3147
0
      snprintf(buffer, buffersize, "0");
3148
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
3149
0
                   (number == (int) number)) {
3150
0
      char work[30];
3151
0
      char *ptr, *cur;
3152
0
      int value = (int) number;
3153
3154
0
            ptr = &buffer[0];
3155
0
      if (value == 0) {
3156
0
    *ptr++ = '0';
3157
0
      } else {
3158
0
    snprintf(work, 29, "%d", value);
3159
0
    cur = &work[0];
3160
0
    while ((*cur) && (ptr - buffer < buffersize)) {
3161
0
        *ptr++ = *cur++;
3162
0
    }
3163
0
      }
3164
0
      if (ptr - buffer < buffersize) {
3165
0
    *ptr = 0;
3166
0
      } else if (buffersize > 0) {
3167
0
    ptr--;
3168
0
    *ptr = 0;
3169
0
      }
3170
0
  } else {
3171
      /*
3172
        For the dimension of work,
3173
            DBL_DIG is number of significant digits
3174
      EXPONENT is only needed for "scientific notation"
3175
            3 is sign, decimal point, and terminating zero
3176
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3177
        Note that this dimension is slightly (a few characters)
3178
        larger than actually necessary.
3179
      */
3180
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3181
0
      int integer_place, fraction_place;
3182
0
      char *ptr;
3183
0
      char *after_fraction;
3184
0
      double absolute_value;
3185
0
      int size;
3186
3187
0
      absolute_value = fabs(number);
3188
3189
      /*
3190
       * First choose format - scientific or regular floating point.
3191
       * In either case, result is in work, and after_fraction points
3192
       * just past the fractional part.
3193
      */
3194
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
3195
0
      (absolute_value < LOWER_DOUBLE)) &&
3196
0
     (absolute_value != 0.0) ) {
3197
    /* Use scientific notation */
3198
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3199
0
    fraction_place = DBL_DIG - 1;
3200
0
    size = snprintf(work, sizeof(work),"%*.*e",
3201
0
       integer_place, fraction_place, number);
3202
0
    while ((size > 0) && (work[size] != 'e')) size--;
3203
3204
0
      }
3205
0
      else {
3206
    /* Use regular notation */
3207
0
    if (absolute_value > 0.0) {
3208
0
        integer_place = (int)log10(absolute_value);
3209
0
        if (integer_place > 0)
3210
0
            fraction_place = DBL_DIG - integer_place - 1;
3211
0
        else
3212
0
            fraction_place = DBL_DIG - integer_place;
3213
0
    } else {
3214
0
        fraction_place = 1;
3215
0
    }
3216
0
    size = snprintf(work, sizeof(work), "%0.*f",
3217
0
        fraction_place, number);
3218
0
      }
3219
3220
      /* Remove leading spaces sometimes inserted by snprintf */
3221
0
      while (work[0] == ' ') {
3222
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3223
0
    size--;
3224
0
      }
3225
3226
      /* Remove fractional trailing zeroes */
3227
0
      after_fraction = work + size;
3228
0
      ptr = after_fraction;
3229
0
      while (*(--ptr) == '0')
3230
0
    ;
3231
0
      if (*ptr != '.')
3232
0
          ptr++;
3233
0
      while ((*ptr++ = *after_fraction++) != 0);
3234
3235
      /* Finally copy result back to caller */
3236
0
      size = strlen(work) + 1;
3237
0
      if (size > buffersize) {
3238
0
    work[buffersize - 1] = 0;
3239
0
    size = buffersize;
3240
0
      }
3241
0
      memmove(buffer, work, size);
3242
0
  }
3243
0
  break;
3244
0
    }
3245
0
}
3246
3247
3248
/************************************************************************
3249
 *                  *
3250
 *      Routines to handle NodeSets     *
3251
 *                  *
3252
 ************************************************************************/
3253
3254
/**
3255
 * xmlXPathOrderDocElems:
3256
 * @doc:  an input document
3257
 *
3258
 * Call this routine to speed up XPath computation on static documents.
3259
 * This stamps all the element nodes with the document order
3260
 * Like for line information, the order is kept in the element->content
3261
 * field, the value stored is actually - the node number (starting at -1)
3262
 * to be able to differentiate from line numbers.
3263
 *
3264
 * Returns the number of elements found in the document or -1 in case
3265
 *    of error.
3266
 */
3267
long
3268
0
xmlXPathOrderDocElems(xmlDocPtr doc) {
3269
0
    ptrdiff_t count = 0;
3270
0
    xmlNodePtr cur;
3271
3272
0
    if (doc == NULL)
3273
0
  return(-1);
3274
0
    cur = doc->children;
3275
0
    while (cur != NULL) {
3276
0
  if (cur->type == XML_ELEMENT_NODE) {
3277
0
      cur->content = (void *) (-(++count));
3278
0
      if (cur->children != NULL) {
3279
0
    cur = cur->children;
3280
0
    continue;
3281
0
      }
3282
0
  }
3283
0
  if (cur->next != NULL) {
3284
0
      cur = cur->next;
3285
0
      continue;
3286
0
  }
3287
0
  do {
3288
0
      cur = cur->parent;
3289
0
      if (cur == NULL)
3290
0
    break;
3291
0
      if (cur == (xmlNodePtr) doc) {
3292
0
    cur = NULL;
3293
0
    break;
3294
0
      }
3295
0
      if (cur->next != NULL) {
3296
0
    cur = cur->next;
3297
0
    break;
3298
0
      }
3299
0
  } while (cur != NULL);
3300
0
    }
3301
0
    return((long) count);
3302
0
}
3303
3304
/**
3305
 * xmlXPathCmpNodes:
3306
 * @node1:  the first node
3307
 * @node2:  the second node
3308
 *
3309
 * Compare two nodes w.r.t document order
3310
 *
3311
 * Returns -2 in case of error 1 if first point < second point, 0 if
3312
 *         it's the same node, -1 otherwise
3313
 */
3314
int
3315
0
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3316
0
    int depth1, depth2;
3317
0
    int attr1 = 0, attr2 = 0;
3318
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3319
0
    xmlNodePtr cur, root;
3320
3321
0
    if ((node1 == NULL) || (node2 == NULL))
3322
0
  return(-2);
3323
    /*
3324
     * a couple of optimizations which will avoid computations in most cases
3325
     */
3326
0
    if (node1 == node2)   /* trivial case */
3327
0
  return(0);
3328
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
3329
0
  attr1 = 1;
3330
0
  attrNode1 = node1;
3331
0
  node1 = node1->parent;
3332
0
    }
3333
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
3334
0
  attr2 = 1;
3335
0
  attrNode2 = node2;
3336
0
  node2 = node2->parent;
3337
0
    }
3338
0
    if (node1 == node2) {
3339
0
  if (attr1 == attr2) {
3340
      /* not required, but we keep attributes in order */
3341
0
      if (attr1 != 0) {
3342
0
          cur = attrNode2->prev;
3343
0
    while (cur != NULL) {
3344
0
        if (cur == attrNode1)
3345
0
            return (1);
3346
0
        cur = cur->prev;
3347
0
    }
3348
0
    return (-1);
3349
0
      }
3350
0
      return(0);
3351
0
  }
3352
0
  if (attr2 == 1)
3353
0
      return(1);
3354
0
  return(-1);
3355
0
    }
3356
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
3357
0
        (node2->type == XML_NAMESPACE_DECL))
3358
0
  return(1);
3359
0
    if (node1 == node2->prev)
3360
0
  return(1);
3361
0
    if (node1 == node2->next)
3362
0
  return(-1);
3363
3364
    /*
3365
     * Speedup using document order if available.
3366
     */
3367
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3368
0
  (node2->type == XML_ELEMENT_NODE) &&
3369
0
  (0 > (ptrdiff_t) node1->content) &&
3370
0
  (0 > (ptrdiff_t) node2->content) &&
3371
0
  (node1->doc == node2->doc)) {
3372
0
  ptrdiff_t l1, l2;
3373
3374
0
  l1 = -((ptrdiff_t) node1->content);
3375
0
  l2 = -((ptrdiff_t) node2->content);
3376
0
  if (l1 < l2)
3377
0
      return(1);
3378
0
  if (l1 > l2)
3379
0
      return(-1);
3380
0
    }
3381
3382
    /*
3383
     * compute depth to root
3384
     */
3385
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3386
0
  if (cur->parent == node1)
3387
0
      return(1);
3388
0
  depth2++;
3389
0
    }
3390
0
    root = cur;
3391
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3392
0
  if (cur->parent == node2)
3393
0
      return(-1);
3394
0
  depth1++;
3395
0
    }
3396
    /*
3397
     * Distinct document (or distinct entities :-( ) case.
3398
     */
3399
0
    if (root != cur) {
3400
0
  return(-2);
3401
0
    }
3402
    /*
3403
     * get the nearest common ancestor.
3404
     */
3405
0
    while (depth1 > depth2) {
3406
0
  depth1--;
3407
0
  node1 = node1->parent;
3408
0
    }
3409
0
    while (depth2 > depth1) {
3410
0
  depth2--;
3411
0
  node2 = node2->parent;
3412
0
    }
3413
0
    while (node1->parent != node2->parent) {
3414
0
  node1 = node1->parent;
3415
0
  node2 = node2->parent;
3416
  /* should not happen but just in case ... */
3417
0
  if ((node1 == NULL) || (node2 == NULL))
3418
0
      return(-2);
3419
0
    }
3420
    /*
3421
     * Find who's first.
3422
     */
3423
0
    if (node1 == node2->prev)
3424
0
  return(1);
3425
0
    if (node1 == node2->next)
3426
0
  return(-1);
3427
    /*
3428
     * Speedup using document order if available.
3429
     */
3430
0
    if ((node1->type == XML_ELEMENT_NODE) &&
3431
0
  (node2->type == XML_ELEMENT_NODE) &&
3432
0
  (0 > (ptrdiff_t) node1->content) &&
3433
0
  (0 > (ptrdiff_t) node2->content) &&
3434
0
  (node1->doc == node2->doc)) {
3435
0
  ptrdiff_t l1, l2;
3436
3437
0
  l1 = -((ptrdiff_t) node1->content);
3438
0
  l2 = -((ptrdiff_t) node2->content);
3439
0
  if (l1 < l2)
3440
0
      return(1);
3441
0
  if (l1 > l2)
3442
0
      return(-1);
3443
0
    }
3444
3445
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
3446
0
  if (cur == node2)
3447
0
      return(1);
3448
0
    return(-1); /* assume there is no sibling list corruption */
3449
0
}
3450
3451
/**
3452
 * xmlXPathNodeSetSort:
3453
 * @set:  the node set
3454
 *
3455
 * Sort the node set in document order
3456
 */
3457
void
3458
0
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3459
#ifndef WITH_TIM_SORT
3460
    int i, j, incr, len;
3461
    xmlNodePtr tmp;
3462
#endif
3463
3464
0
    if (set == NULL)
3465
0
  return;
3466
3467
#ifndef WITH_TIM_SORT
3468
    /*
3469
     * Use the old Shell's sort implementation to sort the node-set
3470
     * Timsort ought to be quite faster
3471
     */
3472
    len = set->nodeNr;
3473
    for (incr = len / 2; incr > 0; incr /= 2) {
3474
  for (i = incr; i < len; i++) {
3475
      j = i - incr;
3476
      while (j >= 0) {
3477
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3478
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
3479
      set->nodeTab[j + incr]) == -1)
3480
#else
3481
    if (xmlXPathCmpNodes(set->nodeTab[j],
3482
      set->nodeTab[j + incr]) == -1)
3483
#endif
3484
    {
3485
        tmp = set->nodeTab[j];
3486
        set->nodeTab[j] = set->nodeTab[j + incr];
3487
        set->nodeTab[j + incr] = tmp;
3488
        j -= incr;
3489
    } else
3490
        break;
3491
      }
3492
  }
3493
    }
3494
#else /* WITH_TIM_SORT */
3495
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3496
0
#endif /* WITH_TIM_SORT */
3497
0
}
3498
3499
0
#define XML_NODESET_DEFAULT 10
3500
/**
3501
 * xmlXPathNodeSetDupNs:
3502
 * @node:  the parent node of the namespace XPath node
3503
 * @ns:  the libxml namespace declaration node.
3504
 *
3505
 * Namespace node in libxml don't match the XPath semantic. In a node set
3506
 * the namespace nodes are duplicated and the next pointer is set to the
3507
 * parent node in the XPath semantic.
3508
 *
3509
 * Returns the newly created object.
3510
 */
3511
static xmlNodePtr
3512
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3513
0
    xmlNsPtr cur;
3514
3515
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3516
0
  return(NULL);
3517
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3518
0
  return((xmlNodePtr) ns);
3519
3520
    /*
3521
     * Allocate a new Namespace and fill the fields.
3522
     */
3523
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3524
0
    if (cur == NULL) {
3525
0
        xmlXPathErrMemory(NULL, "duplicating namespace\n");
3526
0
  return(NULL);
3527
0
    }
3528
0
    memset(cur, 0, sizeof(xmlNs));
3529
0
    cur->type = XML_NAMESPACE_DECL;
3530
0
    if (ns->href != NULL)
3531
0
  cur->href = xmlStrdup(ns->href);
3532
0
    if (ns->prefix != NULL)
3533
0
  cur->prefix = xmlStrdup(ns->prefix);
3534
0
    cur->next = (xmlNsPtr) node;
3535
0
    return((xmlNodePtr) cur);
3536
0
}
3537
3538
/**
3539
 * xmlXPathNodeSetFreeNs:
3540
 * @ns:  the XPath namespace node found in a nodeset.
3541
 *
3542
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3543
 * the namespace nodes are duplicated and the next pointer is set to the
3544
 * parent node in the XPath semantic. Check if such a node needs to be freed
3545
 */
3546
void
3547
0
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3548
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3549
0
  return;
3550
3551
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3552
0
  if (ns->href != NULL)
3553
0
      xmlFree((xmlChar *)ns->href);
3554
0
  if (ns->prefix != NULL)
3555
0
      xmlFree((xmlChar *)ns->prefix);
3556
0
  xmlFree(ns);
3557
0
    }
3558
0
}
3559
3560
/**
3561
 * xmlXPathNodeSetCreate:
3562
 * @val:  an initial xmlNodePtr, or NULL
3563
 *
3564
 * Create a new xmlNodeSetPtr of type double and of value @val
3565
 *
3566
 * Returns the newly created object.
3567
 */
3568
xmlNodeSetPtr
3569
0
xmlXPathNodeSetCreate(xmlNodePtr val) {
3570
0
    xmlNodeSetPtr ret;
3571
3572
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3573
0
    if (ret == NULL) {
3574
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
3575
0
  return(NULL);
3576
0
    }
3577
0
    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3578
0
    if (val != NULL) {
3579
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3580
0
               sizeof(xmlNodePtr));
3581
0
  if (ret->nodeTab == NULL) {
3582
0
      xmlXPathErrMemory(NULL, "creating nodeset\n");
3583
0
      xmlFree(ret);
3584
0
      return(NULL);
3585
0
  }
3586
0
  memset(ret->nodeTab, 0 ,
3587
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3588
0
        ret->nodeMax = XML_NODESET_DEFAULT;
3589
0
  if (val->type == XML_NAMESPACE_DECL) {
3590
0
      xmlNsPtr ns = (xmlNsPtr) val;
3591
3592
            /* TODO: Check memory error. */
3593
0
      ret->nodeTab[ret->nodeNr++] =
3594
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3595
0
  } else
3596
0
      ret->nodeTab[ret->nodeNr++] = val;
3597
0
    }
3598
0
    return(ret);
3599
0
}
3600
3601
/**
3602
 * xmlXPathNodeSetContains:
3603
 * @cur:  the node-set
3604
 * @val:  the node
3605
 *
3606
 * checks whether @cur contains @val
3607
 *
3608
 * Returns true (1) if @cur contains @val, false (0) otherwise
3609
 */
3610
int
3611
0
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3612
0
    int i;
3613
3614
0
    if ((cur == NULL) || (val == NULL)) return(0);
3615
0
    if (val->type == XML_NAMESPACE_DECL) {
3616
0
  for (i = 0; i < cur->nodeNr; i++) {
3617
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3618
0
    xmlNsPtr ns1, ns2;
3619
3620
0
    ns1 = (xmlNsPtr) val;
3621
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
3622
0
    if (ns1 == ns2)
3623
0
        return(1);
3624
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3625
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
3626
0
        return(1);
3627
0
      }
3628
0
  }
3629
0
    } else {
3630
0
  for (i = 0; i < cur->nodeNr; i++) {
3631
0
      if (cur->nodeTab[i] == val)
3632
0
    return(1);
3633
0
  }
3634
0
    }
3635
0
    return(0);
3636
0
}
3637
3638
/**
3639
 * xmlXPathNodeSetAddNs:
3640
 * @cur:  the initial node set
3641
 * @node:  the hosting node
3642
 * @ns:  a the namespace node
3643
 *
3644
 * add a new namespace node to an existing NodeSet
3645
 *
3646
 * Returns 0 in case of success and -1 in case of error
3647
 */
3648
int
3649
0
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3650
0
    int i;
3651
3652
3653
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3654
0
        (ns->type != XML_NAMESPACE_DECL) ||
3655
0
  (node->type != XML_ELEMENT_NODE))
3656
0
  return(-1);
3657
3658
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3659
    /*
3660
     * prevent duplicates
3661
     */
3662
0
    for (i = 0;i < cur->nodeNr;i++) {
3663
0
        if ((cur->nodeTab[i] != NULL) &&
3664
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3665
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3666
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3667
0
      return(0);
3668
0
    }
3669
3670
    /*
3671
     * grow the nodeTab if needed
3672
     */
3673
0
    if (cur->nodeMax == 0) {
3674
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3675
0
               sizeof(xmlNodePtr));
3676
0
  if (cur->nodeTab == NULL) {
3677
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3678
0
      return(-1);
3679
0
  }
3680
0
  memset(cur->nodeTab, 0 ,
3681
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3682
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3683
0
    } else if (cur->nodeNr == cur->nodeMax) {
3684
0
        xmlNodePtr *temp;
3685
3686
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3687
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3688
0
            return(-1);
3689
0
        }
3690
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3691
0
              sizeof(xmlNodePtr));
3692
0
  if (temp == NULL) {
3693
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3694
0
      return(-1);
3695
0
  }
3696
0
        cur->nodeMax *= 2;
3697
0
  cur->nodeTab = temp;
3698
0
    }
3699
    /* TODO: Check memory error. */
3700
0
    cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3701
0
    return(0);
3702
0
}
3703
3704
/**
3705
 * xmlXPathNodeSetAdd:
3706
 * @cur:  the initial node set
3707
 * @val:  a new xmlNodePtr
3708
 *
3709
 * add a new xmlNodePtr to an existing NodeSet
3710
 *
3711
 * Returns 0 in case of success, and -1 in case of error
3712
 */
3713
int
3714
0
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3715
0
    int i;
3716
3717
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3718
3719
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3720
    /*
3721
     * prevent duplicates
3722
     */
3723
0
    for (i = 0;i < cur->nodeNr;i++)
3724
0
        if (cur->nodeTab[i] == val) return(0);
3725
3726
    /*
3727
     * grow the nodeTab if needed
3728
     */
3729
0
    if (cur->nodeMax == 0) {
3730
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3731
0
               sizeof(xmlNodePtr));
3732
0
  if (cur->nodeTab == NULL) {
3733
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3734
0
      return(-1);
3735
0
  }
3736
0
  memset(cur->nodeTab, 0 ,
3737
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3738
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3739
0
    } else if (cur->nodeNr == cur->nodeMax) {
3740
0
        xmlNodePtr *temp;
3741
3742
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3743
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3744
0
            return(-1);
3745
0
        }
3746
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3747
0
              sizeof(xmlNodePtr));
3748
0
  if (temp == NULL) {
3749
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3750
0
      return(-1);
3751
0
  }
3752
0
        cur->nodeMax *= 2;
3753
0
  cur->nodeTab = temp;
3754
0
    }
3755
0
    if (val->type == XML_NAMESPACE_DECL) {
3756
0
  xmlNsPtr ns = (xmlNsPtr) val;
3757
3758
        /* TODO: Check memory error. */
3759
0
  cur->nodeTab[cur->nodeNr++] =
3760
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3761
0
    } else
3762
0
  cur->nodeTab[cur->nodeNr++] = val;
3763
0
    return(0);
3764
0
}
3765
3766
/**
3767
 * xmlXPathNodeSetAddUnique:
3768
 * @cur:  the initial node set
3769
 * @val:  a new xmlNodePtr
3770
 *
3771
 * add a new xmlNodePtr to an existing NodeSet, optimized version
3772
 * when we are sure the node is not already in the set.
3773
 *
3774
 * Returns 0 in case of success and -1 in case of failure
3775
 */
3776
int
3777
0
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3778
0
    if ((cur == NULL) || (val == NULL)) return(-1);
3779
3780
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3781
    /*
3782
     * grow the nodeTab if needed
3783
     */
3784
0
    if (cur->nodeMax == 0) {
3785
0
        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3786
0
               sizeof(xmlNodePtr));
3787
0
  if (cur->nodeTab == NULL) {
3788
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3789
0
      return(-1);
3790
0
  }
3791
0
  memset(cur->nodeTab, 0 ,
3792
0
         XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3793
0
        cur->nodeMax = XML_NODESET_DEFAULT;
3794
0
    } else if (cur->nodeNr == cur->nodeMax) {
3795
0
        xmlNodePtr *temp;
3796
3797
0
        if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3798
0
            xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3799
0
            return(-1);
3800
0
        }
3801
0
  temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3802
0
              sizeof(xmlNodePtr));
3803
0
  if (temp == NULL) {
3804
0
      xmlXPathErrMemory(NULL, "growing nodeset\n");
3805
0
      return(-1);
3806
0
  }
3807
0
  cur->nodeTab = temp;
3808
0
        cur->nodeMax *= 2;
3809
0
    }
3810
0
    if (val->type == XML_NAMESPACE_DECL) {
3811
0
  xmlNsPtr ns = (xmlNsPtr) val;
3812
3813
        /* TODO: Check memory error. */
3814
0
  cur->nodeTab[cur->nodeNr++] =
3815
0
      xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3816
0
    } else
3817
0
  cur->nodeTab[cur->nodeNr++] = val;
3818
0
    return(0);
3819
0
}
3820
3821
/**
3822
 * xmlXPathNodeSetMerge:
3823
 * @val1:  the first NodeSet or NULL
3824
 * @val2:  the second NodeSet
3825
 *
3826
 * Merges two nodesets, all nodes from @val2 are added to @val1
3827
 * if @val1 is NULL, a new set is created and copied from @val2
3828
 *
3829
 * Returns @val1 once extended or NULL in case of error.
3830
 */
3831
xmlNodeSetPtr
3832
0
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3833
0
    int i, j, initNr, skip;
3834
0
    xmlNodePtr n1, n2;
3835
3836
0
    if (val2 == NULL) return(val1);
3837
0
    if (val1 == NULL) {
3838
0
  val1 = xmlXPathNodeSetCreate(NULL);
3839
0
    if (val1 == NULL)
3840
0
        return (NULL);
3841
#if 0
3842
  /*
3843
  * TODO: The optimization won't work in every case, since
3844
  *  those nasty namespace nodes need to be added with
3845
  *  xmlXPathNodeSetDupNs() to the set; thus a pure
3846
  *  memcpy is not possible.
3847
  *  If there was a flag on the nodesetval, indicating that
3848
  *  some temporary nodes are in, that would be helpful.
3849
  */
3850
  /*
3851
  * Optimization: Create an equally sized node-set
3852
  * and memcpy the content.
3853
  */
3854
  val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3855
  if (val1 == NULL)
3856
      return(NULL);
3857
  if (val2->nodeNr != 0) {
3858
      if (val2->nodeNr == 1)
3859
    *(val1->nodeTab) = *(val2->nodeTab);
3860
      else {
3861
    memcpy(val1->nodeTab, val2->nodeTab,
3862
        val2->nodeNr * sizeof(xmlNodePtr));
3863
      }
3864
      val1->nodeNr = val2->nodeNr;
3865
  }
3866
  return(val1);
3867
#endif
3868
0
    }
3869
3870
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3871
0
    initNr = val1->nodeNr;
3872
3873
0
    for (i = 0;i < val2->nodeNr;i++) {
3874
0
  n2 = val2->nodeTab[i];
3875
  /*
3876
   * check against duplicates
3877
   */
3878
0
  skip = 0;
3879
0
  for (j = 0; j < initNr; j++) {
3880
0
      n1 = val1->nodeTab[j];
3881
0
      if (n1 == n2) {
3882
0
    skip = 1;
3883
0
    break;
3884
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
3885
0
           (n2->type == XML_NAMESPACE_DECL)) {
3886
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888
0
      ((xmlNsPtr) n2)->prefix)))
3889
0
    {
3890
0
        skip = 1;
3891
0
        break;
3892
0
    }
3893
0
      }
3894
0
  }
3895
0
  if (skip)
3896
0
      continue;
3897
3898
  /*
3899
   * grow the nodeTab if needed
3900
   */
3901
0
  if (val1->nodeMax == 0) {
3902
0
      val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903
0
                sizeof(xmlNodePtr));
3904
0
      if (val1->nodeTab == NULL) {
3905
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3906
0
    return(NULL);
3907
0
      }
3908
0
      memset(val1->nodeTab, 0 ,
3909
0
       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910
0
      val1->nodeMax = XML_NODESET_DEFAULT;
3911
0
  } else if (val1->nodeNr == val1->nodeMax) {
3912
0
      xmlNodePtr *temp;
3913
3914
0
            if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915
0
                xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3916
0
                return(NULL);
3917
0
            }
3918
0
      temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3919
0
               sizeof(xmlNodePtr));
3920
0
      if (temp == NULL) {
3921
0
          xmlXPathErrMemory(NULL, "merging nodeset\n");
3922
0
    return(NULL);
3923
0
      }
3924
0
      val1->nodeTab = temp;
3925
0
      val1->nodeMax *= 2;
3926
0
  }
3927
0
  if (n2->type == XML_NAMESPACE_DECL) {
3928
0
      xmlNsPtr ns = (xmlNsPtr) n2;
3929
3930
            /* TODO: Check memory error. */
3931
0
      val1->nodeTab[val1->nodeNr++] =
3932
0
    xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933
0
  } else
3934
0
      val1->nodeTab[val1->nodeNr++] = n2;
3935
0
    }
3936
3937
0
    return(val1);
3938
0
}
3939
3940
3941
/**
3942
 * xmlXPathNodeSetMergeAndClear:
3943
 * @set1:  the first NodeSet or NULL
3944
 * @set2:  the second NodeSet
3945
 *
3946
 * Merges two nodesets, all nodes from @set2 are added to @set1.
3947
 * Checks for duplicate nodes. Clears set2.
3948
 *
3949
 * Returns @set1 once extended or NULL in case of error.
3950
 */
3951
static xmlNodeSetPtr
3952
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3953
0
{
3954
0
    {
3955
0
  int i, j, initNbSet1;
3956
0
  xmlNodePtr n1, n2;
3957
3958
0
  initNbSet1 = set1->nodeNr;
3959
0
  for (i = 0;i < set2->nodeNr;i++) {
3960
0
      n2 = set2->nodeTab[i];
3961
      /*
3962
      * Skip duplicates.
3963
      */
3964
0
      for (j = 0; j < initNbSet1; j++) {
3965
0
    n1 = set1->nodeTab[j];
3966
0
    if (n1 == n2) {
3967
0
        goto skip_node;
3968
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
3969
0
        (n2->type == XML_NAMESPACE_DECL))
3970
0
    {
3971
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3972
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3973
0
      ((xmlNsPtr) n2)->prefix)))
3974
0
        {
3975
      /*
3976
      * Free the namespace node.
3977
      */
3978
0
      set2->nodeTab[i] = NULL;
3979
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3980
0
      goto skip_node;
3981
0
        }
3982
0
    }
3983
0
      }
3984
      /*
3985
      * grow the nodeTab if needed
3986
      */
3987
0
      if (set1->nodeMax == 0) {
3988
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3989
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3990
0
    if (set1->nodeTab == NULL) {
3991
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
3992
0
        return(NULL);
3993
0
    }
3994
0
    memset(set1->nodeTab, 0,
3995
0
        XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3996
0
    set1->nodeMax = XML_NODESET_DEFAULT;
3997
0
      } else if (set1->nodeNr >= set1->nodeMax) {
3998
0
    xmlNodePtr *temp;
3999
4000
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4001
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4002
0
                    return(NULL);
4003
0
                }
4004
0
    temp = (xmlNodePtr *) xmlRealloc(
4005
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4006
0
    if (temp == NULL) {
4007
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4008
0
        return(NULL);
4009
0
    }
4010
0
    set1->nodeTab = temp;
4011
0
    set1->nodeMax *= 2;
4012
0
      }
4013
0
      set1->nodeTab[set1->nodeNr++] = n2;
4014
0
skip_node:
4015
0
      {}
4016
0
  }
4017
0
    }
4018
0
    set2->nodeNr = 0;
4019
0
    return(set1);
4020
0
}
4021
4022
/**
4023
 * xmlXPathNodeSetMergeAndClearNoDupls:
4024
 * @set1:  the first NodeSet or NULL
4025
 * @set2:  the second NodeSet
4026
 *
4027
 * Merges two nodesets, all nodes from @set2 are added to @set1.
4028
 * Doesn't check for duplicate nodes. Clears set2.
4029
 *
4030
 * Returns @set1 once extended or NULL in case of error.
4031
 */
4032
static xmlNodeSetPtr
4033
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
4034
0
{
4035
0
    {
4036
0
  int i;
4037
0
  xmlNodePtr n2;
4038
4039
0
  for (i = 0;i < set2->nodeNr;i++) {
4040
0
      n2 = set2->nodeTab[i];
4041
0
      if (set1->nodeMax == 0) {
4042
0
    set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4043
0
        XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4044
0
    if (set1->nodeTab == NULL) {
4045
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4046
0
        return(NULL);
4047
0
    }
4048
0
    memset(set1->nodeTab, 0,
4049
0
        XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4050
0
    set1->nodeMax = XML_NODESET_DEFAULT;
4051
0
      } else if (set1->nodeNr >= set1->nodeMax) {
4052
0
    xmlNodePtr *temp;
4053
4054
0
                if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4055
0
                    xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4056
0
                    return(NULL);
4057
0
                }
4058
0
    temp = (xmlNodePtr *) xmlRealloc(
4059
0
        set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4060
0
    if (temp == NULL) {
4061
0
        xmlXPathErrMemory(NULL, "merging nodeset\n");
4062
0
        return(NULL);
4063
0
    }
4064
0
    set1->nodeTab = temp;
4065
0
    set1->nodeMax *= 2;
4066
0
      }
4067
0
      set1->nodeTab[set1->nodeNr++] = n2;
4068
0
  }
4069
0
    }
4070
0
    set2->nodeNr = 0;
4071
0
    return(set1);
4072
0
}
4073
4074
/**
4075
 * xmlXPathNodeSetDel:
4076
 * @cur:  the initial node set
4077
 * @val:  an xmlNodePtr
4078
 *
4079
 * Removes an xmlNodePtr from an existing NodeSet
4080
 */
4081
void
4082
0
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4083
0
    int i;
4084
4085
0
    if (cur == NULL) return;
4086
0
    if (val == NULL) return;
4087
4088
    /*
4089
     * find node in nodeTab
4090
     */
4091
0
    for (i = 0;i < cur->nodeNr;i++)
4092
0
        if (cur->nodeTab[i] == val) break;
4093
4094
0
    if (i >= cur->nodeNr) { /* not found */
4095
#ifdef DEBUG
4096
        xmlGenericError(xmlGenericErrorContext,
4097
          "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4098
    val->name);
4099
#endif
4100
0
        return;
4101
0
    }
4102
0
    if ((cur->nodeTab[i] != NULL) &&
4103
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4104
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4105
0
    cur->nodeNr--;
4106
0
    for (;i < cur->nodeNr;i++)
4107
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
4108
0
    cur->nodeTab[cur->nodeNr] = NULL;
4109
0
}
4110
4111
/**
4112
 * xmlXPathNodeSetRemove:
4113
 * @cur:  the initial node set
4114
 * @val:  the index to remove
4115
 *
4116
 * Removes an entry from an existing NodeSet list.
4117
 */
4118
void
4119
0
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4120
0
    if (cur == NULL) return;
4121
0
    if (val >= cur->nodeNr) return;
4122
0
    if ((cur->nodeTab[val] != NULL) &&
4123
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4124
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4125
0
    cur->nodeNr--;
4126
0
    for (;val < cur->nodeNr;val++)
4127
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
4128
0
    cur->nodeTab[cur->nodeNr] = NULL;
4129
0
}
4130
4131
/**
4132
 * xmlXPathFreeNodeSet:
4133
 * @obj:  the xmlNodeSetPtr to free
4134
 *
4135
 * Free the NodeSet compound (not the actual nodes !).
4136
 */
4137
void
4138
0
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4139
0
    if (obj == NULL) return;
4140
0
    if (obj->nodeTab != NULL) {
4141
0
  int i;
4142
4143
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4144
0
  for (i = 0;i < obj->nodeNr;i++)
4145
0
      if ((obj->nodeTab[i] != NULL) &&
4146
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4147
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4148
0
  xmlFree(obj->nodeTab);
4149
0
    }
4150
0
    xmlFree(obj);
4151
0
}
4152
4153
/**
4154
 * xmlXPathNodeSetClearFromPos:
4155
 * @set: the node set to be cleared
4156
 * @pos: the start position to clear from
4157
 *
4158
 * Clears the list from temporary XPath objects (e.g. namespace nodes
4159
 * are feed) starting with the entry at @pos, but does *not* free the list
4160
 * itself. Sets the length of the list to @pos.
4161
 */
4162
static void
4163
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4164
0
{
4165
0
    if ((set == NULL) || (pos >= set->nodeNr))
4166
0
  return;
4167
0
    else if ((hasNsNodes)) {
4168
0
  int i;
4169
0
  xmlNodePtr node;
4170
4171
0
  for (i = pos; i < set->nodeNr; i++) {
4172
0
      node = set->nodeTab[i];
4173
0
      if ((node != NULL) &&
4174
0
    (node->type == XML_NAMESPACE_DECL))
4175
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4176
0
  }
4177
0
    }
4178
0
    set->nodeNr = pos;
4179
0
}
4180
4181
/**
4182
 * xmlXPathNodeSetClear:
4183
 * @set:  the node set to clear
4184
 *
4185
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4186
 * are feed), but does *not* free the list itself. Sets the length of the
4187
 * list to 0.
4188
 */
4189
static void
4190
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4191
0
{
4192
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4193
0
}
4194
4195
/**
4196
 * xmlXPathNodeSetKeepLast:
4197
 * @set: the node set to be cleared
4198
 *
4199
 * Move the last node to the first position and clear temporary XPath objects
4200
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4201
 * to 1.
4202
 */
4203
static void
4204
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4205
0
{
4206
0
    int i;
4207
0
    xmlNodePtr node;
4208
4209
0
    if ((set == NULL) || (set->nodeNr <= 1))
4210
0
  return;
4211
0
    for (i = 0; i < set->nodeNr - 1; i++) {
4212
0
        node = set->nodeTab[i];
4213
0
        if ((node != NULL) &&
4214
0
            (node->type == XML_NAMESPACE_DECL))
4215
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4216
0
    }
4217
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4218
0
    set->nodeNr = 1;
4219
0
}
4220
4221
/**
4222
 * xmlXPathFreeValueTree:
4223
 * @obj:  the xmlNodeSetPtr to free
4224
 *
4225
 * Free the NodeSet compound and the actual tree, this is different
4226
 * from xmlXPathFreeNodeSet()
4227
 */
4228
static void
4229
0
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4230
0
    int i;
4231
4232
0
    if (obj == NULL) return;
4233
4234
0
    if (obj->nodeTab != NULL) {
4235
0
  for (i = 0;i < obj->nodeNr;i++) {
4236
0
      if (obj->nodeTab[i] != NULL) {
4237
0
    if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4238
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4239
0
    } else {
4240
0
        xmlFreeNodeList(obj->nodeTab[i]);
4241
0
    }
4242
0
      }
4243
0
  }
4244
0
  xmlFree(obj->nodeTab);
4245
0
    }
4246
0
    xmlFree(obj);
4247
0
}
4248
4249
#if defined(DEBUG) || defined(DEBUG_STEP)
4250
/**
4251
 * xmlGenericErrorContextNodeSet:
4252
 * @output:  a FILE * for the output
4253
 * @obj:  the xmlNodeSetPtr to display
4254
 *
4255
 * Quick display of a NodeSet
4256
 */
4257
void
4258
xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4259
    int i;
4260
4261
    if (output == NULL) output = xmlGenericErrorContext;
4262
    if (obj == NULL)  {
4263
        fprintf(output, "NodeSet == NULL !\n");
4264
  return;
4265
    }
4266
    if (obj->nodeNr == 0) {
4267
        fprintf(output, "NodeSet is empty\n");
4268
  return;
4269
    }
4270
    if (obj->nodeTab == NULL) {
4271
  fprintf(output, " nodeTab == NULL !\n");
4272
  return;
4273
    }
4274
    for (i = 0; i < obj->nodeNr; i++) {
4275
        if (obj->nodeTab[i] == NULL) {
4276
      fprintf(output, " NULL !\n");
4277
      return;
4278
        }
4279
  if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4280
      (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4281
      fprintf(output, " /");
4282
  else if (obj->nodeTab[i]->name == NULL)
4283
      fprintf(output, " noname!");
4284
  else fprintf(output, " %s", obj->nodeTab[i]->name);
4285
    }
4286
    fprintf(output, "\n");
4287
}
4288
#endif
4289
4290
/**
4291
 * xmlXPathNewNodeSet:
4292
 * @val:  the NodePtr value
4293
 *
4294
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4295
 * it with the single Node @val
4296
 *
4297
 * Returns the newly created object.
4298
 */
4299
xmlXPathObjectPtr
4300
0
xmlXPathNewNodeSet(xmlNodePtr val) {
4301
0
    xmlXPathObjectPtr ret;
4302
4303
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4304
0
    if (ret == NULL) {
4305
0
        xmlXPathErrMemory(NULL, "creating nodeset\n");
4306
0
  return(NULL);
4307
0
    }
4308
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4309
0
    ret->type = XPATH_NODESET;
4310
0
    ret->boolval = 0;
4311
    /* TODO: Check memory error. */
4312
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4313
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4314
#ifdef XP_DEBUG_OBJ_USAGE
4315
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4316
#endif
4317
0
    return(ret);
4318
0
}
4319
4320
/**
4321
 * xmlXPathNewValueTree:
4322
 * @val:  the NodePtr value
4323
 *
4324
 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4325
 * it with the tree root @val
4326
 *
4327
 * Returns the newly created object.
4328
 */
4329
xmlXPathObjectPtr
4330
0
xmlXPathNewValueTree(xmlNodePtr val) {
4331
0
    xmlXPathObjectPtr ret;
4332
4333
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4334
0
    if (ret == NULL) {
4335
0
        xmlXPathErrMemory(NULL, "creating result value tree\n");
4336
0
  return(NULL);
4337
0
    }
4338
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4339
0
    ret->type = XPATH_XSLT_TREE;
4340
0
    ret->boolval = 1;
4341
0
    ret->user = (void *) val;
4342
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
4343
#ifdef XP_DEBUG_OBJ_USAGE
4344
    xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4345
#endif
4346
0
    return(ret);
4347
0
}
4348
4349
/**
4350
 * xmlXPathNewNodeSetList:
4351
 * @val:  an existing NodeSet
4352
 *
4353
 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4354
 * it with the Nodeset @val
4355
 *
4356
 * Returns the newly created object.
4357
 */
4358
xmlXPathObjectPtr
4359
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4360
0
{
4361
0
    xmlXPathObjectPtr ret;
4362
0
    int i;
4363
4364
0
    if (val == NULL)
4365
0
        ret = NULL;
4366
0
    else if (val->nodeTab == NULL)
4367
0
        ret = xmlXPathNewNodeSet(NULL);
4368
0
    else {
4369
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4370
0
        if (ret) {
4371
0
            for (i = 1; i < val->nodeNr; ++i) {
4372
                /* TODO: Propagate memory error. */
4373
0
                if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4374
0
        < 0) break;
4375
0
      }
4376
0
  }
4377
0
    }
4378
4379
0
    return (ret);
4380
0
}
4381
4382
/**
4383
 * xmlXPathWrapNodeSet:
4384
 * @val:  the NodePtr value
4385
 *
4386
 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4387
 *
4388
 * Returns the newly created object.
4389
 */
4390
xmlXPathObjectPtr
4391
0
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4392
0
    xmlXPathObjectPtr ret;
4393
4394
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4395
0
    if (ret == NULL) {
4396
0
        xmlXPathErrMemory(NULL, "creating node set object\n");
4397
0
  return(NULL);
4398
0
    }
4399
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4400
0
    ret->type = XPATH_NODESET;
4401
0
    ret->nodesetval = val;
4402
#ifdef XP_DEBUG_OBJ_USAGE
4403
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4404
#endif
4405
0
    return(ret);
4406
0
}
4407
4408
/**
4409
 * xmlXPathFreeNodeSetList:
4410
 * @obj:  an existing NodeSetList object
4411
 *
4412
 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4413
 * the list contrary to xmlXPathFreeObject().
4414
 */
4415
void
4416
0
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4417
0
    if (obj == NULL) return;
4418
#ifdef XP_DEBUG_OBJ_USAGE
4419
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
4420
#endif
4421
0
    xmlFree(obj);
4422
0
}
4423
4424
/**
4425
 * xmlXPathDifference:
4426
 * @nodes1:  a node-set
4427
 * @nodes2:  a node-set
4428
 *
4429
 * Implements the EXSLT - Sets difference() function:
4430
 *    node-set set:difference (node-set, node-set)
4431
 *
4432
 * Returns the difference between the two node sets, or nodes1 if
4433
 *         nodes2 is empty
4434
 */
4435
xmlNodeSetPtr
4436
0
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4437
0
    xmlNodeSetPtr ret;
4438
0
    int i, l1;
4439
0
    xmlNodePtr cur;
4440
4441
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4442
0
  return(nodes1);
4443
4444
    /* TODO: Check memory error. */
4445
0
    ret = xmlXPathNodeSetCreate(NULL);
4446
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4447
0
  return(ret);
4448
4449
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4450
4451
0
    for (i = 0; i < l1; i++) {
4452
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4453
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
4454
            /* TODO: Propagate memory error. */
4455
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4456
0
          break;
4457
0
  }
4458
0
    }
4459
0
    return(ret);
4460
0
}
4461
4462
/**
4463
 * xmlXPathIntersection:
4464
 * @nodes1:  a node-set
4465
 * @nodes2:  a node-set
4466
 *
4467
 * Implements the EXSLT - Sets intersection() function:
4468
 *    node-set set:intersection (node-set, node-set)
4469
 *
4470
 * Returns a node set comprising the nodes that are within both the
4471
 *         node sets passed as arguments
4472
 */
4473
xmlNodeSetPtr
4474
0
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4475
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4476
0
    int i, l1;
4477
0
    xmlNodePtr cur;
4478
4479
0
    if (ret == NULL)
4480
0
        return(ret);
4481
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4482
0
  return(ret);
4483
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4484
0
  return(ret);
4485
4486
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
4487
4488
0
    for (i = 0; i < l1; i++) {
4489
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4490
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
4491
            /* TODO: Propagate memory error. */
4492
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4493
0
          break;
4494
0
  }
4495
0
    }
4496
0
    return(ret);
4497
0
}
4498
4499
/**
4500
 * xmlXPathDistinctSorted:
4501
 * @nodes:  a node-set, sorted by document order
4502
 *
4503
 * Implements the EXSLT - Sets distinct() function:
4504
 *    node-set set:distinct (node-set)
4505
 *
4506
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4507
 *         it is empty
4508
 */
4509
xmlNodeSetPtr
4510
0
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4511
0
    xmlNodeSetPtr ret;
4512
0
    xmlHashTablePtr hash;
4513
0
    int i, l;
4514
0
    xmlChar * strval;
4515
0
    xmlNodePtr cur;
4516
4517
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4518
0
  return(nodes);
4519
4520
0
    ret = xmlXPathNodeSetCreate(NULL);
4521
0
    if (ret == NULL)
4522
0
        return(ret);
4523
0
    l = xmlXPathNodeSetGetLength(nodes);
4524
0
    hash = xmlHashCreate (l);
4525
0
    for (i = 0; i < l; i++) {
4526
0
  cur = xmlXPathNodeSetItem(nodes, i);
4527
0
  strval = xmlXPathCastNodeToString(cur);
4528
0
  if (xmlHashLookup(hash, strval) == NULL) {
4529
0
      xmlHashAddEntry(hash, strval, strval);
4530
            /* TODO: Propagate memory error. */
4531
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4532
0
          break;
4533
0
  } else {
4534
0
      xmlFree(strval);
4535
0
  }
4536
0
    }
4537
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
4538
0
    return(ret);
4539
0
}
4540
4541
/**
4542
 * xmlXPathDistinct:
4543
 * @nodes:  a node-set
4544
 *
4545
 * Implements the EXSLT - Sets distinct() function:
4546
 *    node-set set:distinct (node-set)
4547
 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4548
 * is called with the sorted node-set
4549
 *
4550
 * Returns a subset of the nodes contained in @nodes, or @nodes if
4551
 *         it is empty
4552
 */
4553
xmlNodeSetPtr
4554
0
xmlXPathDistinct (xmlNodeSetPtr nodes) {
4555
0
    if (xmlXPathNodeSetIsEmpty(nodes))
4556
0
  return(nodes);
4557
4558
0
    xmlXPathNodeSetSort(nodes);
4559
0
    return(xmlXPathDistinctSorted(nodes));
4560
0
}
4561
4562
/**
4563
 * xmlXPathHasSameNodes:
4564
 * @nodes1:  a node-set
4565
 * @nodes2:  a node-set
4566
 *
4567
 * Implements the EXSLT - Sets has-same-nodes function:
4568
 *    boolean set:has-same-node(node-set, node-set)
4569
 *
4570
 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4571
 *         otherwise
4572
 */
4573
int
4574
0
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4575
0
    int i, l;
4576
0
    xmlNodePtr cur;
4577
4578
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
4579
0
  xmlXPathNodeSetIsEmpty(nodes2))
4580
0
  return(0);
4581
4582
0
    l = xmlXPathNodeSetGetLength(nodes1);
4583
0
    for (i = 0; i < l; i++) {
4584
0
  cur = xmlXPathNodeSetItem(nodes1, i);
4585
0
  if (xmlXPathNodeSetContains(nodes2, cur))
4586
0
      return(1);
4587
0
    }
4588
0
    return(0);
4589
0
}
4590
4591
/**
4592
 * xmlXPathNodeLeadingSorted:
4593
 * @nodes: a node-set, sorted by document order
4594
 * @node: a node
4595
 *
4596
 * Implements the EXSLT - Sets leading() function:
4597
 *    node-set set:leading (node-set, node-set)
4598
 *
4599
 * Returns the nodes in @nodes that precede @node in document order,
4600
 *         @nodes if @node is NULL or an empty node-set if @nodes
4601
 *         doesn't contain @node
4602
 */
4603
xmlNodeSetPtr
4604
0
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4605
0
    int i, l;
4606
0
    xmlNodePtr cur;
4607
0
    xmlNodeSetPtr ret;
4608
4609
0
    if (node == NULL)
4610
0
  return(nodes);
4611
4612
0
    ret = xmlXPathNodeSetCreate(NULL);
4613
0
    if (ret == NULL)
4614
0
        return(ret);
4615
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4616
0
  (!xmlXPathNodeSetContains(nodes, node)))
4617
0
  return(ret);
4618
4619
0
    l = xmlXPathNodeSetGetLength(nodes);
4620
0
    for (i = 0; i < l; i++) {
4621
0
  cur = xmlXPathNodeSetItem(nodes, i);
4622
0
  if (cur == node)
4623
0
      break;
4624
        /* TODO: Propagate memory error. */
4625
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4626
0
      break;
4627
0
    }
4628
0
    return(ret);
4629
0
}
4630
4631
/**
4632
 * xmlXPathNodeLeading:
4633
 * @nodes:  a node-set
4634
 * @node:  a node
4635
 *
4636
 * Implements the EXSLT - Sets leading() function:
4637
 *    node-set set:leading (node-set, node-set)
4638
 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4639
 * is called.
4640
 *
4641
 * Returns the nodes in @nodes that precede @node in document order,
4642
 *         @nodes if @node is NULL or an empty node-set if @nodes
4643
 *         doesn't contain @node
4644
 */
4645
xmlNodeSetPtr
4646
0
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4647
0
    xmlXPathNodeSetSort(nodes);
4648
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
4649
0
}
4650
4651
/**
4652
 * xmlXPathLeadingSorted:
4653
 * @nodes1:  a node-set, sorted by document order
4654
 * @nodes2:  a node-set, sorted by document order
4655
 *
4656
 * Implements the EXSLT - Sets leading() function:
4657
 *    node-set set:leading (node-set, node-set)
4658
 *
4659
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4660
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4661
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4662
 */
4663
xmlNodeSetPtr
4664
0
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4665
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4666
0
  return(nodes1);
4667
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4668
0
             xmlXPathNodeSetItem(nodes2, 1)));
4669
0
}
4670
4671
/**
4672
 * xmlXPathLeading:
4673
 * @nodes1:  a node-set
4674
 * @nodes2:  a node-set
4675
 *
4676
 * Implements the EXSLT - Sets leading() function:
4677
 *    node-set set:leading (node-set, node-set)
4678
 * @nodes1 and @nodes2 are sorted by document order, then
4679
 * #exslSetsLeadingSorted is called.
4680
 *
4681
 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4682
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4683
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4684
 */
4685
xmlNodeSetPtr
4686
0
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4687
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4688
0
  return(nodes1);
4689
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4690
0
  return(xmlXPathNodeSetCreate(NULL));
4691
0
    xmlXPathNodeSetSort(nodes1);
4692
0
    xmlXPathNodeSetSort(nodes2);
4693
0
    return(xmlXPathNodeLeadingSorted(nodes1,
4694
0
             xmlXPathNodeSetItem(nodes2, 1)));
4695
0
}
4696
4697
/**
4698
 * xmlXPathNodeTrailingSorted:
4699
 * @nodes: a node-set, sorted by document order
4700
 * @node: a node
4701
 *
4702
 * Implements the EXSLT - Sets trailing() function:
4703
 *    node-set set:trailing (node-set, node-set)
4704
 *
4705
 * Returns the nodes in @nodes that follow @node in document order,
4706
 *         @nodes if @node is NULL or an empty node-set if @nodes
4707
 *         doesn't contain @node
4708
 */
4709
xmlNodeSetPtr
4710
0
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4711
0
    int i, l;
4712
0
    xmlNodePtr cur;
4713
0
    xmlNodeSetPtr ret;
4714
4715
0
    if (node == NULL)
4716
0
  return(nodes);
4717
4718
0
    ret = xmlXPathNodeSetCreate(NULL);
4719
0
    if (ret == NULL)
4720
0
        return(ret);
4721
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
4722
0
  (!xmlXPathNodeSetContains(nodes, node)))
4723
0
  return(ret);
4724
4725
0
    l = xmlXPathNodeSetGetLength(nodes);
4726
0
    for (i = l - 1; i >= 0; i--) {
4727
0
  cur = xmlXPathNodeSetItem(nodes, i);
4728
0
  if (cur == node)
4729
0
      break;
4730
        /* TODO: Propagate memory error. */
4731
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4732
0
      break;
4733
0
    }
4734
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
4735
0
    return(ret);
4736
0
}
4737
4738
/**
4739
 * xmlXPathNodeTrailing:
4740
 * @nodes:  a node-set
4741
 * @node:  a node
4742
 *
4743
 * Implements the EXSLT - Sets trailing() function:
4744
 *    node-set set:trailing (node-set, node-set)
4745
 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4746
 * is called.
4747
 *
4748
 * Returns the nodes in @nodes that follow @node in document order,
4749
 *         @nodes if @node is NULL or an empty node-set if @nodes
4750
 *         doesn't contain @node
4751
 */
4752
xmlNodeSetPtr
4753
0
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4754
0
    xmlXPathNodeSetSort(nodes);
4755
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
4756
0
}
4757
4758
/**
4759
 * xmlXPathTrailingSorted:
4760
 * @nodes1:  a node-set, sorted by document order
4761
 * @nodes2:  a node-set, sorted by document order
4762
 *
4763
 * Implements the EXSLT - Sets trailing() function:
4764
 *    node-set set:trailing (node-set, node-set)
4765
 *
4766
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4767
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4768
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4769
 */
4770
xmlNodeSetPtr
4771
0
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4772
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4773
0
  return(nodes1);
4774
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4775
0
              xmlXPathNodeSetItem(nodes2, 0)));
4776
0
}
4777
4778
/**
4779
 * xmlXPathTrailing:
4780
 * @nodes1:  a node-set
4781
 * @nodes2:  a node-set
4782
 *
4783
 * Implements the EXSLT - Sets trailing() function:
4784
 *    node-set set:trailing (node-set, node-set)
4785
 * @nodes1 and @nodes2 are sorted by document order, then
4786
 * #xmlXPathTrailingSorted is called.
4787
 *
4788
 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4789
 *         in document order, @nodes1 if @nodes2 is NULL or empty or
4790
 *         an empty node-set if @nodes1 doesn't contain @nodes2
4791
 */
4792
xmlNodeSetPtr
4793
0
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4794
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
4795
0
  return(nodes1);
4796
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
4797
0
  return(xmlXPathNodeSetCreate(NULL));
4798
0
    xmlXPathNodeSetSort(nodes1);
4799
0
    xmlXPathNodeSetSort(nodes2);
4800
0
    return(xmlXPathNodeTrailingSorted(nodes1,
4801
0
              xmlXPathNodeSetItem(nodes2, 0)));
4802
0
}
4803
4804
/************************************************************************
4805
 *                  *
4806
 *    Routines to handle extra functions      *
4807
 *                  *
4808
 ************************************************************************/
4809
4810
/**
4811
 * xmlXPathRegisterFunc:
4812
 * @ctxt:  the XPath context
4813
 * @name:  the function name
4814
 * @f:  the function implementation or NULL
4815
 *
4816
 * Register a new function. If @f is NULL it unregisters the function
4817
 *
4818
 * Returns 0 in case of success, -1 in case of error
4819
 */
4820
int
4821
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4822
0
         xmlXPathFunction f) {
4823
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4824
0
}
4825
4826
/**
4827
 * xmlXPathRegisterFuncNS:
4828
 * @ctxt:  the XPath context
4829
 * @name:  the function name
4830
 * @ns_uri:  the function namespace URI
4831
 * @f:  the function implementation or NULL
4832
 *
4833
 * Register a new function. If @f is NULL it unregisters the function
4834
 *
4835
 * Returns 0 in case of success, -1 in case of error
4836
 */
4837
int
4838
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4839
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
4840
0
    if (ctxt == NULL)
4841
0
  return(-1);
4842
0
    if (name == NULL)
4843
0
  return(-1);
4844
4845
0
    if (ctxt->funcHash == NULL)
4846
0
  ctxt->funcHash = xmlHashCreate(0);
4847
0
    if (ctxt->funcHash == NULL)
4848
0
  return(-1);
4849
0
    if (f == NULL)
4850
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4851
0
XML_IGNORE_PEDANTIC_WARNINGS
4852
0
    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4853
0
XML_POP_WARNINGS
4854
0
}
4855
4856
/**
4857
 * xmlXPathRegisterFuncLookup:
4858
 * @ctxt:  the XPath context
4859
 * @f:  the lookup function
4860
 * @funcCtxt:  the lookup data
4861
 *
4862
 * Registers an external mechanism to do function lookup.
4863
 */
4864
void
4865
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4866
          xmlXPathFuncLookupFunc f,
4867
0
          void *funcCtxt) {
4868
0
    if (ctxt == NULL)
4869
0
  return;
4870
0
    ctxt->funcLookupFunc = f;
4871
0
    ctxt->funcLookupData = funcCtxt;
4872
0
}
4873
4874
/**
4875
 * xmlXPathFunctionLookup:
4876
 * @ctxt:  the XPath context
4877
 * @name:  the function name
4878
 *
4879
 * Search in the Function array of the context for the given
4880
 * function.
4881
 *
4882
 * Returns the xmlXPathFunction or NULL if not found
4883
 */
4884
xmlXPathFunction
4885
0
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4886
0
    if (ctxt == NULL)
4887
0
  return (NULL);
4888
4889
0
    if (ctxt->funcLookupFunc != NULL) {
4890
0
  xmlXPathFunction ret;
4891
0
  xmlXPathFuncLookupFunc f;
4892
4893
0
  f = ctxt->funcLookupFunc;
4894
0
  ret = f(ctxt->funcLookupData, name, NULL);
4895
0
  if (ret != NULL)
4896
0
      return(ret);
4897
0
    }
4898
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4899
0
}
4900
4901
/**
4902
 * xmlXPathFunctionLookupNS:
4903
 * @ctxt:  the XPath context
4904
 * @name:  the function name
4905
 * @ns_uri:  the function namespace URI
4906
 *
4907
 * Search in the Function array of the context for the given
4908
 * function.
4909
 *
4910
 * Returns the xmlXPathFunction or NULL if not found
4911
 */
4912
xmlXPathFunction
4913
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4914
0
       const xmlChar *ns_uri) {
4915
0
    xmlXPathFunction ret;
4916
4917
0
    if (ctxt == NULL)
4918
0
  return(NULL);
4919
0
    if (name == NULL)
4920
0
  return(NULL);
4921
4922
0
    if (ctxt->funcLookupFunc != NULL) {
4923
0
  xmlXPathFuncLookupFunc f;
4924
4925
0
  f = ctxt->funcLookupFunc;
4926
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
4927
0
  if (ret != NULL)
4928
0
      return(ret);
4929
0
    }
4930
4931
0
    if (ctxt->funcHash == NULL)
4932
0
  return(NULL);
4933
4934
0
XML_IGNORE_PEDANTIC_WARNINGS
4935
0
    ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4936
0
XML_POP_WARNINGS
4937
0
    return(ret);
4938
0
}
4939
4940
/**
4941
 * xmlXPathRegisteredFuncsCleanup:
4942
 * @ctxt:  the XPath context
4943
 *
4944
 * Cleanup the XPath context data associated to registered functions
4945
 */
4946
void
4947
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4948
0
    if (ctxt == NULL)
4949
0
  return;
4950
4951
0
    xmlHashFree(ctxt->funcHash, NULL);
4952
0
    ctxt->funcHash = NULL;
4953
0
}
4954
4955
/************************************************************************
4956
 *                  *
4957
 *      Routines to handle Variables      *
4958
 *                  *
4959
 ************************************************************************/
4960
4961
/**
4962
 * xmlXPathRegisterVariable:
4963
 * @ctxt:  the XPath context
4964
 * @name:  the variable name
4965
 * @value:  the variable value or NULL
4966
 *
4967
 * Register a new variable value. If @value is NULL it unregisters
4968
 * the variable
4969
 *
4970
 * Returns 0 in case of success, -1 in case of error
4971
 */
4972
int
4973
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4974
0
       xmlXPathObjectPtr value) {
4975
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4976
0
}
4977
4978
/**
4979
 * xmlXPathRegisterVariableNS:
4980
 * @ctxt:  the XPath context
4981
 * @name:  the variable name
4982
 * @ns_uri:  the variable namespace URI
4983
 * @value:  the variable value or NULL
4984
 *
4985
 * Register a new variable value. If @value is NULL it unregisters
4986
 * the variable
4987
 *
4988
 * Returns 0 in case of success, -1 in case of error
4989
 */
4990
int
4991
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4992
         const xmlChar *ns_uri,
4993
0
         xmlXPathObjectPtr value) {
4994
0
    if (ctxt == NULL)
4995
0
  return(-1);
4996
0
    if (name == NULL)
4997
0
  return(-1);
4998
4999
0
    if (ctxt->varHash == NULL)
5000
0
  ctxt->varHash = xmlHashCreate(0);
5001
0
    if (ctxt->varHash == NULL)
5002
0
  return(-1);
5003
0
    if (value == NULL)
5004
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5005
0
                             xmlXPathFreeObjectEntry));
5006
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5007
0
             (void *) value, xmlXPathFreeObjectEntry));
5008
0
}
5009
5010
/**
5011
 * xmlXPathRegisterVariableLookup:
5012
 * @ctxt:  the XPath context
5013
 * @f:  the lookup function
5014
 * @data:  the lookup data
5015
 *
5016
 * register an external mechanism to do variable lookup
5017
 */
5018
void
5019
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5020
0
   xmlXPathVariableLookupFunc f, void *data) {
5021
0
    if (ctxt == NULL)
5022
0
  return;
5023
0
    ctxt->varLookupFunc = f;
5024
0
    ctxt->varLookupData = data;
5025
0
}
5026
5027
/**
5028
 * xmlXPathVariableLookup:
5029
 * @ctxt:  the XPath context
5030
 * @name:  the variable name
5031
 *
5032
 * Search in the Variable array of the context for the given
5033
 * variable value.
5034
 *
5035
 * Returns a copy of the value or NULL if not found
5036
 */
5037
xmlXPathObjectPtr
5038
0
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5039
0
    if (ctxt == NULL)
5040
0
  return(NULL);
5041
5042
0
    if (ctxt->varLookupFunc != NULL) {
5043
0
  xmlXPathObjectPtr ret;
5044
5045
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5046
0
          (ctxt->varLookupData, name, NULL);
5047
0
  return(ret);
5048
0
    }
5049
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5050
0
}
5051
5052
/**
5053
 * xmlXPathVariableLookupNS:
5054
 * @ctxt:  the XPath context
5055
 * @name:  the variable name
5056
 * @ns_uri:  the variable namespace URI
5057
 *
5058
 * Search in the Variable array of the context for the given
5059
 * variable value.
5060
 *
5061
 * Returns the a copy of the value or NULL if not found
5062
 */
5063
xmlXPathObjectPtr
5064
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5065
0
       const xmlChar *ns_uri) {
5066
0
    if (ctxt == NULL)
5067
0
  return(NULL);
5068
5069
0
    if (ctxt->varLookupFunc != NULL) {
5070
0
  xmlXPathObjectPtr ret;
5071
5072
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5073
0
          (ctxt->varLookupData, name, ns_uri);
5074
0
  if (ret != NULL) return(ret);
5075
0
    }
5076
5077
0
    if (ctxt->varHash == NULL)
5078
0
  return(NULL);
5079
0
    if (name == NULL)
5080
0
  return(NULL);
5081
5082
0
    return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5083
0
    xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5084
0
}
5085
5086
/**
5087
 * xmlXPathRegisteredVariablesCleanup:
5088
 * @ctxt:  the XPath context
5089
 *
5090
 * Cleanup the XPath context data associated to registered variables
5091
 */
5092
void
5093
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5094
0
    if (ctxt == NULL)
5095
0
  return;
5096
5097
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
5098
0
    ctxt->varHash = NULL;
5099
0
}
5100
5101
/**
5102
 * xmlXPathRegisterNs:
5103
 * @ctxt:  the XPath context
5104
 * @prefix:  the namespace prefix cannot be NULL or empty string
5105
 * @ns_uri:  the namespace name
5106
 *
5107
 * Register a new namespace. If @ns_uri is NULL it unregisters
5108
 * the namespace
5109
 *
5110
 * Returns 0 in case of success, -1 in case of error
5111
 */
5112
int
5113
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5114
0
         const xmlChar *ns_uri) {
5115
0
    if (ctxt == NULL)
5116
0
  return(-1);
5117
0
    if (prefix == NULL)
5118
0
  return(-1);
5119
0
    if (prefix[0] == 0)
5120
0
  return(-1);
5121
5122
0
    if (ctxt->nsHash == NULL)
5123
0
  ctxt->nsHash = xmlHashCreate(10);
5124
0
    if (ctxt->nsHash == NULL)
5125
0
  return(-1);
5126
0
    if (ns_uri == NULL)
5127
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5128
0
                            xmlHashDefaultDeallocator));
5129
0
    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5130
0
            xmlHashDefaultDeallocator));
5131
0
}
5132
5133
/**
5134
 * xmlXPathNsLookup:
5135
 * @ctxt:  the XPath context
5136
 * @prefix:  the namespace prefix value
5137
 *
5138
 * Search in the namespace declaration array of the context for the given
5139
 * namespace name associated to the given prefix
5140
 *
5141
 * Returns the value or NULL if not found
5142
 */
5143
const xmlChar *
5144
0
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5145
0
    if (ctxt == NULL)
5146
0
  return(NULL);
5147
0
    if (prefix == NULL)
5148
0
  return(NULL);
5149
5150
0
#ifdef XML_XML_NAMESPACE
5151
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5152
0
  return(XML_XML_NAMESPACE);
5153
0
#endif
5154
5155
0
    if (ctxt->namespaces != NULL) {
5156
0
  int i;
5157
5158
0
  for (i = 0;i < ctxt->nsNr;i++) {
5159
0
      if ((ctxt->namespaces[i] != NULL) &&
5160
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5161
0
    return(ctxt->namespaces[i]->href);
5162
0
  }
5163
0
    }
5164
5165
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5166
0
}
5167
5168
/**
5169
 * xmlXPathRegisteredNsCleanup:
5170
 * @ctxt:  the XPath context
5171
 *
5172
 * Cleanup the XPath context data associated to registered variables
5173
 */
5174
void
5175
0
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5176
0
    if (ctxt == NULL)
5177
0
  return;
5178
5179
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
5180
0
    ctxt->nsHash = NULL;
5181
0
}
5182
5183
/************************************************************************
5184
 *                  *
5185
 *      Routines to handle Values     *
5186
 *                  *
5187
 ************************************************************************/
5188
5189
/* Allocations are terrible, one needs to optimize all this !!! */
5190
5191
/**
5192
 * xmlXPathNewFloat:
5193
 * @val:  the double value
5194
 *
5195
 * Create a new xmlXPathObjectPtr of type double and of value @val
5196
 *
5197
 * Returns the newly created object.
5198
 */
5199
xmlXPathObjectPtr
5200
0
xmlXPathNewFloat(double val) {
5201
0
    xmlXPathObjectPtr ret;
5202
5203
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5204
0
    if (ret == NULL) {
5205
0
        xmlXPathErrMemory(NULL, "creating float object\n");
5206
0
  return(NULL);
5207
0
    }
5208
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5209
0
    ret->type = XPATH_NUMBER;
5210
0
    ret->floatval = val;
5211
#ifdef XP_DEBUG_OBJ_USAGE
5212
    xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5213
#endif
5214
0
    return(ret);
5215
0
}
5216
5217
/**
5218
 * xmlXPathNewBoolean:
5219
 * @val:  the boolean value
5220
 *
5221
 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5222
 *
5223
 * Returns the newly created object.
5224
 */
5225
xmlXPathObjectPtr
5226
0
xmlXPathNewBoolean(int val) {
5227
0
    xmlXPathObjectPtr ret;
5228
5229
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5230
0
    if (ret == NULL) {
5231
0
        xmlXPathErrMemory(NULL, "creating boolean object\n");
5232
0
  return(NULL);
5233
0
    }
5234
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5235
0
    ret->type = XPATH_BOOLEAN;
5236
0
    ret->boolval = (val != 0);
5237
#ifdef XP_DEBUG_OBJ_USAGE
5238
    xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5239
#endif
5240
0
    return(ret);
5241
0
}
5242
5243
/**
5244
 * xmlXPathNewString:
5245
 * @val:  the xmlChar * value
5246
 *
5247
 * Create a new xmlXPathObjectPtr of type string and of value @val
5248
 *
5249
 * Returns the newly created object.
5250
 */
5251
xmlXPathObjectPtr
5252
0
xmlXPathNewString(const xmlChar *val) {
5253
0
    xmlXPathObjectPtr ret;
5254
5255
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5256
0
    if (ret == NULL) {
5257
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5258
0
  return(NULL);
5259
0
    }
5260
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5261
0
    ret->type = XPATH_STRING;
5262
0
    if (val != NULL)
5263
0
  ret->stringval = xmlStrdup(val);
5264
0
    else
5265
0
  ret->stringval = xmlStrdup((const xmlChar *)"");
5266
#ifdef XP_DEBUG_OBJ_USAGE
5267
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5268
#endif
5269
0
    return(ret);
5270
0
}
5271
5272
/**
5273
 * xmlXPathWrapString:
5274
 * @val:  the xmlChar * value
5275
 *
5276
 * Wraps the @val string into an XPath object.
5277
 *
5278
 * Returns the newly created object.
5279
 */
5280
xmlXPathObjectPtr
5281
0
xmlXPathWrapString (xmlChar *val) {
5282
0
    xmlXPathObjectPtr ret;
5283
5284
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5285
0
    if (ret == NULL) {
5286
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5287
0
  return(NULL);
5288
0
    }
5289
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5290
0
    ret->type = XPATH_STRING;
5291
0
    ret->stringval = val;
5292
#ifdef XP_DEBUG_OBJ_USAGE
5293
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5294
#endif
5295
0
    return(ret);
5296
0
}
5297
5298
/**
5299
 * xmlXPathNewCString:
5300
 * @val:  the char * value
5301
 *
5302
 * Create a new xmlXPathObjectPtr of type string and of value @val
5303
 *
5304
 * Returns the newly created object.
5305
 */
5306
xmlXPathObjectPtr
5307
0
xmlXPathNewCString(const char *val) {
5308
0
    xmlXPathObjectPtr ret;
5309
5310
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5311
0
    if (ret == NULL) {
5312
0
        xmlXPathErrMemory(NULL, "creating string object\n");
5313
0
  return(NULL);
5314
0
    }
5315
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5316
0
    ret->type = XPATH_STRING;
5317
0
    ret->stringval = xmlStrdup(BAD_CAST val);
5318
#ifdef XP_DEBUG_OBJ_USAGE
5319
    xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5320
#endif
5321
0
    return(ret);
5322
0
}
5323
5324
/**
5325
 * xmlXPathWrapCString:
5326
 * @val:  the char * value
5327
 *
5328
 * Wraps a string into an XPath object.
5329
 *
5330
 * Returns the newly created object.
5331
 */
5332
xmlXPathObjectPtr
5333
0
xmlXPathWrapCString (char * val) {
5334
0
    return(xmlXPathWrapString((xmlChar *)(val)));
5335
0
}
5336
5337
/**
5338
 * xmlXPathWrapExternal:
5339
 * @val:  the user data
5340
 *
5341
 * Wraps the @val data into an XPath object.
5342
 *
5343
 * Returns the newly created object.
5344
 */
5345
xmlXPathObjectPtr
5346
0
xmlXPathWrapExternal (void *val) {
5347
0
    xmlXPathObjectPtr ret;
5348
5349
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5350
0
    if (ret == NULL) {
5351
0
        xmlXPathErrMemory(NULL, "creating user object\n");
5352
0
  return(NULL);
5353
0
    }
5354
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5355
0
    ret->type = XPATH_USERS;
5356
0
    ret->user = val;
5357
#ifdef XP_DEBUG_OBJ_USAGE
5358
    xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5359
#endif
5360
0
    return(ret);
5361
0
}
5362
5363
/**
5364
 * xmlXPathObjectCopy:
5365
 * @val:  the original object
5366
 *
5367
 * allocate a new copy of a given object
5368
 *
5369
 * Returns the newly created object.
5370
 */
5371
xmlXPathObjectPtr
5372
0
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5373
0
    xmlXPathObjectPtr ret;
5374
5375
0
    if (val == NULL)
5376
0
  return(NULL);
5377
5378
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5379
0
    if (ret == NULL) {
5380
0
        xmlXPathErrMemory(NULL, "copying object\n");
5381
0
  return(NULL);
5382
0
    }
5383
0
    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5384
#ifdef XP_DEBUG_OBJ_USAGE
5385
    xmlXPathDebugObjUsageRequested(NULL, val->type);
5386
#endif
5387
0
    switch (val->type) {
5388
0
  case XPATH_BOOLEAN:
5389
0
  case XPATH_NUMBER:
5390
#ifdef LIBXML_XPTR_LOCS_ENABLED
5391
  case XPATH_POINT:
5392
  case XPATH_RANGE:
5393
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5394
0
      break;
5395
0
  case XPATH_STRING:
5396
0
      ret->stringval = xmlStrdup(val->stringval);
5397
0
      break;
5398
0
  case XPATH_XSLT_TREE:
5399
#if 0
5400
/*
5401
  Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5402
  this previous handling is no longer correct, and can cause some serious
5403
  problems (ref. bug 145547)
5404
*/
5405
      if ((val->nodesetval != NULL) &&
5406
    (val->nodesetval->nodeTab != NULL)) {
5407
    xmlNodePtr cur, tmp;
5408
    xmlDocPtr top;
5409
5410
    ret->boolval = 1;
5411
    top =  xmlNewDoc(NULL);
5412
    top->name = (char *)
5413
        xmlStrdup(val->nodesetval->nodeTab[0]->name);
5414
    ret->user = top;
5415
    if (top != NULL) {
5416
        top->doc = top;
5417
        cur = val->nodesetval->nodeTab[0]->children;
5418
        while (cur != NULL) {
5419
      tmp = xmlDocCopyNode(cur, top, 1);
5420
      xmlAddChild((xmlNodePtr) top, tmp);
5421
      cur = cur->next;
5422
        }
5423
    }
5424
5425
    ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5426
      } else
5427
    ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5428
      /* Deallocate the copied tree value */
5429
      break;
5430
#endif
5431
0
  case XPATH_NODESET:
5432
            /* TODO: Check memory error. */
5433
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5434
      /* Do not deallocate the copied tree value */
5435
0
      ret->boolval = 0;
5436
0
      break;
5437
#ifdef LIBXML_XPTR_LOCS_ENABLED
5438
  case XPATH_LOCATIONSET:
5439
  {
5440
      xmlLocationSetPtr loc = val->user;
5441
      ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5442
      break;
5443
  }
5444
#endif
5445
0
        case XPATH_USERS:
5446
0
      ret->user = val->user;
5447
0
      break;
5448
0
        case XPATH_UNDEFINED:
5449
0
      xmlGenericError(xmlGenericErrorContext,
5450
0
        "xmlXPathObjectCopy: unsupported type %d\n",
5451
0
        val->type);
5452
0
      break;
5453
0
    }
5454
0
    return(ret);
5455
0
}
5456
5457
/**
5458
 * xmlXPathFreeObject:
5459
 * @obj:  the object to free
5460
 *
5461
 * Free up an xmlXPathObjectPtr object.
5462
 */
5463
void
5464
0
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5465
0
    if (obj == NULL) return;
5466
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5467
0
  if (obj->boolval) {
5468
#if 0
5469
      if (obj->user != NULL) {
5470
                xmlXPathFreeNodeSet(obj->nodesetval);
5471
    xmlFreeNodeList((xmlNodePtr) obj->user);
5472
      } else
5473
#endif
5474
0
      obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5475
0
      if (obj->nodesetval != NULL)
5476
0
    xmlXPathFreeValueTree(obj->nodesetval);
5477
0
  } else {
5478
0
      if (obj->nodesetval != NULL)
5479
0
    xmlXPathFreeNodeSet(obj->nodesetval);
5480
0
  }
5481
#ifdef LIBXML_XPTR_LOCS_ENABLED
5482
    } else if (obj->type == XPATH_LOCATIONSET) {
5483
  if (obj->user != NULL)
5484
      xmlXPtrFreeLocationSet(obj->user);
5485
#endif
5486
0
    } else if (obj->type == XPATH_STRING) {
5487
0
  if (obj->stringval != NULL)
5488
0
      xmlFree(obj->stringval);
5489
0
    }
5490
#ifdef XP_DEBUG_OBJ_USAGE
5491
    xmlXPathDebugObjUsageReleased(NULL, obj->type);
5492
#endif
5493
0
    xmlFree(obj);
5494
0
}
5495
5496
static void
5497
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
5498
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
5499
0
}
5500
5501
/**
5502
 * xmlXPathReleaseObject:
5503
 * @obj:  the xmlXPathObjectPtr to free or to cache
5504
 *
5505
 * Depending on the state of the cache this frees the given
5506
 * XPath object or stores it in the cache.
5507
 */
5508
static void
5509
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5510
0
{
5511
0
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5512
0
  sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5513
0
    if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5514
5515
0
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5516
5517
0
    if (obj == NULL)
5518
0
  return;
5519
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5520
0
   xmlXPathFreeObject(obj);
5521
0
    } else {
5522
0
  xmlXPathContextCachePtr cache =
5523
0
      (xmlXPathContextCachePtr) ctxt->cache;
5524
5525
0
  switch (obj->type) {
5526
0
      case XPATH_NODESET:
5527
0
      case XPATH_XSLT_TREE:
5528
0
    if (obj->nodesetval != NULL) {
5529
0
        if (obj->boolval) {
5530
      /*
5531
      * It looks like the @boolval is used for
5532
      * evaluation if this an XSLT Result Tree Fragment.
5533
      * TODO: Check if this assumption is correct.
5534
      */
5535
0
      obj->type = XPATH_XSLT_TREE; /* just for debugging */
5536
0
      xmlXPathFreeValueTree(obj->nodesetval);
5537
0
      obj->nodesetval = NULL;
5538
0
        } else if ((obj->nodesetval->nodeMax <= 40) &&
5539
0
      (XP_CACHE_WANTS(cache->nodesetObjs,
5540
0
          cache->maxNodeset)))
5541
0
        {
5542
0
      XP_CACHE_ADD(cache->nodesetObjs, obj);
5543
0
      goto obj_cached;
5544
0
        } else {
5545
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5546
0
      obj->nodesetval = NULL;
5547
0
        }
5548
0
    }
5549
0
    break;
5550
0
      case XPATH_STRING:
5551
0
    if (obj->stringval != NULL)
5552
0
        xmlFree(obj->stringval);
5553
5554
0
    if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5555
0
        XP_CACHE_ADD(cache->stringObjs, obj);
5556
0
        goto obj_cached;
5557
0
    }
5558
0
    break;
5559
0
      case XPATH_BOOLEAN:
5560
0
    if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5561
0
        XP_CACHE_ADD(cache->booleanObjs, obj);
5562
0
        goto obj_cached;
5563
0
    }
5564
0
    break;
5565
0
      case XPATH_NUMBER:
5566
0
    if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5567
0
        XP_CACHE_ADD(cache->numberObjs, obj);
5568
0
        goto obj_cached;
5569
0
    }
5570
0
    break;
5571
#ifdef LIBXML_XPTR_LOCS_ENABLED
5572
      case XPATH_LOCATIONSET:
5573
    if (obj->user != NULL) {
5574
        xmlXPtrFreeLocationSet(obj->user);
5575
    }
5576
    goto free_obj;
5577
#endif
5578
0
      default:
5579
0
    goto free_obj;
5580
0
  }
5581
5582
  /*
5583
  * Fallback to adding to the misc-objects slot.
5584
  */
5585
0
  if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5586
0
      XP_CACHE_ADD(cache->miscObjs, obj);
5587
0
  } else
5588
0
      goto free_obj;
5589
5590
0
obj_cached:
5591
5592
#ifdef XP_DEBUG_OBJ_USAGE
5593
  xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5594
#endif
5595
5596
0
  if (obj->nodesetval != NULL) {
5597
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
5598
5599
      /*
5600
      * TODO: Due to those nasty ns-nodes, we need to traverse
5601
      *  the list and free the ns-nodes.
5602
      * URGENT TODO: Check if it's actually slowing things down.
5603
      *  Maybe we shouldn't try to preserve the list.
5604
      */
5605
0
      if (tmpset->nodeNr > 1) {
5606
0
    int i;
5607
0
    xmlNodePtr node;
5608
5609
0
    for (i = 0; i < tmpset->nodeNr; i++) {
5610
0
        node = tmpset->nodeTab[i];
5611
0
        if ((node != NULL) &&
5612
0
      (node->type == XML_NAMESPACE_DECL))
5613
0
        {
5614
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5615
0
        }
5616
0
    }
5617
0
      } else if (tmpset->nodeNr == 1) {
5618
0
    if ((tmpset->nodeTab[0] != NULL) &&
5619
0
        (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5620
0
        xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5621
0
      }
5622
0
      tmpset->nodeNr = 0;
5623
0
      memset(obj, 0, sizeof(xmlXPathObject));
5624
0
      obj->nodesetval = tmpset;
5625
0
  } else
5626
0
      memset(obj, 0, sizeof(xmlXPathObject));
5627
5628
0
  return;
5629
5630
0
free_obj:
5631
  /*
5632
  * Cache is full; free the object.
5633
  */
5634
0
  if (obj->nodesetval != NULL)
5635
0
      xmlXPathFreeNodeSet(obj->nodesetval);
5636
#ifdef XP_DEBUG_OBJ_USAGE
5637
  xmlXPathDebugObjUsageReleased(NULL, obj->type);
5638
#endif
5639
0
  xmlFree(obj);
5640
0
    }
5641
0
    return;
5642
0
}
5643
5644
5645
/************************************************************************
5646
 *                  *
5647
 *      Type Casting Routines       *
5648
 *                  *
5649
 ************************************************************************/
5650
5651
/**
5652
 * xmlXPathCastBooleanToString:
5653
 * @val:  a boolean
5654
 *
5655
 * Converts a boolean to its string value.
5656
 *
5657
 * Returns a newly allocated string.
5658
 */
5659
xmlChar *
5660
0
xmlXPathCastBooleanToString (int val) {
5661
0
    xmlChar *ret;
5662
0
    if (val)
5663
0
  ret = xmlStrdup((const xmlChar *) "true");
5664
0
    else
5665
0
  ret = xmlStrdup((const xmlChar *) "false");
5666
0
    return(ret);
5667
0
}
5668
5669
/**
5670
 * xmlXPathCastNumberToString:
5671
 * @val:  a number
5672
 *
5673
 * Converts a number to its string value.
5674
 *
5675
 * Returns a newly allocated string.
5676
 */
5677
xmlChar *
5678
0
xmlXPathCastNumberToString (double val) {
5679
0
    xmlChar *ret;
5680
0
    switch (xmlXPathIsInf(val)) {
5681
0
    case 1:
5682
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
5683
0
  break;
5684
0
    case -1:
5685
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
5686
0
  break;
5687
0
    default:
5688
0
  if (xmlXPathIsNaN(val)) {
5689
0
      ret = xmlStrdup((const xmlChar *) "NaN");
5690
0
  } else if (val == 0) {
5691
            /* Omit sign for negative zero. */
5692
0
      ret = xmlStrdup((const xmlChar *) "0");
5693
0
  } else {
5694
      /* could be improved */
5695
0
      char buf[100];
5696
0
      xmlXPathFormatNumber(val, buf, 99);
5697
0
      buf[99] = 0;
5698
0
      ret = xmlStrdup((const xmlChar *) buf);
5699
0
  }
5700
0
    }
5701
0
    return(ret);
5702
0
}
5703
5704
/**
5705
 * xmlXPathCastNodeToString:
5706
 * @node:  a node
5707
 *
5708
 * Converts a node to its string value.
5709
 *
5710
 * Returns a newly allocated string.
5711
 */
5712
xmlChar *
5713
0
xmlXPathCastNodeToString (xmlNodePtr node) {
5714
0
xmlChar *ret;
5715
0
    if ((ret = xmlNodeGetContent(node)) == NULL)
5716
0
  ret = xmlStrdup((const xmlChar *) "");
5717
0
    return(ret);
5718
0
}
5719
5720
/**
5721
 * xmlXPathCastNodeSetToString:
5722
 * @ns:  a node-set
5723
 *
5724
 * Converts a node-set to its string value.
5725
 *
5726
 * Returns a newly allocated string.
5727
 */
5728
xmlChar *
5729
0
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5730
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5731
0
  return(xmlStrdup((const xmlChar *) ""));
5732
5733
0
    if (ns->nodeNr > 1)
5734
0
  xmlXPathNodeSetSort(ns);
5735
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5736
0
}
5737
5738
/**
5739
 * xmlXPathCastToString:
5740
 * @val:  an XPath object
5741
 *
5742
 * Converts an existing object to its string() equivalent
5743
 *
5744
 * Returns the allocated string value of the object, NULL in case of error.
5745
 *         It's up to the caller to free the string memory with xmlFree().
5746
 */
5747
xmlChar *
5748
0
xmlXPathCastToString(xmlXPathObjectPtr val) {
5749
0
    xmlChar *ret = NULL;
5750
5751
0
    if (val == NULL)
5752
0
  return(xmlStrdup((const xmlChar *) ""));
5753
0
    switch (val->type) {
5754
0
  case XPATH_UNDEFINED:
5755
#ifdef DEBUG_EXPR
5756
      xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5757
#endif
5758
0
      ret = xmlStrdup((const xmlChar *) "");
5759
0
      break;
5760
0
        case XPATH_NODESET:
5761
0
        case XPATH_XSLT_TREE:
5762
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
5763
0
      break;
5764
0
  case XPATH_STRING:
5765
0
      return(xmlStrdup(val->stringval));
5766
0
        case XPATH_BOOLEAN:
5767
0
      ret = xmlXPathCastBooleanToString(val->boolval);
5768
0
      break;
5769
0
  case XPATH_NUMBER: {
5770
0
      ret = xmlXPathCastNumberToString(val->floatval);
5771
0
      break;
5772
0
  }
5773
0
  case XPATH_USERS:
5774
#ifdef LIBXML_XPTR_LOCS_ENABLED
5775
  case XPATH_POINT:
5776
  case XPATH_RANGE:
5777
  case XPATH_LOCATIONSET:
5778
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5779
0
      TODO
5780
0
      ret = xmlStrdup((const xmlChar *) "");
5781
0
      break;
5782
0
    }
5783
0
    return(ret);
5784
0
}
5785
5786
/**
5787
 * xmlXPathConvertString:
5788
 * @val:  an XPath object
5789
 *
5790
 * Converts an existing object to its string() equivalent
5791
 *
5792
 * Returns the new object, the old one is freed (or the operation
5793
 *         is done directly on @val)
5794
 */
5795
xmlXPathObjectPtr
5796
0
xmlXPathConvertString(xmlXPathObjectPtr val) {
5797
0
    xmlChar *res = NULL;
5798
5799
0
    if (val == NULL)
5800
0
  return(xmlXPathNewCString(""));
5801
5802
0
    switch (val->type) {
5803
0
    case XPATH_UNDEFINED:
5804
#ifdef DEBUG_EXPR
5805
  xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5806
#endif
5807
0
  break;
5808
0
    case XPATH_NODESET:
5809
0
    case XPATH_XSLT_TREE:
5810
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
5811
0
  break;
5812
0
    case XPATH_STRING:
5813
0
  return(val);
5814
0
    case XPATH_BOOLEAN:
5815
0
  res = xmlXPathCastBooleanToString(val->boolval);
5816
0
  break;
5817
0
    case XPATH_NUMBER:
5818
0
  res = xmlXPathCastNumberToString(val->floatval);
5819
0
  break;
5820
0
    case XPATH_USERS:
5821
#ifdef LIBXML_XPTR_LOCS_ENABLED
5822
    case XPATH_POINT:
5823
    case XPATH_RANGE:
5824
    case XPATH_LOCATIONSET:
5825
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5826
0
  TODO;
5827
0
  break;
5828
0
    }
5829
0
    xmlXPathFreeObject(val);
5830
0
    if (res == NULL)
5831
0
  return(xmlXPathNewCString(""));
5832
0
    return(xmlXPathWrapString(res));
5833
0
}
5834
5835
/**
5836
 * xmlXPathCastBooleanToNumber:
5837
 * @val:  a boolean
5838
 *
5839
 * Converts a boolean to its number value
5840
 *
5841
 * Returns the number value
5842
 */
5843
double
5844
0
xmlXPathCastBooleanToNumber(int val) {
5845
0
    if (val)
5846
0
  return(1.0);
5847
0
    return(0.0);
5848
0
}
5849
5850
/**
5851
 * xmlXPathCastStringToNumber:
5852
 * @val:  a string
5853
 *
5854
 * Converts a string to its number value
5855
 *
5856
 * Returns the number value
5857
 */
5858
double
5859
0
xmlXPathCastStringToNumber(const xmlChar * val) {
5860
0
    return(xmlXPathStringEvalNumber(val));
5861
0
}
5862
5863
/**
5864
 * xmlXPathCastNodeToNumber:
5865
 * @node:  a node
5866
 *
5867
 * Converts a node to its number value
5868
 *
5869
 * Returns the number value
5870
 */
5871
double
5872
0
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5873
0
    xmlChar *strval;
5874
0
    double ret;
5875
5876
0
    if (node == NULL)
5877
0
  return(xmlXPathNAN);
5878
0
    strval = xmlXPathCastNodeToString(node);
5879
0
    if (strval == NULL)
5880
0
  return(xmlXPathNAN);
5881
0
    ret = xmlXPathCastStringToNumber(strval);
5882
0
    xmlFree(strval);
5883
5884
0
    return(ret);
5885
0
}
5886
5887
/**
5888
 * xmlXPathCastNodeSetToNumber:
5889
 * @ns:  a node-set
5890
 *
5891
 * Converts a node-set to its number value
5892
 *
5893
 * Returns the number value
5894
 */
5895
double
5896
0
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5897
0
    xmlChar *str;
5898
0
    double ret;
5899
5900
0
    if (ns == NULL)
5901
0
  return(xmlXPathNAN);
5902
0
    str = xmlXPathCastNodeSetToString(ns);
5903
0
    ret = xmlXPathCastStringToNumber(str);
5904
0
    xmlFree(str);
5905
0
    return(ret);
5906
0
}
5907
5908
/**
5909
 * xmlXPathCastToNumber:
5910
 * @val:  an XPath object
5911
 *
5912
 * Converts an XPath object to its number value
5913
 *
5914
 * Returns the number value
5915
 */
5916
double
5917
0
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5918
0
    double ret = 0.0;
5919
5920
0
    if (val == NULL)
5921
0
  return(xmlXPathNAN);
5922
0
    switch (val->type) {
5923
0
    case XPATH_UNDEFINED:
5924
#ifdef DEBUG_EXPR
5925
  xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5926
#endif
5927
0
  ret = xmlXPathNAN;
5928
0
  break;
5929
0
    case XPATH_NODESET:
5930
0
    case XPATH_XSLT_TREE:
5931
0
  ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5932
0
  break;
5933
0
    case XPATH_STRING:
5934
0
  ret = xmlXPathCastStringToNumber(val->stringval);
5935
0
  break;
5936
0
    case XPATH_NUMBER:
5937
0
  ret = val->floatval;
5938
0
  break;
5939
0
    case XPATH_BOOLEAN:
5940
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
5941
0
  break;
5942
0
    case XPATH_USERS:
5943
#ifdef LIBXML_XPTR_LOCS_ENABLED
5944
    case XPATH_POINT:
5945
    case XPATH_RANGE:
5946
    case XPATH_LOCATIONSET:
5947
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5948
0
  TODO;
5949
0
  ret = xmlXPathNAN;
5950
0
  break;
5951
0
    }
5952
0
    return(ret);
5953
0
}
5954
5955
/**
5956
 * xmlXPathConvertNumber:
5957
 * @val:  an XPath object
5958
 *
5959
 * Converts an existing object to its number() equivalent
5960
 *
5961
 * Returns the new object, the old one is freed (or the operation
5962
 *         is done directly on @val)
5963
 */
5964
xmlXPathObjectPtr
5965
0
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5966
0
    xmlXPathObjectPtr ret;
5967
5968
0
    if (val == NULL)
5969
0
  return(xmlXPathNewFloat(0.0));
5970
0
    if (val->type == XPATH_NUMBER)
5971
0
  return(val);
5972
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5973
0
    xmlXPathFreeObject(val);
5974
0
    return(ret);
5975
0
}
5976
5977
/**
5978
 * xmlXPathCastNumberToBoolean:
5979
 * @val:  a number
5980
 *
5981
 * Converts a number to its boolean value
5982
 *
5983
 * Returns the boolean value
5984
 */
5985
int
5986
0
xmlXPathCastNumberToBoolean (double val) {
5987
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
5988
0
   return(0);
5989
0
     return(1);
5990
0
}
5991
5992
/**
5993
 * xmlXPathCastStringToBoolean:
5994
 * @val:  a string
5995
 *
5996
 * Converts a string to its boolean value
5997
 *
5998
 * Returns the boolean value
5999
 */
6000
int
6001
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
6002
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
6003
0
  return(0);
6004
0
    return(1);
6005
0
}
6006
6007
/**
6008
 * xmlXPathCastNodeSetToBoolean:
6009
 * @ns:  a node-set
6010
 *
6011
 * Converts a node-set to its boolean value
6012
 *
6013
 * Returns the boolean value
6014
 */
6015
int
6016
0
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6017
0
    if ((ns == NULL) || (ns->nodeNr == 0))
6018
0
  return(0);
6019
0
    return(1);
6020
0
}
6021
6022
/**
6023
 * xmlXPathCastToBoolean:
6024
 * @val:  an XPath object
6025
 *
6026
 * Converts an XPath object to its boolean value
6027
 *
6028
 * Returns the boolean value
6029
 */
6030
int
6031
0
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6032
0
    int ret = 0;
6033
6034
0
    if (val == NULL)
6035
0
  return(0);
6036
0
    switch (val->type) {
6037
0
    case XPATH_UNDEFINED:
6038
#ifdef DEBUG_EXPR
6039
  xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6040
#endif
6041
0
  ret = 0;
6042
0
  break;
6043
0
    case XPATH_NODESET:
6044
0
    case XPATH_XSLT_TREE:
6045
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6046
0
  break;
6047
0
    case XPATH_STRING:
6048
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
6049
0
  break;
6050
0
    case XPATH_NUMBER:
6051
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
6052
0
  break;
6053
0
    case XPATH_BOOLEAN:
6054
0
  ret = val->boolval;
6055
0
  break;
6056
0
    case XPATH_USERS:
6057
#ifdef LIBXML_XPTR_LOCS_ENABLED
6058
    case XPATH_POINT:
6059
    case XPATH_RANGE:
6060
    case XPATH_LOCATIONSET:
6061
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6062
0
  TODO;
6063
0
  ret = 0;
6064
0
  break;
6065
0
    }
6066
0
    return(ret);
6067
0
}
6068
6069
6070
/**
6071
 * xmlXPathConvertBoolean:
6072
 * @val:  an XPath object
6073
 *
6074
 * Converts an existing object to its boolean() equivalent
6075
 *
6076
 * Returns the new object, the old one is freed (or the operation
6077
 *         is done directly on @val)
6078
 */
6079
xmlXPathObjectPtr
6080
0
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6081
0
    xmlXPathObjectPtr ret;
6082
6083
0
    if (val == NULL)
6084
0
  return(xmlXPathNewBoolean(0));
6085
0
    if (val->type == XPATH_BOOLEAN)
6086
0
  return(val);
6087
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6088
0
    xmlXPathFreeObject(val);
6089
0
    return(ret);
6090
0
}
6091
6092
/************************************************************************
6093
 *                  *
6094
 *    Routines to handle XPath contexts     *
6095
 *                  *
6096
 ************************************************************************/
6097
6098
/**
6099
 * xmlXPathNewContext:
6100
 * @doc:  the XML document
6101
 *
6102
 * Create a new xmlXPathContext
6103
 *
6104
 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6105
 */
6106
xmlXPathContextPtr
6107
0
xmlXPathNewContext(xmlDocPtr doc) {
6108
0
    xmlXPathContextPtr ret;
6109
6110
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6111
0
    if (ret == NULL) {
6112
0
        xmlXPathErrMemory(NULL, "creating context\n");
6113
0
  return(NULL);
6114
0
    }
6115
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6116
0
    ret->doc = doc;
6117
0
    ret->node = NULL;
6118
6119
0
    ret->varHash = NULL;
6120
6121
0
    ret->nb_types = 0;
6122
0
    ret->max_types = 0;
6123
0
    ret->types = NULL;
6124
6125
0
    ret->funcHash = xmlHashCreate(0);
6126
6127
0
    ret->nb_axis = 0;
6128
0
    ret->max_axis = 0;
6129
0
    ret->axis = NULL;
6130
6131
0
    ret->nsHash = NULL;
6132
0
    ret->user = NULL;
6133
6134
0
    ret->contextSize = -1;
6135
0
    ret->proximityPosition = -1;
6136
6137
#ifdef XP_DEFAULT_CACHE_ON
6138
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6139
  xmlXPathFreeContext(ret);
6140
  return(NULL);
6141
    }
6142
#endif
6143
6144
0
    xmlXPathRegisterAllFunctions(ret);
6145
6146
0
    return(ret);
6147
0
}
6148
6149
/**
6150
 * xmlXPathFreeContext:
6151
 * @ctxt:  the context to free
6152
 *
6153
 * Free up an xmlXPathContext
6154
 */
6155
void
6156
0
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6157
0
    if (ctxt == NULL) return;
6158
6159
0
    if (ctxt->cache != NULL)
6160
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6161
0
    xmlXPathRegisteredNsCleanup(ctxt);
6162
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
6163
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
6164
0
    xmlResetError(&ctxt->lastError);
6165
0
    xmlFree(ctxt);
6166
0
}
6167
6168
/************************************************************************
6169
 *                  *
6170
 *    Routines to handle XPath parser contexts    *
6171
 *                  *
6172
 ************************************************************************/
6173
6174
#define CHECK_CTXT(ctxt)            \
6175
0
    if (ctxt == NULL) {           \
6176
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6177
0
    NULL, NULL, XML_FROM_XPATH,       \
6178
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6179
0
    __FILE__, __LINE__,         \
6180
0
    NULL, NULL, NULL, 0, 0,         \
6181
0
    "NULL context pointer\n");        \
6182
0
  return(NULL);             \
6183
0
    }                  \
6184
6185
#define CHECK_CTXT_NEG(ctxt)            \
6186
0
    if (ctxt == NULL) {           \
6187
0
  __xmlRaiseError(NULL, NULL, NULL,       \
6188
0
    NULL, NULL, XML_FROM_XPATH,       \
6189
0
    XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL,      \
6190
0
    __FILE__, __LINE__,         \
6191
0
    NULL, NULL, NULL, 0, 0,         \
6192
0
    "NULL context pointer\n");        \
6193
0
  return(-1);             \
6194
0
    }                  \
6195
6196
6197
#define CHECK_CONTEXT(ctxt)           \
6198
    if ((ctxt == NULL) || (ctxt->doc == NULL) ||      \
6199
        (ctxt->doc->children == NULL)) {        \
6200
  xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT);  \
6201
  return(NULL);             \
6202
    }
6203
6204
6205
/**
6206
 * xmlXPathNewParserContext:
6207
 * @str:  the XPath expression
6208
 * @ctxt:  the XPath context
6209
 *
6210
 * Create a new xmlXPathParserContext
6211
 *
6212
 * Returns the xmlXPathParserContext just allocated.
6213
 */
6214
xmlXPathParserContextPtr
6215
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6216
0
    xmlXPathParserContextPtr ret;
6217
6218
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6219
0
    if (ret == NULL) {
6220
0
        xmlXPathErrMemory(ctxt, "creating parser context\n");
6221
0
  return(NULL);
6222
0
    }
6223
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6224
0
    ret->cur = ret->base = str;
6225
0
    ret->context = ctxt;
6226
6227
0
    ret->comp = xmlXPathNewCompExpr();
6228
0
    if (ret->comp == NULL) {
6229
0
  xmlFree(ret->valueTab);
6230
0
  xmlFree(ret);
6231
0
  return(NULL);
6232
0
    }
6233
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6234
0
        ret->comp->dict = ctxt->dict;
6235
0
  xmlDictReference(ret->comp->dict);
6236
0
    }
6237
6238
0
    return(ret);
6239
0
}
6240
6241
/**
6242
 * xmlXPathCompParserContext:
6243
 * @comp:  the XPath compiled expression
6244
 * @ctxt:  the XPath context
6245
 *
6246
 * Create a new xmlXPathParserContext when processing a compiled expression
6247
 *
6248
 * Returns the xmlXPathParserContext just allocated.
6249
 */
6250
static xmlXPathParserContextPtr
6251
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6252
0
    xmlXPathParserContextPtr ret;
6253
6254
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6255
0
    if (ret == NULL) {
6256
0
        xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6257
0
  return(NULL);
6258
0
    }
6259
0
    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6260
6261
    /* Allocate the value stack */
6262
0
    ret->valueTab = (xmlXPathObjectPtr *)
6263
0
                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6264
0
    if (ret->valueTab == NULL) {
6265
0
  xmlFree(ret);
6266
0
  xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6267
0
  return(NULL);
6268
0
    }
6269
0
    ret->valueNr = 0;
6270
0
    ret->valueMax = 10;
6271
0
    ret->value = NULL;
6272
0
    ret->valueFrame = 0;
6273
6274
0
    ret->context = ctxt;
6275
0
    ret->comp = comp;
6276
6277
0
    return(ret);
6278
0
}
6279
6280
/**
6281
 * xmlXPathFreeParserContext:
6282
 * @ctxt:  the context to free
6283
 *
6284
 * Free up an xmlXPathParserContext
6285
 */
6286
void
6287
0
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6288
0
    int i;
6289
6290
0
    if (ctxt->valueTab != NULL) {
6291
0
        for (i = 0; i < ctxt->valueNr; i++) {
6292
0
            if (ctxt->context)
6293
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6294
0
            else
6295
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
6296
0
        }
6297
0
        xmlFree(ctxt->valueTab);
6298
0
    }
6299
0
    if (ctxt->comp != NULL) {
6300
0
#ifdef XPATH_STREAMING
6301
0
  if (ctxt->comp->stream != NULL) {
6302
0
      xmlFreePatternList(ctxt->comp->stream);
6303
0
      ctxt->comp->stream = NULL;
6304
0
  }
6305
0
#endif
6306
0
  xmlXPathFreeCompExpr(ctxt->comp);
6307
0
    }
6308
0
    xmlFree(ctxt);
6309
0
}
6310
6311
/************************************************************************
6312
 *                  *
6313
 *    The implicit core function library      *
6314
 *                  *
6315
 ************************************************************************/
6316
6317
/**
6318
 * xmlXPathNodeValHash:
6319
 * @node:  a node pointer
6320
 *
6321
 * Function computing the beginning of the string value of the node,
6322
 * used to speed up comparisons
6323
 *
6324
 * Returns an int usable as a hash
6325
 */
6326
static unsigned int
6327
0
xmlXPathNodeValHash(xmlNodePtr node) {
6328
0
    int len = 2;
6329
0
    const xmlChar * string = NULL;
6330
0
    xmlNodePtr tmp = NULL;
6331
0
    unsigned int ret = 0;
6332
6333
0
    if (node == NULL)
6334
0
  return(0);
6335
6336
0
    if (node->type == XML_DOCUMENT_NODE) {
6337
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
6338
0
  if (tmp == NULL)
6339
0
      node = node->children;
6340
0
  else
6341
0
      node = tmp;
6342
6343
0
  if (node == NULL)
6344
0
      return(0);
6345
0
    }
6346
6347
0
    switch (node->type) {
6348
0
  case XML_COMMENT_NODE:
6349
0
  case XML_PI_NODE:
6350
0
  case XML_CDATA_SECTION_NODE:
6351
0
  case XML_TEXT_NODE:
6352
0
      string = node->content;
6353
0
      if (string == NULL)
6354
0
    return(0);
6355
0
      if (string[0] == 0)
6356
0
    return(0);
6357
0
      return(((unsigned int) string[0]) +
6358
0
       (((unsigned int) string[1]) << 8));
6359
0
  case XML_NAMESPACE_DECL:
6360
0
      string = ((xmlNsPtr)node)->href;
6361
0
      if (string == NULL)
6362
0
    return(0);
6363
0
      if (string[0] == 0)
6364
0
    return(0);
6365
0
      return(((unsigned int) string[0]) +
6366
0
       (((unsigned int) string[1]) << 8));
6367
0
  case XML_ATTRIBUTE_NODE:
6368
0
      tmp = ((xmlAttrPtr) node)->children;
6369
0
      break;
6370
0
  case XML_ELEMENT_NODE:
6371
0
      tmp = node->children;
6372
0
      break;
6373
0
  default:
6374
0
      return(0);
6375
0
    }
6376
0
    while (tmp != NULL) {
6377
0
  switch (tmp->type) {
6378
0
      case XML_CDATA_SECTION_NODE:
6379
0
      case XML_TEXT_NODE:
6380
0
    string = tmp->content;
6381
0
    break;
6382
0
      default:
6383
0
                string = NULL;
6384
0
    break;
6385
0
  }
6386
0
  if ((string != NULL) && (string[0] != 0)) {
6387
0
      if (len == 1) {
6388
0
    return(ret + (((unsigned int) string[0]) << 8));
6389
0
      }
6390
0
      if (string[1] == 0) {
6391
0
    len = 1;
6392
0
    ret = (unsigned int) string[0];
6393
0
      } else {
6394
0
    return(((unsigned int) string[0]) +
6395
0
           (((unsigned int) string[1]) << 8));
6396
0
      }
6397
0
  }
6398
  /*
6399
   * Skip to next node
6400
   */
6401
0
  if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6402
0
      if (tmp->children->type != XML_ENTITY_DECL) {
6403
0
    tmp = tmp->children;
6404
0
    continue;
6405
0
      }
6406
0
  }
6407
0
  if (tmp == node)
6408
0
      break;
6409
6410
0
  if (tmp->next != NULL) {
6411
0
      tmp = tmp->next;
6412
0
      continue;
6413
0
  }
6414
6415
0
  do {
6416
0
      tmp = tmp->parent;
6417
0
      if (tmp == NULL)
6418
0
    break;
6419
0
      if (tmp == node) {
6420
0
    tmp = NULL;
6421
0
    break;
6422
0
      }
6423
0
      if (tmp->next != NULL) {
6424
0
    tmp = tmp->next;
6425
0
    break;
6426
0
      }
6427
0
  } while (tmp != NULL);
6428
0
    }
6429
0
    return(ret);
6430
0
}
6431
6432
/**
6433
 * xmlXPathStringHash:
6434
 * @string:  a string
6435
 *
6436
 * Function computing the beginning of the string value of the node,
6437
 * used to speed up comparisons
6438
 *
6439
 * Returns an int usable as a hash
6440
 */
6441
static unsigned int
6442
0
xmlXPathStringHash(const xmlChar * string) {
6443
0
    if (string == NULL)
6444
0
  return((unsigned int) 0);
6445
0
    if (string[0] == 0)
6446
0
  return(0);
6447
0
    return(((unsigned int) string[0]) +
6448
0
     (((unsigned int) string[1]) << 8));
6449
0
}
6450
6451
/**
6452
 * xmlXPathCompareNodeSetFloat:
6453
 * @ctxt:  the XPath Parser context
6454
 * @inf:  less than (1) or greater than (0)
6455
 * @strict:  is the comparison strict
6456
 * @arg:  the node set
6457
 * @f:  the value
6458
 *
6459
 * Implement the compare operation between a nodeset and a number
6460
 *     @ns < @val    (1, 1, ...
6461
 *     @ns <= @val   (1, 0, ...
6462
 *     @ns > @val    (0, 1, ...
6463
 *     @ns >= @val   (0, 0, ...
6464
 *
6465
 * If one object to be compared is a node-set and the other is a number,
6466
 * then the comparison will be true if and only if there is a node in the
6467
 * node-set such that the result of performing the comparison on the number
6468
 * to be compared and on the result of converting the string-value of that
6469
 * node to a number using the number function is true.
6470
 *
6471
 * Returns 0 or 1 depending on the results of the test.
6472
 */
6473
static int
6474
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6475
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6476
0
    int i, ret = 0;
6477
0
    xmlNodeSetPtr ns;
6478
0
    xmlChar *str2;
6479
6480
0
    if ((f == NULL) || (arg == NULL) ||
6481
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6482
0
  xmlXPathReleaseObject(ctxt->context, arg);
6483
0
  xmlXPathReleaseObject(ctxt->context, f);
6484
0
        return(0);
6485
0
    }
6486
0
    ns = arg->nodesetval;
6487
0
    if (ns != NULL) {
6488
0
  for (i = 0;i < ns->nodeNr;i++) {
6489
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6490
0
       if (str2 != NULL) {
6491
0
     valuePush(ctxt,
6492
0
         xmlXPathCacheNewString(ctxt->context, str2));
6493
0
     xmlFree(str2);
6494
0
     xmlXPathNumberFunction(ctxt, 1);
6495
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6496
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6497
0
     if (ret)
6498
0
         break;
6499
0
       }
6500
0
  }
6501
0
    }
6502
0
    xmlXPathReleaseObject(ctxt->context, arg);
6503
0
    xmlXPathReleaseObject(ctxt->context, f);
6504
0
    return(ret);
6505
0
}
6506
6507
/**
6508
 * xmlXPathCompareNodeSetString:
6509
 * @ctxt:  the XPath Parser context
6510
 * @inf:  less than (1) or greater than (0)
6511
 * @strict:  is the comparison strict
6512
 * @arg:  the node set
6513
 * @s:  the value
6514
 *
6515
 * Implement the compare operation between a nodeset and a string
6516
 *     @ns < @val    (1, 1, ...
6517
 *     @ns <= @val   (1, 0, ...
6518
 *     @ns > @val    (0, 1, ...
6519
 *     @ns >= @val   (0, 0, ...
6520
 *
6521
 * If one object to be compared is a node-set and the other is a string,
6522
 * then the comparison will be true if and only if there is a node in
6523
 * the node-set such that the result of performing the comparison on the
6524
 * string-value of the node and the other string is true.
6525
 *
6526
 * Returns 0 or 1 depending on the results of the test.
6527
 */
6528
static int
6529
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6530
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6531
0
    int i, ret = 0;
6532
0
    xmlNodeSetPtr ns;
6533
0
    xmlChar *str2;
6534
6535
0
    if ((s == NULL) || (arg == NULL) ||
6536
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6537
0
  xmlXPathReleaseObject(ctxt->context, arg);
6538
0
  xmlXPathReleaseObject(ctxt->context, s);
6539
0
        return(0);
6540
0
    }
6541
0
    ns = arg->nodesetval;
6542
0
    if (ns != NULL) {
6543
0
  for (i = 0;i < ns->nodeNr;i++) {
6544
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6545
0
       if (str2 != NULL) {
6546
0
     valuePush(ctxt,
6547
0
         xmlXPathCacheNewString(ctxt->context, str2));
6548
0
     xmlFree(str2);
6549
0
     valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6550
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
6551
0
     if (ret)
6552
0
         break;
6553
0
       }
6554
0
  }
6555
0
    }
6556
0
    xmlXPathReleaseObject(ctxt->context, arg);
6557
0
    xmlXPathReleaseObject(ctxt->context, s);
6558
0
    return(ret);
6559
0
}
6560
6561
/**
6562
 * xmlXPathCompareNodeSets:
6563
 * @inf:  less than (1) or greater than (0)
6564
 * @strict:  is the comparison strict
6565
 * @arg1:  the first node set object
6566
 * @arg2:  the second node set object
6567
 *
6568
 * Implement the compare operation on nodesets:
6569
 *
6570
 * If both objects to be compared are node-sets, then the comparison
6571
 * will be true if and only if there is a node in the first node-set
6572
 * and a node in the second node-set such that the result of performing
6573
 * the comparison on the string-values of the two nodes is true.
6574
 * ....
6575
 * When neither object to be compared is a node-set and the operator
6576
 * is <=, <, >= or >, then the objects are compared by converting both
6577
 * objects to numbers and comparing the numbers according to IEEE 754.
6578
 * ....
6579
 * The number function converts its argument to a number as follows:
6580
 *  - a string that consists of optional whitespace followed by an
6581
 *    optional minus sign followed by a Number followed by whitespace
6582
 *    is converted to the IEEE 754 number that is nearest (according
6583
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
6584
 *    represented by the string; any other string is converted to NaN
6585
 *
6586
 * Conclusion all nodes need to be converted first to their string value
6587
 * and then the comparison must be done when possible
6588
 */
6589
static int
6590
xmlXPathCompareNodeSets(int inf, int strict,
6591
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6592
0
    int i, j, init = 0;
6593
0
    double val1;
6594
0
    double *values2;
6595
0
    int ret = 0;
6596
0
    xmlNodeSetPtr ns1;
6597
0
    xmlNodeSetPtr ns2;
6598
6599
0
    if ((arg1 == NULL) ||
6600
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6601
0
  xmlXPathFreeObject(arg2);
6602
0
        return(0);
6603
0
    }
6604
0
    if ((arg2 == NULL) ||
6605
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6606
0
  xmlXPathFreeObject(arg1);
6607
0
  xmlXPathFreeObject(arg2);
6608
0
        return(0);
6609
0
    }
6610
6611
0
    ns1 = arg1->nodesetval;
6612
0
    ns2 = arg2->nodesetval;
6613
6614
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6615
0
  xmlXPathFreeObject(arg1);
6616
0
  xmlXPathFreeObject(arg2);
6617
0
  return(0);
6618
0
    }
6619
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6620
0
  xmlXPathFreeObject(arg1);
6621
0
  xmlXPathFreeObject(arg2);
6622
0
  return(0);
6623
0
    }
6624
6625
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6626
0
    if (values2 == NULL) {
6627
        /* TODO: Propagate memory error. */
6628
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6629
0
  xmlXPathFreeObject(arg1);
6630
0
  xmlXPathFreeObject(arg2);
6631
0
  return(0);
6632
0
    }
6633
0
    for (i = 0;i < ns1->nodeNr;i++) {
6634
0
  val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6635
0
  if (xmlXPathIsNaN(val1))
6636
0
      continue;
6637
0
  for (j = 0;j < ns2->nodeNr;j++) {
6638
0
      if (init == 0) {
6639
0
    values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6640
0
      }
6641
0
      if (xmlXPathIsNaN(values2[j]))
6642
0
    continue;
6643
0
      if (inf && strict)
6644
0
    ret = (val1 < values2[j]);
6645
0
      else if (inf && !strict)
6646
0
    ret = (val1 <= values2[j]);
6647
0
      else if (!inf && strict)
6648
0
    ret = (val1 > values2[j]);
6649
0
      else if (!inf && !strict)
6650
0
    ret = (val1 >= values2[j]);
6651
0
      if (ret)
6652
0
    break;
6653
0
  }
6654
0
  if (ret)
6655
0
      break;
6656
0
  init = 1;
6657
0
    }
6658
0
    xmlFree(values2);
6659
0
    xmlXPathFreeObject(arg1);
6660
0
    xmlXPathFreeObject(arg2);
6661
0
    return(ret);
6662
0
}
6663
6664
/**
6665
 * xmlXPathCompareNodeSetValue:
6666
 * @ctxt:  the XPath Parser context
6667
 * @inf:  less than (1) or greater than (0)
6668
 * @strict:  is the comparison strict
6669
 * @arg:  the node set
6670
 * @val:  the value
6671
 *
6672
 * Implement the compare operation between a nodeset and a value
6673
 *     @ns < @val    (1, 1, ...
6674
 *     @ns <= @val   (1, 0, ...
6675
 *     @ns > @val    (0, 1, ...
6676
 *     @ns >= @val   (0, 0, ...
6677
 *
6678
 * If one object to be compared is a node-set and the other is a boolean,
6679
 * then the comparison will be true if and only if the result of performing
6680
 * the comparison on the boolean and on the result of converting
6681
 * the node-set to a boolean using the boolean function is true.
6682
 *
6683
 * Returns 0 or 1 depending on the results of the test.
6684
 */
6685
static int
6686
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6687
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6688
0
    if ((val == NULL) || (arg == NULL) ||
6689
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6690
0
        return(0);
6691
6692
0
    switch(val->type) {
6693
0
        case XPATH_NUMBER:
6694
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6695
0
        case XPATH_NODESET:
6696
0
        case XPATH_XSLT_TREE:
6697
0
      return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6698
0
        case XPATH_STRING:
6699
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6700
0
        case XPATH_BOOLEAN:
6701
0
      valuePush(ctxt, arg);
6702
0
      xmlXPathBooleanFunction(ctxt, 1);
6703
0
      valuePush(ctxt, val);
6704
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
6705
0
  default:
6706
0
            xmlGenericError(xmlGenericErrorContext,
6707
0
                    "xmlXPathCompareNodeSetValue: Can't compare node set "
6708
0
                    "and object of type %d\n",
6709
0
                    val->type);
6710
0
            xmlXPathReleaseObject(ctxt->context, arg);
6711
0
            xmlXPathReleaseObject(ctxt->context, val);
6712
0
            XP_ERROR0(XPATH_INVALID_TYPE);
6713
0
    }
6714
0
    return(0);
6715
0
}
6716
6717
/**
6718
 * xmlXPathEqualNodeSetString:
6719
 * @arg:  the nodeset object argument
6720
 * @str:  the string to compare to.
6721
 * @neq:  flag to show whether for '=' (0) or '!=' (1)
6722
 *
6723
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6724
 * If one object to be compared is a node-set and the other is a string,
6725
 * then the comparison will be true if and only if there is a node in
6726
 * the node-set such that the result of performing the comparison on the
6727
 * string-value of the node and the other string is true.
6728
 *
6729
 * Returns 0 or 1 depending on the results of the test.
6730
 */
6731
static int
6732
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6733
0
{
6734
0
    int i;
6735
0
    xmlNodeSetPtr ns;
6736
0
    xmlChar *str2;
6737
0
    unsigned int hash;
6738
6739
0
    if ((str == NULL) || (arg == NULL) ||
6740
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6741
0
        return (0);
6742
0
    ns = arg->nodesetval;
6743
    /*
6744
     * A NULL nodeset compared with a string is always false
6745
     * (since there is no node equal, and no node not equal)
6746
     */
6747
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
6748
0
        return (0);
6749
0
    hash = xmlXPathStringHash(str);
6750
0
    for (i = 0; i < ns->nodeNr; i++) {
6751
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6752
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
6753
0
            if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6754
0
                xmlFree(str2);
6755
0
    if (neq)
6756
0
        continue;
6757
0
                return (1);
6758
0
      } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6759
0
    if (neq)
6760
0
        continue;
6761
0
                return (1);
6762
0
            } else if (neq) {
6763
0
    if (str2 != NULL)
6764
0
        xmlFree(str2);
6765
0
    return (1);
6766
0
      }
6767
0
            if (str2 != NULL)
6768
0
                xmlFree(str2);
6769
0
        } else if (neq)
6770
0
      return (1);
6771
0
    }
6772
0
    return (0);
6773
0
}
6774
6775
/**
6776
 * xmlXPathEqualNodeSetFloat:
6777
 * @arg:  the nodeset object argument
6778
 * @f:  the float to compare to
6779
 * @neq:  flag to show whether to compare '=' (0) or '!=' (1)
6780
 *
6781
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6782
 * If one object to be compared is a node-set and the other is a number,
6783
 * then the comparison will be true if and only if there is a node in
6784
 * the node-set such that the result of performing the comparison on the
6785
 * number to be compared and on the result of converting the string-value
6786
 * of that node to a number using the number function is true.
6787
 *
6788
 * Returns 0 or 1 depending on the results of the test.
6789
 */
6790
static int
6791
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6792
0
    xmlXPathObjectPtr arg, double f, int neq) {
6793
0
  int i, ret=0;
6794
0
  xmlNodeSetPtr ns;
6795
0
  xmlChar *str2;
6796
0
  xmlXPathObjectPtr val;
6797
0
  double v;
6798
6799
0
    if ((arg == NULL) ||
6800
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6801
0
        return(0);
6802
6803
0
    ns = arg->nodesetval;
6804
0
    if (ns != NULL) {
6805
0
  for (i=0;i<ns->nodeNr;i++) {
6806
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6807
0
      if (str2 != NULL) {
6808
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6809
0
    xmlFree(str2);
6810
0
    xmlXPathNumberFunction(ctxt, 1);
6811
0
    val = valuePop(ctxt);
6812
0
    v = val->floatval;
6813
0
    xmlXPathReleaseObject(ctxt->context, val);
6814
0
    if (!xmlXPathIsNaN(v)) {
6815
0
        if ((!neq) && (v==f)) {
6816
0
      ret = 1;
6817
0
      break;
6818
0
        } else if ((neq) && (v!=f)) {
6819
0
      ret = 1;
6820
0
      break;
6821
0
        }
6822
0
    } else { /* NaN is unequal to any value */
6823
0
        if (neq)
6824
0
      ret = 1;
6825
0
    }
6826
0
      }
6827
0
  }
6828
0
    }
6829
6830
0
    return(ret);
6831
0
}
6832
6833
6834
/**
6835
 * xmlXPathEqualNodeSets:
6836
 * @arg1:  first nodeset object argument
6837
 * @arg2:  second nodeset object argument
6838
 * @neq:   flag to show whether to test '=' (0) or '!=' (1)
6839
 *
6840
 * Implement the equal / not equal operation on XPath nodesets:
6841
 * @arg1 == @arg2  or  @arg1 != @arg2
6842
 * If both objects to be compared are node-sets, then the comparison
6843
 * will be true if and only if there is a node in the first node-set and
6844
 * a node in the second node-set such that the result of performing the
6845
 * comparison on the string-values of the two nodes is true.
6846
 *
6847
 * (needless to say, this is a costly operation)
6848
 *
6849
 * Returns 0 or 1 depending on the results of the test.
6850
 */
6851
static int
6852
0
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6853
0
    int i, j;
6854
0
    unsigned int *hashs1;
6855
0
    unsigned int *hashs2;
6856
0
    xmlChar **values1;
6857
0
    xmlChar **values2;
6858
0
    int ret = 0;
6859
0
    xmlNodeSetPtr ns1;
6860
0
    xmlNodeSetPtr ns2;
6861
6862
0
    if ((arg1 == NULL) ||
6863
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6864
0
        return(0);
6865
0
    if ((arg2 == NULL) ||
6866
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6867
0
        return(0);
6868
6869
0
    ns1 = arg1->nodesetval;
6870
0
    ns2 = arg2->nodesetval;
6871
6872
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6873
0
  return(0);
6874
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6875
0
  return(0);
6876
6877
    /*
6878
     * for equal, check if there is a node pertaining to both sets
6879
     */
6880
0
    if (neq == 0)
6881
0
  for (i = 0;i < ns1->nodeNr;i++)
6882
0
      for (j = 0;j < ns2->nodeNr;j++)
6883
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
6884
0
        return(1);
6885
6886
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6887
0
    if (values1 == NULL) {
6888
        /* TODO: Propagate memory error. */
6889
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6890
0
  return(0);
6891
0
    }
6892
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6893
0
    if (hashs1 == NULL) {
6894
        /* TODO: Propagate memory error. */
6895
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6896
0
  xmlFree(values1);
6897
0
  return(0);
6898
0
    }
6899
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6900
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6901
0
    if (values2 == NULL) {
6902
        /* TODO: Propagate memory error. */
6903
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6904
0
  xmlFree(hashs1);
6905
0
  xmlFree(values1);
6906
0
  return(0);
6907
0
    }
6908
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6909
0
    if (hashs2 == NULL) {
6910
        /* TODO: Propagate memory error. */
6911
0
        xmlXPathErrMemory(NULL, "comparing nodesets\n");
6912
0
  xmlFree(hashs1);
6913
0
  xmlFree(values1);
6914
0
  xmlFree(values2);
6915
0
  return(0);
6916
0
    }
6917
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6918
0
    for (i = 0;i < ns1->nodeNr;i++) {
6919
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6920
0
  for (j = 0;j < ns2->nodeNr;j++) {
6921
0
      if (i == 0)
6922
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6923
0
      if (hashs1[i] != hashs2[j]) {
6924
0
    if (neq) {
6925
0
        ret = 1;
6926
0
        break;
6927
0
    }
6928
0
      }
6929
0
      else {
6930
0
    if (values1[i] == NULL)
6931
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6932
0
    if (values2[j] == NULL)
6933
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6934
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6935
0
    if (ret)
6936
0
        break;
6937
0
      }
6938
0
  }
6939
0
  if (ret)
6940
0
      break;
6941
0
    }
6942
0
    for (i = 0;i < ns1->nodeNr;i++)
6943
0
  if (values1[i] != NULL)
6944
0
      xmlFree(values1[i]);
6945
0
    for (j = 0;j < ns2->nodeNr;j++)
6946
0
  if (values2[j] != NULL)
6947
0
      xmlFree(values2[j]);
6948
0
    xmlFree(values1);
6949
0
    xmlFree(values2);
6950
0
    xmlFree(hashs1);
6951
0
    xmlFree(hashs2);
6952
0
    return(ret);
6953
0
}
6954
6955
static int
6956
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6957
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6958
0
    int ret = 0;
6959
    /*
6960
     *At this point we are assured neither arg1 nor arg2
6961
     *is a nodeset, so we can just pick the appropriate routine.
6962
     */
6963
0
    switch (arg1->type) {
6964
0
        case XPATH_UNDEFINED:
6965
#ifdef DEBUG_EXPR
6966
      xmlGenericError(xmlGenericErrorContext,
6967
        "Equal: undefined\n");
6968
#endif
6969
0
      break;
6970
0
        case XPATH_BOOLEAN:
6971
0
      switch (arg2->type) {
6972
0
          case XPATH_UNDEFINED:
6973
#ifdef DEBUG_EXPR
6974
        xmlGenericError(xmlGenericErrorContext,
6975
          "Equal: undefined\n");
6976
#endif
6977
0
        break;
6978
0
    case XPATH_BOOLEAN:
6979
#ifdef DEBUG_EXPR
6980
        xmlGenericError(xmlGenericErrorContext,
6981
          "Equal: %d boolean %d \n",
6982
          arg1->boolval, arg2->boolval);
6983
#endif
6984
0
        ret = (arg1->boolval == arg2->boolval);
6985
0
        break;
6986
0
    case XPATH_NUMBER:
6987
0
        ret = (arg1->boolval ==
6988
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
6989
0
        break;
6990
0
    case XPATH_STRING:
6991
0
        if ((arg2->stringval == NULL) ||
6992
0
      (arg2->stringval[0] == 0)) ret = 0;
6993
0
        else
6994
0
      ret = 1;
6995
0
        ret = (arg1->boolval == ret);
6996
0
        break;
6997
0
    case XPATH_USERS:
6998
#ifdef LIBXML_XPTR_LOCS_ENABLED
6999
    case XPATH_POINT:
7000
    case XPATH_RANGE:
7001
    case XPATH_LOCATIONSET:
7002
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7003
0
        TODO
7004
0
        break;
7005
0
    case XPATH_NODESET:
7006
0
    case XPATH_XSLT_TREE:
7007
0
        break;
7008
0
      }
7009
0
      break;
7010
0
        case XPATH_NUMBER:
7011
0
      switch (arg2->type) {
7012
0
          case XPATH_UNDEFINED:
7013
#ifdef DEBUG_EXPR
7014
        xmlGenericError(xmlGenericErrorContext,
7015
          "Equal: undefined\n");
7016
#endif
7017
0
        break;
7018
0
    case XPATH_BOOLEAN:
7019
0
        ret = (arg2->boolval==
7020
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
7021
0
        break;
7022
0
    case XPATH_STRING:
7023
0
        valuePush(ctxt, arg2);
7024
0
        xmlXPathNumberFunction(ctxt, 1);
7025
0
        arg2 = valuePop(ctxt);
7026
                    /* Falls through. */
7027
0
    case XPATH_NUMBER:
7028
        /* Hand check NaN and Infinity equalities */
7029
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7030
0
          xmlXPathIsNaN(arg2->floatval)) {
7031
0
            ret = 0;
7032
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7033
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
7034
0
          ret = 1;
7035
0
      else
7036
0
          ret = 0;
7037
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7038
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7039
0
          ret = 1;
7040
0
      else
7041
0
          ret = 0;
7042
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7043
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7044
0
          ret = 1;
7045
0
      else
7046
0
          ret = 0;
7047
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7048
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7049
0
          ret = 1;
7050
0
      else
7051
0
          ret = 0;
7052
0
        } else {
7053
0
            ret = (arg1->floatval == arg2->floatval);
7054
0
        }
7055
0
        break;
7056
0
    case XPATH_USERS:
7057
#ifdef LIBXML_XPTR_LOCS_ENABLED
7058
    case XPATH_POINT:
7059
    case XPATH_RANGE:
7060
    case XPATH_LOCATIONSET:
7061
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7062
0
        TODO
7063
0
        break;
7064
0
    case XPATH_NODESET:
7065
0
    case XPATH_XSLT_TREE:
7066
0
        break;
7067
0
      }
7068
0
      break;
7069
0
        case XPATH_STRING:
7070
0
      switch (arg2->type) {
7071
0
          case XPATH_UNDEFINED:
7072
#ifdef DEBUG_EXPR
7073
        xmlGenericError(xmlGenericErrorContext,
7074
          "Equal: undefined\n");
7075
#endif
7076
0
        break;
7077
0
    case XPATH_BOOLEAN:
7078
0
        if ((arg1->stringval == NULL) ||
7079
0
      (arg1->stringval[0] == 0)) ret = 0;
7080
0
        else
7081
0
      ret = 1;
7082
0
        ret = (arg2->boolval == ret);
7083
0
        break;
7084
0
    case XPATH_STRING:
7085
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7086
0
        break;
7087
0
    case XPATH_NUMBER:
7088
0
        valuePush(ctxt, arg1);
7089
0
        xmlXPathNumberFunction(ctxt, 1);
7090
0
        arg1 = valuePop(ctxt);
7091
        /* Hand check NaN and Infinity equalities */
7092
0
        if (xmlXPathIsNaN(arg1->floatval) ||
7093
0
          xmlXPathIsNaN(arg2->floatval)) {
7094
0
            ret = 0;
7095
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7096
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
7097
0
          ret = 1;
7098
0
      else
7099
0
          ret = 0;
7100
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7101
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
7102
0
          ret = 1;
7103
0
      else
7104
0
          ret = 0;
7105
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7106
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
7107
0
          ret = 1;
7108
0
      else
7109
0
          ret = 0;
7110
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7111
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
7112
0
          ret = 1;
7113
0
      else
7114
0
          ret = 0;
7115
0
        } else {
7116
0
            ret = (arg1->floatval == arg2->floatval);
7117
0
        }
7118
0
        break;
7119
0
    case XPATH_USERS:
7120
#ifdef LIBXML_XPTR_LOCS_ENABLED
7121
    case XPATH_POINT:
7122
    case XPATH_RANGE:
7123
    case XPATH_LOCATIONSET:
7124
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7125
0
        TODO
7126
0
        break;
7127
0
    case XPATH_NODESET:
7128
0
    case XPATH_XSLT_TREE:
7129
0
        break;
7130
0
      }
7131
0
      break;
7132
0
        case XPATH_USERS:
7133
#ifdef LIBXML_XPTR_LOCS_ENABLED
7134
  case XPATH_POINT:
7135
  case XPATH_RANGE:
7136
  case XPATH_LOCATIONSET:
7137
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7138
0
      TODO
7139
0
      break;
7140
0
  case XPATH_NODESET:
7141
0
  case XPATH_XSLT_TREE:
7142
0
      break;
7143
0
    }
7144
0
    xmlXPathReleaseObject(ctxt->context, arg1);
7145
0
    xmlXPathReleaseObject(ctxt->context, arg2);
7146
0
    return(ret);
7147
0
}
7148
7149
/**
7150
 * xmlXPathEqualValues:
7151
 * @ctxt:  the XPath Parser context
7152
 *
7153
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7154
 *
7155
 * Returns 0 or 1 depending on the results of the test.
7156
 */
7157
int
7158
0
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7159
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
7160
0
    int ret = 0;
7161
7162
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7163
0
    arg2 = valuePop(ctxt);
7164
0
    arg1 = valuePop(ctxt);
7165
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7166
0
  if (arg1 != NULL)
7167
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7168
0
  else
7169
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7170
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7171
0
    }
7172
7173
0
    if (arg1 == arg2) {
7174
#ifdef DEBUG_EXPR
7175
        xmlGenericError(xmlGenericErrorContext,
7176
    "Equal: by pointer\n");
7177
#endif
7178
0
  xmlXPathFreeObject(arg1);
7179
0
        return(1);
7180
0
    }
7181
7182
    /*
7183
     *If either argument is a nodeset, it's a 'special case'
7184
     */
7185
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7186
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7187
  /*
7188
   *Hack it to assure arg1 is the nodeset
7189
   */
7190
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7191
0
    argtmp = arg2;
7192
0
    arg2 = arg1;
7193
0
    arg1 = argtmp;
7194
0
  }
7195
0
  switch (arg2->type) {
7196
0
      case XPATH_UNDEFINED:
7197
#ifdef DEBUG_EXPR
7198
    xmlGenericError(xmlGenericErrorContext,
7199
      "Equal: undefined\n");
7200
#endif
7201
0
    break;
7202
0
      case XPATH_NODESET:
7203
0
      case XPATH_XSLT_TREE:
7204
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7205
0
    break;
7206
0
      case XPATH_BOOLEAN:
7207
0
    if ((arg1->nodesetval == NULL) ||
7208
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7209
0
    else
7210
0
        ret = 1;
7211
0
    ret = (ret == arg2->boolval);
7212
0
    break;
7213
0
      case XPATH_NUMBER:
7214
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7215
0
    break;
7216
0
      case XPATH_STRING:
7217
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7218
0
    break;
7219
0
      case XPATH_USERS:
7220
#ifdef LIBXML_XPTR_LOCS_ENABLED
7221
      case XPATH_POINT:
7222
      case XPATH_RANGE:
7223
      case XPATH_LOCATIONSET:
7224
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7225
0
    TODO
7226
0
    break;
7227
0
  }
7228
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7229
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7230
0
  return(ret);
7231
0
    }
7232
7233
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7234
0
}
7235
7236
/**
7237
 * xmlXPathNotEqualValues:
7238
 * @ctxt:  the XPath Parser context
7239
 *
7240
 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7241
 *
7242
 * Returns 0 or 1 depending on the results of the test.
7243
 */
7244
int
7245
0
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7246
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
7247
0
    int ret = 0;
7248
7249
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7250
0
    arg2 = valuePop(ctxt);
7251
0
    arg1 = valuePop(ctxt);
7252
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7253
0
  if (arg1 != NULL)
7254
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7255
0
  else
7256
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7257
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7258
0
    }
7259
7260
0
    if (arg1 == arg2) {
7261
#ifdef DEBUG_EXPR
7262
        xmlGenericError(xmlGenericErrorContext,
7263
    "NotEqual: by pointer\n");
7264
#endif
7265
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7266
0
        return(0);
7267
0
    }
7268
7269
    /*
7270
     *If either argument is a nodeset, it's a 'special case'
7271
     */
7272
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7273
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7274
  /*
7275
   *Hack it to assure arg1 is the nodeset
7276
   */
7277
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7278
0
    argtmp = arg2;
7279
0
    arg2 = arg1;
7280
0
    arg1 = argtmp;
7281
0
  }
7282
0
  switch (arg2->type) {
7283
0
      case XPATH_UNDEFINED:
7284
#ifdef DEBUG_EXPR
7285
    xmlGenericError(xmlGenericErrorContext,
7286
      "NotEqual: undefined\n");
7287
#endif
7288
0
    break;
7289
0
      case XPATH_NODESET:
7290
0
      case XPATH_XSLT_TREE:
7291
0
    ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7292
0
    break;
7293
0
      case XPATH_BOOLEAN:
7294
0
    if ((arg1->nodesetval == NULL) ||
7295
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
7296
0
    else
7297
0
        ret = 1;
7298
0
    ret = (ret != arg2->boolval);
7299
0
    break;
7300
0
      case XPATH_NUMBER:
7301
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7302
0
    break;
7303
0
      case XPATH_STRING:
7304
0
    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7305
0
    break;
7306
0
      case XPATH_USERS:
7307
#ifdef LIBXML_XPTR_LOCS_ENABLED
7308
      case XPATH_POINT:
7309
      case XPATH_RANGE:
7310
      case XPATH_LOCATIONSET:
7311
#endif /* LIBXML_XPTR_LOCS_ENABLED */
7312
0
    TODO
7313
0
    break;
7314
0
  }
7315
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7316
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7317
0
  return(ret);
7318
0
    }
7319
7320
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7321
0
}
7322
7323
/**
7324
 * xmlXPathCompareValues:
7325
 * @ctxt:  the XPath Parser context
7326
 * @inf:  less than (1) or greater than (0)
7327
 * @strict:  is the comparison strict
7328
 *
7329
 * Implement the compare operation on XPath objects:
7330
 *     @arg1 < @arg2    (1, 1, ...
7331
 *     @arg1 <= @arg2   (1, 0, ...
7332
 *     @arg1 > @arg2    (0, 1, ...
7333
 *     @arg1 >= @arg2   (0, 0, ...
7334
 *
7335
 * When neither object to be compared is a node-set and the operator is
7336
 * <=, <, >=, >, then the objects are compared by converted both objects
7337
 * to numbers and comparing the numbers according to IEEE 754. The <
7338
 * comparison will be true if and only if the first number is less than the
7339
 * second number. The <= comparison will be true if and only if the first
7340
 * number is less than or equal to the second number. The > comparison
7341
 * will be true if and only if the first number is greater than the second
7342
 * number. The >= comparison will be true if and only if the first number
7343
 * is greater than or equal to the second number.
7344
 *
7345
 * Returns 1 if the comparison succeeded, 0 if it failed
7346
 */
7347
int
7348
0
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7349
0
    int ret = 0, arg1i = 0, arg2i = 0;
7350
0
    xmlXPathObjectPtr arg1, arg2;
7351
7352
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7353
0
    arg2 = valuePop(ctxt);
7354
0
    arg1 = valuePop(ctxt);
7355
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
7356
0
  if (arg1 != NULL)
7357
0
      xmlXPathReleaseObject(ctxt->context, arg1);
7358
0
  else
7359
0
      xmlXPathReleaseObject(ctxt->context, arg2);
7360
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7361
0
    }
7362
7363
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7364
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7365
  /*
7366
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7367
   * are not freed from within this routine; they will be freed from the
7368
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7369
   */
7370
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7371
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7372
0
      ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7373
0
  } else {
7374
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7375
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7376
0
                                arg1, arg2);
7377
0
      } else {
7378
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7379
0
                                arg2, arg1);
7380
0
      }
7381
0
  }
7382
0
  return(ret);
7383
0
    }
7384
7385
0
    if (arg1->type != XPATH_NUMBER) {
7386
0
  valuePush(ctxt, arg1);
7387
0
  xmlXPathNumberFunction(ctxt, 1);
7388
0
  arg1 = valuePop(ctxt);
7389
0
    }
7390
0
    if (arg1->type != XPATH_NUMBER) {
7391
0
  xmlXPathFreeObject(arg1);
7392
0
  xmlXPathFreeObject(arg2);
7393
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7394
0
    }
7395
0
    if (arg2->type != XPATH_NUMBER) {
7396
0
  valuePush(ctxt, arg2);
7397
0
  xmlXPathNumberFunction(ctxt, 1);
7398
0
  arg2 = valuePop(ctxt);
7399
0
    }
7400
0
    if (arg2->type != XPATH_NUMBER) {
7401
0
  xmlXPathReleaseObject(ctxt->context, arg1);
7402
0
  xmlXPathReleaseObject(ctxt->context, arg2);
7403
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
7404
0
    }
7405
    /*
7406
     * Add tests for infinity and nan
7407
     * => feedback on 3.4 for Inf and NaN
7408
     */
7409
    /* Hand check NaN and Infinity comparisons */
7410
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7411
0
  ret=0;
7412
0
    } else {
7413
0
  arg1i=xmlXPathIsInf(arg1->floatval);
7414
0
  arg2i=xmlXPathIsInf(arg2->floatval);
7415
0
  if (inf && strict) {
7416
0
      if ((arg1i == -1 && arg2i != -1) ||
7417
0
    (arg2i == 1 && arg1i != 1)) {
7418
0
    ret = 1;
7419
0
      } else if (arg1i == 0 && arg2i == 0) {
7420
0
    ret = (arg1->floatval < arg2->floatval);
7421
0
      } else {
7422
0
    ret = 0;
7423
0
      }
7424
0
  }
7425
0
  else if (inf && !strict) {
7426
0
      if (arg1i == -1 || arg2i == 1) {
7427
0
    ret = 1;
7428
0
      } else if (arg1i == 0 && arg2i == 0) {
7429
0
    ret = (arg1->floatval <= arg2->floatval);
7430
0
      } else {
7431
0
    ret = 0;
7432
0
      }
7433
0
  }
7434
0
  else if (!inf && strict) {
7435
0
      if ((arg1i == 1 && arg2i != 1) ||
7436
0
    (arg2i == -1 && arg1i != -1)) {
7437
0
    ret = 1;
7438
0
      } else if (arg1i == 0 && arg2i == 0) {
7439
0
    ret = (arg1->floatval > arg2->floatval);
7440
0
      } else {
7441
0
    ret = 0;
7442
0
      }
7443
0
  }
7444
0
  else if (!inf && !strict) {
7445
0
      if (arg1i == 1 || arg2i == -1) {
7446
0
    ret = 1;
7447
0
      } else if (arg1i == 0 && arg2i == 0) {
7448
0
    ret = (arg1->floatval >= arg2->floatval);
7449
0
      } else {
7450
0
    ret = 0;
7451
0
      }
7452
0
  }
7453
0
    }
7454
0
    xmlXPathReleaseObject(ctxt->context, arg1);
7455
0
    xmlXPathReleaseObject(ctxt->context, arg2);
7456
0
    return(ret);
7457
0
}
7458
7459
/**
7460
 * xmlXPathValueFlipSign:
7461
 * @ctxt:  the XPath Parser context
7462
 *
7463
 * Implement the unary - operation on an XPath object
7464
 * The numeric operators convert their operands to numbers as if
7465
 * by calling the number function.
7466
 */
7467
void
7468
0
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7469
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7470
0
    CAST_TO_NUMBER;
7471
0
    CHECK_TYPE(XPATH_NUMBER);
7472
0
    ctxt->value->floatval = -ctxt->value->floatval;
7473
0
}
7474
7475
/**
7476
 * xmlXPathAddValues:
7477
 * @ctxt:  the XPath Parser context
7478
 *
7479
 * Implement the add operation on XPath objects:
7480
 * The numeric operators convert their operands to numbers as if
7481
 * by calling the number function.
7482
 */
7483
void
7484
0
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7485
0
    xmlXPathObjectPtr arg;
7486
0
    double val;
7487
7488
0
    arg = valuePop(ctxt);
7489
0
    if (arg == NULL)
7490
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7491
0
    val = xmlXPathCastToNumber(arg);
7492
0
    xmlXPathReleaseObject(ctxt->context, arg);
7493
0
    CAST_TO_NUMBER;
7494
0
    CHECK_TYPE(XPATH_NUMBER);
7495
0
    ctxt->value->floatval += val;
7496
0
}
7497
7498
/**
7499
 * xmlXPathSubValues:
7500
 * @ctxt:  the XPath Parser context
7501
 *
7502
 * Implement the subtraction operation on XPath objects:
7503
 * The numeric operators convert their operands to numbers as if
7504
 * by calling the number function.
7505
 */
7506
void
7507
0
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7508
0
    xmlXPathObjectPtr arg;
7509
0
    double val;
7510
7511
0
    arg = valuePop(ctxt);
7512
0
    if (arg == NULL)
7513
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7514
0
    val = xmlXPathCastToNumber(arg);
7515
0
    xmlXPathReleaseObject(ctxt->context, arg);
7516
0
    CAST_TO_NUMBER;
7517
0
    CHECK_TYPE(XPATH_NUMBER);
7518
0
    ctxt->value->floatval -= val;
7519
0
}
7520
7521
/**
7522
 * xmlXPathMultValues:
7523
 * @ctxt:  the XPath Parser context
7524
 *
7525
 * Implement the multiply operation on XPath objects:
7526
 * The numeric operators convert their operands to numbers as if
7527
 * by calling the number function.
7528
 */
7529
void
7530
0
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7531
0
    xmlXPathObjectPtr arg;
7532
0
    double val;
7533
7534
0
    arg = valuePop(ctxt);
7535
0
    if (arg == NULL)
7536
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7537
0
    val = xmlXPathCastToNumber(arg);
7538
0
    xmlXPathReleaseObject(ctxt->context, arg);
7539
0
    CAST_TO_NUMBER;
7540
0
    CHECK_TYPE(XPATH_NUMBER);
7541
0
    ctxt->value->floatval *= val;
7542
0
}
7543
7544
/**
7545
 * xmlXPathDivValues:
7546
 * @ctxt:  the XPath Parser context
7547
 *
7548
 * Implement the div operation on XPath objects @arg1 / @arg2:
7549
 * The numeric operators convert their operands to numbers as if
7550
 * by calling the number function.
7551
 */
7552
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7553
void
7554
0
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7555
0
    xmlXPathObjectPtr arg;
7556
0
    double val;
7557
7558
0
    arg = valuePop(ctxt);
7559
0
    if (arg == NULL)
7560
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7561
0
    val = xmlXPathCastToNumber(arg);
7562
0
    xmlXPathReleaseObject(ctxt->context, arg);
7563
0
    CAST_TO_NUMBER;
7564
0
    CHECK_TYPE(XPATH_NUMBER);
7565
0
    ctxt->value->floatval /= val;
7566
0
}
7567
7568
/**
7569
 * xmlXPathModValues:
7570
 * @ctxt:  the XPath Parser context
7571
 *
7572
 * Implement the mod operation on XPath objects: @arg1 / @arg2
7573
 * The numeric operators convert their operands to numbers as if
7574
 * by calling the number function.
7575
 */
7576
void
7577
0
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7578
0
    xmlXPathObjectPtr arg;
7579
0
    double arg1, arg2;
7580
7581
0
    arg = valuePop(ctxt);
7582
0
    if (arg == NULL)
7583
0
  XP_ERROR(XPATH_INVALID_OPERAND);
7584
0
    arg2 = xmlXPathCastToNumber(arg);
7585
0
    xmlXPathReleaseObject(ctxt->context, arg);
7586
0
    CAST_TO_NUMBER;
7587
0
    CHECK_TYPE(XPATH_NUMBER);
7588
0
    arg1 = ctxt->value->floatval;
7589
0
    if (arg2 == 0)
7590
0
  ctxt->value->floatval = xmlXPathNAN;
7591
0
    else {
7592
0
  ctxt->value->floatval = fmod(arg1, arg2);
7593
0
    }
7594
0
}
7595
7596
/************************************************************************
7597
 *                  *
7598
 *    The traversal functions         *
7599
 *                  *
7600
 ************************************************************************/
7601
7602
/*
7603
 * A traversal function enumerates nodes along an axis.
7604
 * Initially it must be called with NULL, and it indicates
7605
 * termination on the axis by returning NULL.
7606
 */
7607
typedef xmlNodePtr (*xmlXPathTraversalFunction)
7608
                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7609
7610
/*
7611
 * xmlXPathTraversalFunctionExt:
7612
 * A traversal function enumerates nodes along an axis.
7613
 * Initially it must be called with NULL, and it indicates
7614
 * termination on the axis by returning NULL.
7615
 * The context node of the traversal is specified via @contextNode.
7616
 */
7617
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7618
                    (xmlNodePtr cur, xmlNodePtr contextNode);
7619
7620
/*
7621
 * xmlXPathNodeSetMergeFunction:
7622
 * Used for merging node sets in xmlXPathCollectAndTest().
7623
 */
7624
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7625
        (xmlNodeSetPtr, xmlNodeSetPtr);
7626
7627
7628
/**
7629
 * xmlXPathNextSelf:
7630
 * @ctxt:  the XPath Parser context
7631
 * @cur:  the current node in the traversal
7632
 *
7633
 * Traversal function for the "self" direction
7634
 * The self axis contains just the context node itself
7635
 *
7636
 * Returns the next element following that axis
7637
 */
7638
xmlNodePtr
7639
0
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7640
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7641
0
    if (cur == NULL)
7642
0
        return(ctxt->context->node);
7643
0
    return(NULL);
7644
0
}
7645
7646
/**
7647
 * xmlXPathNextChild:
7648
 * @ctxt:  the XPath Parser context
7649
 * @cur:  the current node in the traversal
7650
 *
7651
 * Traversal function for the "child" direction
7652
 * The child axis contains the children of the context node in document order.
7653
 *
7654
 * Returns the next element following that axis
7655
 */
7656
xmlNodePtr
7657
0
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7658
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7659
0
    if (cur == NULL) {
7660
0
  if (ctxt->context->node == NULL) return(NULL);
7661
0
  switch (ctxt->context->node->type) {
7662
0
            case XML_ELEMENT_NODE:
7663
0
            case XML_TEXT_NODE:
7664
0
            case XML_CDATA_SECTION_NODE:
7665
0
            case XML_ENTITY_REF_NODE:
7666
0
            case XML_ENTITY_NODE:
7667
0
            case XML_PI_NODE:
7668
0
            case XML_COMMENT_NODE:
7669
0
            case XML_NOTATION_NODE:
7670
0
            case XML_DTD_NODE:
7671
0
    return(ctxt->context->node->children);
7672
0
            case XML_DOCUMENT_NODE:
7673
0
            case XML_DOCUMENT_TYPE_NODE:
7674
0
            case XML_DOCUMENT_FRAG_NODE:
7675
0
            case XML_HTML_DOCUMENT_NODE:
7676
0
    return(((xmlDocPtr) ctxt->context->node)->children);
7677
0
      case XML_ELEMENT_DECL:
7678
0
      case XML_ATTRIBUTE_DECL:
7679
0
      case XML_ENTITY_DECL:
7680
0
            case XML_ATTRIBUTE_NODE:
7681
0
      case XML_NAMESPACE_DECL:
7682
0
      case XML_XINCLUDE_START:
7683
0
      case XML_XINCLUDE_END:
7684
0
    return(NULL);
7685
0
  }
7686
0
  return(NULL);
7687
0
    }
7688
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
7689
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
7690
0
  return(NULL);
7691
0
    return(cur->next);
7692
0
}
7693
7694
/**
7695
 * xmlXPathNextChildElement:
7696
 * @ctxt:  the XPath Parser context
7697
 * @cur:  the current node in the traversal
7698
 *
7699
 * Traversal function for the "child" direction and nodes of type element.
7700
 * The child axis contains the children of the context node in document order.
7701
 *
7702
 * Returns the next element following that axis
7703
 */
7704
static xmlNodePtr
7705
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7706
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7707
0
    if (cur == NULL) {
7708
0
  cur = ctxt->context->node;
7709
0
  if (cur == NULL) return(NULL);
7710
  /*
7711
  * Get the first element child.
7712
  */
7713
0
  switch (cur->type) {
7714
0
            case XML_ELEMENT_NODE:
7715
0
      case XML_DOCUMENT_FRAG_NODE:
7716
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7717
0
            case XML_ENTITY_NODE:
7718
0
    cur = cur->children;
7719
0
    if (cur != NULL) {
7720
0
        if (cur->type == XML_ELEMENT_NODE)
7721
0
      return(cur);
7722
0
        do {
7723
0
      cur = cur->next;
7724
0
        } while ((cur != NULL) &&
7725
0
      (cur->type != XML_ELEMENT_NODE));
7726
0
        return(cur);
7727
0
    }
7728
0
    return(NULL);
7729
0
            case XML_DOCUMENT_NODE:
7730
0
            case XML_HTML_DOCUMENT_NODE:
7731
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
7732
0
      default:
7733
0
    return(NULL);
7734
0
  }
7735
0
  return(NULL);
7736
0
    }
7737
    /*
7738
    * Get the next sibling element node.
7739
    */
7740
0
    switch (cur->type) {
7741
0
  case XML_ELEMENT_NODE:
7742
0
  case XML_TEXT_NODE:
7743
0
  case XML_ENTITY_REF_NODE:
7744
0
  case XML_ENTITY_NODE:
7745
0
  case XML_CDATA_SECTION_NODE:
7746
0
  case XML_PI_NODE:
7747
0
  case XML_COMMENT_NODE:
7748
0
  case XML_XINCLUDE_END:
7749
0
      break;
7750
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7751
0
  default:
7752
0
      return(NULL);
7753
0
    }
7754
0
    if (cur->next != NULL) {
7755
0
  if (cur->next->type == XML_ELEMENT_NODE)
7756
0
      return(cur->next);
7757
0
  cur = cur->next;
7758
0
  do {
7759
0
      cur = cur->next;
7760
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7761
0
  return(cur);
7762
0
    }
7763
0
    return(NULL);
7764
0
}
7765
7766
#if 0
7767
/**
7768
 * xmlXPathNextDescendantOrSelfElemParent:
7769
 * @ctxt:  the XPath Parser context
7770
 * @cur:  the current node in the traversal
7771
 *
7772
 * Traversal function for the "descendant-or-self" axis.
7773
 * Additionally it returns only nodes which can be parents of
7774
 * element nodes.
7775
 *
7776
 *
7777
 * Returns the next element following that axis
7778
 */
7779
static xmlNodePtr
7780
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7781
               xmlNodePtr contextNode)
7782
{
7783
    if (cur == NULL) {
7784
  if (contextNode == NULL)
7785
      return(NULL);
7786
  switch (contextNode->type) {
7787
      case XML_ELEMENT_NODE:
7788
      case XML_XINCLUDE_START:
7789
      case XML_DOCUMENT_FRAG_NODE:
7790
      case XML_DOCUMENT_NODE:
7791
      case XML_HTML_DOCUMENT_NODE:
7792
    return(contextNode);
7793
      default:
7794
    return(NULL);
7795
  }
7796
  return(NULL);
7797
    } else {
7798
  xmlNodePtr start = cur;
7799
7800
  while (cur != NULL) {
7801
      switch (cur->type) {
7802
    case XML_ELEMENT_NODE:
7803
    /* TODO: OK to have XInclude here? */
7804
    case XML_XINCLUDE_START:
7805
    case XML_DOCUMENT_FRAG_NODE:
7806
        if (cur != start)
7807
      return(cur);
7808
        if (cur->children != NULL) {
7809
      cur = cur->children;
7810
      continue;
7811
        }
7812
        break;
7813
    /* Not sure if we need those here. */
7814
    case XML_DOCUMENT_NODE:
7815
    case XML_HTML_DOCUMENT_NODE:
7816
        if (cur != start)
7817
      return(cur);
7818
        return(xmlDocGetRootElement((xmlDocPtr) cur));
7819
    default:
7820
        break;
7821
      }
7822
7823
next_sibling:
7824
      if ((cur == NULL) || (cur == contextNode))
7825
    return(NULL);
7826
      if (cur->next != NULL) {
7827
    cur = cur->next;
7828
      } else {
7829
    cur = cur->parent;
7830
    goto next_sibling;
7831
      }
7832
  }
7833
    }
7834
    return(NULL);
7835
}
7836
#endif
7837
7838
/**
7839
 * xmlXPathNextDescendant:
7840
 * @ctxt:  the XPath Parser context
7841
 * @cur:  the current node in the traversal
7842
 *
7843
 * Traversal function for the "descendant" direction
7844
 * the descendant axis contains the descendants of the context node in document
7845
 * order; a descendant is a child or a child of a child and so on.
7846
 *
7847
 * Returns the next element following that axis
7848
 */
7849
xmlNodePtr
7850
0
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7851
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7852
0
    if (cur == NULL) {
7853
0
  if (ctxt->context->node == NULL)
7854
0
      return(NULL);
7855
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7856
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
7857
0
      return(NULL);
7858
7859
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7860
0
      return(ctxt->context->doc->children);
7861
0
        return(ctxt->context->node->children);
7862
0
    }
7863
7864
0
    if (cur->type == XML_NAMESPACE_DECL)
7865
0
        return(NULL);
7866
0
    if (cur->children != NULL) {
7867
  /*
7868
   * Do not descend on entities declarations
7869
   */
7870
0
  if (cur->children->type != XML_ENTITY_DECL) {
7871
0
      cur = cur->children;
7872
      /*
7873
       * Skip DTDs
7874
       */
7875
0
      if (cur->type != XML_DTD_NODE)
7876
0
    return(cur);
7877
0
  }
7878
0
    }
7879
7880
0
    if (cur == ctxt->context->node) return(NULL);
7881
7882
0
    while (cur->next != NULL) {
7883
0
  cur = cur->next;
7884
0
  if ((cur->type != XML_ENTITY_DECL) &&
7885
0
      (cur->type != XML_DTD_NODE))
7886
0
      return(cur);
7887
0
    }
7888
7889
0
    do {
7890
0
        cur = cur->parent;
7891
0
  if (cur == NULL) break;
7892
0
  if (cur == ctxt->context->node) return(NULL);
7893
0
  if (cur->next != NULL) {
7894
0
      cur = cur->next;
7895
0
      return(cur);
7896
0
  }
7897
0
    } while (cur != NULL);
7898
0
    return(cur);
7899
0
}
7900
7901
/**
7902
 * xmlXPathNextDescendantOrSelf:
7903
 * @ctxt:  the XPath Parser context
7904
 * @cur:  the current node in the traversal
7905
 *
7906
 * Traversal function for the "descendant-or-self" direction
7907
 * the descendant-or-self axis contains the context node and the descendants
7908
 * of the context node in document order; thus the context node is the first
7909
 * node on the axis, and the first child of the context node is the second node
7910
 * on the axis
7911
 *
7912
 * Returns the next element following that axis
7913
 */
7914
xmlNodePtr
7915
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7916
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7917
0
    if (cur == NULL)
7918
0
        return(ctxt->context->node);
7919
7920
0
    if (ctxt->context->node == NULL)
7921
0
        return(NULL);
7922
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7923
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
7924
0
        return(NULL);
7925
7926
0
    return(xmlXPathNextDescendant(ctxt, cur));
7927
0
}
7928
7929
/**
7930
 * xmlXPathNextParent:
7931
 * @ctxt:  the XPath Parser context
7932
 * @cur:  the current node in the traversal
7933
 *
7934
 * Traversal function for the "parent" direction
7935
 * The parent axis contains the parent of the context node, if there is one.
7936
 *
7937
 * Returns the next element following that axis
7938
 */
7939
xmlNodePtr
7940
0
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7941
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7942
    /*
7943
     * the parent of an attribute or namespace node is the element
7944
     * to which the attribute or namespace node is attached
7945
     * Namespace handling !!!
7946
     */
7947
0
    if (cur == NULL) {
7948
0
  if (ctxt->context->node == NULL) return(NULL);
7949
0
  switch (ctxt->context->node->type) {
7950
0
            case XML_ELEMENT_NODE:
7951
0
            case XML_TEXT_NODE:
7952
0
            case XML_CDATA_SECTION_NODE:
7953
0
            case XML_ENTITY_REF_NODE:
7954
0
            case XML_ENTITY_NODE:
7955
0
            case XML_PI_NODE:
7956
0
            case XML_COMMENT_NODE:
7957
0
            case XML_NOTATION_NODE:
7958
0
            case XML_DTD_NODE:
7959
0
      case XML_ELEMENT_DECL:
7960
0
      case XML_ATTRIBUTE_DECL:
7961
0
      case XML_XINCLUDE_START:
7962
0
      case XML_XINCLUDE_END:
7963
0
      case XML_ENTITY_DECL:
7964
0
    if (ctxt->context->node->parent == NULL)
7965
0
        return((xmlNodePtr) ctxt->context->doc);
7966
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7967
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
7968
0
         (xmlStrEqual(ctxt->context->node->parent->name,
7969
0
         BAD_CAST "fake node libxslt"))))
7970
0
        return(NULL);
7971
0
    return(ctxt->context->node->parent);
7972
0
            case XML_ATTRIBUTE_NODE: {
7973
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7974
7975
0
    return(att->parent);
7976
0
      }
7977
0
            case XML_DOCUMENT_NODE:
7978
0
            case XML_DOCUMENT_TYPE_NODE:
7979
0
            case XML_DOCUMENT_FRAG_NODE:
7980
0
            case XML_HTML_DOCUMENT_NODE:
7981
0
                return(NULL);
7982
0
      case XML_NAMESPACE_DECL: {
7983
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7984
7985
0
    if ((ns->next != NULL) &&
7986
0
        (ns->next->type != XML_NAMESPACE_DECL))
7987
0
        return((xmlNodePtr) ns->next);
7988
0
                return(NULL);
7989
0
      }
7990
0
  }
7991
0
    }
7992
0
    return(NULL);
7993
0
}
7994
7995
/**
7996
 * xmlXPathNextAncestor:
7997
 * @ctxt:  the XPath Parser context
7998
 * @cur:  the current node in the traversal
7999
 *
8000
 * Traversal function for the "ancestor" direction
8001
 * the ancestor axis contains the ancestors of the context node; the ancestors
8002
 * of the context node consist of the parent of context node and the parent's
8003
 * parent and so on; the nodes are ordered in reverse document order; thus the
8004
 * parent is the first node on the axis, and the parent's parent is the second
8005
 * node on the axis
8006
 *
8007
 * Returns the next element following that axis
8008
 */
8009
xmlNodePtr
8010
0
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8011
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8012
    /*
8013
     * the parent of an attribute or namespace node is the element
8014
     * to which the attribute or namespace node is attached
8015
     * !!!!!!!!!!!!!
8016
     */
8017
0
    if (cur == NULL) {
8018
0
  if (ctxt->context->node == NULL) return(NULL);
8019
0
  switch (ctxt->context->node->type) {
8020
0
            case XML_ELEMENT_NODE:
8021
0
            case XML_TEXT_NODE:
8022
0
            case XML_CDATA_SECTION_NODE:
8023
0
            case XML_ENTITY_REF_NODE:
8024
0
            case XML_ENTITY_NODE:
8025
0
            case XML_PI_NODE:
8026
0
            case XML_COMMENT_NODE:
8027
0
      case XML_DTD_NODE:
8028
0
      case XML_ELEMENT_DECL:
8029
0
      case XML_ATTRIBUTE_DECL:
8030
0
      case XML_ENTITY_DECL:
8031
0
            case XML_NOTATION_NODE:
8032
0
      case XML_XINCLUDE_START:
8033
0
      case XML_XINCLUDE_END:
8034
0
    if (ctxt->context->node->parent == NULL)
8035
0
        return((xmlNodePtr) ctxt->context->doc);
8036
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8037
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
8038
0
         (xmlStrEqual(ctxt->context->node->parent->name,
8039
0
         BAD_CAST "fake node libxslt"))))
8040
0
        return(NULL);
8041
0
    return(ctxt->context->node->parent);
8042
0
            case XML_ATTRIBUTE_NODE: {
8043
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8044
8045
0
    return(tmp->parent);
8046
0
      }
8047
0
            case XML_DOCUMENT_NODE:
8048
0
            case XML_DOCUMENT_TYPE_NODE:
8049
0
            case XML_DOCUMENT_FRAG_NODE:
8050
0
            case XML_HTML_DOCUMENT_NODE:
8051
0
                return(NULL);
8052
0
      case XML_NAMESPACE_DECL: {
8053
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8054
8055
0
    if ((ns->next != NULL) &&
8056
0
        (ns->next->type != XML_NAMESPACE_DECL))
8057
0
        return((xmlNodePtr) ns->next);
8058
    /* Bad, how did that namespace end up here ? */
8059
0
                return(NULL);
8060
0
      }
8061
0
  }
8062
0
  return(NULL);
8063
0
    }
8064
0
    if (cur == ctxt->context->doc->children)
8065
0
  return((xmlNodePtr) ctxt->context->doc);
8066
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8067
0
  return(NULL);
8068
0
    switch (cur->type) {
8069
0
  case XML_ELEMENT_NODE:
8070
0
  case XML_TEXT_NODE:
8071
0
  case XML_CDATA_SECTION_NODE:
8072
0
  case XML_ENTITY_REF_NODE:
8073
0
  case XML_ENTITY_NODE:
8074
0
  case XML_PI_NODE:
8075
0
  case XML_COMMENT_NODE:
8076
0
  case XML_NOTATION_NODE:
8077
0
  case XML_DTD_NODE:
8078
0
        case XML_ELEMENT_DECL:
8079
0
        case XML_ATTRIBUTE_DECL:
8080
0
        case XML_ENTITY_DECL:
8081
0
  case XML_XINCLUDE_START:
8082
0
  case XML_XINCLUDE_END:
8083
0
      if (cur->parent == NULL)
8084
0
    return(NULL);
8085
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
8086
0
    ((cur->parent->name[0] == ' ') ||
8087
0
     (xmlStrEqual(cur->parent->name,
8088
0
            BAD_CAST "fake node libxslt"))))
8089
0
    return(NULL);
8090
0
      return(cur->parent);
8091
0
  case XML_ATTRIBUTE_NODE: {
8092
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
8093
8094
0
      return(att->parent);
8095
0
  }
8096
0
  case XML_NAMESPACE_DECL: {
8097
0
      xmlNsPtr ns = (xmlNsPtr) cur;
8098
8099
0
      if ((ns->next != NULL) &&
8100
0
          (ns->next->type != XML_NAMESPACE_DECL))
8101
0
          return((xmlNodePtr) ns->next);
8102
      /* Bad, how did that namespace end up here ? */
8103
0
            return(NULL);
8104
0
  }
8105
0
  case XML_DOCUMENT_NODE:
8106
0
  case XML_DOCUMENT_TYPE_NODE:
8107
0
  case XML_DOCUMENT_FRAG_NODE:
8108
0
  case XML_HTML_DOCUMENT_NODE:
8109
0
      return(NULL);
8110
0
    }
8111
0
    return(NULL);
8112
0
}
8113
8114
/**
8115
 * xmlXPathNextAncestorOrSelf:
8116
 * @ctxt:  the XPath Parser context
8117
 * @cur:  the current node in the traversal
8118
 *
8119
 * Traversal function for the "ancestor-or-self" direction
8120
 * he ancestor-or-self axis contains the context node and ancestors of
8121
 * the context node in reverse document order; thus the context node is
8122
 * the first node on the axis, and the context node's parent the second;
8123
 * parent here is defined the same as with the parent axis.
8124
 *
8125
 * Returns the next element following that axis
8126
 */
8127
xmlNodePtr
8128
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8129
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8130
0
    if (cur == NULL)
8131
0
        return(ctxt->context->node);
8132
0
    return(xmlXPathNextAncestor(ctxt, cur));
8133
0
}
8134
8135
/**
8136
 * xmlXPathNextFollowingSibling:
8137
 * @ctxt:  the XPath Parser context
8138
 * @cur:  the current node in the traversal
8139
 *
8140
 * Traversal function for the "following-sibling" direction
8141
 * The following-sibling axis contains the following siblings of the context
8142
 * node in document order.
8143
 *
8144
 * Returns the next element following that axis
8145
 */
8146
xmlNodePtr
8147
0
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8148
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8149
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8150
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8151
0
  return(NULL);
8152
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8153
0
        return(NULL);
8154
0
    if (cur == NULL)
8155
0
        return(ctxt->context->node->next);
8156
0
    return(cur->next);
8157
0
}
8158
8159
/**
8160
 * xmlXPathNextPrecedingSibling:
8161
 * @ctxt:  the XPath Parser context
8162
 * @cur:  the current node in the traversal
8163
 *
8164
 * Traversal function for the "preceding-sibling" direction
8165
 * The preceding-sibling axis contains the preceding siblings of the context
8166
 * node in reverse document order; the first preceding sibling is first on the
8167
 * axis; the sibling preceding that node is the second on the axis and so on.
8168
 *
8169
 * Returns the next element following that axis
8170
 */
8171
xmlNodePtr
8172
0
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8173
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8174
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8175
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
8176
0
  return(NULL);
8177
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
8178
0
        return(NULL);
8179
0
    if (cur == NULL)
8180
0
        return(ctxt->context->node->prev);
8181
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8182
0
  cur = cur->prev;
8183
0
  if (cur == NULL)
8184
0
      return(ctxt->context->node->prev);
8185
0
    }
8186
0
    return(cur->prev);
8187
0
}
8188
8189
/**
8190
 * xmlXPathNextFollowing:
8191
 * @ctxt:  the XPath Parser context
8192
 * @cur:  the current node in the traversal
8193
 *
8194
 * Traversal function for the "following" direction
8195
 * The following axis contains all nodes in the same document as the context
8196
 * node that are after the context node in document order, excluding any
8197
 * descendants and excluding attribute nodes and namespace nodes; the nodes
8198
 * are ordered in document order
8199
 *
8200
 * Returns the next element following that axis
8201
 */
8202
xmlNodePtr
8203
0
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8204
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8205
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
8206
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8207
0
        return(cur->children);
8208
8209
0
    if (cur == NULL) {
8210
0
        cur = ctxt->context->node;
8211
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8212
0
            cur = cur->parent;
8213
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8214
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8215
8216
0
            if ((ns->next == NULL) ||
8217
0
                (ns->next->type == XML_NAMESPACE_DECL))
8218
0
                return (NULL);
8219
0
            cur = (xmlNodePtr) ns->next;
8220
0
        }
8221
0
    }
8222
0
    if (cur == NULL) return(NULL) ; /* ERROR */
8223
0
    if (cur->next != NULL) return(cur->next) ;
8224
0
    do {
8225
0
        cur = cur->parent;
8226
0
        if (cur == NULL) break;
8227
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8228
0
        if (cur->next != NULL) return(cur->next);
8229
0
    } while (cur != NULL);
8230
0
    return(cur);
8231
0
}
8232
8233
/*
8234
 * xmlXPathIsAncestor:
8235
 * @ancestor:  the ancestor node
8236
 * @node:  the current node
8237
 *
8238
 * Check that @ancestor is a @node's ancestor
8239
 *
8240
 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8241
 */
8242
static int
8243
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8244
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
8245
0
    if (node->type == XML_NAMESPACE_DECL)
8246
0
        return(0);
8247
0
    if (ancestor->type == XML_NAMESPACE_DECL)
8248
0
        return(0);
8249
    /* nodes need to be in the same document */
8250
0
    if (ancestor->doc != node->doc) return(0);
8251
    /* avoid searching if ancestor or node is the root node */
8252
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
8253
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
8254
0
    while (node->parent != NULL) {
8255
0
        if (node->parent == ancestor)
8256
0
            return(1);
8257
0
  node = node->parent;
8258
0
    }
8259
0
    return(0);
8260
0
}
8261
8262
/**
8263
 * xmlXPathNextPreceding:
8264
 * @ctxt:  the XPath Parser context
8265
 * @cur:  the current node in the traversal
8266
 *
8267
 * Traversal function for the "preceding" direction
8268
 * the preceding axis contains all nodes in the same document as the context
8269
 * node that are before the context node in document order, excluding any
8270
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8271
 * ordered in reverse document order
8272
 *
8273
 * Returns the next element following that axis
8274
 */
8275
xmlNodePtr
8276
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8277
0
{
8278
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8279
0
    if (cur == NULL) {
8280
0
        cur = ctxt->context->node;
8281
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8282
0
            cur = cur->parent;
8283
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8284
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8285
8286
0
            if ((ns->next == NULL) ||
8287
0
                (ns->next->type == XML_NAMESPACE_DECL))
8288
0
                return (NULL);
8289
0
            cur = (xmlNodePtr) ns->next;
8290
0
        }
8291
0
    }
8292
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8293
0
  return (NULL);
8294
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8295
0
  cur = cur->prev;
8296
0
    do {
8297
0
        if (cur->prev != NULL) {
8298
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8299
0
            return (cur);
8300
0
        }
8301
8302
0
        cur = cur->parent;
8303
0
        if (cur == NULL)
8304
0
            return (NULL);
8305
0
        if (cur == ctxt->context->doc->children)
8306
0
            return (NULL);
8307
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8308
0
    return (cur);
8309
0
}
8310
8311
/**
8312
 * xmlXPathNextPrecedingInternal:
8313
 * @ctxt:  the XPath Parser context
8314
 * @cur:  the current node in the traversal
8315
 *
8316
 * Traversal function for the "preceding" direction
8317
 * the preceding axis contains all nodes in the same document as the context
8318
 * node that are before the context node in document order, excluding any
8319
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8320
 * ordered in reverse document order
8321
 * This is a faster implementation but internal only since it requires a
8322
 * state kept in the parser context: ctxt->ancestor.
8323
 *
8324
 * Returns the next element following that axis
8325
 */
8326
static xmlNodePtr
8327
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8328
                              xmlNodePtr cur)
8329
0
{
8330
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8331
0
    if (cur == NULL) {
8332
0
        cur = ctxt->context->node;
8333
0
        if (cur == NULL)
8334
0
            return (NULL);
8335
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
8336
0
            cur = cur->parent;
8337
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
8338
0
            xmlNsPtr ns = (xmlNsPtr) cur;
8339
8340
0
            if ((ns->next == NULL) ||
8341
0
                (ns->next->type == XML_NAMESPACE_DECL))
8342
0
                return (NULL);
8343
0
            cur = (xmlNodePtr) ns->next;
8344
0
        }
8345
0
        ctxt->ancestor = cur->parent;
8346
0
    }
8347
0
    if (cur->type == XML_NAMESPACE_DECL)
8348
0
        return(NULL);
8349
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8350
0
  cur = cur->prev;
8351
0
    while (cur->prev == NULL) {
8352
0
        cur = cur->parent;
8353
0
        if (cur == NULL)
8354
0
            return (NULL);
8355
0
        if (cur == ctxt->context->doc->children)
8356
0
            return (NULL);
8357
0
        if (cur != ctxt->ancestor)
8358
0
            return (cur);
8359
0
        ctxt->ancestor = cur->parent;
8360
0
    }
8361
0
    cur = cur->prev;
8362
0
    while (cur->last != NULL)
8363
0
        cur = cur->last;
8364
0
    return (cur);
8365
0
}
8366
8367
/**
8368
 * xmlXPathNextNamespace:
8369
 * @ctxt:  the XPath Parser context
8370
 * @cur:  the current attribute in the traversal
8371
 *
8372
 * Traversal function for the "namespace" direction
8373
 * the namespace axis contains the namespace nodes of the context node;
8374
 * the order of nodes on this axis is implementation-defined; the axis will
8375
 * be empty unless the context node is an element
8376
 *
8377
 * We keep the XML namespace node at the end of the list.
8378
 *
8379
 * Returns the next element following that axis
8380
 */
8381
xmlNodePtr
8382
0
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8383
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8384
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8385
0
    if (cur == NULL) {
8386
0
        if (ctxt->context->tmpNsList != NULL)
8387
0
      xmlFree(ctxt->context->tmpNsList);
8388
0
  ctxt->context->tmpNsList =
8389
0
      xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8390
0
  ctxt->context->tmpNsNr = 0;
8391
0
  if (ctxt->context->tmpNsList != NULL) {
8392
0
      while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8393
0
    ctxt->context->tmpNsNr++;
8394
0
      }
8395
0
  }
8396
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
8397
0
    }
8398
0
    if (ctxt->context->tmpNsNr > 0) {
8399
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8400
0
    } else {
8401
0
  if (ctxt->context->tmpNsList != NULL)
8402
0
      xmlFree(ctxt->context->tmpNsList);
8403
0
  ctxt->context->tmpNsList = NULL;
8404
0
  return(NULL);
8405
0
    }
8406
0
}
8407
8408
/**
8409
 * xmlXPathNextAttribute:
8410
 * @ctxt:  the XPath Parser context
8411
 * @cur:  the current attribute in the traversal
8412
 *
8413
 * Traversal function for the "attribute" direction
8414
 * TODO: support DTD inherited default attributes
8415
 *
8416
 * Returns the next element following that axis
8417
 */
8418
xmlNodePtr
8419
0
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8420
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8421
0
    if (ctxt->context->node == NULL)
8422
0
  return(NULL);
8423
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
8424
0
  return(NULL);
8425
0
    if (cur == NULL) {
8426
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8427
0
      return(NULL);
8428
0
        return((xmlNodePtr)ctxt->context->node->properties);
8429
0
    }
8430
0
    return((xmlNodePtr)cur->next);
8431
0
}
8432
8433
/************************************************************************
8434
 *                  *
8435
 *    NodeTest Functions          *
8436
 *                  *
8437
 ************************************************************************/
8438
8439
#define IS_FUNCTION     200
8440
8441
8442
/************************************************************************
8443
 *                  *
8444
 *    Implicit tree core function library     *
8445
 *                  *
8446
 ************************************************************************/
8447
8448
/**
8449
 * xmlXPathRoot:
8450
 * @ctxt:  the XPath Parser context
8451
 *
8452
 * Initialize the context to the root of the document
8453
 */
8454
void
8455
0
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8456
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
8457
0
  return;
8458
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8459
0
  (xmlNodePtr) ctxt->context->doc));
8460
0
}
8461
8462
/************************************************************************
8463
 *                  *
8464
 *    The explicit core function library      *
8465
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8466
 *                  *
8467
 ************************************************************************/
8468
8469
8470
/**
8471
 * xmlXPathLastFunction:
8472
 * @ctxt:  the XPath Parser context
8473
 * @nargs:  the number of arguments
8474
 *
8475
 * Implement the last() XPath function
8476
 *    number last()
8477
 * The last function returns the number of nodes in the context node list.
8478
 */
8479
void
8480
0
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8481
0
    CHECK_ARITY(0);
8482
0
    if (ctxt->context->contextSize >= 0) {
8483
0
  valuePush(ctxt,
8484
0
      xmlXPathCacheNewFloat(ctxt->context,
8485
0
    (double) ctxt->context->contextSize));
8486
#ifdef DEBUG_EXPR
8487
  xmlGenericError(xmlGenericErrorContext,
8488
    "last() : %d\n", ctxt->context->contextSize);
8489
#endif
8490
0
    } else {
8491
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8492
0
    }
8493
0
}
8494
8495
/**
8496
 * xmlXPathPositionFunction:
8497
 * @ctxt:  the XPath Parser context
8498
 * @nargs:  the number of arguments
8499
 *
8500
 * Implement the position() XPath function
8501
 *    number position()
8502
 * The position function returns the position of the context node in the
8503
 * context node list. The first position is 1, and so the last position
8504
 * will be equal to last().
8505
 */
8506
void
8507
0
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8508
0
    CHECK_ARITY(0);
8509
0
    if (ctxt->context->proximityPosition >= 0) {
8510
0
  valuePush(ctxt,
8511
0
        xmlXPathCacheNewFloat(ctxt->context,
8512
0
    (double) ctxt->context->proximityPosition));
8513
#ifdef DEBUG_EXPR
8514
  xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8515
    ctxt->context->proximityPosition);
8516
#endif
8517
0
    } else {
8518
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8519
0
    }
8520
0
}
8521
8522
/**
8523
 * xmlXPathCountFunction:
8524
 * @ctxt:  the XPath Parser context
8525
 * @nargs:  the number of arguments
8526
 *
8527
 * Implement the count() XPath function
8528
 *    number count(node-set)
8529
 */
8530
void
8531
0
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8532
0
    xmlXPathObjectPtr cur;
8533
8534
0
    CHECK_ARITY(1);
8535
0
    if ((ctxt->value == NULL) ||
8536
0
  ((ctxt->value->type != XPATH_NODESET) &&
8537
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8538
0
  XP_ERROR(XPATH_INVALID_TYPE);
8539
0
    cur = valuePop(ctxt);
8540
8541
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
8542
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8543
0
    else
8544
0
  valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8545
0
      (double) cur->nodesetval->nodeNr));
8546
0
    xmlXPathReleaseObject(ctxt->context, cur);
8547
0
}
8548
8549
/**
8550
 * xmlXPathGetElementsByIds:
8551
 * @doc:  the document
8552
 * @ids:  a whitespace separated list of IDs
8553
 *
8554
 * Selects elements by their unique ID.
8555
 *
8556
 * Returns a node-set of selected elements.
8557
 */
8558
static xmlNodeSetPtr
8559
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8560
0
    xmlNodeSetPtr ret;
8561
0
    const xmlChar *cur = ids;
8562
0
    xmlChar *ID;
8563
0
    xmlAttrPtr attr;
8564
0
    xmlNodePtr elem = NULL;
8565
8566
0
    if (ids == NULL) return(NULL);
8567
8568
0
    ret = xmlXPathNodeSetCreate(NULL);
8569
0
    if (ret == NULL)
8570
0
        return(ret);
8571
8572
0
    while (IS_BLANK_CH(*cur)) cur++;
8573
0
    while (*cur != 0) {
8574
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8575
0
      cur++;
8576
8577
0
        ID = xmlStrndup(ids, cur - ids);
8578
0
  if (ID != NULL) {
8579
      /*
8580
       * We used to check the fact that the value passed
8581
       * was an NCName, but this generated much troubles for
8582
       * me and Aleksey Sanin, people blatantly violated that
8583
       * constraint, like Visa3D spec.
8584
       * if (xmlValidateNCName(ID, 1) == 0)
8585
       */
8586
0
      attr = xmlGetID(doc, ID);
8587
0
      if (attr != NULL) {
8588
0
    if (attr->type == XML_ATTRIBUTE_NODE)
8589
0
        elem = attr->parent;
8590
0
    else if (attr->type == XML_ELEMENT_NODE)
8591
0
        elem = (xmlNodePtr) attr;
8592
0
    else
8593
0
        elem = NULL;
8594
                /* TODO: Check memory error. */
8595
0
    if (elem != NULL)
8596
0
        xmlXPathNodeSetAdd(ret, elem);
8597
0
      }
8598
0
      xmlFree(ID);
8599
0
  }
8600
8601
0
  while (IS_BLANK_CH(*cur)) cur++;
8602
0
  ids = cur;
8603
0
    }
8604
0
    return(ret);
8605
0
}
8606
8607
/**
8608
 * xmlXPathIdFunction:
8609
 * @ctxt:  the XPath Parser context
8610
 * @nargs:  the number of arguments
8611
 *
8612
 * Implement the id() XPath function
8613
 *    node-set id(object)
8614
 * The id function selects elements by their unique ID
8615
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8616
 * then the result is the union of the result of applying id to the
8617
 * string value of each of the nodes in the argument node-set. When the
8618
 * argument to id is of any other type, the argument is converted to a
8619
 * string as if by a call to the string function; the string is split
8620
 * into a whitespace-separated list of tokens (whitespace is any sequence
8621
 * of characters matching the production S); the result is a node-set
8622
 * containing the elements in the same document as the context node that
8623
 * have a unique ID equal to any of the tokens in the list.
8624
 */
8625
void
8626
0
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8627
0
    xmlChar *tokens;
8628
0
    xmlNodeSetPtr ret;
8629
0
    xmlXPathObjectPtr obj;
8630
8631
0
    CHECK_ARITY(1);
8632
0
    obj = valuePop(ctxt);
8633
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8634
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8635
0
  xmlNodeSetPtr ns;
8636
0
  int i;
8637
8638
        /* TODO: Check memory error. */
8639
0
  ret = xmlXPathNodeSetCreate(NULL);
8640
8641
0
  if (obj->nodesetval != NULL) {
8642
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8643
0
    tokens =
8644
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8645
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8646
                /* TODO: Check memory error. */
8647
0
    ret = xmlXPathNodeSetMerge(ret, ns);
8648
0
    xmlXPathFreeNodeSet(ns);
8649
0
    if (tokens != NULL)
8650
0
        xmlFree(tokens);
8651
0
      }
8652
0
  }
8653
0
  xmlXPathReleaseObject(ctxt->context, obj);
8654
0
  valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8655
0
  return;
8656
0
    }
8657
0
    obj = xmlXPathCacheConvertString(ctxt->context, obj);
8658
0
    if (obj == NULL) return;
8659
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8660
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8661
0
    xmlXPathReleaseObject(ctxt->context, obj);
8662
0
    return;
8663
0
}
8664
8665
/**
8666
 * xmlXPathLocalNameFunction:
8667
 * @ctxt:  the XPath Parser context
8668
 * @nargs:  the number of arguments
8669
 *
8670
 * Implement the local-name() XPath function
8671
 *    string local-name(node-set?)
8672
 * The local-name function returns a string containing the local part
8673
 * of the name of the node in the argument node-set that is first in
8674
 * document order. If the node-set is empty or the first node has no
8675
 * name, an empty string is returned. If the argument is omitted it
8676
 * defaults to the context node.
8677
 */
8678
void
8679
0
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8680
0
    xmlXPathObjectPtr cur;
8681
8682
0
    if (ctxt == NULL) return;
8683
8684
0
    if (nargs == 0) {
8685
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8686
0
      ctxt->context->node));
8687
0
  nargs = 1;
8688
0
    }
8689
8690
0
    CHECK_ARITY(1);
8691
0
    if ((ctxt->value == NULL) ||
8692
0
  ((ctxt->value->type != XPATH_NODESET) &&
8693
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8694
0
  XP_ERROR(XPATH_INVALID_TYPE);
8695
0
    cur = valuePop(ctxt);
8696
8697
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8698
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8699
0
    } else {
8700
0
  int i = 0; /* Should be first in document order !!!!! */
8701
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8702
0
  case XML_ELEMENT_NODE:
8703
0
  case XML_ATTRIBUTE_NODE:
8704
0
  case XML_PI_NODE:
8705
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8706
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8707
0
      else
8708
0
    valuePush(ctxt,
8709
0
          xmlXPathCacheNewString(ctxt->context,
8710
0
      cur->nodesetval->nodeTab[i]->name));
8711
0
      break;
8712
0
  case XML_NAMESPACE_DECL:
8713
0
      valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8714
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8715
0
      break;
8716
0
  default:
8717
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8718
0
  }
8719
0
    }
8720
0
    xmlXPathReleaseObject(ctxt->context, cur);
8721
0
}
8722
8723
/**
8724
 * xmlXPathNamespaceURIFunction:
8725
 * @ctxt:  the XPath Parser context
8726
 * @nargs:  the number of arguments
8727
 *
8728
 * Implement the namespace-uri() XPath function
8729
 *    string namespace-uri(node-set?)
8730
 * The namespace-uri function returns a string containing the
8731
 * namespace URI of the expanded name of the node in the argument
8732
 * node-set that is first in document order. If the node-set is empty,
8733
 * the first node has no name, or the expanded name has no namespace
8734
 * URI, an empty string is returned. If the argument is omitted it
8735
 * defaults to the context node.
8736
 */
8737
void
8738
0
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8739
0
    xmlXPathObjectPtr cur;
8740
8741
0
    if (ctxt == NULL) return;
8742
8743
0
    if (nargs == 0) {
8744
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8745
0
      ctxt->context->node));
8746
0
  nargs = 1;
8747
0
    }
8748
0
    CHECK_ARITY(1);
8749
0
    if ((ctxt->value == NULL) ||
8750
0
  ((ctxt->value->type != XPATH_NODESET) &&
8751
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
8752
0
  XP_ERROR(XPATH_INVALID_TYPE);
8753
0
    cur = valuePop(ctxt);
8754
8755
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8756
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8757
0
    } else {
8758
0
  int i = 0; /* Should be first in document order !!!!! */
8759
0
  switch (cur->nodesetval->nodeTab[i]->type) {
8760
0
  case XML_ELEMENT_NODE:
8761
0
  case XML_ATTRIBUTE_NODE:
8762
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
8763
0
    valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8764
0
      else
8765
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8766
0
        cur->nodesetval->nodeTab[i]->ns->href));
8767
0
      break;
8768
0
  default:
8769
0
      valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8770
0
  }
8771
0
    }
8772
0
    xmlXPathReleaseObject(ctxt->context, cur);
8773
0
}
8774
8775
/**
8776
 * xmlXPathNameFunction:
8777
 * @ctxt:  the XPath Parser context
8778
 * @nargs:  the number of arguments
8779
 *
8780
 * Implement the name() XPath function
8781
 *    string name(node-set?)
8782
 * The name function returns a string containing a QName representing
8783
 * the name of the node in the argument node-set that is first in document
8784
 * order. The QName must represent the name with respect to the namespace
8785
 * declarations in effect on the node whose name is being represented.
8786
 * Typically, this will be the form in which the name occurred in the XML
8787
 * source. This need not be the case if there are namespace declarations
8788
 * in effect on the node that associate multiple prefixes with the same
8789
 * namespace. However, an implementation may include information about
8790
 * the original prefix in its representation of nodes; in this case, an
8791
 * implementation can ensure that the returned string is always the same
8792
 * as the QName used in the XML source. If the argument it omitted it
8793
 * defaults to the context node.
8794
 * Libxml keep the original prefix so the "real qualified name" used is
8795
 * returned.
8796
 */
8797
static void
8798
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8799
0
{
8800
0
    xmlXPathObjectPtr cur;
8801
8802
0
    if (nargs == 0) {
8803
0
  valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8804
0
      ctxt->context->node));
8805
0
        nargs = 1;
8806
0
    }
8807
8808
0
    CHECK_ARITY(1);
8809
0
    if ((ctxt->value == NULL) ||
8810
0
        ((ctxt->value->type != XPATH_NODESET) &&
8811
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
8812
0
        XP_ERROR(XPATH_INVALID_TYPE);
8813
0
    cur = valuePop(ctxt);
8814
8815
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8816
0
        valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8817
0
    } else {
8818
0
        int i = 0;              /* Should be first in document order !!!!! */
8819
8820
0
        switch (cur->nodesetval->nodeTab[i]->type) {
8821
0
            case XML_ELEMENT_NODE:
8822
0
            case XML_ATTRIBUTE_NODE:
8823
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8824
0
        valuePush(ctxt,
8825
0
      xmlXPathCacheNewCString(ctxt->context, ""));
8826
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8827
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8828
0
        valuePush(ctxt,
8829
0
            xmlXPathCacheNewString(ctxt->context,
8830
0
          cur->nodesetval->nodeTab[i]->name));
8831
0
    } else {
8832
0
        xmlChar *fullname;
8833
8834
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8835
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
8836
0
             NULL, 0);
8837
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
8838
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8839
0
        if (fullname == NULL) {
8840
0
      XP_ERROR(XPATH_MEMORY_ERROR);
8841
0
        }
8842
0
        valuePush(ctxt, xmlXPathCacheWrapString(
8843
0
      ctxt->context, fullname));
8844
0
                }
8845
0
                break;
8846
0
            default:
8847
0
    valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8848
0
        cur->nodesetval->nodeTab[i]));
8849
0
                xmlXPathLocalNameFunction(ctxt, 1);
8850
0
        }
8851
0
    }
8852
0
    xmlXPathReleaseObject(ctxt->context, cur);
8853
0
}
8854
8855
8856
/**
8857
 * xmlXPathStringFunction:
8858
 * @ctxt:  the XPath Parser context
8859
 * @nargs:  the number of arguments
8860
 *
8861
 * Implement the string() XPath function
8862
 *    string string(object?)
8863
 * The string function converts an object to a string as follows:
8864
 *    - A node-set is converted to a string by returning the value of
8865
 *      the node in the node-set that is first in document order.
8866
 *      If the node-set is empty, an empty string is returned.
8867
 *    - A number is converted to a string as follows
8868
 *      + NaN is converted to the string NaN
8869
 *      + positive zero is converted to the string 0
8870
 *      + negative zero is converted to the string 0
8871
 *      + positive infinity is converted to the string Infinity
8872
 *      + negative infinity is converted to the string -Infinity
8873
 *      + if the number is an integer, the number is represented in
8874
 *        decimal form as a Number with no decimal point and no leading
8875
 *        zeros, preceded by a minus sign (-) if the number is negative
8876
 *      + otherwise, the number is represented in decimal form as a
8877
 *        Number including a decimal point with at least one digit
8878
 *        before the decimal point and at least one digit after the
8879
 *        decimal point, preceded by a minus sign (-) if the number
8880
 *        is negative; there must be no leading zeros before the decimal
8881
 *        point apart possibly from the one required digit immediately
8882
 *        before the decimal point; beyond the one required digit
8883
 *        after the decimal point there must be as many, but only as
8884
 *        many, more digits as are needed to uniquely distinguish the
8885
 *        number from all other IEEE 754 numeric values.
8886
 *    - The boolean false value is converted to the string false.
8887
 *      The boolean true value is converted to the string true.
8888
 *
8889
 * If the argument is omitted, it defaults to a node-set with the
8890
 * context node as its only member.
8891
 */
8892
void
8893
0
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8894
0
    xmlXPathObjectPtr cur;
8895
8896
0
    if (ctxt == NULL) return;
8897
0
    if (nargs == 0) {
8898
0
    valuePush(ctxt,
8899
0
  xmlXPathCacheWrapString(ctxt->context,
8900
0
      xmlXPathCastNodeToString(ctxt->context->node)));
8901
0
  return;
8902
0
    }
8903
8904
0
    CHECK_ARITY(1);
8905
0
    cur = valuePop(ctxt);
8906
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8907
0
    valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8908
0
}
8909
8910
/**
8911
 * xmlXPathStringLengthFunction:
8912
 * @ctxt:  the XPath Parser context
8913
 * @nargs:  the number of arguments
8914
 *
8915
 * Implement the string-length() XPath function
8916
 *    number string-length(string?)
8917
 * The string-length returns the number of characters in the string
8918
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8919
 * the context node converted to a string, in other words the value
8920
 * of the context node.
8921
 */
8922
void
8923
0
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8924
0
    xmlXPathObjectPtr cur;
8925
8926
0
    if (nargs == 0) {
8927
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
8928
0
      return;
8929
0
  if (ctxt->context->node == NULL) {
8930
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8931
0
  } else {
8932
0
      xmlChar *content;
8933
8934
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
8935
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8936
0
    xmlUTF8Strlen(content)));
8937
0
      xmlFree(content);
8938
0
  }
8939
0
  return;
8940
0
    }
8941
0
    CHECK_ARITY(1);
8942
0
    CAST_TO_STRING;
8943
0
    CHECK_TYPE(XPATH_STRING);
8944
0
    cur = valuePop(ctxt);
8945
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8946
0
  xmlUTF8Strlen(cur->stringval)));
8947
0
    xmlXPathReleaseObject(ctxt->context, cur);
8948
0
}
8949
8950
/**
8951
 * xmlXPathConcatFunction:
8952
 * @ctxt:  the XPath Parser context
8953
 * @nargs:  the number of arguments
8954
 *
8955
 * Implement the concat() XPath function
8956
 *    string concat(string, string, string*)
8957
 * The concat function returns the concatenation of its arguments.
8958
 */
8959
void
8960
0
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8961
0
    xmlXPathObjectPtr cur, newobj;
8962
0
    xmlChar *tmp;
8963
8964
0
    if (ctxt == NULL) return;
8965
0
    if (nargs < 2) {
8966
0
  CHECK_ARITY(2);
8967
0
    }
8968
8969
0
    CAST_TO_STRING;
8970
0
    cur = valuePop(ctxt);
8971
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8972
0
  xmlXPathReleaseObject(ctxt->context, cur);
8973
0
  return;
8974
0
    }
8975
0
    nargs--;
8976
8977
0
    while (nargs > 0) {
8978
0
  CAST_TO_STRING;
8979
0
  newobj = valuePop(ctxt);
8980
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8981
0
      xmlXPathReleaseObject(ctxt->context, newobj);
8982
0
      xmlXPathReleaseObject(ctxt->context, cur);
8983
0
      XP_ERROR(XPATH_INVALID_TYPE);
8984
0
  }
8985
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
8986
0
  newobj->stringval = cur->stringval;
8987
0
  cur->stringval = tmp;
8988
0
  xmlXPathReleaseObject(ctxt->context, newobj);
8989
0
  nargs--;
8990
0
    }
8991
0
    valuePush(ctxt, cur);
8992
0
}
8993
8994
/**
8995
 * xmlXPathContainsFunction:
8996
 * @ctxt:  the XPath Parser context
8997
 * @nargs:  the number of arguments
8998
 *
8999
 * Implement the contains() XPath function
9000
 *    boolean contains(string, string)
9001
 * The contains function returns true if the first argument string
9002
 * contains the second argument string, and otherwise returns false.
9003
 */
9004
void
9005
0
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9006
0
    xmlXPathObjectPtr hay, needle;
9007
9008
0
    CHECK_ARITY(2);
9009
0
    CAST_TO_STRING;
9010
0
    CHECK_TYPE(XPATH_STRING);
9011
0
    needle = valuePop(ctxt);
9012
0
    CAST_TO_STRING;
9013
0
    hay = valuePop(ctxt);
9014
9015
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9016
0
  xmlXPathReleaseObject(ctxt->context, hay);
9017
0
  xmlXPathReleaseObject(ctxt->context, needle);
9018
0
  XP_ERROR(XPATH_INVALID_TYPE);
9019
0
    }
9020
0
    if (xmlStrstr(hay->stringval, needle->stringval))
9021
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9022
0
    else
9023
0
  valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9024
0
    xmlXPathReleaseObject(ctxt->context, hay);
9025
0
    xmlXPathReleaseObject(ctxt->context, needle);
9026
0
}
9027
9028
/**
9029
 * xmlXPathStartsWithFunction:
9030
 * @ctxt:  the XPath Parser context
9031
 * @nargs:  the number of arguments
9032
 *
9033
 * Implement the starts-with() XPath function
9034
 *    boolean starts-with(string, string)
9035
 * The starts-with function returns true if the first argument string
9036
 * starts with the second argument string, and otherwise returns false.
9037
 */
9038
void
9039
0
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9040
0
    xmlXPathObjectPtr hay, needle;
9041
0
    int n;
9042
9043
0
    CHECK_ARITY(2);
9044
0
    CAST_TO_STRING;
9045
0
    CHECK_TYPE(XPATH_STRING);
9046
0
    needle = valuePop(ctxt);
9047
0
    CAST_TO_STRING;
9048
0
    hay = valuePop(ctxt);
9049
9050
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9051
0
  xmlXPathReleaseObject(ctxt->context, hay);
9052
0
  xmlXPathReleaseObject(ctxt->context, needle);
9053
0
  XP_ERROR(XPATH_INVALID_TYPE);
9054
0
    }
9055
0
    n = xmlStrlen(needle->stringval);
9056
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
9057
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9058
0
    else
9059
0
        valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9060
0
    xmlXPathReleaseObject(ctxt->context, hay);
9061
0
    xmlXPathReleaseObject(ctxt->context, needle);
9062
0
}
9063
9064
/**
9065
 * xmlXPathSubstringFunction:
9066
 * @ctxt:  the XPath Parser context
9067
 * @nargs:  the number of arguments
9068
 *
9069
 * Implement the substring() XPath function
9070
 *    string substring(string, number, number?)
9071
 * The substring function returns the substring of the first argument
9072
 * starting at the position specified in the second argument with
9073
 * length specified in the third argument. For example,
9074
 * substring("12345",2,3) returns "234". If the third argument is not
9075
 * specified, it returns the substring starting at the position specified
9076
 * in the second argument and continuing to the end of the string. For
9077
 * example, substring("12345",2) returns "2345".  More precisely, each
9078
 * character in the string (see [3.6 Strings]) is considered to have a
9079
 * numeric position: the position of the first character is 1, the position
9080
 * of the second character is 2 and so on. The returned substring contains
9081
 * those characters for which the position of the character is greater than
9082
 * or equal to the second argument and, if the third argument is specified,
9083
 * less than the sum of the second and third arguments; the comparisons
9084
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9085
 *  - substring("12345", 1.5, 2.6) returns "234"
9086
 *  - substring("12345", 0, 3) returns "12"
9087
 *  - substring("12345", 0 div 0, 3) returns ""
9088
 *  - substring("12345", 1, 0 div 0) returns ""
9089
 *  - substring("12345", -42, 1 div 0) returns "12345"
9090
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
9091
 */
9092
void
9093
0
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9094
0
    xmlXPathObjectPtr str, start, len;
9095
0
    double le=0, in;
9096
0
    int i = 1, j = INT_MAX;
9097
9098
0
    if (nargs < 2) {
9099
0
  CHECK_ARITY(2);
9100
0
    }
9101
0
    if (nargs > 3) {
9102
0
  CHECK_ARITY(3);
9103
0
    }
9104
    /*
9105
     * take care of possible last (position) argument
9106
    */
9107
0
    if (nargs == 3) {
9108
0
  CAST_TO_NUMBER;
9109
0
  CHECK_TYPE(XPATH_NUMBER);
9110
0
  len = valuePop(ctxt);
9111
0
  le = len->floatval;
9112
0
  xmlXPathReleaseObject(ctxt->context, len);
9113
0
    }
9114
9115
0
    CAST_TO_NUMBER;
9116
0
    CHECK_TYPE(XPATH_NUMBER);
9117
0
    start = valuePop(ctxt);
9118
0
    in = start->floatval;
9119
0
    xmlXPathReleaseObject(ctxt->context, start);
9120
0
    CAST_TO_STRING;
9121
0
    CHECK_TYPE(XPATH_STRING);
9122
0
    str = valuePop(ctxt);
9123
9124
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
9125
0
        i = INT_MAX;
9126
0
    } else if (in >= 1.0) {
9127
0
        i = (int)in;
9128
0
        if (in - floor(in) >= 0.5)
9129
0
            i += 1;
9130
0
    }
9131
9132
0
    if (nargs == 3) {
9133
0
        double rin, rle, end;
9134
9135
0
        rin = floor(in);
9136
0
        if (in - rin >= 0.5)
9137
0
            rin += 1.0;
9138
9139
0
        rle = floor(le);
9140
0
        if (le - rle >= 0.5)
9141
0
            rle += 1.0;
9142
9143
0
        end = rin + rle;
9144
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
9145
0
            j = 1;
9146
0
        } else if (end < INT_MAX) {
9147
0
            j = (int)end;
9148
0
        }
9149
0
    }
9150
9151
0
    if (i < j) {
9152
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
9153
0
  valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9154
0
  xmlFree(ret);
9155
0
    } else {
9156
0
  valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9157
0
    }
9158
9159
0
    xmlXPathReleaseObject(ctxt->context, str);
9160
0
}
9161
9162
/**
9163
 * xmlXPathSubstringBeforeFunction:
9164
 * @ctxt:  the XPath Parser context
9165
 * @nargs:  the number of arguments
9166
 *
9167
 * Implement the substring-before() XPath function
9168
 *    string substring-before(string, string)
9169
 * The substring-before function returns the substring of the first
9170
 * argument string that precedes the first occurrence of the second
9171
 * argument string in the first argument string, or the empty string
9172
 * if the first argument string does not contain the second argument
9173
 * string. For example, substring-before("1999/04/01","/") returns 1999.
9174
 */
9175
void
9176
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9177
0
  xmlXPathObjectPtr str;
9178
0
  xmlXPathObjectPtr find;
9179
0
  xmlBufPtr target;
9180
0
  const xmlChar *point;
9181
0
  int offset;
9182
9183
0
  CHECK_ARITY(2);
9184
0
  CAST_TO_STRING;
9185
0
  find = valuePop(ctxt);
9186
0
  CAST_TO_STRING;
9187
0
  str = valuePop(ctxt);
9188
9189
0
  target = xmlBufCreate();
9190
0
  if (target) {
9191
0
    point = xmlStrstr(str->stringval, find->stringval);
9192
0
    if (point) {
9193
0
      offset = (int)(point - str->stringval);
9194
0
      xmlBufAdd(target, str->stringval, offset);
9195
0
    }
9196
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9197
0
  xmlBufContent(target)));
9198
0
    xmlBufFree(target);
9199
0
  }
9200
0
  xmlXPathReleaseObject(ctxt->context, str);
9201
0
  xmlXPathReleaseObject(ctxt->context, find);
9202
0
}
9203
9204
/**
9205
 * xmlXPathSubstringAfterFunction:
9206
 * @ctxt:  the XPath Parser context
9207
 * @nargs:  the number of arguments
9208
 *
9209
 * Implement the substring-after() XPath function
9210
 *    string substring-after(string, string)
9211
 * The substring-after function returns the substring of the first
9212
 * argument string that follows the first occurrence of the second
9213
 * argument string in the first argument string, or the empty stringi
9214
 * if the first argument string does not contain the second argument
9215
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9216
 * and substring-after("1999/04/01","19") returns 99/04/01.
9217
 */
9218
void
9219
0
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9220
0
  xmlXPathObjectPtr str;
9221
0
  xmlXPathObjectPtr find;
9222
0
  xmlBufPtr target;
9223
0
  const xmlChar *point;
9224
0
  int offset;
9225
9226
0
  CHECK_ARITY(2);
9227
0
  CAST_TO_STRING;
9228
0
  find = valuePop(ctxt);
9229
0
  CAST_TO_STRING;
9230
0
  str = valuePop(ctxt);
9231
9232
0
  target = xmlBufCreate();
9233
0
  if (target) {
9234
0
    point = xmlStrstr(str->stringval, find->stringval);
9235
0
    if (point) {
9236
0
      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9237
0
      xmlBufAdd(target, &str->stringval[offset],
9238
0
       xmlStrlen(str->stringval) - offset);
9239
0
    }
9240
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9241
0
  xmlBufContent(target)));
9242
0
    xmlBufFree(target);
9243
0
  }
9244
0
  xmlXPathReleaseObject(ctxt->context, str);
9245
0
  xmlXPathReleaseObject(ctxt->context, find);
9246
0
}
9247
9248
/**
9249
 * xmlXPathNormalizeFunction:
9250
 * @ctxt:  the XPath Parser context
9251
 * @nargs:  the number of arguments
9252
 *
9253
 * Implement the normalize-space() XPath function
9254
 *    string normalize-space(string?)
9255
 * The normalize-space function returns the argument string with white
9256
 * space normalized by stripping leading and trailing whitespace
9257
 * and replacing sequences of whitespace characters by a single
9258
 * space. Whitespace characters are the same allowed by the S production
9259
 * in XML. If the argument is omitted, it defaults to the context
9260
 * node converted to a string, in other words the value of the context node.
9261
 */
9262
void
9263
0
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9264
0
    xmlChar *source, *target;
9265
0
    int blank;
9266
9267
0
    if (ctxt == NULL) return;
9268
0
    if (nargs == 0) {
9269
        /* Use current context node */
9270
0
        valuePush(ctxt,
9271
0
            xmlXPathCacheWrapString(ctxt->context,
9272
0
                xmlXPathCastNodeToString(ctxt->context->node)));
9273
0
        nargs = 1;
9274
0
    }
9275
9276
0
    CHECK_ARITY(1);
9277
0
    CAST_TO_STRING;
9278
0
    CHECK_TYPE(XPATH_STRING);
9279
0
    source = ctxt->value->stringval;
9280
0
    if (source == NULL)
9281
0
        return;
9282
0
    target = source;
9283
9284
    /* Skip leading whitespaces */
9285
0
    while (IS_BLANK_CH(*source))
9286
0
        source++;
9287
9288
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9289
0
    blank = 0;
9290
0
    while (*source) {
9291
0
        if (IS_BLANK_CH(*source)) {
9292
0
      blank = 1;
9293
0
        } else {
9294
0
            if (blank) {
9295
0
                *target++ = 0x20;
9296
0
                blank = 0;
9297
0
            }
9298
0
            *target++ = *source;
9299
0
        }
9300
0
        source++;
9301
0
    }
9302
0
    *target = 0;
9303
0
}
9304
9305
/**
9306
 * xmlXPathTranslateFunction:
9307
 * @ctxt:  the XPath Parser context
9308
 * @nargs:  the number of arguments
9309
 *
9310
 * Implement the translate() XPath function
9311
 *    string translate(string, string, string)
9312
 * The translate function returns the first argument string with
9313
 * occurrences of characters in the second argument string replaced
9314
 * by the character at the corresponding position in the third argument
9315
 * string. For example, translate("bar","abc","ABC") returns the string
9316
 * BAr. If there is a character in the second argument string with no
9317
 * character at a corresponding position in the third argument string
9318
 * (because the second argument string is longer than the third argument
9319
 * string), then occurrences of that character in the first argument
9320
 * string are removed. For example, translate("--aaa--","abc-","ABC")
9321
 * returns "AAA". If a character occurs more than once in second
9322
 * argument string, then the first occurrence determines the replacement
9323
 * character. If the third argument string is longer than the second
9324
 * argument string, then excess characters are ignored.
9325
 */
9326
void
9327
0
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9328
0
    xmlXPathObjectPtr str;
9329
0
    xmlXPathObjectPtr from;
9330
0
    xmlXPathObjectPtr to;
9331
0
    xmlBufPtr target;
9332
0
    int offset, max;
9333
0
    xmlChar ch;
9334
0
    const xmlChar *point;
9335
0
    xmlChar *cptr;
9336
9337
0
    CHECK_ARITY(3);
9338
9339
0
    CAST_TO_STRING;
9340
0
    to = valuePop(ctxt);
9341
0
    CAST_TO_STRING;
9342
0
    from = valuePop(ctxt);
9343
0
    CAST_TO_STRING;
9344
0
    str = valuePop(ctxt);
9345
9346
0
    target = xmlBufCreate();
9347
0
    if (target) {
9348
0
  max = xmlUTF8Strlen(to->stringval);
9349
0
  for (cptr = str->stringval; (ch=*cptr); ) {
9350
0
      offset = xmlUTF8Strloc(from->stringval, cptr);
9351
0
      if (offset >= 0) {
9352
0
    if (offset < max) {
9353
0
        point = xmlUTF8Strpos(to->stringval, offset);
9354
0
        if (point)
9355
0
      xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9356
0
    }
9357
0
      } else
9358
0
    xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9359
9360
      /* Step to next character in input */
9361
0
      cptr++;
9362
0
      if ( ch & 0x80 ) {
9363
    /* if not simple ascii, verify proper format */
9364
0
    if ( (ch & 0xc0) != 0xc0 ) {
9365
0
        xmlGenericError(xmlGenericErrorContext,
9366
0
      "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9367
                    /* not asserting an XPath error is probably better */
9368
0
        break;
9369
0
    }
9370
    /* then skip over remaining bytes for this char */
9371
0
    while ( (ch <<= 1) & 0x80 )
9372
0
        if ( (*cptr++ & 0xc0) != 0x80 ) {
9373
0
      xmlGenericError(xmlGenericErrorContext,
9374
0
          "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9375
                        /* not asserting an XPath error is probably better */
9376
0
      break;
9377
0
        }
9378
0
    if (ch & 0x80) /* must have had error encountered */
9379
0
        break;
9380
0
      }
9381
0
  }
9382
0
    }
9383
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9384
0
  xmlBufContent(target)));
9385
0
    xmlBufFree(target);
9386
0
    xmlXPathReleaseObject(ctxt->context, str);
9387
0
    xmlXPathReleaseObject(ctxt->context, from);
9388
0
    xmlXPathReleaseObject(ctxt->context, to);
9389
0
}
9390
9391
/**
9392
 * xmlXPathBooleanFunction:
9393
 * @ctxt:  the XPath Parser context
9394
 * @nargs:  the number of arguments
9395
 *
9396
 * Implement the boolean() XPath function
9397
 *    boolean boolean(object)
9398
 * The boolean function converts its argument to a boolean as follows:
9399
 *    - a number is true if and only if it is neither positive or
9400
 *      negative zero nor NaN
9401
 *    - a node-set is true if and only if it is non-empty
9402
 *    - a string is true if and only if its length is non-zero
9403
 */
9404
void
9405
0
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9406
0
    xmlXPathObjectPtr cur;
9407
9408
0
    CHECK_ARITY(1);
9409
0
    cur = valuePop(ctxt);
9410
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9411
0
    cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9412
0
    valuePush(ctxt, cur);
9413
0
}
9414
9415
/**
9416
 * xmlXPathNotFunction:
9417
 * @ctxt:  the XPath Parser context
9418
 * @nargs:  the number of arguments
9419
 *
9420
 * Implement the not() XPath function
9421
 *    boolean not(boolean)
9422
 * The not function returns true if its argument is false,
9423
 * and false otherwise.
9424
 */
9425
void
9426
0
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9427
0
    CHECK_ARITY(1);
9428
0
    CAST_TO_BOOLEAN;
9429
0
    CHECK_TYPE(XPATH_BOOLEAN);
9430
0
    ctxt->value->boolval = ! ctxt->value->boolval;
9431
0
}
9432
9433
/**
9434
 * xmlXPathTrueFunction:
9435
 * @ctxt:  the XPath Parser context
9436
 * @nargs:  the number of arguments
9437
 *
9438
 * Implement the true() XPath function
9439
 *    boolean true()
9440
 */
9441
void
9442
0
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9443
0
    CHECK_ARITY(0);
9444
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9445
0
}
9446
9447
/**
9448
 * xmlXPathFalseFunction:
9449
 * @ctxt:  the XPath Parser context
9450
 * @nargs:  the number of arguments
9451
 *
9452
 * Implement the false() XPath function
9453
 *    boolean false()
9454
 */
9455
void
9456
0
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9457
0
    CHECK_ARITY(0);
9458
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9459
0
}
9460
9461
/**
9462
 * xmlXPathLangFunction:
9463
 * @ctxt:  the XPath Parser context
9464
 * @nargs:  the number of arguments
9465
 *
9466
 * Implement the lang() XPath function
9467
 *    boolean lang(string)
9468
 * The lang function returns true or false depending on whether the
9469
 * language of the context node as specified by xml:lang attributes
9470
 * is the same as or is a sublanguage of the language specified by
9471
 * the argument string. The language of the context node is determined
9472
 * by the value of the xml:lang attribute on the context node, or, if
9473
 * the context node has no xml:lang attribute, by the value of the
9474
 * xml:lang attribute on the nearest ancestor of the context node that
9475
 * has an xml:lang attribute. If there is no such attribute, then lang
9476
 * returns false. If there is such an attribute, then lang returns
9477
 * true if the attribute value is equal to the argument ignoring case,
9478
 * or if there is some suffix starting with - such that the attribute
9479
 * value is equal to the argument ignoring that suffix of the attribute
9480
 * value and ignoring case.
9481
 */
9482
void
9483
0
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9484
0
    xmlXPathObjectPtr val = NULL;
9485
0
    const xmlChar *theLang = NULL;
9486
0
    const xmlChar *lang;
9487
0
    int ret = 0;
9488
0
    int i;
9489
9490
0
    CHECK_ARITY(1);
9491
0
    CAST_TO_STRING;
9492
0
    CHECK_TYPE(XPATH_STRING);
9493
0
    val = valuePop(ctxt);
9494
0
    lang = val->stringval;
9495
0
    theLang = xmlNodeGetLang(ctxt->context->node);
9496
0
    if ((theLang != NULL) && (lang != NULL)) {
9497
0
        for (i = 0;lang[i] != 0;i++)
9498
0
      if (toupper(lang[i]) != toupper(theLang[i]))
9499
0
          goto not_equal;
9500
0
  if ((theLang[i] == 0) || (theLang[i] == '-'))
9501
0
      ret = 1;
9502
0
    }
9503
0
not_equal:
9504
0
    if (theLang != NULL)
9505
0
  xmlFree((void *)theLang);
9506
9507
0
    xmlXPathReleaseObject(ctxt->context, val);
9508
0
    valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9509
0
}
9510
9511
/**
9512
 * xmlXPathNumberFunction:
9513
 * @ctxt:  the XPath Parser context
9514
 * @nargs:  the number of arguments
9515
 *
9516
 * Implement the number() XPath function
9517
 *    number number(object?)
9518
 */
9519
void
9520
0
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9521
0
    xmlXPathObjectPtr cur;
9522
0
    double res;
9523
9524
0
    if (ctxt == NULL) return;
9525
0
    if (nargs == 0) {
9526
0
  if (ctxt->context->node == NULL) {
9527
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9528
0
  } else {
9529
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9530
9531
0
      res = xmlXPathStringEvalNumber(content);
9532
0
      valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9533
0
      xmlFree(content);
9534
0
  }
9535
0
  return;
9536
0
    }
9537
9538
0
    CHECK_ARITY(1);
9539
0
    cur = valuePop(ctxt);
9540
0
    valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9541
0
}
9542
9543
/**
9544
 * xmlXPathSumFunction:
9545
 * @ctxt:  the XPath Parser context
9546
 * @nargs:  the number of arguments
9547
 *
9548
 * Implement the sum() XPath function
9549
 *    number sum(node-set)
9550
 * The sum function returns the sum of the values of the nodes in
9551
 * the argument node-set.
9552
 */
9553
void
9554
0
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9555
0
    xmlXPathObjectPtr cur;
9556
0
    int i;
9557
0
    double res = 0.0;
9558
9559
0
    CHECK_ARITY(1);
9560
0
    if ((ctxt->value == NULL) ||
9561
0
  ((ctxt->value->type != XPATH_NODESET) &&
9562
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
9563
0
  XP_ERROR(XPATH_INVALID_TYPE);
9564
0
    cur = valuePop(ctxt);
9565
9566
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9567
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9568
0
      res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9569
0
  }
9570
0
    }
9571
0
    valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9572
0
    xmlXPathReleaseObject(ctxt->context, cur);
9573
0
}
9574
9575
/**
9576
 * xmlXPathFloorFunction:
9577
 * @ctxt:  the XPath Parser context
9578
 * @nargs:  the number of arguments
9579
 *
9580
 * Implement the floor() XPath function
9581
 *    number floor(number)
9582
 * The floor function returns the largest (closest to positive infinity)
9583
 * number that is not greater than the argument and that is an integer.
9584
 */
9585
void
9586
0
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9587
0
    CHECK_ARITY(1);
9588
0
    CAST_TO_NUMBER;
9589
0
    CHECK_TYPE(XPATH_NUMBER);
9590
9591
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
9592
0
}
9593
9594
/**
9595
 * xmlXPathCeilingFunction:
9596
 * @ctxt:  the XPath Parser context
9597
 * @nargs:  the number of arguments
9598
 *
9599
 * Implement the ceiling() XPath function
9600
 *    number ceiling(number)
9601
 * The ceiling function returns the smallest (closest to negative infinity)
9602
 * number that is not less than the argument and that is an integer.
9603
 */
9604
void
9605
0
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9606
0
    CHECK_ARITY(1);
9607
0
    CAST_TO_NUMBER;
9608
0
    CHECK_TYPE(XPATH_NUMBER);
9609
9610
#ifdef _AIX
9611
    /* Work around buggy ceil() function on AIX */
9612
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
9613
#else
9614
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
9615
0
#endif
9616
0
}
9617
9618
/**
9619
 * xmlXPathRoundFunction:
9620
 * @ctxt:  the XPath Parser context
9621
 * @nargs:  the number of arguments
9622
 *
9623
 * Implement the round() XPath function
9624
 *    number round(number)
9625
 * The round function returns the number that is closest to the
9626
 * argument and that is an integer. If there are two such numbers,
9627
 * then the one that is closest to positive infinity is returned.
9628
 */
9629
void
9630
0
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9631
0
    double f;
9632
9633
0
    CHECK_ARITY(1);
9634
0
    CAST_TO_NUMBER;
9635
0
    CHECK_TYPE(XPATH_NUMBER);
9636
9637
0
    f = ctxt->value->floatval;
9638
9639
0
    if ((f >= -0.5) && (f < 0.5)) {
9640
        /* Handles negative zero. */
9641
0
        ctxt->value->floatval *= 0.0;
9642
0
    }
9643
0
    else {
9644
0
        double rounded = floor(f);
9645
0
        if (f - rounded >= 0.5)
9646
0
            rounded += 1.0;
9647
0
        ctxt->value->floatval = rounded;
9648
0
    }
9649
0
}
9650
9651
/************************************************************************
9652
 *                  *
9653
 *      The Parser          *
9654
 *                  *
9655
 ************************************************************************/
9656
9657
/*
9658
 * a few forward declarations since we use a recursive call based
9659
 * implementation.
9660
 */
9661
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9662
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9663
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9664
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9665
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9666
                                    int qualified);
9667
9668
/**
9669
 * xmlXPathCurrentChar:
9670
 * @ctxt:  the XPath parser context
9671
 * @cur:  pointer to the beginning of the char
9672
 * @len:  pointer to the length of the char read
9673
 *
9674
 * The current char value, if using UTF-8 this may actually span multiple
9675
 * bytes in the input buffer.
9676
 *
9677
 * Returns the current char value and its length
9678
 */
9679
9680
static int
9681
0
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9682
0
    unsigned char c;
9683
0
    unsigned int val;
9684
0
    const xmlChar *cur;
9685
9686
0
    if (ctxt == NULL)
9687
0
  return(0);
9688
0
    cur = ctxt->cur;
9689
9690
    /*
9691
     * We are supposed to handle UTF8, check it's valid
9692
     * From rfc2044: encoding of the Unicode values on UTF-8:
9693
     *
9694
     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
9695
     * 0000 0000-0000 007F   0xxxxxxx
9696
     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
9697
     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
9698
     *
9699
     * Check for the 0x110000 limit too
9700
     */
9701
0
    c = *cur;
9702
0
    if (c & 0x80) {
9703
0
  if ((cur[1] & 0xc0) != 0x80)
9704
0
      goto encoding_error;
9705
0
  if ((c & 0xe0) == 0xe0) {
9706
9707
0
      if ((cur[2] & 0xc0) != 0x80)
9708
0
    goto encoding_error;
9709
0
      if ((c & 0xf0) == 0xf0) {
9710
0
    if (((c & 0xf8) != 0xf0) ||
9711
0
        ((cur[3] & 0xc0) != 0x80))
9712
0
        goto encoding_error;
9713
    /* 4-byte code */
9714
0
    *len = 4;
9715
0
    val = (cur[0] & 0x7) << 18;
9716
0
    val |= (cur[1] & 0x3f) << 12;
9717
0
    val |= (cur[2] & 0x3f) << 6;
9718
0
    val |= cur[3] & 0x3f;
9719
0
      } else {
9720
        /* 3-byte code */
9721
0
    *len = 3;
9722
0
    val = (cur[0] & 0xf) << 12;
9723
0
    val |= (cur[1] & 0x3f) << 6;
9724
0
    val |= cur[2] & 0x3f;
9725
0
      }
9726
0
  } else {
9727
    /* 2-byte code */
9728
0
      *len = 2;
9729
0
      val = (cur[0] & 0x1f) << 6;
9730
0
      val |= cur[1] & 0x3f;
9731
0
  }
9732
0
  if (!IS_CHAR(val)) {
9733
0
      XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9734
0
  }
9735
0
  return(val);
9736
0
    } else {
9737
  /* 1-byte code */
9738
0
  *len = 1;
9739
0
  return((int) *cur);
9740
0
    }
9741
0
encoding_error:
9742
    /*
9743
     * If we detect an UTF8 error that probably means that the
9744
     * input encoding didn't get properly advertised in the
9745
     * declaration header. Report the error and switch the encoding
9746
     * to ISO-Latin-1 (if you don't like this policy, just declare the
9747
     * encoding !)
9748
     */
9749
0
    *len = 0;
9750
0
    XP_ERROR0(XPATH_ENCODING_ERROR);
9751
0
}
9752
9753
/**
9754
 * xmlXPathParseNCName:
9755
 * @ctxt:  the XPath Parser context
9756
 *
9757
 * parse an XML namespace non qualified name.
9758
 *
9759
 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9760
 *
9761
 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9762
 *                       CombiningChar | Extender
9763
 *
9764
 * Returns the namespace name or NULL
9765
 */
9766
9767
xmlChar *
9768
0
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9769
0
    const xmlChar *in;
9770
0
    xmlChar *ret;
9771
0
    int count = 0;
9772
9773
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9774
    /*
9775
     * Accelerator for simple ASCII names
9776
     */
9777
0
    in = ctxt->cur;
9778
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9779
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9780
0
  (*in == '_')) {
9781
0
  in++;
9782
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9783
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9784
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9785
0
         (*in == '_') || (*in == '.') ||
9786
0
         (*in == '-'))
9787
0
      in++;
9788
0
  if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9789
0
            (*in == '[') || (*in == ']') || (*in == ':') ||
9790
0
            (*in == '@') || (*in == '*')) {
9791
0
      count = in - ctxt->cur;
9792
0
      if (count == 0)
9793
0
    return(NULL);
9794
0
      ret = xmlStrndup(ctxt->cur, count);
9795
0
      ctxt->cur = in;
9796
0
      return(ret);
9797
0
  }
9798
0
    }
9799
0
    return(xmlXPathParseNameComplex(ctxt, 0));
9800
0
}
9801
9802
9803
/**
9804
 * xmlXPathParseQName:
9805
 * @ctxt:  the XPath Parser context
9806
 * @prefix:  a xmlChar **
9807
 *
9808
 * parse an XML qualified name
9809
 *
9810
 * [NS 5] QName ::= (Prefix ':')? LocalPart
9811
 *
9812
 * [NS 6] Prefix ::= NCName
9813
 *
9814
 * [NS 7] LocalPart ::= NCName
9815
 *
9816
 * Returns the function returns the local part, and prefix is updated
9817
 *   to get the Prefix if any.
9818
 */
9819
9820
static xmlChar *
9821
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9822
0
    xmlChar *ret = NULL;
9823
9824
0
    *prefix = NULL;
9825
0
    ret = xmlXPathParseNCName(ctxt);
9826
0
    if (ret && CUR == ':') {
9827
0
        *prefix = ret;
9828
0
  NEXT;
9829
0
  ret = xmlXPathParseNCName(ctxt);
9830
0
    }
9831
0
    return(ret);
9832
0
}
9833
9834
/**
9835
 * xmlXPathParseName:
9836
 * @ctxt:  the XPath Parser context
9837
 *
9838
 * parse an XML name
9839
 *
9840
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9841
 *                  CombiningChar | Extender
9842
 *
9843
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9844
 *
9845
 * Returns the namespace name or NULL
9846
 */
9847
9848
xmlChar *
9849
0
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9850
0
    const xmlChar *in;
9851
0
    xmlChar *ret;
9852
0
    size_t count = 0;
9853
9854
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9855
    /*
9856
     * Accelerator for simple ASCII names
9857
     */
9858
0
    in = ctxt->cur;
9859
0
    if (((*in >= 0x61) && (*in <= 0x7A)) ||
9860
0
  ((*in >= 0x41) && (*in <= 0x5A)) ||
9861
0
  (*in == '_') || (*in == ':')) {
9862
0
  in++;
9863
0
  while (((*in >= 0x61) && (*in <= 0x7A)) ||
9864
0
         ((*in >= 0x41) && (*in <= 0x5A)) ||
9865
0
         ((*in >= 0x30) && (*in <= 0x39)) ||
9866
0
         (*in == '_') || (*in == '-') ||
9867
0
         (*in == ':') || (*in == '.'))
9868
0
      in++;
9869
0
  if ((*in > 0) && (*in < 0x80)) {
9870
0
      count = in - ctxt->cur;
9871
0
            if (count > XML_MAX_NAME_LENGTH) {
9872
0
                ctxt->cur = in;
9873
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9874
0
            }
9875
0
      ret = xmlStrndup(ctxt->cur, count);
9876
0
      ctxt->cur = in;
9877
0
      return(ret);
9878
0
  }
9879
0
    }
9880
0
    return(xmlXPathParseNameComplex(ctxt, 1));
9881
0
}
9882
9883
static xmlChar *
9884
0
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9885
0
    xmlChar buf[XML_MAX_NAMELEN + 5];
9886
0
    int len = 0, l;
9887
0
    int c;
9888
9889
    /*
9890
     * Handler for more complex cases
9891
     */
9892
0
    c = CUR_CHAR(l);
9893
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9894
0
        (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9895
0
        (c == '*') || /* accelerators */
9896
0
  (!IS_LETTER(c) && (c != '_') &&
9897
0
         ((!qualified) || (c != ':')))) {
9898
0
  return(NULL);
9899
0
    }
9900
9901
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9902
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9903
0
            (c == '.') || (c == '-') ||
9904
0
      (c == '_') || ((qualified) && (c == ':')) ||
9905
0
      (IS_COMBINING(c)) ||
9906
0
      (IS_EXTENDER(c)))) {
9907
0
  COPY_BUF(l,buf,len,c);
9908
0
  NEXTL(l);
9909
0
  c = CUR_CHAR(l);
9910
0
  if (len >= XML_MAX_NAMELEN) {
9911
      /*
9912
       * Okay someone managed to make a huge name, so he's ready to pay
9913
       * for the processing speed.
9914
       */
9915
0
      xmlChar *buffer;
9916
0
      int max = len * 2;
9917
9918
0
            if (len > XML_MAX_NAME_LENGTH) {
9919
0
                XP_ERRORNULL(XPATH_EXPR_ERROR);
9920
0
            }
9921
0
      buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9922
0
      if (buffer == NULL) {
9923
0
    XP_ERRORNULL(XPATH_MEMORY_ERROR);
9924
0
      }
9925
0
      memcpy(buffer, buf, len);
9926
0
      while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9927
0
       (c == '.') || (c == '-') ||
9928
0
       (c == '_') || ((qualified) && (c == ':')) ||
9929
0
       (IS_COMBINING(c)) ||
9930
0
       (IS_EXTENDER(c))) {
9931
0
    if (len + 10 > max) {
9932
0
                    xmlChar *tmp;
9933
0
                    if (max > XML_MAX_NAME_LENGTH) {
9934
0
                        xmlFree(buffer);
9935
0
                        XP_ERRORNULL(XPATH_EXPR_ERROR);
9936
0
                    }
9937
0
        max *= 2;
9938
0
        tmp = (xmlChar *) xmlRealloc(buffer,
9939
0
                               max * sizeof(xmlChar));
9940
0
        if (tmp == NULL) {
9941
0
                        xmlFree(buffer);
9942
0
      XP_ERRORNULL(XPATH_MEMORY_ERROR);
9943
0
        }
9944
0
                    buffer = tmp;
9945
0
    }
9946
0
    COPY_BUF(l,buffer,len,c);
9947
0
    NEXTL(l);
9948
0
    c = CUR_CHAR(l);
9949
0
      }
9950
0
      buffer[len] = 0;
9951
0
      return(buffer);
9952
0
  }
9953
0
    }
9954
0
    if (len == 0)
9955
0
  return(NULL);
9956
0
    return(xmlStrndup(buf, len));
9957
0
}
9958
9959
0
#define MAX_FRAC 20
9960
9961
/**
9962
 * xmlXPathStringEvalNumber:
9963
 * @str:  A string to scan
9964
 *
9965
 *  [30a]  Float  ::= Number ('e' Digits?)?
9966
 *
9967
 *  [30]   Number ::=   Digits ('.' Digits?)?
9968
 *                    | '.' Digits
9969
 *  [31]   Digits ::=   [0-9]+
9970
 *
9971
 * Compile a Number in the string
9972
 * In complement of the Number expression, this function also handles
9973
 * negative values : '-' Number.
9974
 *
9975
 * Returns the double value.
9976
 */
9977
double
9978
0
xmlXPathStringEvalNumber(const xmlChar *str) {
9979
0
    const xmlChar *cur = str;
9980
0
    double ret;
9981
0
    int ok = 0;
9982
0
    int isneg = 0;
9983
0
    int exponent = 0;
9984
0
    int is_exponent_negative = 0;
9985
0
#ifdef __GNUC__
9986
0
    unsigned long tmp = 0;
9987
0
    double temp;
9988
0
#endif
9989
0
    if (cur == NULL) return(0);
9990
0
    while (IS_BLANK_CH(*cur)) cur++;
9991
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9992
0
        return(xmlXPathNAN);
9993
0
    }
9994
0
    if (*cur == '-') {
9995
0
  isneg = 1;
9996
0
  cur++;
9997
0
    }
9998
9999
0
#ifdef __GNUC__
10000
    /*
10001
     * tmp/temp is a workaround against a gcc compiler bug
10002
     * http://veillard.com/gcc.bug
10003
     */
10004
0
    ret = 0;
10005
0
    while ((*cur >= '0') && (*cur <= '9')) {
10006
0
  ret = ret * 10;
10007
0
  tmp = (*cur - '0');
10008
0
  ok = 1;
10009
0
  cur++;
10010
0
  temp = (double) tmp;
10011
0
  ret = ret + temp;
10012
0
    }
10013
#else
10014
    ret = 0;
10015
    while ((*cur >= '0') && (*cur <= '9')) {
10016
  ret = ret * 10 + (*cur - '0');
10017
  ok = 1;
10018
  cur++;
10019
    }
10020
#endif
10021
10022
0
    if (*cur == '.') {
10023
0
  int v, frac = 0, max;
10024
0
  double fraction = 0;
10025
10026
0
        cur++;
10027
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10028
0
      return(xmlXPathNAN);
10029
0
  }
10030
0
        while (*cur == '0') {
10031
0
      frac = frac + 1;
10032
0
      cur++;
10033
0
        }
10034
0
        max = frac + MAX_FRAC;
10035
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10036
0
      v = (*cur - '0');
10037
0
      fraction = fraction * 10 + v;
10038
0
      frac = frac + 1;
10039
0
      cur++;
10040
0
  }
10041
0
  fraction /= pow(10.0, frac);
10042
0
  ret = ret + fraction;
10043
0
  while ((*cur >= '0') && (*cur <= '9'))
10044
0
      cur++;
10045
0
    }
10046
0
    if ((*cur == 'e') || (*cur == 'E')) {
10047
0
      cur++;
10048
0
      if (*cur == '-') {
10049
0
  is_exponent_negative = 1;
10050
0
  cur++;
10051
0
      } else if (*cur == '+') {
10052
0
        cur++;
10053
0
      }
10054
0
      while ((*cur >= '0') && (*cur <= '9')) {
10055
0
        if (exponent < 1000000)
10056
0
    exponent = exponent * 10 + (*cur - '0');
10057
0
  cur++;
10058
0
      }
10059
0
    }
10060
0
    while (IS_BLANK_CH(*cur)) cur++;
10061
0
    if (*cur != 0) return(xmlXPathNAN);
10062
0
    if (isneg) ret = -ret;
10063
0
    if (is_exponent_negative) exponent = -exponent;
10064
0
    ret *= pow(10.0, (double)exponent);
10065
0
    return(ret);
10066
0
}
10067
10068
/**
10069
 * xmlXPathCompNumber:
10070
 * @ctxt:  the XPath Parser context
10071
 *
10072
 *  [30]   Number ::=   Digits ('.' Digits?)?
10073
 *                    | '.' Digits
10074
 *  [31]   Digits ::=   [0-9]+
10075
 *
10076
 * Compile a Number, then push it on the stack
10077
 *
10078
 */
10079
static void
10080
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10081
0
{
10082
0
    double ret = 0.0;
10083
0
    int ok = 0;
10084
0
    int exponent = 0;
10085
0
    int is_exponent_negative = 0;
10086
0
    xmlXPathObjectPtr num;
10087
0
#ifdef __GNUC__
10088
0
    unsigned long tmp = 0;
10089
0
    double temp;
10090
0
#endif
10091
10092
0
    CHECK_ERROR;
10093
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10094
0
        XP_ERROR(XPATH_NUMBER_ERROR);
10095
0
    }
10096
0
#ifdef __GNUC__
10097
    /*
10098
     * tmp/temp is a workaround against a gcc compiler bug
10099
     * http://veillard.com/gcc.bug
10100
     */
10101
0
    ret = 0;
10102
0
    while ((CUR >= '0') && (CUR <= '9')) {
10103
0
  ret = ret * 10;
10104
0
  tmp = (CUR - '0');
10105
0
        ok = 1;
10106
0
        NEXT;
10107
0
  temp = (double) tmp;
10108
0
  ret = ret + temp;
10109
0
    }
10110
#else
10111
    ret = 0;
10112
    while ((CUR >= '0') && (CUR <= '9')) {
10113
  ret = ret * 10 + (CUR - '0');
10114
  ok = 1;
10115
  NEXT;
10116
    }
10117
#endif
10118
0
    if (CUR == '.') {
10119
0
  int v, frac = 0, max;
10120
0
  double fraction = 0;
10121
10122
0
        NEXT;
10123
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10124
0
            XP_ERROR(XPATH_NUMBER_ERROR);
10125
0
        }
10126
0
        while (CUR == '0') {
10127
0
            frac = frac + 1;
10128
0
            NEXT;
10129
0
        }
10130
0
        max = frac + MAX_FRAC;
10131
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10132
0
      v = (CUR - '0');
10133
0
      fraction = fraction * 10 + v;
10134
0
      frac = frac + 1;
10135
0
            NEXT;
10136
0
        }
10137
0
        fraction /= pow(10.0, frac);
10138
0
        ret = ret + fraction;
10139
0
        while ((CUR >= '0') && (CUR <= '9'))
10140
0
            NEXT;
10141
0
    }
10142
0
    if ((CUR == 'e') || (CUR == 'E')) {
10143
0
        NEXT;
10144
0
        if (CUR == '-') {
10145
0
            is_exponent_negative = 1;
10146
0
            NEXT;
10147
0
        } else if (CUR == '+') {
10148
0
      NEXT;
10149
0
  }
10150
0
        while ((CUR >= '0') && (CUR <= '9')) {
10151
0
            if (exponent < 1000000)
10152
0
                exponent = exponent * 10 + (CUR - '0');
10153
0
            NEXT;
10154
0
        }
10155
0
        if (is_exponent_negative)
10156
0
            exponent = -exponent;
10157
0
        ret *= pow(10.0, (double) exponent);
10158
0
    }
10159
0
    num = xmlXPathCacheNewFloat(ctxt->context, ret);
10160
0
    if (num == NULL) {
10161
0
  ctxt->error = XPATH_MEMORY_ERROR;
10162
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
10163
0
                              NULL) == -1) {
10164
0
        xmlXPathReleaseObject(ctxt->context, num);
10165
0
    }
10166
0
}
10167
10168
/**
10169
 * xmlXPathParseLiteral:
10170
 * @ctxt:  the XPath Parser context
10171
 *
10172
 * Parse a Literal
10173
 *
10174
 *  [29]   Literal ::=   '"' [^"]* '"'
10175
 *                    | "'" [^']* "'"
10176
 *
10177
 * Returns the value found or NULL in case of error
10178
 */
10179
static xmlChar *
10180
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10181
0
    const xmlChar *q;
10182
0
    xmlChar *ret = NULL;
10183
10184
0
    if (CUR == '"') {
10185
0
        NEXT;
10186
0
  q = CUR_PTR;
10187
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10188
0
      NEXT;
10189
0
  if (!IS_CHAR_CH(CUR)) {
10190
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10191
0
  } else {
10192
0
      ret = xmlStrndup(q, CUR_PTR - q);
10193
0
      NEXT;
10194
0
        }
10195
0
    } else if (CUR == '\'') {
10196
0
        NEXT;
10197
0
  q = CUR_PTR;
10198
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10199
0
      NEXT;
10200
0
  if (!IS_CHAR_CH(CUR)) {
10201
0
      XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10202
0
  } else {
10203
0
      ret = xmlStrndup(q, CUR_PTR - q);
10204
0
      NEXT;
10205
0
        }
10206
0
    } else {
10207
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10208
0
    }
10209
0
    return(ret);
10210
0
}
10211
10212
/**
10213
 * xmlXPathCompLiteral:
10214
 * @ctxt:  the XPath Parser context
10215
 *
10216
 * Parse a Literal and push it on the stack.
10217
 *
10218
 *  [29]   Literal ::=   '"' [^"]* '"'
10219
 *                    | "'" [^']* "'"
10220
 *
10221
 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10222
 */
10223
static void
10224
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10225
0
    const xmlChar *q;
10226
0
    xmlChar *ret = NULL;
10227
0
    xmlXPathObjectPtr lit;
10228
10229
0
    if (CUR == '"') {
10230
0
        NEXT;
10231
0
  q = CUR_PTR;
10232
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10233
0
      NEXT;
10234
0
  if (!IS_CHAR_CH(CUR)) {
10235
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10236
0
  } else {
10237
0
      ret = xmlStrndup(q, CUR_PTR - q);
10238
0
      NEXT;
10239
0
        }
10240
0
    } else if (CUR == '\'') {
10241
0
        NEXT;
10242
0
  q = CUR_PTR;
10243
0
  while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10244
0
      NEXT;
10245
0
  if (!IS_CHAR_CH(CUR)) {
10246
0
      XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10247
0
  } else {
10248
0
      ret = xmlStrndup(q, CUR_PTR - q);
10249
0
      NEXT;
10250
0
        }
10251
0
    } else {
10252
0
  XP_ERROR(XPATH_START_LITERAL_ERROR);
10253
0
    }
10254
0
    if (ret == NULL) return;
10255
0
    lit = xmlXPathCacheNewString(ctxt->context, ret);
10256
0
    if (lit == NULL) {
10257
0
  ctxt->error = XPATH_MEMORY_ERROR;
10258
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
10259
0
                              NULL) == -1) {
10260
0
        xmlXPathReleaseObject(ctxt->context, lit);
10261
0
    }
10262
0
    xmlFree(ret);
10263
0
}
10264
10265
/**
10266
 * xmlXPathCompVariableReference:
10267
 * @ctxt:  the XPath Parser context
10268
 *
10269
 * Parse a VariableReference, evaluate it and push it on the stack.
10270
 *
10271
 * The variable bindings consist of a mapping from variable names
10272
 * to variable values. The value of a variable is an object, which can be
10273
 * of any of the types that are possible for the value of an expression,
10274
 * and may also be of additional types not specified here.
10275
 *
10276
 * Early evaluation is possible since:
10277
 * The variable bindings [...] used to evaluate a subexpression are
10278
 * always the same as those used to evaluate the containing expression.
10279
 *
10280
 *  [36]   VariableReference ::=   '$' QName
10281
 */
10282
static void
10283
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10284
0
    xmlChar *name;
10285
0
    xmlChar *prefix;
10286
10287
0
    SKIP_BLANKS;
10288
0
    if (CUR != '$') {
10289
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10290
0
    }
10291
0
    NEXT;
10292
0
    name = xmlXPathParseQName(ctxt, &prefix);
10293
0
    if (name == NULL) {
10294
0
        xmlFree(prefix);
10295
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10296
0
    }
10297
0
    ctxt->comp->last = -1;
10298
0
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
10299
0
        xmlFree(prefix);
10300
0
        xmlFree(name);
10301
0
    }
10302
0
    SKIP_BLANKS;
10303
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10304
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10305
0
    }
10306
0
}
10307
10308
/**
10309
 * xmlXPathIsNodeType:
10310
 * @name:  a name string
10311
 *
10312
 * Is the name given a NodeType one.
10313
 *
10314
 *  [38]   NodeType ::=   'comment'
10315
 *                    | 'text'
10316
 *                    | 'processing-instruction'
10317
 *                    | 'node'
10318
 *
10319
 * Returns 1 if true 0 otherwise
10320
 */
10321
int
10322
0
xmlXPathIsNodeType(const xmlChar *name) {
10323
0
    if (name == NULL)
10324
0
  return(0);
10325
10326
0
    if (xmlStrEqual(name, BAD_CAST "node"))
10327
0
  return(1);
10328
0
    if (xmlStrEqual(name, BAD_CAST "text"))
10329
0
  return(1);
10330
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
10331
0
  return(1);
10332
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10333
0
  return(1);
10334
0
    return(0);
10335
0
}
10336
10337
/**
10338
 * xmlXPathCompFunctionCall:
10339
 * @ctxt:  the XPath Parser context
10340
 *
10341
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10342
 *  [17]   Argument ::=   Expr
10343
 *
10344
 * Compile a function call, the evaluation of all arguments are
10345
 * pushed on the stack
10346
 */
10347
static void
10348
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10349
0
    xmlChar *name;
10350
0
    xmlChar *prefix;
10351
0
    int nbargs = 0;
10352
0
    int sort = 1;
10353
10354
0
    name = xmlXPathParseQName(ctxt, &prefix);
10355
0
    if (name == NULL) {
10356
0
  xmlFree(prefix);
10357
0
  XP_ERROR(XPATH_EXPR_ERROR);
10358
0
    }
10359
0
    SKIP_BLANKS;
10360
#ifdef DEBUG_EXPR
10361
    if (prefix == NULL)
10362
  xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10363
      name);
10364
    else
10365
  xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10366
      prefix, name);
10367
#endif
10368
10369
0
    if (CUR != '(') {
10370
0
  xmlFree(name);
10371
0
  xmlFree(prefix);
10372
0
  XP_ERROR(XPATH_EXPR_ERROR);
10373
0
    }
10374
0
    NEXT;
10375
0
    SKIP_BLANKS;
10376
10377
    /*
10378
    * Optimization for count(): we don't need the node-set to be sorted.
10379
    */
10380
0
    if ((prefix == NULL) && (name[0] == 'c') &&
10381
0
  xmlStrEqual(name, BAD_CAST "count"))
10382
0
    {
10383
0
  sort = 0;
10384
0
    }
10385
0
    ctxt->comp->last = -1;
10386
0
    if (CUR != ')') {
10387
0
  while (CUR != 0) {
10388
0
      int op1 = ctxt->comp->last;
10389
0
      ctxt->comp->last = -1;
10390
0
      xmlXPathCompileExpr(ctxt, sort);
10391
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10392
0
    xmlFree(name);
10393
0
    xmlFree(prefix);
10394
0
    return;
10395
0
      }
10396
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10397
0
      nbargs++;
10398
0
      if (CUR == ')') break;
10399
0
      if (CUR != ',') {
10400
0
    xmlFree(name);
10401
0
    xmlFree(prefix);
10402
0
    XP_ERROR(XPATH_EXPR_ERROR);
10403
0
      }
10404
0
      NEXT;
10405
0
      SKIP_BLANKS;
10406
0
  }
10407
0
    }
10408
0
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
10409
0
        xmlFree(prefix);
10410
0
        xmlFree(name);
10411
0
    }
10412
0
    NEXT;
10413
0
    SKIP_BLANKS;
10414
0
}
10415
10416
/**
10417
 * xmlXPathCompPrimaryExpr:
10418
 * @ctxt:  the XPath Parser context
10419
 *
10420
 *  [15]   PrimaryExpr ::=   VariableReference
10421
 *                | '(' Expr ')'
10422
 *                | Literal
10423
 *                | Number
10424
 *                | FunctionCall
10425
 *
10426
 * Compile a primary expression.
10427
 */
10428
static void
10429
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10430
0
    SKIP_BLANKS;
10431
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10432
0
    else if (CUR == '(') {
10433
0
  NEXT;
10434
0
  SKIP_BLANKS;
10435
0
  xmlXPathCompileExpr(ctxt, 1);
10436
0
  CHECK_ERROR;
10437
0
  if (CUR != ')') {
10438
0
      XP_ERROR(XPATH_EXPR_ERROR);
10439
0
  }
10440
0
  NEXT;
10441
0
  SKIP_BLANKS;
10442
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10443
0
  xmlXPathCompNumber(ctxt);
10444
0
    } else if ((CUR == '\'') || (CUR == '"')) {
10445
0
  xmlXPathCompLiteral(ctxt);
10446
0
    } else {
10447
0
  xmlXPathCompFunctionCall(ctxt);
10448
0
    }
10449
0
    SKIP_BLANKS;
10450
0
}
10451
10452
/**
10453
 * xmlXPathCompFilterExpr:
10454
 * @ctxt:  the XPath Parser context
10455
 *
10456
 *  [20]   FilterExpr ::=   PrimaryExpr
10457
 *               | FilterExpr Predicate
10458
 *
10459
 * Compile a filter expression.
10460
 * Square brackets are used to filter expressions in the same way that
10461
 * they are used in location paths. It is an error if the expression to
10462
 * be filtered does not evaluate to a node-set. The context node list
10463
 * used for evaluating the expression in square brackets is the node-set
10464
 * to be filtered listed in document order.
10465
 */
10466
10467
static void
10468
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10469
0
    xmlXPathCompPrimaryExpr(ctxt);
10470
0
    CHECK_ERROR;
10471
0
    SKIP_BLANKS;
10472
10473
0
    while (CUR == '[') {
10474
0
  xmlXPathCompPredicate(ctxt, 1);
10475
0
  SKIP_BLANKS;
10476
0
    }
10477
10478
10479
0
}
10480
10481
/**
10482
 * xmlXPathScanName:
10483
 * @ctxt:  the XPath Parser context
10484
 *
10485
 * Trickery: parse an XML name but without consuming the input flow
10486
 * Needed to avoid insanity in the parser state.
10487
 *
10488
 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10489
 *                  CombiningChar | Extender
10490
 *
10491
 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10492
 *
10493
 * [6] Names ::= Name (S Name)*
10494
 *
10495
 * Returns the Name parsed or NULL
10496
 */
10497
10498
static xmlChar *
10499
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10500
0
    int len = 0, l;
10501
0
    int c;
10502
0
    const xmlChar *cur;
10503
0
    xmlChar *ret;
10504
10505
0
    cur = ctxt->cur;
10506
10507
0
    c = CUR_CHAR(l);
10508
0
    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10509
0
  (!IS_LETTER(c) && (c != '_') &&
10510
0
         (c != ':'))) {
10511
0
  return(NULL);
10512
0
    }
10513
10514
0
    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10515
0
     ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10516
0
            (c == '.') || (c == '-') ||
10517
0
      (c == '_') || (c == ':') ||
10518
0
      (IS_COMBINING(c)) ||
10519
0
      (IS_EXTENDER(c)))) {
10520
0
  len += l;
10521
0
  NEXTL(l);
10522
0
  c = CUR_CHAR(l);
10523
0
    }
10524
0
    ret = xmlStrndup(cur, ctxt->cur - cur);
10525
0
    ctxt->cur = cur;
10526
0
    return(ret);
10527
0
}
10528
10529
/**
10530
 * xmlXPathCompPathExpr:
10531
 * @ctxt:  the XPath Parser context
10532
 *
10533
 *  [19]   PathExpr ::=   LocationPath
10534
 *               | FilterExpr
10535
 *               | FilterExpr '/' RelativeLocationPath
10536
 *               | FilterExpr '//' RelativeLocationPath
10537
 *
10538
 * Compile a path expression.
10539
 * The / operator and // operators combine an arbitrary expression
10540
 * and a relative location path. It is an error if the expression
10541
 * does not evaluate to a node-set.
10542
 * The / operator does composition in the same way as when / is
10543
 * used in a location path. As in location paths, // is short for
10544
 * /descendant-or-self::node()/.
10545
 */
10546
10547
static void
10548
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10549
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
10550
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
10551
10552
0
    SKIP_BLANKS;
10553
0
    if ((CUR == '$') || (CUR == '(') ||
10554
0
  (IS_ASCII_DIGIT(CUR)) ||
10555
0
        (CUR == '\'') || (CUR == '"') ||
10556
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10557
0
  lc = 0;
10558
0
    } else if (CUR == '*') {
10559
  /* relative or absolute location path */
10560
0
  lc = 1;
10561
0
    } else if (CUR == '/') {
10562
  /* relative or absolute location path */
10563
0
  lc = 1;
10564
0
    } else if (CUR == '@') {
10565
  /* relative abbreviated attribute location path */
10566
0
  lc = 1;
10567
0
    } else if (CUR == '.') {
10568
  /* relative abbreviated attribute location path */
10569
0
  lc = 1;
10570
0
    } else {
10571
  /*
10572
   * Problem is finding if we have a name here whether it's:
10573
   *   - a nodetype
10574
   *   - a function call in which case it's followed by '('
10575
   *   - an axis in which case it's followed by ':'
10576
   *   - a element name
10577
   * We do an a priori analysis here rather than having to
10578
   * maintain parsed token content through the recursive function
10579
   * calls. This looks uglier but makes the code easier to
10580
   * read/write/debug.
10581
   */
10582
0
  SKIP_BLANKS;
10583
0
  name = xmlXPathScanName(ctxt);
10584
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10585
#ifdef DEBUG_STEP
10586
      xmlGenericError(xmlGenericErrorContext,
10587
        "PathExpr: Axis\n");
10588
#endif
10589
0
      lc = 1;
10590
0
      xmlFree(name);
10591
0
  } else if (name != NULL) {
10592
0
      int len =xmlStrlen(name);
10593
10594
10595
0
      while (NXT(len) != 0) {
10596
0
    if (NXT(len) == '/') {
10597
        /* element name */
10598
#ifdef DEBUG_STEP
10599
        xmlGenericError(xmlGenericErrorContext,
10600
          "PathExpr: AbbrRelLocation\n");
10601
#endif
10602
0
        lc = 1;
10603
0
        break;
10604
0
    } else if (IS_BLANK_CH(NXT(len))) {
10605
        /* ignore blanks */
10606
0
        ;
10607
0
    } else if (NXT(len) == ':') {
10608
#ifdef DEBUG_STEP
10609
        xmlGenericError(xmlGenericErrorContext,
10610
          "PathExpr: AbbrRelLocation\n");
10611
#endif
10612
0
        lc = 1;
10613
0
        break;
10614
0
    } else if ((NXT(len) == '(')) {
10615
        /* Node Type or Function */
10616
0
        if (xmlXPathIsNodeType(name)) {
10617
#ifdef DEBUG_STEP
10618
            xmlGenericError(xmlGenericErrorContext,
10619
        "PathExpr: Type search\n");
10620
#endif
10621
0
      lc = 1;
10622
#ifdef LIBXML_XPTR_LOCS_ENABLED
10623
                    } else if (ctxt->xptr &&
10624
                               xmlStrEqual(name, BAD_CAST "range-to")) {
10625
                        lc = 1;
10626
#endif
10627
0
        } else {
10628
#ifdef DEBUG_STEP
10629
            xmlGenericError(xmlGenericErrorContext,
10630
        "PathExpr: function call\n");
10631
#endif
10632
0
      lc = 0;
10633
0
        }
10634
0
                    break;
10635
0
    } else if ((NXT(len) == '[')) {
10636
        /* element name */
10637
#ifdef DEBUG_STEP
10638
        xmlGenericError(xmlGenericErrorContext,
10639
          "PathExpr: AbbrRelLocation\n");
10640
#endif
10641
0
        lc = 1;
10642
0
        break;
10643
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10644
0
         (NXT(len) == '=')) {
10645
0
        lc = 1;
10646
0
        break;
10647
0
    } else {
10648
0
        lc = 1;
10649
0
        break;
10650
0
    }
10651
0
    len++;
10652
0
      }
10653
0
      if (NXT(len) == 0) {
10654
#ifdef DEBUG_STEP
10655
    xmlGenericError(xmlGenericErrorContext,
10656
      "PathExpr: AbbrRelLocation\n");
10657
#endif
10658
    /* element name */
10659
0
    lc = 1;
10660
0
      }
10661
0
      xmlFree(name);
10662
0
  } else {
10663
      /* make sure all cases are covered explicitly */
10664
0
      XP_ERROR(XPATH_EXPR_ERROR);
10665
0
  }
10666
0
    }
10667
10668
0
    if (lc) {
10669
0
  if (CUR == '/') {
10670
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10671
0
  } else {
10672
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10673
0
  }
10674
0
  xmlXPathCompLocationPath(ctxt);
10675
0
    } else {
10676
0
  xmlXPathCompFilterExpr(ctxt);
10677
0
  CHECK_ERROR;
10678
0
  if ((CUR == '/') && (NXT(1) == '/')) {
10679
0
      SKIP(2);
10680
0
      SKIP_BLANKS;
10681
10682
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10683
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10684
10685
0
      xmlXPathCompRelativeLocationPath(ctxt);
10686
0
  } else if (CUR == '/') {
10687
0
      xmlXPathCompRelativeLocationPath(ctxt);
10688
0
  }
10689
0
    }
10690
0
    SKIP_BLANKS;
10691
0
}
10692
10693
/**
10694
 * xmlXPathCompUnionExpr:
10695
 * @ctxt:  the XPath Parser context
10696
 *
10697
 *  [18]   UnionExpr ::=   PathExpr
10698
 *               | UnionExpr '|' PathExpr
10699
 *
10700
 * Compile an union expression.
10701
 */
10702
10703
static void
10704
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10705
0
    xmlXPathCompPathExpr(ctxt);
10706
0
    CHECK_ERROR;
10707
0
    SKIP_BLANKS;
10708
0
    while (CUR == '|') {
10709
0
  int op1 = ctxt->comp->last;
10710
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10711
10712
0
  NEXT;
10713
0
  SKIP_BLANKS;
10714
0
  xmlXPathCompPathExpr(ctxt);
10715
10716
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10717
10718
0
  SKIP_BLANKS;
10719
0
    }
10720
0
}
10721
10722
/**
10723
 * xmlXPathCompUnaryExpr:
10724
 * @ctxt:  the XPath Parser context
10725
 *
10726
 *  [27]   UnaryExpr ::=   UnionExpr
10727
 *                   | '-' UnaryExpr
10728
 *
10729
 * Compile an unary expression.
10730
 */
10731
10732
static void
10733
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10734
0
    int minus = 0;
10735
0
    int found = 0;
10736
10737
0
    SKIP_BLANKS;
10738
0
    while (CUR == '-') {
10739
0
        minus = 1 - minus;
10740
0
  found = 1;
10741
0
  NEXT;
10742
0
  SKIP_BLANKS;
10743
0
    }
10744
10745
0
    xmlXPathCompUnionExpr(ctxt);
10746
0
    CHECK_ERROR;
10747
0
    if (found) {
10748
0
  if (minus)
10749
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10750
0
  else
10751
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10752
0
    }
10753
0
}
10754
10755
/**
10756
 * xmlXPathCompMultiplicativeExpr:
10757
 * @ctxt:  the XPath Parser context
10758
 *
10759
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
10760
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
10761
 *                   | MultiplicativeExpr 'div' UnaryExpr
10762
 *                   | MultiplicativeExpr 'mod' UnaryExpr
10763
 *  [34]   MultiplyOperator ::=   '*'
10764
 *
10765
 * Compile an Additive expression.
10766
 */
10767
10768
static void
10769
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10770
0
    xmlXPathCompUnaryExpr(ctxt);
10771
0
    CHECK_ERROR;
10772
0
    SKIP_BLANKS;
10773
0
    while ((CUR == '*') ||
10774
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10775
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10776
0
  int op = -1;
10777
0
  int op1 = ctxt->comp->last;
10778
10779
0
        if (CUR == '*') {
10780
0
      op = 0;
10781
0
      NEXT;
10782
0
  } else if (CUR == 'd') {
10783
0
      op = 1;
10784
0
      SKIP(3);
10785
0
  } else if (CUR == 'm') {
10786
0
      op = 2;
10787
0
      SKIP(3);
10788
0
  }
10789
0
  SKIP_BLANKS;
10790
0
        xmlXPathCompUnaryExpr(ctxt);
10791
0
  CHECK_ERROR;
10792
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10793
0
  SKIP_BLANKS;
10794
0
    }
10795
0
}
10796
10797
/**
10798
 * xmlXPathCompAdditiveExpr:
10799
 * @ctxt:  the XPath Parser context
10800
 *
10801
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
10802
 *                   | AdditiveExpr '+' MultiplicativeExpr
10803
 *                   | AdditiveExpr '-' MultiplicativeExpr
10804
 *
10805
 * Compile an Additive expression.
10806
 */
10807
10808
static void
10809
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10810
10811
0
    xmlXPathCompMultiplicativeExpr(ctxt);
10812
0
    CHECK_ERROR;
10813
0
    SKIP_BLANKS;
10814
0
    while ((CUR == '+') || (CUR == '-')) {
10815
0
  int plus;
10816
0
  int op1 = ctxt->comp->last;
10817
10818
0
        if (CUR == '+') plus = 1;
10819
0
  else plus = 0;
10820
0
  NEXT;
10821
0
  SKIP_BLANKS;
10822
0
        xmlXPathCompMultiplicativeExpr(ctxt);
10823
0
  CHECK_ERROR;
10824
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10825
0
  SKIP_BLANKS;
10826
0
    }
10827
0
}
10828
10829
/**
10830
 * xmlXPathCompRelationalExpr:
10831
 * @ctxt:  the XPath Parser context
10832
 *
10833
 *  [24]   RelationalExpr ::=   AdditiveExpr
10834
 *                 | RelationalExpr '<' AdditiveExpr
10835
 *                 | RelationalExpr '>' AdditiveExpr
10836
 *                 | RelationalExpr '<=' AdditiveExpr
10837
 *                 | RelationalExpr '>=' AdditiveExpr
10838
 *
10839
 *  A <= B > C is allowed ? Answer from James, yes with
10840
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10841
 *  which is basically what got implemented.
10842
 *
10843
 * Compile a Relational expression, then push the result
10844
 * on the stack
10845
 */
10846
10847
static void
10848
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10849
0
    xmlXPathCompAdditiveExpr(ctxt);
10850
0
    CHECK_ERROR;
10851
0
    SKIP_BLANKS;
10852
0
    while ((CUR == '<') || (CUR == '>')) {
10853
0
  int inf, strict;
10854
0
  int op1 = ctxt->comp->last;
10855
10856
0
        if (CUR == '<') inf = 1;
10857
0
  else inf = 0;
10858
0
  if (NXT(1) == '=') strict = 0;
10859
0
  else strict = 1;
10860
0
  NEXT;
10861
0
  if (!strict) NEXT;
10862
0
  SKIP_BLANKS;
10863
0
        xmlXPathCompAdditiveExpr(ctxt);
10864
0
  CHECK_ERROR;
10865
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10866
0
  SKIP_BLANKS;
10867
0
    }
10868
0
}
10869
10870
/**
10871
 * xmlXPathCompEqualityExpr:
10872
 * @ctxt:  the XPath Parser context
10873
 *
10874
 *  [23]   EqualityExpr ::=   RelationalExpr
10875
 *                 | EqualityExpr '=' RelationalExpr
10876
 *                 | EqualityExpr '!=' RelationalExpr
10877
 *
10878
 *  A != B != C is allowed ? Answer from James, yes with
10879
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
10880
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
10881
 *  which is basically what got implemented.
10882
 *
10883
 * Compile an Equality expression.
10884
 *
10885
 */
10886
static void
10887
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10888
0
    xmlXPathCompRelationalExpr(ctxt);
10889
0
    CHECK_ERROR;
10890
0
    SKIP_BLANKS;
10891
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10892
0
  int eq;
10893
0
  int op1 = ctxt->comp->last;
10894
10895
0
        if (CUR == '=') eq = 1;
10896
0
  else eq = 0;
10897
0
  NEXT;
10898
0
  if (!eq) NEXT;
10899
0
  SKIP_BLANKS;
10900
0
        xmlXPathCompRelationalExpr(ctxt);
10901
0
  CHECK_ERROR;
10902
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10903
0
  SKIP_BLANKS;
10904
0
    }
10905
0
}
10906
10907
/**
10908
 * xmlXPathCompAndExpr:
10909
 * @ctxt:  the XPath Parser context
10910
 *
10911
 *  [22]   AndExpr ::=   EqualityExpr
10912
 *                 | AndExpr 'and' EqualityExpr
10913
 *
10914
 * Compile an AND expression.
10915
 *
10916
 */
10917
static void
10918
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10919
0
    xmlXPathCompEqualityExpr(ctxt);
10920
0
    CHECK_ERROR;
10921
0
    SKIP_BLANKS;
10922
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10923
0
  int op1 = ctxt->comp->last;
10924
0
        SKIP(3);
10925
0
  SKIP_BLANKS;
10926
0
        xmlXPathCompEqualityExpr(ctxt);
10927
0
  CHECK_ERROR;
10928
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10929
0
  SKIP_BLANKS;
10930
0
    }
10931
0
}
10932
10933
/**
10934
 * xmlXPathCompileExpr:
10935
 * @ctxt:  the XPath Parser context
10936
 *
10937
 *  [14]   Expr ::=   OrExpr
10938
 *  [21]   OrExpr ::=   AndExpr
10939
 *                 | OrExpr 'or' AndExpr
10940
 *
10941
 * Parse and compile an expression
10942
 */
10943
static void
10944
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10945
0
    xmlXPathContextPtr xpctxt = ctxt->context;
10946
10947
0
    if (xpctxt != NULL) {
10948
0
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10949
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10950
        /*
10951
         * Parsing a single '(' pushes about 10 functions on the call stack
10952
         * before recursing!
10953
         */
10954
0
        xpctxt->depth += 10;
10955
0
    }
10956
10957
0
    xmlXPathCompAndExpr(ctxt);
10958
0
    CHECK_ERROR;
10959
0
    SKIP_BLANKS;
10960
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
10961
0
  int op1 = ctxt->comp->last;
10962
0
        SKIP(2);
10963
0
  SKIP_BLANKS;
10964
0
        xmlXPathCompAndExpr(ctxt);
10965
0
  CHECK_ERROR;
10966
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10967
0
  SKIP_BLANKS;
10968
0
    }
10969
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10970
  /* more ops could be optimized too */
10971
  /*
10972
  * This is the main place to eliminate sorting for
10973
  * operations which don't require a sorted node-set.
10974
  * E.g. count().
10975
  */
10976
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10977
0
    }
10978
10979
0
    if (xpctxt != NULL)
10980
0
        xpctxt->depth -= 10;
10981
0
}
10982
10983
/**
10984
 * xmlXPathCompPredicate:
10985
 * @ctxt:  the XPath Parser context
10986
 * @filter:  act as a filter
10987
 *
10988
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
10989
 *  [9]   PredicateExpr ::=   Expr
10990
 *
10991
 * Compile a predicate expression
10992
 */
10993
static void
10994
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10995
0
    int op1 = ctxt->comp->last;
10996
10997
0
    SKIP_BLANKS;
10998
0
    if (CUR != '[') {
10999
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11000
0
    }
11001
0
    NEXT;
11002
0
    SKIP_BLANKS;
11003
11004
0
    ctxt->comp->last = -1;
11005
    /*
11006
    * This call to xmlXPathCompileExpr() will deactivate sorting
11007
    * of the predicate result.
11008
    * TODO: Sorting is still activated for filters, since I'm not
11009
    *  sure if needed. Normally sorting should not be needed, since
11010
    *  a filter can only diminish the number of items in a sequence,
11011
    *  but won't change its order; so if the initial sequence is sorted,
11012
    *  subsequent sorting is not needed.
11013
    */
11014
0
    if (! filter)
11015
0
  xmlXPathCompileExpr(ctxt, 0);
11016
0
    else
11017
0
  xmlXPathCompileExpr(ctxt, 1);
11018
0
    CHECK_ERROR;
11019
11020
0
    if (CUR != ']') {
11021
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11022
0
    }
11023
11024
0
    if (filter)
11025
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11026
0
    else
11027
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11028
11029
0
    NEXT;
11030
0
    SKIP_BLANKS;
11031
0
}
11032
11033
/**
11034
 * xmlXPathCompNodeTest:
11035
 * @ctxt:  the XPath Parser context
11036
 * @test:  pointer to a xmlXPathTestVal
11037
 * @type:  pointer to a xmlXPathTypeVal
11038
 * @prefix:  placeholder for a possible name prefix
11039
 *
11040
 * [7] NodeTest ::=   NameTest
11041
 *        | NodeType '(' ')'
11042
 *        | 'processing-instruction' '(' Literal ')'
11043
 *
11044
 * [37] NameTest ::=  '*'
11045
 *        | NCName ':' '*'
11046
 *        | QName
11047
 * [38] NodeType ::= 'comment'
11048
 *       | 'text'
11049
 *       | 'processing-instruction'
11050
 *       | 'node'
11051
 *
11052
 * Returns the name found and updates @test, @type and @prefix appropriately
11053
 */
11054
static xmlChar *
11055
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11056
               xmlXPathTypeVal *type, xmlChar **prefix,
11057
0
         xmlChar *name) {
11058
0
    int blanks;
11059
11060
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11061
0
  STRANGE;
11062
0
  return(NULL);
11063
0
    }
11064
0
    *type = (xmlXPathTypeVal) 0;
11065
0
    *test = (xmlXPathTestVal) 0;
11066
0
    *prefix = NULL;
11067
0
    SKIP_BLANKS;
11068
11069
0
    if ((name == NULL) && (CUR == '*')) {
11070
  /*
11071
   * All elements
11072
   */
11073
0
  NEXT;
11074
0
  *test = NODE_TEST_ALL;
11075
0
  return(NULL);
11076
0
    }
11077
11078
0
    if (name == NULL)
11079
0
  name = xmlXPathParseNCName(ctxt);
11080
0
    if (name == NULL) {
11081
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
11082
0
    }
11083
11084
0
    blanks = IS_BLANK_CH(CUR);
11085
0
    SKIP_BLANKS;
11086
0
    if (CUR == '(') {
11087
0
  NEXT;
11088
  /*
11089
   * NodeType or PI search
11090
   */
11091
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
11092
0
      *type = NODE_TYPE_COMMENT;
11093
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
11094
0
      *type = NODE_TYPE_NODE;
11095
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11096
0
      *type = NODE_TYPE_PI;
11097
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
11098
0
      *type = NODE_TYPE_TEXT;
11099
0
  else {
11100
0
      if (name != NULL)
11101
0
    xmlFree(name);
11102
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11103
0
  }
11104
11105
0
  *test = NODE_TEST_TYPE;
11106
11107
0
  SKIP_BLANKS;
11108
0
  if (*type == NODE_TYPE_PI) {
11109
      /*
11110
       * Specific case: search a PI by name.
11111
       */
11112
0
      if (name != NULL)
11113
0
    xmlFree(name);
11114
0
      name = NULL;
11115
0
      if (CUR != ')') {
11116
0
    name = xmlXPathParseLiteral(ctxt);
11117
0
                if (name == NULL) {
11118
0
              XP_ERRORNULL(XPATH_EXPR_ERROR);
11119
0
                }
11120
0
    *test = NODE_TEST_PI;
11121
0
    SKIP_BLANKS;
11122
0
      }
11123
0
  }
11124
0
  if (CUR != ')') {
11125
0
      if (name != NULL)
11126
0
    xmlFree(name);
11127
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11128
0
  }
11129
0
  NEXT;
11130
0
  return(name);
11131
0
    }
11132
0
    *test = NODE_TEST_NAME;
11133
0
    if ((!blanks) && (CUR == ':')) {
11134
0
  NEXT;
11135
11136
  /*
11137
   * Since currently the parser context don't have a
11138
   * namespace list associated:
11139
   * The namespace name for this prefix can be computed
11140
   * only at evaluation time. The compilation is done
11141
   * outside of any context.
11142
   */
11143
#if 0
11144
  *prefix = xmlXPathNsLookup(ctxt->context, name);
11145
  if (name != NULL)
11146
      xmlFree(name);
11147
  if (*prefix == NULL) {
11148
      XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11149
  }
11150
#else
11151
0
  *prefix = name;
11152
0
#endif
11153
11154
0
  if (CUR == '*') {
11155
      /*
11156
       * All elements
11157
       */
11158
0
      NEXT;
11159
0
      *test = NODE_TEST_ALL;
11160
0
      return(NULL);
11161
0
  }
11162
11163
0
  name = xmlXPathParseNCName(ctxt);
11164
0
  if (name == NULL) {
11165
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
11166
0
  }
11167
0
    }
11168
0
    return(name);
11169
0
}
11170
11171
/**
11172
 * xmlXPathIsAxisName:
11173
 * @name:  a preparsed name token
11174
 *
11175
 * [6] AxisName ::=   'ancestor'
11176
 *                  | 'ancestor-or-self'
11177
 *                  | 'attribute'
11178
 *                  | 'child'
11179
 *                  | 'descendant'
11180
 *                  | 'descendant-or-self'
11181
 *                  | 'following'
11182
 *                  | 'following-sibling'
11183
 *                  | 'namespace'
11184
 *                  | 'parent'
11185
 *                  | 'preceding'
11186
 *                  | 'preceding-sibling'
11187
 *                  | 'self'
11188
 *
11189
 * Returns the axis or 0
11190
 */
11191
static xmlXPathAxisVal
11192
0
xmlXPathIsAxisName(const xmlChar *name) {
11193
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11194
0
    switch (name[0]) {
11195
0
  case 'a':
11196
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
11197
0
    ret = AXIS_ANCESTOR;
11198
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11199
0
    ret = AXIS_ANCESTOR_OR_SELF;
11200
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
11201
0
    ret = AXIS_ATTRIBUTE;
11202
0
      break;
11203
0
  case 'c':
11204
0
      if (xmlStrEqual(name, BAD_CAST "child"))
11205
0
    ret = AXIS_CHILD;
11206
0
      break;
11207
0
  case 'd':
11208
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
11209
0
    ret = AXIS_DESCENDANT;
11210
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11211
0
    ret = AXIS_DESCENDANT_OR_SELF;
11212
0
      break;
11213
0
  case 'f':
11214
0
      if (xmlStrEqual(name, BAD_CAST "following"))
11215
0
    ret = AXIS_FOLLOWING;
11216
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11217
0
    ret = AXIS_FOLLOWING_SIBLING;
11218
0
      break;
11219
0
  case 'n':
11220
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
11221
0
    ret = AXIS_NAMESPACE;
11222
0
      break;
11223
0
  case 'p':
11224
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
11225
0
    ret = AXIS_PARENT;
11226
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
11227
0
    ret = AXIS_PRECEDING;
11228
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11229
0
    ret = AXIS_PRECEDING_SIBLING;
11230
0
      break;
11231
0
  case 's':
11232
0
      if (xmlStrEqual(name, BAD_CAST "self"))
11233
0
    ret = AXIS_SELF;
11234
0
      break;
11235
0
    }
11236
0
    return(ret);
11237
0
}
11238
11239
/**
11240
 * xmlXPathCompStep:
11241
 * @ctxt:  the XPath Parser context
11242
 *
11243
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
11244
 *                  | AbbreviatedStep
11245
 *
11246
 * [12] AbbreviatedStep ::=   '.' | '..'
11247
 *
11248
 * [5] AxisSpecifier ::= AxisName '::'
11249
 *                  | AbbreviatedAxisSpecifier
11250
 *
11251
 * [13] AbbreviatedAxisSpecifier ::= '@'?
11252
 *
11253
 * Modified for XPtr range support as:
11254
 *
11255
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11256
 *                     | AbbreviatedStep
11257
 *                     | 'range-to' '(' Expr ')' Predicate*
11258
 *
11259
 * Compile one step in a Location Path
11260
 * A location step of . is short for self::node(). This is
11261
 * particularly useful in conjunction with //. For example, the
11262
 * location path .//para is short for
11263
 * self::node()/descendant-or-self::node()/child::para
11264
 * and so will select all para descendant elements of the context
11265
 * node.
11266
 * Similarly, a location step of .. is short for parent::node().
11267
 * For example, ../title is short for parent::node()/child::title
11268
 * and so will select the title children of the parent of the context
11269
 * node.
11270
 */
11271
static void
11272
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11273
#ifdef LIBXML_XPTR_LOCS_ENABLED
11274
    int rangeto = 0;
11275
    int op2 = -1;
11276
#endif
11277
11278
0
    SKIP_BLANKS;
11279
0
    if ((CUR == '.') && (NXT(1) == '.')) {
11280
0
  SKIP(2);
11281
0
  SKIP_BLANKS;
11282
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11283
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11284
0
    } else if (CUR == '.') {
11285
0
  NEXT;
11286
0
  SKIP_BLANKS;
11287
0
    } else {
11288
0
  xmlChar *name = NULL;
11289
0
  xmlChar *prefix = NULL;
11290
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
11291
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11292
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11293
0
  int op1;
11294
11295
  /*
11296
   * The modification needed for XPointer change to the production
11297
   */
11298
#ifdef LIBXML_XPTR_LOCS_ENABLED
11299
  if (ctxt->xptr) {
11300
      name = xmlXPathParseNCName(ctxt);
11301
      if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11302
                op2 = ctxt->comp->last;
11303
    xmlFree(name);
11304
    SKIP_BLANKS;
11305
    if (CUR != '(') {
11306
        XP_ERROR(XPATH_EXPR_ERROR);
11307
    }
11308
    NEXT;
11309
    SKIP_BLANKS;
11310
11311
    xmlXPathCompileExpr(ctxt, 1);
11312
    /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11313
    CHECK_ERROR;
11314
11315
    SKIP_BLANKS;
11316
    if (CUR != ')') {
11317
        XP_ERROR(XPATH_EXPR_ERROR);
11318
    }
11319
    NEXT;
11320
    rangeto = 1;
11321
    goto eval_predicates;
11322
      }
11323
  }
11324
#endif
11325
0
  if (CUR == '*') {
11326
0
      axis = AXIS_CHILD;
11327
0
  } else {
11328
0
      if (name == NULL)
11329
0
    name = xmlXPathParseNCName(ctxt);
11330
0
      if (name != NULL) {
11331
0
    axis = xmlXPathIsAxisName(name);
11332
0
    if (axis != 0) {
11333
0
        SKIP_BLANKS;
11334
0
        if ((CUR == ':') && (NXT(1) == ':')) {
11335
0
      SKIP(2);
11336
0
      xmlFree(name);
11337
0
      name = NULL;
11338
0
        } else {
11339
      /* an element name can conflict with an axis one :-\ */
11340
0
      axis = AXIS_CHILD;
11341
0
        }
11342
0
    } else {
11343
0
        axis = AXIS_CHILD;
11344
0
    }
11345
0
      } else if (CUR == '@') {
11346
0
    NEXT;
11347
0
    axis = AXIS_ATTRIBUTE;
11348
0
      } else {
11349
0
    axis = AXIS_CHILD;
11350
0
      }
11351
0
  }
11352
11353
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
11354
0
            xmlFree(name);
11355
0
            return;
11356
0
        }
11357
11358
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11359
0
  if (test == 0)
11360
0
      return;
11361
11362
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
11363
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11364
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11365
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11366
0
      }
11367
0
  }
11368
#ifdef DEBUG_STEP
11369
  xmlGenericError(xmlGenericErrorContext,
11370
    "Basis : computing new set\n");
11371
#endif
11372
11373
#ifdef DEBUG_STEP
11374
  xmlGenericError(xmlGenericErrorContext, "Basis : ");
11375
  if (ctxt->value == NULL)
11376
      xmlGenericError(xmlGenericErrorContext, "no value\n");
11377
  else if (ctxt->value->nodesetval == NULL)
11378
      xmlGenericError(xmlGenericErrorContext, "Empty\n");
11379
  else
11380
      xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11381
#endif
11382
11383
#ifdef LIBXML_XPTR_LOCS_ENABLED
11384
eval_predicates:
11385
#endif
11386
0
  op1 = ctxt->comp->last;
11387
0
  ctxt->comp->last = -1;
11388
11389
0
  SKIP_BLANKS;
11390
0
  while (CUR == '[') {
11391
0
      xmlXPathCompPredicate(ctxt, 0);
11392
0
  }
11393
11394
#ifdef LIBXML_XPTR_LOCS_ENABLED
11395
  if (rangeto) {
11396
      PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11397
  } else
11398
#endif
11399
0
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11400
0
                           test, type, (void *)prefix, (void *)name) == -1) {
11401
0
            xmlFree(prefix);
11402
0
            xmlFree(name);
11403
0
        }
11404
0
    }
11405
#ifdef DEBUG_STEP
11406
    xmlGenericError(xmlGenericErrorContext, "Step : ");
11407
    if (ctxt->value == NULL)
11408
  xmlGenericError(xmlGenericErrorContext, "no value\n");
11409
    else if (ctxt->value->nodesetval == NULL)
11410
  xmlGenericError(xmlGenericErrorContext, "Empty\n");
11411
    else
11412
  xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11413
    ctxt->value->nodesetval);
11414
#endif
11415
0
}
11416
11417
/**
11418
 * xmlXPathCompRelativeLocationPath:
11419
 * @ctxt:  the XPath Parser context
11420
 *
11421
 *  [3]   RelativeLocationPath ::=   Step
11422
 *                     | RelativeLocationPath '/' Step
11423
 *                     | AbbreviatedRelativeLocationPath
11424
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
11425
 *
11426
 * Compile a relative location path.
11427
 */
11428
static void
11429
xmlXPathCompRelativeLocationPath
11430
0
(xmlXPathParserContextPtr ctxt) {
11431
0
    SKIP_BLANKS;
11432
0
    if ((CUR == '/') && (NXT(1) == '/')) {
11433
0
  SKIP(2);
11434
0
  SKIP_BLANKS;
11435
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11436
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11437
0
    } else if (CUR == '/') {
11438
0
      NEXT;
11439
0
  SKIP_BLANKS;
11440
0
    }
11441
0
    xmlXPathCompStep(ctxt);
11442
0
    CHECK_ERROR;
11443
0
    SKIP_BLANKS;
11444
0
    while (CUR == '/') {
11445
0
  if ((CUR == '/') && (NXT(1) == '/')) {
11446
0
      SKIP(2);
11447
0
      SKIP_BLANKS;
11448
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11449
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11450
0
      xmlXPathCompStep(ctxt);
11451
0
  } else if (CUR == '/') {
11452
0
      NEXT;
11453
0
      SKIP_BLANKS;
11454
0
      xmlXPathCompStep(ctxt);
11455
0
  }
11456
0
  SKIP_BLANKS;
11457
0
    }
11458
0
}
11459
11460
/**
11461
 * xmlXPathCompLocationPath:
11462
 * @ctxt:  the XPath Parser context
11463
 *
11464
 *  [1]   LocationPath ::=   RelativeLocationPath
11465
 *                     | AbsoluteLocationPath
11466
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
11467
 *                     | AbbreviatedAbsoluteLocationPath
11468
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
11469
 *                           '//' RelativeLocationPath
11470
 *
11471
 * Compile a location path
11472
 *
11473
 * // is short for /descendant-or-self::node()/. For example,
11474
 * //para is short for /descendant-or-self::node()/child::para and
11475
 * so will select any para element in the document (even a para element
11476
 * that is a document element will be selected by //para since the
11477
 * document element node is a child of the root node); div//para is
11478
 * short for div/descendant-or-self::node()/child::para and so will
11479
 * select all para descendants of div children.
11480
 */
11481
static void
11482
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11483
0
    SKIP_BLANKS;
11484
0
    if (CUR != '/') {
11485
0
        xmlXPathCompRelativeLocationPath(ctxt);
11486
0
    } else {
11487
0
  while (CUR == '/') {
11488
0
      if ((CUR == '/') && (NXT(1) == '/')) {
11489
0
    SKIP(2);
11490
0
    SKIP_BLANKS;
11491
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11492
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11493
0
    xmlXPathCompRelativeLocationPath(ctxt);
11494
0
      } else if (CUR == '/') {
11495
0
    NEXT;
11496
0
    SKIP_BLANKS;
11497
0
    if ((CUR != 0 ) &&
11498
0
        ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11499
0
         (CUR == '@') || (CUR == '*')))
11500
0
        xmlXPathCompRelativeLocationPath(ctxt);
11501
0
      }
11502
0
      CHECK_ERROR;
11503
0
  }
11504
0
    }
11505
0
}
11506
11507
/************************************************************************
11508
 *                  *
11509
 *    XPath precompiled expression evaluation     *
11510
 *                  *
11511
 ************************************************************************/
11512
11513
static int
11514
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11515
11516
#ifdef DEBUG_STEP
11517
static void
11518
xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11519
        int nbNodes)
11520
{
11521
    xmlGenericError(xmlGenericErrorContext, "new step : ");
11522
    switch (op->value) {
11523
        case AXIS_ANCESTOR:
11524
            xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11525
            break;
11526
        case AXIS_ANCESTOR_OR_SELF:
11527
            xmlGenericError(xmlGenericErrorContext,
11528
                            "axis 'ancestors-or-self' ");
11529
            break;
11530
        case AXIS_ATTRIBUTE:
11531
            xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11532
            break;
11533
        case AXIS_CHILD:
11534
            xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11535
            break;
11536
        case AXIS_DESCENDANT:
11537
            xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11538
            break;
11539
        case AXIS_DESCENDANT_OR_SELF:
11540
            xmlGenericError(xmlGenericErrorContext,
11541
                            "axis 'descendant-or-self' ");
11542
            break;
11543
        case AXIS_FOLLOWING:
11544
            xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11545
            break;
11546
        case AXIS_FOLLOWING_SIBLING:
11547
            xmlGenericError(xmlGenericErrorContext,
11548
                            "axis 'following-siblings' ");
11549
            break;
11550
        case AXIS_NAMESPACE:
11551
            xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11552
            break;
11553
        case AXIS_PARENT:
11554
            xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11555
            break;
11556
        case AXIS_PRECEDING:
11557
            xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11558
            break;
11559
        case AXIS_PRECEDING_SIBLING:
11560
            xmlGenericError(xmlGenericErrorContext,
11561
                            "axis 'preceding-sibling' ");
11562
            break;
11563
        case AXIS_SELF:
11564
            xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11565
            break;
11566
    }
11567
    xmlGenericError(xmlGenericErrorContext,
11568
  " context contains %d nodes\n", nbNodes);
11569
    switch (op->value2) {
11570
        case NODE_TEST_NONE:
11571
            xmlGenericError(xmlGenericErrorContext,
11572
                            "           searching for none !!!\n");
11573
            break;
11574
        case NODE_TEST_TYPE:
11575
            xmlGenericError(xmlGenericErrorContext,
11576
                            "           searching for type %d\n", op->value3);
11577
            break;
11578
        case NODE_TEST_PI:
11579
            xmlGenericError(xmlGenericErrorContext,
11580
                            "           searching for PI !!!\n");
11581
            break;
11582
        case NODE_TEST_ALL:
11583
            xmlGenericError(xmlGenericErrorContext,
11584
                            "           searching for *\n");
11585
            break;
11586
        case NODE_TEST_NS:
11587
            xmlGenericError(xmlGenericErrorContext,
11588
                            "           searching for namespace %s\n",
11589
                            op->value5);
11590
            break;
11591
        case NODE_TEST_NAME:
11592
            xmlGenericError(xmlGenericErrorContext,
11593
                            "           searching for name %s\n", op->value5);
11594
            if (op->value4)
11595
                xmlGenericError(xmlGenericErrorContext,
11596
                                "           with namespace %s\n", op->value4);
11597
            break;
11598
    }
11599
    xmlGenericError(xmlGenericErrorContext, "Testing : ");
11600
}
11601
#endif /* DEBUG_STEP */
11602
11603
/**
11604
 * xmlXPathNodeSetFilter:
11605
 * @ctxt:  the XPath Parser context
11606
 * @set: the node set to filter
11607
 * @filterOpIndex: the index of the predicate/filter op
11608
 * @minPos: minimum position in the filtered set (1-based)
11609
 * @maxPos: maximum position in the filtered set (1-based)
11610
 * @hasNsNodes: true if the node set may contain namespace nodes
11611
 *
11612
 * Filter a node set, keeping only nodes for which the predicate expression
11613
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11614
 * filtered result.
11615
 */
11616
static void
11617
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
11618
          xmlNodeSetPtr set,
11619
          int filterOpIndex,
11620
                      int minPos, int maxPos,
11621
          int hasNsNodes)
11622
0
{
11623
0
    xmlXPathContextPtr xpctxt;
11624
0
    xmlNodePtr oldnode;
11625
0
    xmlDocPtr olddoc;
11626
0
    xmlXPathStepOpPtr filterOp;
11627
0
    int oldcs, oldpp;
11628
0
    int i, j, pos;
11629
11630
0
    if ((set == NULL) || (set->nodeNr == 0))
11631
0
        return;
11632
11633
    /*
11634
    * Check if the node set contains a sufficient number of nodes for
11635
    * the requested range.
11636
    */
11637
0
    if (set->nodeNr < minPos) {
11638
0
        xmlXPathNodeSetClear(set, hasNsNodes);
11639
0
        return;
11640
0
    }
11641
11642
0
    xpctxt = ctxt->context;
11643
0
    oldnode = xpctxt->node;
11644
0
    olddoc = xpctxt->doc;
11645
0
    oldcs = xpctxt->contextSize;
11646
0
    oldpp = xpctxt->proximityPosition;
11647
0
    filterOp = &ctxt->comp->steps[filterOpIndex];
11648
11649
0
    xpctxt->contextSize = set->nodeNr;
11650
11651
0
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
11652
0
        xmlNodePtr node = set->nodeTab[i];
11653
0
        int res;
11654
11655
0
        xpctxt->node = node;
11656
0
        xpctxt->proximityPosition = i + 1;
11657
11658
        /*
11659
        * Also set the xpath document in case things like
11660
        * key() are evaluated in the predicate.
11661
        *
11662
        * TODO: Get real doc for namespace nodes.
11663
        */
11664
0
        if ((node->type != XML_NAMESPACE_DECL) &&
11665
0
            (node->doc != NULL))
11666
0
            xpctxt->doc = node->doc;
11667
11668
0
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11669
11670
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
11671
0
            break;
11672
0
        if (res < 0) {
11673
            /* Shouldn't happen */
11674
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11675
0
            break;
11676
0
        }
11677
11678
0
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11679
0
            if (i != j) {
11680
0
                set->nodeTab[j] = node;
11681
0
                set->nodeTab[i] = NULL;
11682
0
            }
11683
11684
0
            j += 1;
11685
0
        } else {
11686
            /* Remove the entry from the initial node set. */
11687
0
            set->nodeTab[i] = NULL;
11688
0
            if (node->type == XML_NAMESPACE_DECL)
11689
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11690
0
        }
11691
11692
0
        if (res != 0) {
11693
0
            if (pos == maxPos) {
11694
0
                i += 1;
11695
0
                break;
11696
0
            }
11697
11698
0
            pos += 1;
11699
0
        }
11700
0
    }
11701
11702
    /* Free remaining nodes. */
11703
0
    if (hasNsNodes) {
11704
0
        for (; i < set->nodeNr; i++) {
11705
0
            xmlNodePtr node = set->nodeTab[i];
11706
0
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
11707
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
11708
0
        }
11709
0
    }
11710
11711
0
    set->nodeNr = j;
11712
11713
    /* If too many elements were removed, shrink table to preserve memory. */
11714
0
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
11715
0
        (set->nodeNr < set->nodeMax / 2)) {
11716
0
        xmlNodePtr *tmp;
11717
0
        int nodeMax = set->nodeNr;
11718
11719
0
        if (nodeMax < XML_NODESET_DEFAULT)
11720
0
            nodeMax = XML_NODESET_DEFAULT;
11721
0
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
11722
0
                nodeMax * sizeof(xmlNodePtr));
11723
0
        if (tmp == NULL) {
11724
0
            xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
11725
0
        } else {
11726
0
            set->nodeTab = tmp;
11727
0
            set->nodeMax = nodeMax;
11728
0
        }
11729
0
    }
11730
11731
0
    xpctxt->node = oldnode;
11732
0
    xpctxt->doc = olddoc;
11733
0
    xpctxt->contextSize = oldcs;
11734
0
    xpctxt->proximityPosition = oldpp;
11735
0
}
11736
11737
#ifdef LIBXML_XPTR_LOCS_ENABLED
11738
/**
11739
 * xmlXPathLocationSetFilter:
11740
 * @ctxt:  the XPath Parser context
11741
 * @locset: the location set to filter
11742
 * @filterOpIndex: the index of the predicate/filter op
11743
 * @minPos: minimum position in the filtered set (1-based)
11744
 * @maxPos: maximum position in the filtered set (1-based)
11745
 *
11746
 * Filter a location set, keeping only nodes for which the predicate
11747
 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11748
 * in the filtered result.
11749
 */
11750
static void
11751
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
11752
              xmlLocationSetPtr locset,
11753
              int filterOpIndex,
11754
                          int minPos, int maxPos)
11755
{
11756
    xmlXPathContextPtr xpctxt;
11757
    xmlNodePtr oldnode;
11758
    xmlDocPtr olddoc;
11759
    xmlXPathStepOpPtr filterOp;
11760
    int oldcs, oldpp;
11761
    int i, j, pos;
11762
11763
    if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
11764
        return;
11765
11766
    xpctxt = ctxt->context;
11767
    oldnode = xpctxt->node;
11768
    olddoc = xpctxt->doc;
11769
    oldcs = xpctxt->contextSize;
11770
    oldpp = xpctxt->proximityPosition;
11771
    filterOp = &ctxt->comp->steps[filterOpIndex];
11772
11773
    xpctxt->contextSize = locset->locNr;
11774
11775
    for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
11776
        xmlNodePtr contextNode = locset->locTab[i]->user;
11777
        int res;
11778
11779
        xpctxt->node = contextNode;
11780
        xpctxt->proximityPosition = i + 1;
11781
11782
        /*
11783
        * Also set the xpath document in case things like
11784
        * key() are evaluated in the predicate.
11785
        *
11786
        * TODO: Get real doc for namespace nodes.
11787
        */
11788
        if ((contextNode->type != XML_NAMESPACE_DECL) &&
11789
            (contextNode->doc != NULL))
11790
            xpctxt->doc = contextNode->doc;
11791
11792
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
11793
11794
        if (ctxt->error != XPATH_EXPRESSION_OK)
11795
            break;
11796
        if (res < 0) {
11797
            /* Shouldn't happen */
11798
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
11799
            break;
11800
        }
11801
11802
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
11803
            if (i != j) {
11804
                locset->locTab[j] = locset->locTab[i];
11805
                locset->locTab[i] = NULL;
11806
            }
11807
11808
            j += 1;
11809
        } else {
11810
            /* Remove the entry from the initial location set. */
11811
            xmlXPathFreeObject(locset->locTab[i]);
11812
            locset->locTab[i] = NULL;
11813
        }
11814
11815
        if (res != 0) {
11816
            if (pos == maxPos) {
11817
                i += 1;
11818
                break;
11819
            }
11820
11821
            pos += 1;
11822
        }
11823
    }
11824
11825
    /* Free remaining nodes. */
11826
    for (; i < locset->locNr; i++)
11827
        xmlXPathFreeObject(locset->locTab[i]);
11828
11829
    locset->locNr = j;
11830
11831
    /* If too many elements were removed, shrink table to preserve memory. */
11832
    if ((locset->locMax > XML_NODESET_DEFAULT) &&
11833
        (locset->locNr < locset->locMax / 2)) {
11834
        xmlXPathObjectPtr *tmp;
11835
        int locMax = locset->locNr;
11836
11837
        if (locMax < XML_NODESET_DEFAULT)
11838
            locMax = XML_NODESET_DEFAULT;
11839
        tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
11840
                locMax * sizeof(xmlXPathObjectPtr));
11841
        if (tmp == NULL) {
11842
            xmlXPathPErrMemory(ctxt, "shrinking locset\n");
11843
        } else {
11844
            locset->locTab = tmp;
11845
            locset->locMax = locMax;
11846
        }
11847
    }
11848
11849
    xpctxt->node = oldnode;
11850
    xpctxt->doc = olddoc;
11851
    xpctxt->contextSize = oldcs;
11852
    xpctxt->proximityPosition = oldpp;
11853
}
11854
#endif /* LIBXML_XPTR_LOCS_ENABLED */
11855
11856
/**
11857
 * xmlXPathCompOpEvalPredicate:
11858
 * @ctxt:  the XPath Parser context
11859
 * @op: the predicate op
11860
 * @set: the node set to filter
11861
 * @minPos: minimum position in the filtered set (1-based)
11862
 * @maxPos: maximum position in the filtered set (1-based)
11863
 * @hasNsNodes: true if the node set may contain namespace nodes
11864
 *
11865
 * Filter a node set, keeping only nodes for which the sequence of predicate
11866
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11867
 * in the filtered result.
11868
 */
11869
static void
11870
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11871
          xmlXPathStepOpPtr op,
11872
          xmlNodeSetPtr set,
11873
                            int minPos, int maxPos,
11874
          int hasNsNodes)
11875
0
{
11876
0
    if (op->ch1 != -1) {
11877
0
  xmlXPathCompExprPtr comp = ctxt->comp;
11878
  /*
11879
  * Process inner predicates first.
11880
  */
11881
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11882
0
            xmlGenericError(xmlGenericErrorContext,
11883
0
                "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11884
0
            XP_ERROR(XPATH_INVALID_OPERAND);
11885
0
  }
11886
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11887
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11888
0
        ctxt->context->depth += 1;
11889
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11890
0
                                    1, set->nodeNr, hasNsNodes);
11891
0
        ctxt->context->depth -= 1;
11892
0
  CHECK_ERROR;
11893
0
    }
11894
11895
0
    if (op->ch2 != -1)
11896
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11897
0
}
11898
11899
static int
11900
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11901
          xmlXPathStepOpPtr op,
11902
          int *maxPos)
11903
0
{
11904
11905
0
    xmlXPathStepOpPtr exprOp;
11906
11907
    /*
11908
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11909
    */
11910
11911
    /*
11912
    * If not -1, then ch1 will point to:
11913
    * 1) For predicates (XPATH_OP_PREDICATE):
11914
    *    - an inner predicate operator
11915
    * 2) For filters (XPATH_OP_FILTER):
11916
    *    - an inner filter operator OR
11917
    *    - an expression selecting the node set.
11918
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
11919
    */
11920
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11921
0
  return(0);
11922
11923
0
    if (op->ch2 != -1) {
11924
0
  exprOp = &ctxt->comp->steps[op->ch2];
11925
0
    } else
11926
0
  return(0);
11927
11928
0
    if ((exprOp != NULL) &&
11929
0
  (exprOp->op == XPATH_OP_VALUE) &&
11930
0
  (exprOp->value4 != NULL) &&
11931
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11932
0
    {
11933
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11934
11935
  /*
11936
  * We have a "[n]" predicate here.
11937
  * TODO: Unfortunately this simplistic test here is not
11938
  * able to detect a position() predicate in compound
11939
  * expressions like "[@attr = 'a" and position() = 1],
11940
  * and even not the usage of position() in
11941
  * "[position() = 1]"; thus - obviously - a position-range,
11942
  * like it "[position() < 5]", is also not detected.
11943
  * Maybe we could rewrite the AST to ease the optimization.
11944
  */
11945
11946
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11947
0
      *maxPos = (int) floatval;
11948
0
            if (floatval == (double) *maxPos)
11949
0
                return(1);
11950
0
        }
11951
0
    }
11952
0
    return(0);
11953
0
}
11954
11955
static int
11956
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11957
                           xmlXPathStepOpPtr op,
11958
         xmlNodePtr * first, xmlNodePtr * last,
11959
         int toBool)
11960
0
{
11961
11962
0
#define XP_TEST_HIT \
11963
0
    if (hasAxisRange != 0) { \
11964
0
  if (++pos == maxPos) { \
11965
0
      if (addNode(seq, cur) < 0) \
11966
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11967
0
      goto axis_range_end; } \
11968
0
    } else { \
11969
0
  if (addNode(seq, cur) < 0) \
11970
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11971
0
  if (breakOnFirstHit) goto first_hit; }
11972
11973
0
#define XP_TEST_HIT_NS \
11974
0
    if (hasAxisRange != 0) { \
11975
0
  if (++pos == maxPos) { \
11976
0
      hasNsNodes = 1; \
11977
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11978
0
          ctxt->error = XPATH_MEMORY_ERROR; \
11979
0
  goto axis_range_end; } \
11980
0
    } else { \
11981
0
  hasNsNodes = 1; \
11982
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11983
0
      ctxt->error = XPATH_MEMORY_ERROR; \
11984
0
  if (breakOnFirstHit) goto first_hit; }
11985
11986
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11987
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11988
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11989
0
    const xmlChar *prefix = op->value4;
11990
0
    const xmlChar *name = op->value5;
11991
0
    const xmlChar *URI = NULL;
11992
11993
#ifdef DEBUG_STEP
11994
    int nbMatches = 0, prevMatches = 0;
11995
#endif
11996
0
    int total = 0, hasNsNodes = 0;
11997
    /* The popped object holding the context nodes */
11998
0
    xmlXPathObjectPtr obj;
11999
    /* The set of context nodes for the node tests */
12000
0
    xmlNodeSetPtr contextSeq;
12001
0
    int contextIdx;
12002
0
    xmlNodePtr contextNode;
12003
    /* The final resulting node set wrt to all context nodes */
12004
0
    xmlNodeSetPtr outSeq;
12005
    /*
12006
    * The temporary resulting node set wrt 1 context node.
12007
    * Used to feed predicate evaluation.
12008
    */
12009
0
    xmlNodeSetPtr seq;
12010
0
    xmlNodePtr cur;
12011
    /* First predicate operator */
12012
0
    xmlXPathStepOpPtr predOp;
12013
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
12014
0
    int hasPredicateRange, hasAxisRange, pos;
12015
0
    int breakOnFirstHit;
12016
12017
0
    xmlXPathTraversalFunction next = NULL;
12018
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12019
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
12020
0
    xmlNodePtr oldContextNode;
12021
0
    xmlXPathContextPtr xpctxt = ctxt->context;
12022
12023
12024
0
    CHECK_TYPE0(XPATH_NODESET);
12025
0
    obj = valuePop(ctxt);
12026
    /*
12027
    * Setup namespaces.
12028
    */
12029
0
    if (prefix != NULL) {
12030
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
12031
0
        if (URI == NULL) {
12032
0
      xmlXPathReleaseObject(xpctxt, obj);
12033
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12034
0
  }
12035
0
    }
12036
    /*
12037
    * Setup axis.
12038
    *
12039
    * MAYBE FUTURE TODO: merging optimizations:
12040
    * - If the nodes to be traversed wrt to the initial nodes and
12041
    *   the current axis cannot overlap, then we could avoid searching
12042
    *   for duplicates during the merge.
12043
    *   But the question is how/when to evaluate if they cannot overlap.
12044
    *   Example: if we know that for two initial nodes, the one is
12045
    *   not in the ancestor-or-self axis of the other, then we could safely
12046
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12047
    *   the descendant-or-self axis.
12048
    */
12049
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
12050
0
    switch (axis) {
12051
0
        case AXIS_ANCESTOR:
12052
0
            first = NULL;
12053
0
            next = xmlXPathNextAncestor;
12054
0
            break;
12055
0
        case AXIS_ANCESTOR_OR_SELF:
12056
0
            first = NULL;
12057
0
            next = xmlXPathNextAncestorOrSelf;
12058
0
            break;
12059
0
        case AXIS_ATTRIBUTE:
12060
0
            first = NULL;
12061
0
      last = NULL;
12062
0
            next = xmlXPathNextAttribute;
12063
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12064
0
            break;
12065
0
        case AXIS_CHILD:
12066
0
      last = NULL;
12067
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12068
0
    (type == NODE_TYPE_NODE))
12069
0
      {
12070
    /*
12071
    * Optimization if an element node type is 'element'.
12072
    */
12073
0
    next = xmlXPathNextChildElement;
12074
0
      } else
12075
0
    next = xmlXPathNextChild;
12076
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12077
0
            break;
12078
0
        case AXIS_DESCENDANT:
12079
0
      last = NULL;
12080
0
            next = xmlXPathNextDescendant;
12081
0
            break;
12082
0
        case AXIS_DESCENDANT_OR_SELF:
12083
0
      last = NULL;
12084
0
            next = xmlXPathNextDescendantOrSelf;
12085
0
            break;
12086
0
        case AXIS_FOLLOWING:
12087
0
      last = NULL;
12088
0
            next = xmlXPathNextFollowing;
12089
0
            break;
12090
0
        case AXIS_FOLLOWING_SIBLING:
12091
0
      last = NULL;
12092
0
            next = xmlXPathNextFollowingSibling;
12093
0
            break;
12094
0
        case AXIS_NAMESPACE:
12095
0
            first = NULL;
12096
0
      last = NULL;
12097
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12098
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12099
0
            break;
12100
0
        case AXIS_PARENT:
12101
0
            first = NULL;
12102
0
            next = xmlXPathNextParent;
12103
0
            break;
12104
0
        case AXIS_PRECEDING:
12105
0
            first = NULL;
12106
0
            next = xmlXPathNextPrecedingInternal;
12107
0
            break;
12108
0
        case AXIS_PRECEDING_SIBLING:
12109
0
            first = NULL;
12110
0
            next = xmlXPathNextPrecedingSibling;
12111
0
            break;
12112
0
        case AXIS_SELF:
12113
0
            first = NULL;
12114
0
      last = NULL;
12115
0
            next = xmlXPathNextSelf;
12116
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12117
0
            break;
12118
0
    }
12119
12120
#ifdef DEBUG_STEP
12121
    xmlXPathDebugDumpStepAxis(op,
12122
  (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12123
#endif
12124
12125
0
    if (next == NULL) {
12126
0
  xmlXPathReleaseObject(xpctxt, obj);
12127
0
        return(0);
12128
0
    }
12129
0
    contextSeq = obj->nodesetval;
12130
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12131
0
  xmlXPathReleaseObject(xpctxt, obj);
12132
0
        valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12133
0
        return(0);
12134
0
    }
12135
    /*
12136
    * Predicate optimization ---------------------------------------------
12137
    * If this step has a last predicate, which contains a position(),
12138
    * then we'll optimize (although not exactly "position()", but only
12139
    * the  short-hand form, i.e., "[n]".
12140
    *
12141
    * Example - expression "/foo[parent::bar][1]":
12142
    *
12143
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
12144
    *   ROOT                               -- op->ch1
12145
    *   PREDICATE                          -- op->ch2 (predOp)
12146
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
12147
    *       SORT
12148
    *         COLLECT  'parent' 'name' 'node' bar
12149
    *           NODE
12150
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
12151
    *
12152
    */
12153
0
    maxPos = 0;
12154
0
    predOp = NULL;
12155
0
    hasPredicateRange = 0;
12156
0
    hasAxisRange = 0;
12157
0
    if (op->ch2 != -1) {
12158
  /*
12159
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12160
  */
12161
0
  predOp = &ctxt->comp->steps[op->ch2];
12162
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12163
0
      if (predOp->ch1 != -1) {
12164
    /*
12165
    * Use the next inner predicate operator.
12166
    */
12167
0
    predOp = &ctxt->comp->steps[predOp->ch1];
12168
0
    hasPredicateRange = 1;
12169
0
      } else {
12170
    /*
12171
    * There's no other predicate than the [n] predicate.
12172
    */
12173
0
    predOp = NULL;
12174
0
    hasAxisRange = 1;
12175
0
      }
12176
0
  }
12177
0
    }
12178
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12179
    /*
12180
    * Axis traversal -----------------------------------------------------
12181
    */
12182
    /*
12183
     * 2.3 Node Tests
12184
     *  - For the attribute axis, the principal node type is attribute.
12185
     *  - For the namespace axis, the principal node type is namespace.
12186
     *  - For other axes, the principal node type is element.
12187
     *
12188
     * A node test * is true for any node of the
12189
     * principal node type. For example, child::* will
12190
     * select all element children of the context node
12191
     */
12192
0
    oldContextNode = xpctxt->node;
12193
0
    addNode = xmlXPathNodeSetAddUnique;
12194
0
    outSeq = NULL;
12195
0
    seq = NULL;
12196
0
    contextNode = NULL;
12197
0
    contextIdx = 0;
12198
12199
12200
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12201
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
12202
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
12203
12204
0
  if (seq == NULL) {
12205
0
      seq = xmlXPathNodeSetCreate(NULL);
12206
0
      if (seq == NULL) {
12207
                /* TODO: Propagate memory error. */
12208
0
    total = 0;
12209
0
    goto error;
12210
0
      }
12211
0
  }
12212
  /*
12213
  * Traverse the axis and test the nodes.
12214
  */
12215
0
  pos = 0;
12216
0
  cur = NULL;
12217
0
  hasNsNodes = 0;
12218
0
        do {
12219
0
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
12220
0
                goto error;
12221
12222
0
            cur = next(ctxt, cur);
12223
0
            if (cur == NULL)
12224
0
                break;
12225
12226
      /*
12227
      * QUESTION TODO: What does the "first" and "last" stuff do?
12228
      */
12229
0
            if ((first != NULL) && (*first != NULL)) {
12230
0
    if (*first == cur)
12231
0
        break;
12232
0
    if (((total % 256) == 0) &&
12233
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12234
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
12235
#else
12236
        (xmlXPathCmpNodes(*first, cur) >= 0))
12237
#endif
12238
0
    {
12239
0
        break;
12240
0
    }
12241
0
      }
12242
0
      if ((last != NULL) && (*last != NULL)) {
12243
0
    if (*last == cur)
12244
0
        break;
12245
0
    if (((total % 256) == 0) &&
12246
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12247
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
12248
#else
12249
        (xmlXPathCmpNodes(cur, *last) >= 0))
12250
#endif
12251
0
    {
12252
0
        break;
12253
0
    }
12254
0
      }
12255
12256
0
            total++;
12257
12258
#ifdef DEBUG_STEP
12259
            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12260
#endif
12261
12262
0
      switch (test) {
12263
0
                case NODE_TEST_NONE:
12264
0
        total = 0;
12265
0
                    STRANGE
12266
0
        goto error;
12267
0
                case NODE_TEST_TYPE:
12268
0
        if (type == NODE_TYPE_NODE) {
12269
0
      switch (cur->type) {
12270
0
          case XML_DOCUMENT_NODE:
12271
0
          case XML_HTML_DOCUMENT_NODE:
12272
0
          case XML_ELEMENT_NODE:
12273
0
          case XML_ATTRIBUTE_NODE:
12274
0
          case XML_PI_NODE:
12275
0
          case XML_COMMENT_NODE:
12276
0
          case XML_CDATA_SECTION_NODE:
12277
0
          case XML_TEXT_NODE:
12278
0
        XP_TEST_HIT
12279
0
        break;
12280
0
          case XML_NAMESPACE_DECL: {
12281
0
        if (axis == AXIS_NAMESPACE) {
12282
0
            XP_TEST_HIT_NS
12283
0
        } else {
12284
0
                              hasNsNodes = 1;
12285
0
            XP_TEST_HIT
12286
0
        }
12287
0
        break;
12288
0
                            }
12289
0
          default:
12290
0
        break;
12291
0
      }
12292
0
        } else if (cur->type == (xmlElementType) type) {
12293
0
      if (cur->type == XML_NAMESPACE_DECL)
12294
0
          XP_TEST_HIT_NS
12295
0
      else
12296
0
          XP_TEST_HIT
12297
0
        } else if ((type == NODE_TYPE_TEXT) &&
12298
0
       (cur->type == XML_CDATA_SECTION_NODE))
12299
0
        {
12300
0
      XP_TEST_HIT
12301
0
        }
12302
0
        break;
12303
0
                case NODE_TEST_PI:
12304
0
                    if ((cur->type == XML_PI_NODE) &&
12305
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
12306
0
        {
12307
0
      XP_TEST_HIT
12308
0
                    }
12309
0
                    break;
12310
0
                case NODE_TEST_ALL:
12311
0
                    if (axis == AXIS_ATTRIBUTE) {
12312
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
12313
0
      {
12314
0
                            if (prefix == NULL)
12315
0
          {
12316
0
        XP_TEST_HIT
12317
0
                            } else if ((cur->ns != NULL) &&
12318
0
        (xmlStrEqual(URI, cur->ns->href)))
12319
0
          {
12320
0
        XP_TEST_HIT
12321
0
                            }
12322
0
                        }
12323
0
                    } else if (axis == AXIS_NAMESPACE) {
12324
0
                        if (cur->type == XML_NAMESPACE_DECL)
12325
0
      {
12326
0
          XP_TEST_HIT_NS
12327
0
                        }
12328
0
                    } else {
12329
0
                        if (cur->type == XML_ELEMENT_NODE) {
12330
0
                            if (prefix == NULL)
12331
0
          {
12332
0
        XP_TEST_HIT
12333
12334
0
                            } else if ((cur->ns != NULL) &&
12335
0
        (xmlStrEqual(URI, cur->ns->href)))
12336
0
          {
12337
0
        XP_TEST_HIT
12338
0
                            }
12339
0
                        }
12340
0
                    }
12341
0
                    break;
12342
0
                case NODE_TEST_NS:{
12343
0
                        TODO;
12344
0
                        break;
12345
0
                    }
12346
0
                case NODE_TEST_NAME:
12347
0
                    if (axis == AXIS_ATTRIBUTE) {
12348
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
12349
0
          break;
12350
0
        } else if (axis == AXIS_NAMESPACE) {
12351
0
                        if (cur->type != XML_NAMESPACE_DECL)
12352
0
          break;
12353
0
        } else {
12354
0
            if (cur->type != XML_ELEMENT_NODE)
12355
0
          break;
12356
0
        }
12357
0
                    switch (cur->type) {
12358
0
                        case XML_ELEMENT_NODE:
12359
0
                            if (xmlStrEqual(name, cur->name)) {
12360
0
                                if (prefix == NULL) {
12361
0
                                    if (cur->ns == NULL)
12362
0
            {
12363
0
          XP_TEST_HIT
12364
0
                                    }
12365
0
                                } else {
12366
0
                                    if ((cur->ns != NULL) &&
12367
0
                                        (xmlStrEqual(URI, cur->ns->href)))
12368
0
            {
12369
0
          XP_TEST_HIT
12370
0
                                    }
12371
0
                                }
12372
0
                            }
12373
0
                            break;
12374
0
                        case XML_ATTRIBUTE_NODE:{
12375
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
12376
12377
0
                                if (xmlStrEqual(name, attr->name)) {
12378
0
                                    if (prefix == NULL) {
12379
0
                                        if ((attr->ns == NULL) ||
12380
0
                                            (attr->ns->prefix == NULL))
12381
0
          {
12382
0
              XP_TEST_HIT
12383
0
                                        }
12384
0
                                    } else {
12385
0
                                        if ((attr->ns != NULL) &&
12386
0
                                            (xmlStrEqual(URI,
12387
0
                attr->ns->href)))
12388
0
          {
12389
0
              XP_TEST_HIT
12390
0
                                        }
12391
0
                                    }
12392
0
                                }
12393
0
                                break;
12394
0
                            }
12395
0
                        case XML_NAMESPACE_DECL:
12396
0
                            if (cur->type == XML_NAMESPACE_DECL) {
12397
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
12398
12399
0
                                if ((ns->prefix != NULL) && (name != NULL)
12400
0
                                    && (xmlStrEqual(ns->prefix, name)))
12401
0
        {
12402
0
            XP_TEST_HIT_NS
12403
0
                                }
12404
0
                            }
12405
0
                            break;
12406
0
                        default:
12407
0
                            break;
12408
0
                    }
12409
0
                    break;
12410
0
      } /* switch(test) */
12411
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12412
12413
0
  goto apply_predicates;
12414
12415
0
axis_range_end: /* ----------------------------------------------------- */
12416
  /*
12417
  * We have a "/foo[n]", and position() = n was reached.
12418
  * Note that we can have as well "/foo/::parent::foo[1]", so
12419
  * a duplicate-aware merge is still needed.
12420
  * Merge with the result.
12421
  */
12422
0
  if (outSeq == NULL) {
12423
0
      outSeq = seq;
12424
0
      seq = NULL;
12425
0
  } else
12426
            /* TODO: Check memory error. */
12427
0
      outSeq = mergeAndClear(outSeq, seq);
12428
  /*
12429
  * Break if only a true/false result was requested.
12430
  */
12431
0
  if (toBool)
12432
0
      break;
12433
0
  continue;
12434
12435
0
first_hit: /* ---------------------------------------------------------- */
12436
  /*
12437
  * Break if only a true/false result was requested and
12438
  * no predicates existed and a node test succeeded.
12439
  */
12440
0
  if (outSeq == NULL) {
12441
0
      outSeq = seq;
12442
0
      seq = NULL;
12443
0
  } else
12444
            /* TODO: Check memory error. */
12445
0
      outSeq = mergeAndClear(outSeq, seq);
12446
0
  break;
12447
12448
#ifdef DEBUG_STEP
12449
  if (seq != NULL)
12450
      nbMatches += seq->nodeNr;
12451
#endif
12452
12453
0
apply_predicates: /* --------------------------------------------------- */
12454
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
12455
0
      goto error;
12456
12457
        /*
12458
  * Apply predicates.
12459
  */
12460
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
12461
      /*
12462
      * E.g. when we have a "/foo[some expression][n]".
12463
      */
12464
      /*
12465
      * QUESTION TODO: The old predicate evaluation took into
12466
      *  account location-sets.
12467
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12468
      *  Do we expect such a set here?
12469
      *  All what I learned now from the evaluation semantics
12470
      *  does not indicate that a location-set will be processed
12471
      *  here, so this looks OK.
12472
      */
12473
      /*
12474
      * Iterate over all predicates, starting with the outermost
12475
      * predicate.
12476
      * TODO: Problem: we cannot execute the inner predicates first
12477
      *  since we cannot go back *up* the operator tree!
12478
      *  Options we have:
12479
      *  1) Use of recursive functions (like is it currently done
12480
      *     via xmlXPathCompOpEval())
12481
      *  2) Add a predicate evaluation information stack to the
12482
      *     context struct
12483
      *  3) Change the way the operators are linked; we need a
12484
      *     "parent" field on xmlXPathStepOp
12485
      *
12486
      * For the moment, I'll try to solve this with a recursive
12487
      * function: xmlXPathCompOpEvalPredicate().
12488
      */
12489
0
      if (hasPredicateRange != 0)
12490
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
12491
0
              hasNsNodes);
12492
0
      else
12493
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
12494
0
              hasNsNodes);
12495
12496
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
12497
0
    total = 0;
12498
0
    goto error;
12499
0
      }
12500
0
        }
12501
12502
0
        if (seq->nodeNr > 0) {
12503
      /*
12504
      * Add to result set.
12505
      */
12506
0
      if (outSeq == NULL) {
12507
0
    outSeq = seq;
12508
0
    seq = NULL;
12509
0
      } else {
12510
                /* TODO: Check memory error. */
12511
0
    outSeq = mergeAndClear(outSeq, seq);
12512
0
      }
12513
12514
0
            if (toBool)
12515
0
                break;
12516
0
  }
12517
0
    }
12518
12519
0
error:
12520
0
    if ((obj->boolval) && (obj->user != NULL)) {
12521
  /*
12522
  * QUESTION TODO: What does this do and why?
12523
  * TODO: Do we have to do this also for the "error"
12524
  * cleanup further down?
12525
  */
12526
0
  ctxt->value->boolval = 1;
12527
0
  ctxt->value->user = obj->user;
12528
0
  obj->user = NULL;
12529
0
  obj->boolval = 0;
12530
0
    }
12531
0
    xmlXPathReleaseObject(xpctxt, obj);
12532
12533
    /*
12534
    * Ensure we return at least an empty set.
12535
    */
12536
0
    if (outSeq == NULL) {
12537
0
  if ((seq != NULL) && (seq->nodeNr == 0))
12538
0
      outSeq = seq;
12539
0
  else
12540
            /* TODO: Check memory error. */
12541
0
      outSeq = xmlXPathNodeSetCreate(NULL);
12542
0
    }
12543
0
    if ((seq != NULL) && (seq != outSeq)) {
12544
0
   xmlXPathFreeNodeSet(seq);
12545
0
    }
12546
    /*
12547
    * Hand over the result. Better to push the set also in
12548
    * case of errors.
12549
    */
12550
0
    valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12551
    /*
12552
    * Reset the context node.
12553
    */
12554
0
    xpctxt->node = oldContextNode;
12555
    /*
12556
    * When traversing the namespace axis in "toBool" mode, it's
12557
    * possible that tmpNsList wasn't freed.
12558
    */
12559
0
    if (xpctxt->tmpNsList != NULL) {
12560
0
        xmlFree(xpctxt->tmpNsList);
12561
0
        xpctxt->tmpNsList = NULL;
12562
0
    }
12563
12564
#ifdef DEBUG_STEP
12565
    xmlGenericError(xmlGenericErrorContext,
12566
  "\nExamined %d nodes, found %d nodes at that step\n",
12567
  total, nbMatches);
12568
#endif
12569
12570
0
    return(total);
12571
0
}
12572
12573
static int
12574
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12575
            xmlXPathStepOpPtr op, xmlNodePtr * first);
12576
12577
/**
12578
 * xmlXPathCompOpEvalFirst:
12579
 * @ctxt:  the XPath parser context with the compiled expression
12580
 * @op:  an XPath compiled operation
12581
 * @first:  the first elem found so far
12582
 *
12583
 * Evaluate the Precompiled XPath operation searching only the first
12584
 * element in document order
12585
 *
12586
 * Returns the number of examined objects.
12587
 */
12588
static int
12589
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12590
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
12591
0
{
12592
0
    int total = 0, cur;
12593
0
    xmlXPathCompExprPtr comp;
12594
0
    xmlXPathObjectPtr arg1, arg2;
12595
12596
0
    CHECK_ERROR0;
12597
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12598
0
        return(0);
12599
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12600
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12601
0
    ctxt->context->depth += 1;
12602
0
    comp = ctxt->comp;
12603
0
    switch (op->op) {
12604
0
        case XPATH_OP_END:
12605
0
            break;
12606
0
        case XPATH_OP_UNION:
12607
0
            total =
12608
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12609
0
                                        first);
12610
0
      CHECK_ERROR0;
12611
0
            if ((ctxt->value != NULL)
12612
0
                && (ctxt->value->type == XPATH_NODESET)
12613
0
                && (ctxt->value->nodesetval != NULL)
12614
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12615
                /*
12616
                 * limit tree traversing to first node in the result
12617
                 */
12618
    /*
12619
    * OPTIMIZE TODO: This implicitly sorts
12620
    *  the result, even if not needed. E.g. if the argument
12621
    *  of the count() function, no sorting is needed.
12622
    * OPTIMIZE TODO: How do we know if the node-list wasn't
12623
    *  already sorted?
12624
    */
12625
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12626
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12627
0
                *first = ctxt->value->nodesetval->nodeTab[0];
12628
0
            }
12629
0
            cur =
12630
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12631
0
                                        first);
12632
0
      CHECK_ERROR0;
12633
12634
0
            arg2 = valuePop(ctxt);
12635
0
            arg1 = valuePop(ctxt);
12636
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12637
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12638
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12639
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12640
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12641
0
            }
12642
0
            if ((ctxt->context->opLimit != 0) &&
12643
0
                (((arg1->nodesetval != NULL) &&
12644
0
                  (xmlXPathCheckOpLimit(ctxt,
12645
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12646
0
                 ((arg2->nodesetval != NULL) &&
12647
0
                  (xmlXPathCheckOpLimit(ctxt,
12648
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12649
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12650
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12651
0
                break;
12652
0
            }
12653
12654
            /* TODO: Check memory error. */
12655
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12656
0
                                                    arg2->nodesetval);
12657
0
            valuePush(ctxt, arg1);
12658
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12659
            /* optimizer */
12660
0
      if (total > cur)
12661
0
    xmlXPathCompSwap(op);
12662
0
            total += cur;
12663
0
            break;
12664
0
        case XPATH_OP_ROOT:
12665
0
            xmlXPathRoot(ctxt);
12666
0
            break;
12667
0
        case XPATH_OP_NODE:
12668
0
            if (op->ch1 != -1)
12669
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12670
0
      CHECK_ERROR0;
12671
0
            if (op->ch2 != -1)
12672
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12673
0
      CHECK_ERROR0;
12674
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12675
0
    ctxt->context->node));
12676
0
            break;
12677
0
        case XPATH_OP_COLLECT:{
12678
0
                if (op->ch1 == -1)
12679
0
                    break;
12680
12681
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12682
0
    CHECK_ERROR0;
12683
12684
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12685
0
                break;
12686
0
            }
12687
0
        case XPATH_OP_VALUE:
12688
0
            valuePush(ctxt,
12689
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12690
0
      (xmlXPathObjectPtr) op->value4));
12691
0
            break;
12692
0
        case XPATH_OP_SORT:
12693
0
            if (op->ch1 != -1)
12694
0
                total +=
12695
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12696
0
                                            first);
12697
0
      CHECK_ERROR0;
12698
0
            if ((ctxt->value != NULL)
12699
0
                && (ctxt->value->type == XPATH_NODESET)
12700
0
                && (ctxt->value->nodesetval != NULL)
12701
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12702
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12703
0
            break;
12704
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
12705
0
  case XPATH_OP_FILTER:
12706
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12707
0
            break;
12708
0
#endif
12709
0
        default:
12710
0
            total += xmlXPathCompOpEval(ctxt, op);
12711
0
            break;
12712
0
    }
12713
12714
0
    ctxt->context->depth -= 1;
12715
0
    return(total);
12716
0
}
12717
12718
/**
12719
 * xmlXPathCompOpEvalLast:
12720
 * @ctxt:  the XPath parser context with the compiled expression
12721
 * @op:  an XPath compiled operation
12722
 * @last:  the last elem found so far
12723
 *
12724
 * Evaluate the Precompiled XPath operation searching only the last
12725
 * element in document order
12726
 *
12727
 * Returns the number of nodes traversed
12728
 */
12729
static int
12730
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12731
                       xmlNodePtr * last)
12732
0
{
12733
0
    int total = 0, cur;
12734
0
    xmlXPathCompExprPtr comp;
12735
0
    xmlXPathObjectPtr arg1, arg2;
12736
12737
0
    CHECK_ERROR0;
12738
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12739
0
        return(0);
12740
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12741
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12742
0
    ctxt->context->depth += 1;
12743
0
    comp = ctxt->comp;
12744
0
    switch (op->op) {
12745
0
        case XPATH_OP_END:
12746
0
            break;
12747
0
        case XPATH_OP_UNION:
12748
0
            total =
12749
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12750
0
      CHECK_ERROR0;
12751
0
            if ((ctxt->value != NULL)
12752
0
                && (ctxt->value->type == XPATH_NODESET)
12753
0
                && (ctxt->value->nodesetval != NULL)
12754
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
12755
                /*
12756
                 * limit tree traversing to first node in the result
12757
                 */
12758
0
    if (ctxt->value->nodesetval->nodeNr > 1)
12759
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
12760
0
                *last =
12761
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
12762
0
                                                     nodesetval->nodeNr -
12763
0
                                                     1];
12764
0
            }
12765
0
            cur =
12766
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12767
0
      CHECK_ERROR0;
12768
0
            if ((ctxt->value != NULL)
12769
0
                && (ctxt->value->type == XPATH_NODESET)
12770
0
                && (ctxt->value->nodesetval != NULL)
12771
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12772
0
            }
12773
12774
0
            arg2 = valuePop(ctxt);
12775
0
            arg1 = valuePop(ctxt);
12776
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12777
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12778
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12779
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12780
0
                XP_ERROR0(XPATH_INVALID_TYPE);
12781
0
            }
12782
0
            if ((ctxt->context->opLimit != 0) &&
12783
0
                (((arg1->nodesetval != NULL) &&
12784
0
                  (xmlXPathCheckOpLimit(ctxt,
12785
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
12786
0
                 ((arg2->nodesetval != NULL) &&
12787
0
                  (xmlXPathCheckOpLimit(ctxt,
12788
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
12789
0
          xmlXPathReleaseObject(ctxt->context, arg1);
12790
0
          xmlXPathReleaseObject(ctxt->context, arg2);
12791
0
                break;
12792
0
            }
12793
12794
            /* TODO: Check memory error. */
12795
0
            arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12796
0
                                                    arg2->nodesetval);
12797
0
            valuePush(ctxt, arg1);
12798
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12799
            /* optimizer */
12800
0
      if (total > cur)
12801
0
    xmlXPathCompSwap(op);
12802
0
            total += cur;
12803
0
            break;
12804
0
        case XPATH_OP_ROOT:
12805
0
            xmlXPathRoot(ctxt);
12806
0
            break;
12807
0
        case XPATH_OP_NODE:
12808
0
            if (op->ch1 != -1)
12809
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12810
0
      CHECK_ERROR0;
12811
0
            if (op->ch2 != -1)
12812
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12813
0
      CHECK_ERROR0;
12814
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12815
0
    ctxt->context->node));
12816
0
            break;
12817
0
        case XPATH_OP_COLLECT:{
12818
0
                if (op->ch1 == -1)
12819
0
                    break;
12820
12821
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822
0
    CHECK_ERROR0;
12823
12824
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12825
0
                break;
12826
0
            }
12827
0
        case XPATH_OP_VALUE:
12828
0
            valuePush(ctxt,
12829
0
                      xmlXPathCacheObjectCopy(ctxt->context,
12830
0
      (xmlXPathObjectPtr) op->value4));
12831
0
            break;
12832
0
        case XPATH_OP_SORT:
12833
0
            if (op->ch1 != -1)
12834
0
                total +=
12835
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12836
0
                                           last);
12837
0
      CHECK_ERROR0;
12838
0
            if ((ctxt->value != NULL)
12839
0
                && (ctxt->value->type == XPATH_NODESET)
12840
0
                && (ctxt->value->nodesetval != NULL)
12841
0
    && (ctxt->value->nodesetval->nodeNr > 1))
12842
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
12843
0
            break;
12844
0
        default:
12845
0
            total += xmlXPathCompOpEval(ctxt, op);
12846
0
            break;
12847
0
    }
12848
12849
0
    ctxt->context->depth -= 1;
12850
0
    return (total);
12851
0
}
12852
12853
#ifdef XP_OPTIMIZED_FILTER_FIRST
12854
static int
12855
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12856
            xmlXPathStepOpPtr op, xmlNodePtr * first)
12857
0
{
12858
0
    int total = 0;
12859
0
    xmlXPathCompExprPtr comp;
12860
0
    xmlNodeSetPtr set;
12861
12862
0
    CHECK_ERROR0;
12863
0
    comp = ctxt->comp;
12864
    /*
12865
    * Optimization for ()[last()] selection i.e. the last elem
12866
    */
12867
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
12868
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12869
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12870
0
  int f = comp->steps[op->ch2].ch1;
12871
12872
0
  if ((f != -1) &&
12873
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12874
0
      (comp->steps[f].value5 == NULL) &&
12875
0
      (comp->steps[f].value == 0) &&
12876
0
      (comp->steps[f].value4 != NULL) &&
12877
0
      (xmlStrEqual
12878
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
12879
0
      xmlNodePtr last = NULL;
12880
12881
0
      total +=
12882
0
    xmlXPathCompOpEvalLast(ctxt,
12883
0
        &comp->steps[op->ch1],
12884
0
        &last);
12885
0
      CHECK_ERROR0;
12886
      /*
12887
      * The nodeset should be in document order,
12888
      * Keep only the last value
12889
      */
12890
0
      if ((ctxt->value != NULL) &&
12891
0
    (ctxt->value->type == XPATH_NODESET) &&
12892
0
    (ctxt->value->nodesetval != NULL) &&
12893
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
12894
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
12895
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12896
0
    *first = *(ctxt->value->nodesetval->nodeTab);
12897
0
      }
12898
0
      return (total);
12899
0
  }
12900
0
    }
12901
12902
0
    if (op->ch1 != -1)
12903
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12904
0
    CHECK_ERROR0;
12905
0
    if (op->ch2 == -1)
12906
0
  return (total);
12907
0
    if (ctxt->value == NULL)
12908
0
  return (total);
12909
12910
#ifdef LIBXML_XPTR_LOCS_ENABLED
12911
    /*
12912
    * Hum are we filtering the result of an XPointer expression
12913
    */
12914
    if (ctxt->value->type == XPATH_LOCATIONSET) {
12915
        xmlLocationSetPtr locset = ctxt->value->user;
12916
12917
        if (locset != NULL) {
12918
            xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12919
            if (locset->locNr > 0)
12920
                *first = (xmlNodePtr) locset->locTab[0]->user;
12921
        }
12922
12923
  return (total);
12924
    }
12925
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12926
12927
0
    CHECK_TYPE0(XPATH_NODESET);
12928
0
    set = ctxt->value->nodesetval;
12929
0
    if (set != NULL) {
12930
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12931
0
        if (set->nodeNr > 0)
12932
0
            *first = set->nodeTab[0];
12933
0
    }
12934
12935
0
    return (total);
12936
0
}
12937
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12938
12939
/**
12940
 * xmlXPathCompOpEval:
12941
 * @ctxt:  the XPath parser context with the compiled expression
12942
 * @op:  an XPath compiled operation
12943
 *
12944
 * Evaluate the Precompiled XPath operation
12945
 * Returns the number of nodes traversed
12946
 */
12947
static int
12948
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12949
0
{
12950
0
    int total = 0;
12951
0
    int equal, ret;
12952
0
    xmlXPathCompExprPtr comp;
12953
0
    xmlXPathObjectPtr arg1, arg2;
12954
12955
0
    CHECK_ERROR0;
12956
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
12957
0
        return(0);
12958
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12959
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12960
0
    ctxt->context->depth += 1;
12961
0
    comp = ctxt->comp;
12962
0
    switch (op->op) {
12963
0
        case XPATH_OP_END:
12964
0
            break;
12965
0
        case XPATH_OP_AND:
12966
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12967
0
      CHECK_ERROR0;
12968
0
            xmlXPathBooleanFunction(ctxt, 1);
12969
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12970
0
                break;
12971
0
            arg2 = valuePop(ctxt);
12972
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12973
0
      if (ctxt->error) {
12974
0
    xmlXPathFreeObject(arg2);
12975
0
    break;
12976
0
      }
12977
0
            xmlXPathBooleanFunction(ctxt, 1);
12978
0
            if (ctxt->value != NULL)
12979
0
                ctxt->value->boolval &= arg2->boolval;
12980
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12981
0
            break;
12982
0
        case XPATH_OP_OR:
12983
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12984
0
      CHECK_ERROR0;
12985
0
            xmlXPathBooleanFunction(ctxt, 1);
12986
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12987
0
                break;
12988
0
            arg2 = valuePop(ctxt);
12989
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12990
0
      if (ctxt->error) {
12991
0
    xmlXPathFreeObject(arg2);
12992
0
    break;
12993
0
      }
12994
0
            xmlXPathBooleanFunction(ctxt, 1);
12995
0
            if (ctxt->value != NULL)
12996
0
                ctxt->value->boolval |= arg2->boolval;
12997
0
      xmlXPathReleaseObject(ctxt->context, arg2);
12998
0
            break;
12999
0
        case XPATH_OP_EQUAL:
13000
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13001
0
      CHECK_ERROR0;
13002
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13003
0
      CHECK_ERROR0;
13004
0
      if (op->value)
13005
0
    equal = xmlXPathEqualValues(ctxt);
13006
0
      else
13007
0
    equal = xmlXPathNotEqualValues(ctxt);
13008
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13009
0
            break;
13010
0
        case XPATH_OP_CMP:
13011
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13012
0
      CHECK_ERROR0;
13013
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13014
0
      CHECK_ERROR0;
13015
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13016
0
      valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13017
0
            break;
13018
0
        case XPATH_OP_PLUS:
13019
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13020
0
      CHECK_ERROR0;
13021
0
            if (op->ch2 != -1) {
13022
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13023
0
      }
13024
0
      CHECK_ERROR0;
13025
0
            if (op->value == 0)
13026
0
                xmlXPathSubValues(ctxt);
13027
0
            else if (op->value == 1)
13028
0
                xmlXPathAddValues(ctxt);
13029
0
            else if (op->value == 2)
13030
0
                xmlXPathValueFlipSign(ctxt);
13031
0
            else if (op->value == 3) {
13032
0
                CAST_TO_NUMBER;
13033
0
                CHECK_TYPE0(XPATH_NUMBER);
13034
0
            }
13035
0
            break;
13036
0
        case XPATH_OP_MULT:
13037
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13038
0
      CHECK_ERROR0;
13039
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13040
0
      CHECK_ERROR0;
13041
0
            if (op->value == 0)
13042
0
                xmlXPathMultValues(ctxt);
13043
0
            else if (op->value == 1)
13044
0
                xmlXPathDivValues(ctxt);
13045
0
            else if (op->value == 2)
13046
0
                xmlXPathModValues(ctxt);
13047
0
            break;
13048
0
        case XPATH_OP_UNION:
13049
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13050
0
      CHECK_ERROR0;
13051
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13052
0
      CHECK_ERROR0;
13053
13054
0
            arg2 = valuePop(ctxt);
13055
0
            arg1 = valuePop(ctxt);
13056
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13057
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13058
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13059
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13060
0
                XP_ERROR0(XPATH_INVALID_TYPE);
13061
0
            }
13062
0
            if ((ctxt->context->opLimit != 0) &&
13063
0
                (((arg1->nodesetval != NULL) &&
13064
0
                  (xmlXPathCheckOpLimit(ctxt,
13065
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
13066
0
                 ((arg2->nodesetval != NULL) &&
13067
0
                  (xmlXPathCheckOpLimit(ctxt,
13068
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
13069
0
          xmlXPathReleaseObject(ctxt->context, arg1);
13070
0
          xmlXPathReleaseObject(ctxt->context, arg2);
13071
0
                break;
13072
0
            }
13073
13074
0
      if ((arg1->nodesetval == NULL) ||
13075
0
    ((arg2->nodesetval != NULL) &&
13076
0
     (arg2->nodesetval->nodeNr != 0)))
13077
0
      {
13078
                /* TODO: Check memory error. */
13079
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13080
0
              arg2->nodesetval);
13081
0
      }
13082
13083
0
            valuePush(ctxt, arg1);
13084
0
      xmlXPathReleaseObject(ctxt->context, arg2);
13085
0
            break;
13086
0
        case XPATH_OP_ROOT:
13087
0
            xmlXPathRoot(ctxt);
13088
0
            break;
13089
0
        case XPATH_OP_NODE:
13090
0
            if (op->ch1 != -1)
13091
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13092
0
      CHECK_ERROR0;
13093
0
            if (op->ch2 != -1)
13094
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13095
0
      CHECK_ERROR0;
13096
0
      valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13097
0
    ctxt->context->node));
13098
0
            break;
13099
0
        case XPATH_OP_COLLECT:{
13100
0
                if (op->ch1 == -1)
13101
0
                    break;
13102
13103
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13104
0
    CHECK_ERROR0;
13105
13106
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13107
0
                break;
13108
0
            }
13109
0
        case XPATH_OP_VALUE:
13110
0
            valuePush(ctxt,
13111
0
                      xmlXPathCacheObjectCopy(ctxt->context,
13112
0
      (xmlXPathObjectPtr) op->value4));
13113
0
            break;
13114
0
        case XPATH_OP_VARIABLE:{
13115
0
    xmlXPathObjectPtr val;
13116
13117
0
                if (op->ch1 != -1)
13118
0
                    total +=
13119
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13120
0
                if (op->value5 == NULL) {
13121
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
13122
0
        if (val == NULL)
13123
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13124
0
                    valuePush(ctxt, val);
13125
0
    } else {
13126
0
                    const xmlChar *URI;
13127
13128
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
13129
0
                    if (URI == NULL) {
13130
0
                        xmlGenericError(xmlGenericErrorContext,
13131
0
            "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13132
0
                                    (char *) op->value4, (char *)op->value5);
13133
0
                        ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13134
0
                        break;
13135
0
                    }
13136
0
        val = xmlXPathVariableLookupNS(ctxt->context,
13137
0
                                                       op->value4, URI);
13138
0
        if (val == NULL)
13139
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13140
0
                    valuePush(ctxt, val);
13141
0
                }
13142
0
                break;
13143
0
            }
13144
0
        case XPATH_OP_FUNCTION:{
13145
0
                xmlXPathFunction func;
13146
0
                const xmlChar *oldFunc, *oldFuncURI;
13147
0
    int i;
13148
0
                int frame;
13149
13150
0
                frame = xmlXPathSetFrame(ctxt);
13151
0
                if (op->ch1 != -1) {
13152
0
                    total +=
13153
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13154
0
                    if (ctxt->error != XPATH_EXPRESSION_OK) {
13155
0
                        xmlXPathPopFrame(ctxt, frame);
13156
0
                        break;
13157
0
                    }
13158
0
                }
13159
0
    if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13160
0
        xmlGenericError(xmlGenericErrorContext,
13161
0
          "xmlXPathCompOpEval: parameter error\n");
13162
0
        ctxt->error = XPATH_INVALID_OPERAND;
13163
0
                    xmlXPathPopFrame(ctxt, frame);
13164
0
        break;
13165
0
    }
13166
0
    for (i = 0; i < op->value; i++) {
13167
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13168
0
      xmlGenericError(xmlGenericErrorContext,
13169
0
        "xmlXPathCompOpEval: parameter error\n");
13170
0
      ctxt->error = XPATH_INVALID_OPERAND;
13171
0
                        xmlXPathPopFrame(ctxt, frame);
13172
0
      break;
13173
0
        }
13174
0
                }
13175
0
                if (op->cache != NULL)
13176
0
                    func = op->cache;
13177
0
                else {
13178
0
                    const xmlChar *URI = NULL;
13179
13180
0
                    if (op->value5 == NULL)
13181
0
                        func =
13182
0
                            xmlXPathFunctionLookup(ctxt->context,
13183
0
                                                   op->value4);
13184
0
                    else {
13185
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
13186
0
                        if (URI == NULL) {
13187
0
                            xmlGenericError(xmlGenericErrorContext,
13188
0
            "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13189
0
                                    (char *)op->value4, (char *)op->value5);
13190
0
                            xmlXPathPopFrame(ctxt, frame);
13191
0
                            ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13192
0
                            break;
13193
0
                        }
13194
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
13195
0
                                                        op->value4, URI);
13196
0
                    }
13197
0
                    if (func == NULL) {
13198
0
                        xmlGenericError(xmlGenericErrorContext,
13199
0
                                "xmlXPathCompOpEval: function %s not found\n",
13200
0
                                        (char *)op->value4);
13201
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13202
0
                    }
13203
0
                    op->cache = func;
13204
0
                    op->cacheURI = (void *) URI;
13205
0
                }
13206
0
                oldFunc = ctxt->context->function;
13207
0
                oldFuncURI = ctxt->context->functionURI;
13208
0
                ctxt->context->function = op->value4;
13209
0
                ctxt->context->functionURI = op->cacheURI;
13210
0
                func(ctxt, op->value);
13211
0
                ctxt->context->function = oldFunc;
13212
0
                ctxt->context->functionURI = oldFuncURI;
13213
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
13214
0
                    (ctxt->valueNr != ctxt->valueFrame + 1))
13215
0
                    XP_ERROR0(XPATH_STACK_ERROR);
13216
0
                xmlXPathPopFrame(ctxt, frame);
13217
0
                break;
13218
0
            }
13219
0
        case XPATH_OP_ARG:
13220
0
            if (op->ch1 != -1) {
13221
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13222
0
          CHECK_ERROR0;
13223
0
            }
13224
0
            if (op->ch2 != -1) {
13225
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13226
0
          CHECK_ERROR0;
13227
0
      }
13228
0
            break;
13229
0
        case XPATH_OP_PREDICATE:
13230
0
        case XPATH_OP_FILTER:{
13231
0
                xmlNodeSetPtr set;
13232
13233
                /*
13234
                 * Optimization for ()[1] selection i.e. the first elem
13235
                 */
13236
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13237
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
13238
        /*
13239
        * FILTER TODO: Can we assume that the inner processing
13240
        *  will result in an ordered list if we have an
13241
        *  XPATH_OP_FILTER?
13242
        *  What about an additional field or flag on
13243
        *  xmlXPathObject like @sorted ? This way we wouldn't need
13244
        *  to assume anything, so it would be more robust and
13245
        *  easier to optimize.
13246
        */
13247
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13248
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13249
#else
13250
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13251
#endif
13252
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13253
0
                    xmlXPathObjectPtr val;
13254
13255
0
                    val = comp->steps[op->ch2].value4;
13256
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13257
0
                        (val->floatval == 1.0)) {
13258
0
                        xmlNodePtr first = NULL;
13259
13260
0
                        total +=
13261
0
                            xmlXPathCompOpEvalFirst(ctxt,
13262
0
                                                    &comp->steps[op->ch1],
13263
0
                                                    &first);
13264
0
      CHECK_ERROR0;
13265
                        /*
13266
                         * The nodeset should be in document order,
13267
                         * Keep only the first value
13268
                         */
13269
0
                        if ((ctxt->value != NULL) &&
13270
0
                            (ctxt->value->type == XPATH_NODESET) &&
13271
0
                            (ctxt->value->nodesetval != NULL) &&
13272
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13273
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13274
0
                                                        1, 1);
13275
0
                        break;
13276
0
                    }
13277
0
                }
13278
                /*
13279
                 * Optimization for ()[last()] selection i.e. the last elem
13280
                 */
13281
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
13282
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13283
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13284
0
                    int f = comp->steps[op->ch2].ch1;
13285
13286
0
                    if ((f != -1) &&
13287
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13288
0
                        (comp->steps[f].value5 == NULL) &&
13289
0
                        (comp->steps[f].value == 0) &&
13290
0
                        (comp->steps[f].value4 != NULL) &&
13291
0
                        (xmlStrEqual
13292
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
13293
0
                        xmlNodePtr last = NULL;
13294
13295
0
                        total +=
13296
0
                            xmlXPathCompOpEvalLast(ctxt,
13297
0
                                                   &comp->steps[op->ch1],
13298
0
                                                   &last);
13299
0
      CHECK_ERROR0;
13300
                        /*
13301
                         * The nodeset should be in document order,
13302
                         * Keep only the last value
13303
                         */
13304
0
                        if ((ctxt->value != NULL) &&
13305
0
                            (ctxt->value->type == XPATH_NODESET) &&
13306
0
                            (ctxt->value->nodesetval != NULL) &&
13307
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
13308
0
                            (ctxt->value->nodesetval->nodeNr > 1))
13309
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13310
0
                        break;
13311
0
                    }
13312
0
                }
13313
    /*
13314
    * Process inner predicates first.
13315
    * Example "index[parent::book][1]":
13316
    * ...
13317
    *   PREDICATE   <-- we are here "[1]"
13318
    *     PREDICATE <-- process "[parent::book]" first
13319
    *       SORT
13320
    *         COLLECT  'parent' 'name' 'node' book
13321
    *           NODE
13322
    *     ELEM Object is a number : 1
13323
    */
13324
0
                if (op->ch1 != -1)
13325
0
                    total +=
13326
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13327
0
    CHECK_ERROR0;
13328
0
                if (op->ch2 == -1)
13329
0
                    break;
13330
0
                if (ctxt->value == NULL)
13331
0
                    break;
13332
13333
#ifdef LIBXML_XPTR_LOCS_ENABLED
13334
                /*
13335
                 * Hum are we filtering the result of an XPointer expression
13336
                 */
13337
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13338
                    xmlLocationSetPtr locset = ctxt->value->user;
13339
                    xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
13340
                                              1, locset->locNr);
13341
                    break;
13342
                }
13343
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13344
13345
0
                CHECK_TYPE0(XPATH_NODESET);
13346
0
                set = ctxt->value->nodesetval;
13347
0
                if (set != NULL)
13348
0
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
13349
0
                                          1, set->nodeNr, 1);
13350
0
                break;
13351
0
            }
13352
0
        case XPATH_OP_SORT:
13353
0
            if (op->ch1 != -1)
13354
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13355
0
      CHECK_ERROR0;
13356
0
            if ((ctxt->value != NULL) &&
13357
0
                (ctxt->value->type == XPATH_NODESET) &&
13358
0
                (ctxt->value->nodesetval != NULL) &&
13359
0
    (ctxt->value->nodesetval->nodeNr > 1))
13360
0
      {
13361
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
13362
0
      }
13363
0
            break;
13364
#ifdef LIBXML_XPTR_LOCS_ENABLED
13365
        case XPATH_OP_RANGETO:{
13366
                xmlXPathObjectPtr range;
13367
                xmlXPathObjectPtr res, obj;
13368
                xmlXPathObjectPtr tmp;
13369
                xmlLocationSetPtr newlocset = NULL;
13370
        xmlLocationSetPtr oldlocset;
13371
                xmlNodeSetPtr oldset;
13372
                xmlNodePtr oldnode = ctxt->context->node;
13373
                int oldcs = ctxt->context->contextSize;
13374
                int oldpp = ctxt->context->proximityPosition;
13375
                int i, j;
13376
13377
                if (op->ch1 != -1) {
13378
                    total +=
13379
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13380
                    CHECK_ERROR0;
13381
                }
13382
                if (ctxt->value == NULL) {
13383
                    XP_ERROR0(XPATH_INVALID_OPERAND);
13384
                }
13385
                if (op->ch2 == -1)
13386
                    break;
13387
13388
                if (ctxt->value->type == XPATH_LOCATIONSET) {
13389
                    /*
13390
                     * Extract the old locset, and then evaluate the result of the
13391
                     * expression for all the element in the locset. use it to grow
13392
                     * up a new locset.
13393
                     */
13394
                    CHECK_TYPE0(XPATH_LOCATIONSET);
13395
13396
                    if ((ctxt->value->user == NULL) ||
13397
                        (((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
13398
                        break;
13399
13400
                    obj = valuePop(ctxt);
13401
                    oldlocset = obj->user;
13402
13403
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13404
13405
                    for (i = 0; i < oldlocset->locNr; i++) {
13406
                        /*
13407
                         * Run the evaluation with a node list made of a
13408
                         * single item in the nodelocset.
13409
                         */
13410
                        ctxt->context->node = oldlocset->locTab[i]->user;
13411
                        ctxt->context->contextSize = oldlocset->locNr;
13412
                        ctxt->context->proximityPosition = i + 1;
13413
      tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13414
          ctxt->context->node);
13415
                        valuePush(ctxt, tmp);
13416
13417
                        if (op->ch2 != -1)
13418
                            total +=
13419
                                xmlXPathCompOpEval(ctxt,
13420
                                                   &comp->steps[op->ch2]);
13421
      if (ctxt->error != XPATH_EXPRESSION_OK) {
13422
                            xmlXPtrFreeLocationSet(newlocset);
13423
                            goto rangeto_error;
13424
      }
13425
13426
                        res = valuePop(ctxt);
13427
      if (res->type == XPATH_LOCATIONSET) {
13428
          xmlLocationSetPtr rloc =
13429
              (xmlLocationSetPtr)res->user;
13430
          for (j=0; j<rloc->locNr; j++) {
13431
              range = xmlXPtrNewRange(
13432
          oldlocset->locTab[i]->user,
13433
          oldlocset->locTab[i]->index,
13434
          rloc->locTab[j]->user2,
13435
          rloc->locTab[j]->index2);
13436
        if (range != NULL) {
13437
            xmlXPtrLocationSetAdd(newlocset, range);
13438
        }
13439
          }
13440
      } else {
13441
          range = xmlXPtrNewRangeNodeObject(
13442
        (xmlNodePtr)oldlocset->locTab[i]->user, res);
13443
                            if (range != NULL) {
13444
                                xmlXPtrLocationSetAdd(newlocset,range);
13445
          }
13446
                        }
13447
13448
                        /*
13449
                         * Cleanup
13450
                         */
13451
                        if (res != NULL) {
13452
          xmlXPathReleaseObject(ctxt->context, res);
13453
      }
13454
                        if (ctxt->value == tmp) {
13455
                            res = valuePop(ctxt);
13456
          xmlXPathReleaseObject(ctxt->context, res);
13457
                        }
13458
                    }
13459
    } else {  /* Not a location set */
13460
                    CHECK_TYPE0(XPATH_NODESET);
13461
                    obj = valuePop(ctxt);
13462
                    oldset = obj->nodesetval;
13463
13464
                    newlocset = xmlXPtrLocationSetCreate(NULL);
13465
13466
                    if (oldset != NULL) {
13467
                        for (i = 0; i < oldset->nodeNr; i++) {
13468
                            /*
13469
                             * Run the evaluation with a node list made of a single item
13470
                             * in the nodeset.
13471
                             */
13472
                            ctxt->context->node = oldset->nodeTab[i];
13473
          /*
13474
          * OPTIMIZE TODO: Avoid recreation for every iteration.
13475
          */
13476
          tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13477
        ctxt->context->node);
13478
                            valuePush(ctxt, tmp);
13479
13480
                            if (op->ch2 != -1)
13481
                                total +=
13482
                                    xmlXPathCompOpEval(ctxt,
13483
                                                   &comp->steps[op->ch2]);
13484
          if (ctxt->error != XPATH_EXPRESSION_OK) {
13485
                                xmlXPtrFreeLocationSet(newlocset);
13486
                                goto rangeto_error;
13487
          }
13488
13489
                            res = valuePop(ctxt);
13490
                            range =
13491
                                xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13492
                                                      res);
13493
                            if (range != NULL) {
13494
                                xmlXPtrLocationSetAdd(newlocset, range);
13495
                            }
13496
13497
                            /*
13498
                             * Cleanup
13499
                             */
13500
                            if (res != NULL) {
13501
        xmlXPathReleaseObject(ctxt->context, res);
13502
          }
13503
                            if (ctxt->value == tmp) {
13504
                                res = valuePop(ctxt);
13505
        xmlXPathReleaseObject(ctxt->context, res);
13506
                            }
13507
                        }
13508
                    }
13509
                }
13510
13511
                /*
13512
                 * The result is used as the new evaluation set.
13513
                 */
13514
                valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13515
rangeto_error:
13516
    xmlXPathReleaseObject(ctxt->context, obj);
13517
                ctxt->context->node = oldnode;
13518
                ctxt->context->contextSize = oldcs;
13519
                ctxt->context->proximityPosition = oldpp;
13520
                break;
13521
            }
13522
#endif /* LIBXML_XPTR_LOCS_ENABLED */
13523
0
        default:
13524
0
            xmlGenericError(xmlGenericErrorContext,
13525
0
                            "XPath: unknown precompiled operation %d\n", op->op);
13526
0
            ctxt->error = XPATH_INVALID_OPERAND;
13527
0
            break;
13528
0
    }
13529
13530
0
    ctxt->context->depth -= 1;
13531
0
    return (total);
13532
0
}
13533
13534
/**
13535
 * xmlXPathCompOpEvalToBoolean:
13536
 * @ctxt:  the XPath parser context
13537
 *
13538
 * Evaluates if the expression evaluates to true.
13539
 *
13540
 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13541
 */
13542
static int
13543
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13544
          xmlXPathStepOpPtr op,
13545
          int isPredicate)
13546
0
{
13547
0
    xmlXPathObjectPtr resObj = NULL;
13548
13549
0
start:
13550
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
13551
0
        return(0);
13552
    /* comp = ctxt->comp; */
13553
0
    switch (op->op) {
13554
0
        case XPATH_OP_END:
13555
0
            return (0);
13556
0
  case XPATH_OP_VALUE:
13557
0
      resObj = (xmlXPathObjectPtr) op->value4;
13558
0
      if (isPredicate)
13559
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13560
0
      return(xmlXPathCastToBoolean(resObj));
13561
0
  case XPATH_OP_SORT:
13562
      /*
13563
      * We don't need sorting for boolean results. Skip this one.
13564
      */
13565
0
            if (op->ch1 != -1) {
13566
0
    op = &ctxt->comp->steps[op->ch1];
13567
0
    goto start;
13568
0
      }
13569
0
      return(0);
13570
0
  case XPATH_OP_COLLECT:
13571
0
      if (op->ch1 == -1)
13572
0
    return(0);
13573
13574
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13575
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13576
0
    return(-1);
13577
13578
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13579
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13580
0
    return(-1);
13581
13582
0
      resObj = valuePop(ctxt);
13583
0
      if (resObj == NULL)
13584
0
    return(-1);
13585
0
      break;
13586
0
  default:
13587
      /*
13588
      * Fallback to call xmlXPathCompOpEval().
13589
      */
13590
0
      xmlXPathCompOpEval(ctxt, op);
13591
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
13592
0
    return(-1);
13593
13594
0
      resObj = valuePop(ctxt);
13595
0
      if (resObj == NULL)
13596
0
    return(-1);
13597
0
      break;
13598
0
    }
13599
13600
0
    if (resObj) {
13601
0
  int res;
13602
13603
0
  if (resObj->type == XPATH_BOOLEAN) {
13604
0
      res = resObj->boolval;
13605
0
  } else if (isPredicate) {
13606
      /*
13607
      * For predicates a result of type "number" is handled
13608
      * differently:
13609
      * SPEC XPath 1.0:
13610
      * "If the result is a number, the result will be converted
13611
      *  to true if the number is equal to the context position
13612
      *  and will be converted to false otherwise;"
13613
      */
13614
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13615
0
  } else {
13616
0
      res = xmlXPathCastToBoolean(resObj);
13617
0
  }
13618
0
  xmlXPathReleaseObject(ctxt->context, resObj);
13619
0
  return(res);
13620
0
    }
13621
13622
0
    return(0);
13623
0
}
13624
13625
#ifdef XPATH_STREAMING
13626
/**
13627
 * xmlXPathRunStreamEval:
13628
 * @ctxt:  the XPath parser context with the compiled expression
13629
 *
13630
 * Evaluate the Precompiled Streamable XPath expression in the given context.
13631
 */
13632
static int
13633
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13634
          xmlXPathObjectPtr *resultSeq, int toBool)
13635
0
{
13636
0
    int max_depth, min_depth;
13637
0
    int from_root;
13638
0
    int ret, depth;
13639
0
    int eval_all_nodes;
13640
0
    xmlNodePtr cur = NULL, limit = NULL;
13641
0
    xmlStreamCtxtPtr patstream = NULL;
13642
13643
0
    int nb_nodes = 0;
13644
13645
0
    if ((ctxt == NULL) || (comp == NULL))
13646
0
        return(-1);
13647
0
    max_depth = xmlPatternMaxDepth(comp);
13648
0
    if (max_depth == -1)
13649
0
        return(-1);
13650
0
    if (max_depth == -2)
13651
0
        max_depth = 10000;
13652
0
    min_depth = xmlPatternMinDepth(comp);
13653
0
    if (min_depth == -1)
13654
0
        return(-1);
13655
0
    from_root = xmlPatternFromRoot(comp);
13656
0
    if (from_root < 0)
13657
0
        return(-1);
13658
#if 0
13659
    printf("stream eval: depth %d from root %d\n", max_depth, from_root);
13660
#endif
13661
13662
0
    if (! toBool) {
13663
0
  if (resultSeq == NULL)
13664
0
      return(-1);
13665
0
  *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
13666
0
  if (*resultSeq == NULL)
13667
0
      return(-1);
13668
0
    }
13669
13670
    /*
13671
     * handle the special cases of "/" amd "." being matched
13672
     */
13673
0
    if (min_depth == 0) {
13674
0
  if (from_root) {
13675
      /* Select "/" */
13676
0
      if (toBool)
13677
0
    return(1);
13678
            /* TODO: Check memory error. */
13679
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
13680
0
                         (xmlNodePtr) ctxt->doc);
13681
0
  } else {
13682
      /* Select "self::node()" */
13683
0
      if (toBool)
13684
0
    return(1);
13685
            /* TODO: Check memory error. */
13686
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
13687
0
  }
13688
0
    }
13689
0
    if (max_depth == 0) {
13690
0
  return(0);
13691
0
    }
13692
13693
0
    if (from_root) {
13694
0
        cur = (xmlNodePtr)ctxt->doc;
13695
0
    } else if (ctxt->node != NULL) {
13696
0
        switch (ctxt->node->type) {
13697
0
            case XML_ELEMENT_NODE:
13698
0
            case XML_DOCUMENT_NODE:
13699
0
            case XML_DOCUMENT_FRAG_NODE:
13700
0
            case XML_HTML_DOCUMENT_NODE:
13701
0
          cur = ctxt->node;
13702
0
    break;
13703
0
            case XML_ATTRIBUTE_NODE:
13704
0
            case XML_TEXT_NODE:
13705
0
            case XML_CDATA_SECTION_NODE:
13706
0
            case XML_ENTITY_REF_NODE:
13707
0
            case XML_ENTITY_NODE:
13708
0
            case XML_PI_NODE:
13709
0
            case XML_COMMENT_NODE:
13710
0
            case XML_NOTATION_NODE:
13711
0
            case XML_DTD_NODE:
13712
0
            case XML_DOCUMENT_TYPE_NODE:
13713
0
            case XML_ELEMENT_DECL:
13714
0
            case XML_ATTRIBUTE_DECL:
13715
0
            case XML_ENTITY_DECL:
13716
0
            case XML_NAMESPACE_DECL:
13717
0
            case XML_XINCLUDE_START:
13718
0
            case XML_XINCLUDE_END:
13719
0
    break;
13720
0
  }
13721
0
  limit = cur;
13722
0
    }
13723
0
    if (cur == NULL) {
13724
0
        return(0);
13725
0
    }
13726
13727
0
    patstream = xmlPatternGetStreamCtxt(comp);
13728
0
    if (patstream == NULL) {
13729
  /*
13730
  * QUESTION TODO: Is this an error?
13731
  */
13732
0
  return(0);
13733
0
    }
13734
13735
0
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
13736
13737
0
    if (from_root) {
13738
0
  ret = xmlStreamPush(patstream, NULL, NULL);
13739
0
  if (ret < 0) {
13740
0
  } else if (ret == 1) {
13741
0
      if (toBool)
13742
0
    goto return_1;
13743
            /* TODO: Check memory error. */
13744
0
      xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
13745
0
  }
13746
0
    }
13747
0
    depth = 0;
13748
0
    goto scan_children;
13749
0
next_node:
13750
0
    do {
13751
0
        if (ctxt->opLimit != 0) {
13752
0
            if (ctxt->opCount >= ctxt->opLimit) {
13753
0
                xmlGenericError(xmlGenericErrorContext,
13754
0
                        "XPath operation limit exceeded\n");
13755
0
                xmlFreeStreamCtxt(patstream);
13756
0
                return(-1);
13757
0
            }
13758
0
            ctxt->opCount++;
13759
0
        }
13760
13761
0
        nb_nodes++;
13762
13763
0
  switch (cur->type) {
13764
0
      case XML_ELEMENT_NODE:
13765
0
      case XML_TEXT_NODE:
13766
0
      case XML_CDATA_SECTION_NODE:
13767
0
      case XML_COMMENT_NODE:
13768
0
      case XML_PI_NODE:
13769
0
    if (cur->type == XML_ELEMENT_NODE) {
13770
0
        ret = xmlStreamPush(patstream, cur->name,
13771
0
        (cur->ns ? cur->ns->href : NULL));
13772
0
    } else if (eval_all_nodes)
13773
0
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
13774
0
    else
13775
0
        break;
13776
13777
0
    if (ret < 0) {
13778
        /* NOP. */
13779
0
    } else if (ret == 1) {
13780
0
        if (toBool)
13781
0
      goto return_1;
13782
0
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
13783
0
            < 0) {
13784
0
      ctxt->lastError.domain = XML_FROM_XPATH;
13785
0
      ctxt->lastError.code = XML_ERR_NO_MEMORY;
13786
0
        }
13787
0
    }
13788
0
    if ((cur->children == NULL) || (depth >= max_depth)) {
13789
0
        ret = xmlStreamPop(patstream);
13790
0
        while (cur->next != NULL) {
13791
0
      cur = cur->next;
13792
0
      if ((cur->type != XML_ENTITY_DECL) &&
13793
0
          (cur->type != XML_DTD_NODE))
13794
0
          goto next_node;
13795
0
        }
13796
0
    }
13797
0
      default:
13798
0
    break;
13799
0
  }
13800
13801
0
scan_children:
13802
0
  if (cur->type == XML_NAMESPACE_DECL) break;
13803
0
  if ((cur->children != NULL) && (depth < max_depth)) {
13804
      /*
13805
       * Do not descend on entities declarations
13806
       */
13807
0
      if (cur->children->type != XML_ENTITY_DECL) {
13808
0
    cur = cur->children;
13809
0
    depth++;
13810
    /*
13811
     * Skip DTDs
13812
     */
13813
0
    if (cur->type != XML_DTD_NODE)
13814
0
        continue;
13815
0
      }
13816
0
  }
13817
13818
0
  if (cur == limit)
13819
0
      break;
13820
13821
0
  while (cur->next != NULL) {
13822
0
      cur = cur->next;
13823
0
      if ((cur->type != XML_ENTITY_DECL) &&
13824
0
    (cur->type != XML_DTD_NODE))
13825
0
    goto next_node;
13826
0
  }
13827
13828
0
  do {
13829
0
      cur = cur->parent;
13830
0
      depth--;
13831
0
      if ((cur == NULL) || (cur == limit) ||
13832
0
                (cur->type == XML_DOCUMENT_NODE))
13833
0
          goto done;
13834
0
      if (cur->type == XML_ELEMENT_NODE) {
13835
0
    ret = xmlStreamPop(patstream);
13836
0
      } else if ((eval_all_nodes) &&
13837
0
    ((cur->type == XML_TEXT_NODE) ||
13838
0
     (cur->type == XML_CDATA_SECTION_NODE) ||
13839
0
     (cur->type == XML_COMMENT_NODE) ||
13840
0
     (cur->type == XML_PI_NODE)))
13841
0
      {
13842
0
    ret = xmlStreamPop(patstream);
13843
0
      }
13844
0
      if (cur->next != NULL) {
13845
0
    cur = cur->next;
13846
0
    break;
13847
0
      }
13848
0
  } while (cur != NULL);
13849
13850
0
    } while ((cur != NULL) && (depth >= 0));
13851
13852
0
done:
13853
13854
#if 0
13855
    printf("stream eval: checked %d nodes selected %d\n",
13856
           nb_nodes, retObj->nodesetval->nodeNr);
13857
#endif
13858
13859
0
    if (patstream)
13860
0
  xmlFreeStreamCtxt(patstream);
13861
0
    return(0);
13862
13863
0
return_1:
13864
0
    if (patstream)
13865
0
  xmlFreeStreamCtxt(patstream);
13866
0
    return(1);
13867
0
}
13868
#endif /* XPATH_STREAMING */
13869
13870
/**
13871
 * xmlXPathRunEval:
13872
 * @ctxt:  the XPath parser context with the compiled expression
13873
 * @toBool:  evaluate to a boolean result
13874
 *
13875
 * Evaluate the Precompiled XPath expression in the given context.
13876
 */
13877
static int
13878
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
13879
0
{
13880
0
    xmlXPathCompExprPtr comp;
13881
13882
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
13883
0
  return(-1);
13884
13885
0
    ctxt->context->depth = 0;
13886
13887
0
    if (ctxt->valueTab == NULL) {
13888
  /* Allocate the value stack */
13889
0
  ctxt->valueTab = (xmlXPathObjectPtr *)
13890
0
       xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13891
0
  if (ctxt->valueTab == NULL) {
13892
0
      xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13893
0
      return(-1);
13894
0
  }
13895
0
  ctxt->valueNr = 0;
13896
0
  ctxt->valueMax = 10;
13897
0
  ctxt->value = NULL;
13898
0
        ctxt->valueFrame = 0;
13899
0
    }
13900
0
#ifdef XPATH_STREAMING
13901
0
    if (ctxt->comp->stream) {
13902
0
  int res;
13903
13904
0
  if (toBool) {
13905
      /*
13906
      * Evaluation to boolean result.
13907
      */
13908
0
      res = xmlXPathRunStreamEval(ctxt->context,
13909
0
    ctxt->comp->stream, NULL, 1);
13910
0
      if (res != -1)
13911
0
    return(res);
13912
0
  } else {
13913
0
      xmlXPathObjectPtr resObj = NULL;
13914
13915
      /*
13916
      * Evaluation to a sequence.
13917
      */
13918
0
      res = xmlXPathRunStreamEval(ctxt->context,
13919
0
    ctxt->comp->stream, &resObj, 0);
13920
13921
0
      if ((res != -1) && (resObj != NULL)) {
13922
0
    valuePush(ctxt, resObj);
13923
0
    return(0);
13924
0
      }
13925
0
      if (resObj != NULL)
13926
0
    xmlXPathReleaseObject(ctxt->context, resObj);
13927
0
  }
13928
  /*
13929
  * QUESTION TODO: This falls back to normal XPath evaluation
13930
  * if res == -1. Is this intended?
13931
  */
13932
0
    }
13933
0
#endif
13934
0
    comp = ctxt->comp;
13935
0
    if (comp->last < 0) {
13936
0
  xmlGenericError(xmlGenericErrorContext,
13937
0
      "xmlXPathRunEval: last is less than zero\n");
13938
0
  return(-1);
13939
0
    }
13940
0
    if (toBool)
13941
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
13942
0
      &comp->steps[comp->last], 0));
13943
0
    else
13944
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13945
13946
0
    return(0);
13947
0
}
13948
13949
/************************************************************************
13950
 *                  *
13951
 *      Public interfaces       *
13952
 *                  *
13953
 ************************************************************************/
13954
13955
/**
13956
 * xmlXPathEvalPredicate:
13957
 * @ctxt:  the XPath context
13958
 * @res:  the Predicate Expression evaluation result
13959
 *
13960
 * Evaluate a predicate result for the current node.
13961
 * A PredicateExpr is evaluated by evaluating the Expr and converting
13962
 * the result to a boolean. If the result is a number, the result will
13963
 * be converted to true if the number is equal to the position of the
13964
 * context node in the context node list (as returned by the position
13965
 * function) and will be converted to false otherwise; if the result
13966
 * is not a number, then the result will be converted as if by a call
13967
 * to the boolean function.
13968
 *
13969
 * Returns 1 if predicate is true, 0 otherwise
13970
 */
13971
int
13972
0
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13973
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
13974
0
    switch (res->type) {
13975
0
        case XPATH_BOOLEAN:
13976
0
      return(res->boolval);
13977
0
        case XPATH_NUMBER:
13978
0
      return(res->floatval == ctxt->proximityPosition);
13979
0
        case XPATH_NODESET:
13980
0
        case XPATH_XSLT_TREE:
13981
0
      if (res->nodesetval == NULL)
13982
0
    return(0);
13983
0
      return(res->nodesetval->nodeNr != 0);
13984
0
        case XPATH_STRING:
13985
0
      return((res->stringval != NULL) &&
13986
0
             (xmlStrlen(res->stringval) != 0));
13987
0
        default:
13988
0
      STRANGE
13989
0
    }
13990
0
    return(0);
13991
0
}
13992
13993
/**
13994
 * xmlXPathEvaluatePredicateResult:
13995
 * @ctxt:  the XPath Parser context
13996
 * @res:  the Predicate Expression evaluation result
13997
 *
13998
 * Evaluate a predicate result for the current node.
13999
 * A PredicateExpr is evaluated by evaluating the Expr and converting
14000
 * the result to a boolean. If the result is a number, the result will
14001
 * be converted to true if the number is equal to the position of the
14002
 * context node in the context node list (as returned by the position
14003
 * function) and will be converted to false otherwise; if the result
14004
 * is not a number, then the result will be converted as if by a call
14005
 * to the boolean function.
14006
 *
14007
 * Returns 1 if predicate is true, 0 otherwise
14008
 */
14009
int
14010
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14011
0
                                xmlXPathObjectPtr res) {
14012
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
14013
0
    switch (res->type) {
14014
0
        case XPATH_BOOLEAN:
14015
0
      return(res->boolval);
14016
0
        case XPATH_NUMBER:
14017
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14018
      return((res->floatval == ctxt->context->proximityPosition) &&
14019
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14020
#else
14021
0
      return(res->floatval == ctxt->context->proximityPosition);
14022
0
#endif
14023
0
        case XPATH_NODESET:
14024
0
        case XPATH_XSLT_TREE:
14025
0
      if (res->nodesetval == NULL)
14026
0
    return(0);
14027
0
      return(res->nodesetval->nodeNr != 0);
14028
0
        case XPATH_STRING:
14029
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
14030
#ifdef LIBXML_XPTR_LOCS_ENABLED
14031
  case XPATH_LOCATIONSET:{
14032
      xmlLocationSetPtr ptr = res->user;
14033
      if (ptr == NULL)
14034
          return(0);
14035
      return (ptr->locNr != 0);
14036
      }
14037
#endif
14038
0
        default:
14039
0
      STRANGE
14040
0
    }
14041
0
    return(0);
14042
0
}
14043
14044
#ifdef XPATH_STREAMING
14045
/**
14046
 * xmlXPathTryStreamCompile:
14047
 * @ctxt: an XPath context
14048
 * @str:  the XPath expression
14049
 *
14050
 * Try to compile the XPath expression as a streamable subset.
14051
 *
14052
 * Returns the compiled expression or NULL if failed to compile.
14053
 */
14054
static xmlXPathCompExprPtr
14055
0
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14056
    /*
14057
     * Optimization: use streaming patterns when the XPath expression can
14058
     * be compiled to a stream lookup
14059
     */
14060
0
    xmlPatternPtr stream;
14061
0
    xmlXPathCompExprPtr comp;
14062
0
    xmlDictPtr dict = NULL;
14063
0
    const xmlChar **namespaces = NULL;
14064
0
    xmlNsPtr ns;
14065
0
    int i, j;
14066
14067
0
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14068
0
        (!xmlStrchr(str, '@'))) {
14069
0
  const xmlChar *tmp;
14070
14071
  /*
14072
   * We don't try to handle expressions using the verbose axis
14073
   * specifiers ("::"), just the simplified form at this point.
14074
   * Additionally, if there is no list of namespaces available and
14075
   *  there's a ":" in the expression, indicating a prefixed QName,
14076
   *  then we won't try to compile either. xmlPatterncompile() needs
14077
   *  to have a list of namespaces at compilation time in order to
14078
   *  compile prefixed name tests.
14079
   */
14080
0
  tmp = xmlStrchr(str, ':');
14081
0
  if ((tmp != NULL) &&
14082
0
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14083
0
      return(NULL);
14084
14085
0
  if (ctxt != NULL) {
14086
0
      dict = ctxt->dict;
14087
0
      if (ctxt->nsNr > 0) {
14088
0
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14089
0
    if (namespaces == NULL) {
14090
0
        xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14091
0
        return(NULL);
14092
0
    }
14093
0
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14094
0
        ns = ctxt->namespaces[j];
14095
0
        namespaces[i++] = ns->href;
14096
0
        namespaces[i++] = ns->prefix;
14097
0
    }
14098
0
    namespaces[i++] = NULL;
14099
0
    namespaces[i] = NULL;
14100
0
      }
14101
0
  }
14102
14103
0
  stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
14104
0
  if (namespaces != NULL) {
14105
0
      xmlFree((xmlChar **)namespaces);
14106
0
  }
14107
0
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14108
0
      comp = xmlXPathNewCompExpr();
14109
0
      if (comp == NULL) {
14110
0
    xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14111
0
    return(NULL);
14112
0
      }
14113
0
      comp->stream = stream;
14114
0
      comp->dict = dict;
14115
0
      if (comp->dict)
14116
0
    xmlDictReference(comp->dict);
14117
0
      return(comp);
14118
0
  }
14119
0
  xmlFreePattern(stream);
14120
0
    }
14121
0
    return(NULL);
14122
0
}
14123
#endif /* XPATH_STREAMING */
14124
14125
static void
14126
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
14127
                           xmlXPathStepOpPtr op)
14128
0
{
14129
0
    xmlXPathCompExprPtr comp = pctxt->comp;
14130
0
    xmlXPathContextPtr ctxt;
14131
14132
    /*
14133
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14134
    * internal representation.
14135
    */
14136
14137
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14138
0
        (op->ch1 != -1) &&
14139
0
        (op->ch2 == -1 /* no predicate */))
14140
0
    {
14141
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14142
14143
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14144
0
            ((xmlXPathAxisVal) prevop->value ==
14145
0
                AXIS_DESCENDANT_OR_SELF) &&
14146
0
            (prevop->ch2 == -1) &&
14147
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14148
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14149
0
        {
14150
            /*
14151
            * This is a "descendant-or-self::node()" without predicates.
14152
            * Try to eliminate it.
14153
            */
14154
14155
0
            switch ((xmlXPathAxisVal) op->value) {
14156
0
                case AXIS_CHILD:
14157
0
                case AXIS_DESCENDANT:
14158
                    /*
14159
                    * Convert "descendant-or-self::node()/child::" or
14160
                    * "descendant-or-self::node()/descendant::" to
14161
                    * "descendant::"
14162
                    */
14163
0
                    op->ch1   = prevop->ch1;
14164
0
                    op->value = AXIS_DESCENDANT;
14165
0
                    break;
14166
0
                case AXIS_SELF:
14167
0
                case AXIS_DESCENDANT_OR_SELF:
14168
                    /*
14169
                    * Convert "descendant-or-self::node()/self::" or
14170
                    * "descendant-or-self::node()/descendant-or-self::" to
14171
                    * to "descendant-or-self::"
14172
                    */
14173
0
                    op->ch1   = prevop->ch1;
14174
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
14175
0
                    break;
14176
0
                default:
14177
0
                    break;
14178
0
            }
14179
0
  }
14180
0
    }
14181
14182
    /* OP_VALUE has invalid ch1. */
14183
0
    if (op->op == XPATH_OP_VALUE)
14184
0
        return;
14185
14186
    /* Recurse */
14187
0
    ctxt = pctxt->context;
14188
0
    if (ctxt != NULL) {
14189
0
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
14190
0
            return;
14191
0
        ctxt->depth += 1;
14192
0
    }
14193
0
    if (op->ch1 != -1)
14194
0
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
14195
0
    if (op->ch2 != -1)
14196
0
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
14197
0
    if (ctxt != NULL)
14198
0
        ctxt->depth -= 1;
14199
0
}
14200
14201
/**
14202
 * xmlXPathCtxtCompile:
14203
 * @ctxt: an XPath context
14204
 * @str:  the XPath expression
14205
 *
14206
 * Compile an XPath expression
14207
 *
14208
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14209
 *         the caller has to free the object.
14210
 */
14211
xmlXPathCompExprPtr
14212
0
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14213
0
    xmlXPathParserContextPtr pctxt;
14214
0
    xmlXPathCompExprPtr comp;
14215
14216
0
#ifdef XPATH_STREAMING
14217
0
    comp = xmlXPathTryStreamCompile(ctxt, str);
14218
0
    if (comp != NULL)
14219
0
        return(comp);
14220
0
#endif
14221
14222
0
    xmlInitParser();
14223
14224
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
14225
0
    if (pctxt == NULL)
14226
0
        return NULL;
14227
0
    if (ctxt != NULL)
14228
0
        ctxt->depth = 0;
14229
0
    xmlXPathCompileExpr(pctxt, 1);
14230
14231
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
14232
0
    {
14233
0
        xmlXPathFreeParserContext(pctxt);
14234
0
        return(NULL);
14235
0
    }
14236
14237
0
    if (*pctxt->cur != 0) {
14238
  /*
14239
   * aleksey: in some cases this line prints *second* error message
14240
   * (see bug #78858) and probably this should be fixed.
14241
   * However, we are not sure that all error messages are printed
14242
   * out in other places. It's not critical so we leave it as-is for now
14243
   */
14244
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14245
0
  comp = NULL;
14246
0
    } else {
14247
0
  comp = pctxt->comp;
14248
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
14249
0
            if (ctxt != NULL)
14250
0
                ctxt->depth = 0;
14251
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
14252
0
  }
14253
0
  pctxt->comp = NULL;
14254
0
    }
14255
0
    xmlXPathFreeParserContext(pctxt);
14256
14257
0
    if (comp != NULL) {
14258
0
  comp->expr = xmlStrdup(str);
14259
#ifdef DEBUG_EVAL_COUNTS
14260
  comp->string = xmlStrdup(str);
14261
  comp->nb = 0;
14262
#endif
14263
0
    }
14264
0
    return(comp);
14265
0
}
14266
14267
/**
14268
 * xmlXPathCompile:
14269
 * @str:  the XPath expression
14270
 *
14271
 * Compile an XPath expression
14272
 *
14273
 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14274
 *         the caller has to free the object.
14275
 */
14276
xmlXPathCompExprPtr
14277
0
xmlXPathCompile(const xmlChar *str) {
14278
0
    return(xmlXPathCtxtCompile(NULL, str));
14279
0
}
14280
14281
/**
14282
 * xmlXPathCompiledEvalInternal:
14283
 * @comp:  the compiled XPath expression
14284
 * @ctxt:  the XPath context
14285
 * @resObj: the resulting XPath object or NULL
14286
 * @toBool: 1 if only a boolean result is requested
14287
 *
14288
 * Evaluate the Precompiled XPath expression in the given context.
14289
 * The caller has to free @resObj.
14290
 *
14291
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14292
 *         the caller has to free the object.
14293
 */
14294
static int
14295
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14296
           xmlXPathContextPtr ctxt,
14297
           xmlXPathObjectPtr *resObjPtr,
14298
           int toBool)
14299
0
{
14300
0
    xmlXPathParserContextPtr pctxt;
14301
0
    xmlXPathObjectPtr resObj;
14302
#ifndef LIBXML_THREAD_ENABLED
14303
    static int reentance = 0;
14304
#endif
14305
0
    int res;
14306
14307
0
    CHECK_CTXT_NEG(ctxt)
14308
14309
0
    if (comp == NULL)
14310
0
  return(-1);
14311
0
    xmlInitParser();
14312
14313
#ifndef LIBXML_THREAD_ENABLED
14314
    reentance++;
14315
    if (reentance > 1)
14316
  xmlXPathDisableOptimizer = 1;
14317
#endif
14318
14319
#ifdef DEBUG_EVAL_COUNTS
14320
    comp->nb++;
14321
    if ((comp->string != NULL) && (comp->nb > 100)) {
14322
  fprintf(stderr, "100 x %s\n", comp->string);
14323
  comp->nb = 0;
14324
    }
14325
#endif
14326
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
14327
0
    res = xmlXPathRunEval(pctxt, toBool);
14328
14329
0
    if (pctxt->error != XPATH_EXPRESSION_OK) {
14330
0
        resObj = NULL;
14331
0
    } else {
14332
0
        resObj = valuePop(pctxt);
14333
0
        if (resObj == NULL) {
14334
0
            if (!toBool)
14335
0
                xmlGenericError(xmlGenericErrorContext,
14336
0
                    "xmlXPathCompiledEval: No result on the stack.\n");
14337
0
        } else if (pctxt->valueNr > 0) {
14338
0
            xmlGenericError(xmlGenericErrorContext,
14339
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14340
0
                pctxt->valueNr);
14341
0
        }
14342
0
    }
14343
14344
0
    if (resObjPtr)
14345
0
        *resObjPtr = resObj;
14346
0
    else
14347
0
        xmlXPathReleaseObject(ctxt, resObj);
14348
14349
0
    pctxt->comp = NULL;
14350
0
    xmlXPathFreeParserContext(pctxt);
14351
#ifndef LIBXML_THREAD_ENABLED
14352
    reentance--;
14353
#endif
14354
14355
0
    return(res);
14356
0
}
14357
14358
/**
14359
 * xmlXPathCompiledEval:
14360
 * @comp:  the compiled XPath expression
14361
 * @ctx:  the XPath context
14362
 *
14363
 * Evaluate the Precompiled XPath expression in the given context.
14364
 *
14365
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14366
 *         the caller has to free the object.
14367
 */
14368
xmlXPathObjectPtr
14369
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14370
0
{
14371
0
    xmlXPathObjectPtr res = NULL;
14372
14373
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14374
0
    return(res);
14375
0
}
14376
14377
/**
14378
 * xmlXPathCompiledEvalToBoolean:
14379
 * @comp:  the compiled XPath expression
14380
 * @ctxt:  the XPath context
14381
 *
14382
 * Applies the XPath boolean() function on the result of the given
14383
 * compiled expression.
14384
 *
14385
 * Returns 1 if the expression evaluated to true, 0 if to false and
14386
 *         -1 in API and internal errors.
14387
 */
14388
int
14389
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14390
            xmlXPathContextPtr ctxt)
14391
0
{
14392
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14393
0
}
14394
14395
/**
14396
 * xmlXPathEvalExpr:
14397
 * @ctxt:  the XPath Parser context
14398
 *
14399
 * Parse and evaluate an XPath expression in the given context,
14400
 * then push the result on the context stack
14401
 */
14402
void
14403
0
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14404
0
#ifdef XPATH_STREAMING
14405
0
    xmlXPathCompExprPtr comp;
14406
0
#endif
14407
14408
0
    if (ctxt == NULL) return;
14409
14410
0
#ifdef XPATH_STREAMING
14411
0
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14412
0
    if (comp != NULL) {
14413
0
        if (ctxt->comp != NULL)
14414
0
      xmlXPathFreeCompExpr(ctxt->comp);
14415
0
        ctxt->comp = comp;
14416
0
    } else
14417
0
#endif
14418
0
    {
14419
0
        if (ctxt->context != NULL)
14420
0
            ctxt->context->depth = 0;
14421
0
  xmlXPathCompileExpr(ctxt, 1);
14422
0
        CHECK_ERROR;
14423
14424
        /* Check for trailing characters. */
14425
0
        if (*ctxt->cur != 0)
14426
0
            XP_ERROR(XPATH_EXPR_ERROR);
14427
14428
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
14429
0
            if (ctxt->context != NULL)
14430
0
                ctxt->context->depth = 0;
14431
0
      xmlXPathOptimizeExpression(ctxt,
14432
0
    &ctxt->comp->steps[ctxt->comp->last]);
14433
0
        }
14434
0
    }
14435
14436
0
    xmlXPathRunEval(ctxt, 0);
14437
0
}
14438
14439
/**
14440
 * xmlXPathEval:
14441
 * @str:  the XPath expression
14442
 * @ctx:  the XPath context
14443
 *
14444
 * Evaluate the XPath Location Path in the given context.
14445
 *
14446
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14447
 *         the caller has to free the object.
14448
 */
14449
xmlXPathObjectPtr
14450
0
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14451
0
    xmlXPathParserContextPtr ctxt;
14452
0
    xmlXPathObjectPtr res;
14453
14454
0
    CHECK_CTXT(ctx)
14455
14456
0
    xmlInitParser();
14457
14458
0
    ctxt = xmlXPathNewParserContext(str, ctx);
14459
0
    if (ctxt == NULL)
14460
0
        return NULL;
14461
0
    xmlXPathEvalExpr(ctxt);
14462
14463
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
14464
0
  res = NULL;
14465
0
    } else {
14466
0
  res = valuePop(ctxt);
14467
0
        if (res == NULL) {
14468
0
            xmlGenericError(xmlGenericErrorContext,
14469
0
                "xmlXPathCompiledEval: No result on the stack.\n");
14470
0
        } else if (ctxt->valueNr > 0) {
14471
0
            xmlGenericError(xmlGenericErrorContext,
14472
0
                "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14473
0
                ctxt->valueNr);
14474
0
        }
14475
0
    }
14476
14477
0
    xmlXPathFreeParserContext(ctxt);
14478
0
    return(res);
14479
0
}
14480
14481
/**
14482
 * xmlXPathSetContextNode:
14483
 * @node: the node to to use as the context node
14484
 * @ctx:  the XPath context
14485
 *
14486
 * Sets 'node' as the context node. The node must be in the same
14487
 * document as that associated with the context.
14488
 *
14489
 * Returns -1 in case of error or 0 if successful
14490
 */
14491
int
14492
0
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
14493
0
    if ((node == NULL) || (ctx == NULL))
14494
0
        return(-1);
14495
14496
0
    if (node->doc == ctx->doc) {
14497
0
        ctx->node = node;
14498
0
  return(0);
14499
0
    }
14500
0
    return(-1);
14501
0
}
14502
14503
/**
14504
 * xmlXPathNodeEval:
14505
 * @node: the node to to use as the context node
14506
 * @str:  the XPath expression
14507
 * @ctx:  the XPath context
14508
 *
14509
 * Evaluate the XPath Location Path in the given context. The node 'node'
14510
 * is set as the context node. The context node is not restored.
14511
 *
14512
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14513
 *         the caller has to free the object.
14514
 */
14515
xmlXPathObjectPtr
14516
0
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
14517
0
    if (str == NULL)
14518
0
        return(NULL);
14519
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
14520
0
        return(NULL);
14521
0
    return(xmlXPathEval(str, ctx));
14522
0
}
14523
14524
/**
14525
 * xmlXPathEvalExpression:
14526
 * @str:  the XPath expression
14527
 * @ctxt:  the XPath context
14528
 *
14529
 * Alias for xmlXPathEval().
14530
 *
14531
 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14532
 *         the caller has to free the object.
14533
 */
14534
xmlXPathObjectPtr
14535
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14536
0
    return(xmlXPathEval(str, ctxt));
14537
0
}
14538
14539
/************************************************************************
14540
 *                  *
14541
 *  Extra functions not pertaining to the XPath spec    *
14542
 *                  *
14543
 ************************************************************************/
14544
/**
14545
 * xmlXPathEscapeUriFunction:
14546
 * @ctxt:  the XPath Parser context
14547
 * @nargs:  the number of arguments
14548
 *
14549
 * Implement the escape-uri() XPath function
14550
 *    string escape-uri(string $str, bool $escape-reserved)
14551
 *
14552
 * This function applies the URI escaping rules defined in section 2 of [RFC
14553
 * 2396] to the string supplied as $uri-part, which typically represents all
14554
 * or part of a URI. The effect of the function is to replace any special
14555
 * character in the string by an escape sequence of the form %xx%yy...,
14556
 * where xxyy... is the hexadecimal representation of the octets used to
14557
 * represent the character in UTF-8.
14558
 *
14559
 * The set of characters that are escaped depends on the setting of the
14560
 * boolean argument $escape-reserved.
14561
 *
14562
 * If $escape-reserved is true, all characters are escaped other than lower
14563
 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14564
 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14565
 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14566
 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14567
 * A-F).
14568
 *
14569
 * If $escape-reserved is false, the behavior differs in that characters
14570
 * referred to in [RFC 2396] as reserved characters are not escaped. These
14571
 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14572
 *
14573
 * [RFC 2396] does not define whether escaped URIs should use lower case or
14574
 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14575
 * compared using string comparison functions, this function must always use
14576
 * the upper-case letters A-F.
14577
 *
14578
 * Generally, $escape-reserved should be set to true when escaping a string
14579
 * that is to form a single part of a URI, and to false when escaping an
14580
 * entire URI or URI reference.
14581
 *
14582
 * In the case of non-ascii characters, the string is encoded according to
14583
 * utf-8 and then converted according to RFC 2396.
14584
 *
14585
 * Examples
14586
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14587
 *  returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14588
 *  xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14589
 *  returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14590
 *
14591
 */
14592
static void
14593
0
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14594
0
    xmlXPathObjectPtr str;
14595
0
    int escape_reserved;
14596
0
    xmlBufPtr target;
14597
0
    xmlChar *cptr;
14598
0
    xmlChar escape[4];
14599
14600
0
    CHECK_ARITY(2);
14601
14602
0
    escape_reserved = xmlXPathPopBoolean(ctxt);
14603
14604
0
    CAST_TO_STRING;
14605
0
    str = valuePop(ctxt);
14606
14607
0
    target = xmlBufCreate();
14608
14609
0
    escape[0] = '%';
14610
0
    escape[3] = 0;
14611
14612
0
    if (target) {
14613
0
  for (cptr = str->stringval; *cptr; cptr++) {
14614
0
      if ((*cptr >= 'A' && *cptr <= 'Z') ||
14615
0
    (*cptr >= 'a' && *cptr <= 'z') ||
14616
0
    (*cptr >= '0' && *cptr <= '9') ||
14617
0
    *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14618
0
    *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14619
0
    *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14620
0
    (*cptr == '%' &&
14621
0
     ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14622
0
      (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14623
0
      (cptr[1] >= '0' && cptr[1] <= '9')) &&
14624
0
     ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14625
0
      (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14626
0
      (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14627
0
    (!escape_reserved &&
14628
0
     (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14629
0
      *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14630
0
      *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14631
0
      *cptr == ','))) {
14632
0
    xmlBufAdd(target, cptr, 1);
14633
0
      } else {
14634
0
    if ((*cptr >> 4) < 10)
14635
0
        escape[1] = '0' + (*cptr >> 4);
14636
0
    else
14637
0
        escape[1] = 'A' - 10 + (*cptr >> 4);
14638
0
    if ((*cptr & 0xF) < 10)
14639
0
        escape[2] = '0' + (*cptr & 0xF);
14640
0
    else
14641
0
        escape[2] = 'A' - 10 + (*cptr & 0xF);
14642
14643
0
    xmlBufAdd(target, &escape[0], 3);
14644
0
      }
14645
0
  }
14646
0
    }
14647
0
    valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14648
0
  xmlBufContent(target)));
14649
0
    xmlBufFree(target);
14650
0
    xmlXPathReleaseObject(ctxt->context, str);
14651
0
}
14652
14653
/**
14654
 * xmlXPathRegisterAllFunctions:
14655
 * @ctxt:  the XPath context
14656
 *
14657
 * Registers all default XPath functions in this context
14658
 */
14659
void
14660
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
14661
0
{
14662
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
14663
0
                         xmlXPathBooleanFunction);
14664
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
14665
0
                         xmlXPathCeilingFunction);
14666
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
14667
0
                         xmlXPathCountFunction);
14668
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
14669
0
                         xmlXPathConcatFunction);
14670
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
14671
0
                         xmlXPathContainsFunction);
14672
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
14673
0
                         xmlXPathIdFunction);
14674
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
14675
0
                         xmlXPathFalseFunction);
14676
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
14677
0
                         xmlXPathFloorFunction);
14678
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
14679
0
                         xmlXPathLastFunction);
14680
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
14681
0
                         xmlXPathLangFunction);
14682
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
14683
0
                         xmlXPathLocalNameFunction);
14684
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
14685
0
                         xmlXPathNotFunction);
14686
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
14687
0
                         xmlXPathNameFunction);
14688
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
14689
0
                         xmlXPathNamespaceURIFunction);
14690
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
14691
0
                         xmlXPathNormalizeFunction);
14692
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
14693
0
                         xmlXPathNumberFunction);
14694
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
14695
0
                         xmlXPathPositionFunction);
14696
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
14697
0
                         xmlXPathRoundFunction);
14698
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
14699
0
                         xmlXPathStringFunction);
14700
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
14701
0
                         xmlXPathStringLengthFunction);
14702
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
14703
0
                         xmlXPathStartsWithFunction);
14704
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
14705
0
                         xmlXPathSubstringFunction);
14706
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
14707
0
                         xmlXPathSubstringBeforeFunction);
14708
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
14709
0
                         xmlXPathSubstringAfterFunction);
14710
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
14711
0
                         xmlXPathSumFunction);
14712
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
14713
0
                         xmlXPathTrueFunction);
14714
0
    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
14715
0
                         xmlXPathTranslateFunction);
14716
14717
0
    xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
14718
0
   (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
14719
0
                         xmlXPathEscapeUriFunction);
14720
0
}
14721
14722
#endif /* LIBXML_XPATH_ENABLED */