Coverage Report

Created: 2025-06-22 06:55

/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
14
 */
15
16
/* To avoid EBCDIC trouble when parsing on zOS */
17
#if defined(__MVS__)
18
#pragma convert("ISO8859-1")
19
#endif
20
21
#define IN_LIBXML
22
#include "libxml.h"
23
24
#include <limits.h>
25
#include <string.h>
26
#include <stddef.h>
27
#include <math.h>
28
#include <float.h>
29
#include <ctype.h>
30
31
#include <libxml/xmlmemory.h>
32
#include <libxml/tree.h>
33
#include <libxml/xpath.h>
34
#include <libxml/xpathInternals.h>
35
#include <libxml/parserInternals.h>
36
#include <libxml/hash.h>
37
#ifdef LIBXML_DEBUG_ENABLED
38
#include <libxml/debugXML.h>
39
#endif
40
#include <libxml/xmlerror.h>
41
#include <libxml/threads.h>
42
#ifdef LIBXML_PATTERN_ENABLED
43
#include <libxml/pattern.h>
44
#endif
45
46
#include "private/buf.h"
47
#include "private/error.h"
48
#include "private/memory.h"
49
#include "private/parser.h"
50
#include "private/xpath.h"
51
52
/* Disabled for now */
53
#if 0
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
#endif
58
59
/**
60
 * Use the Timsort algorithm provided in timsort.h to sort
61
 * nodeset as this is a great improvement over the old Shell sort
62
 * used in #xmlXPathNodeSetSort
63
 */
64
#define WITH_TIM_SORT
65
66
/*
67
* If defined, this will use xmlXPathCmpNodesExt() instead of
68
* xmlXPathCmpNodes(). The new function is optimized comparison of
69
* non-element nodes; actually it will speed up comparison only if
70
* xmlXPathOrderDocElems() was called in order to index the elements of
71
* a tree in document order; Libxslt does such an indexing, thus it will
72
* benefit from this optimization.
73
*/
74
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
75
76
/*
77
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
78
* in a way, that it stop evaluation at the first node.
79
*/
80
#define XP_OPTIMIZED_FILTER_FIRST
81
82
/*
83
 * when compiling an XPath expression we arbitrary limit the maximum
84
 * number of step operation in the compiled expression. 1000000 is
85
 * an insanely large value which should never be reached under normal
86
 * circumstances
87
 */
88
0
#define XPATH_MAX_STEPS 1000000
89
90
/*
91
 * when evaluating an XPath expression we arbitrary limit the maximum
92
 * number of object allowed to be pushed on the stack. 1000000 is
93
 * an insanely large value which should never be reached under normal
94
 * circumstances
95
 */
96
0
#define XPATH_MAX_STACK_DEPTH 1000000
97
98
/*
99
 * when evaluating an XPath expression nodesets are created and we
100
 * arbitrary limit the maximum length of those node set. 10000000 is
101
 * an insanely large value which should never be reached under normal
102
 * circumstances, one would first need to construct an in memory tree
103
 * with more than 10 millions nodes.
104
 */
105
0
#define XPATH_MAX_NODESET_LENGTH 10000000
106
107
/*
108
 * Maximum amount of nested functions calls when parsing or evaluating
109
 * expressions
110
 */
111
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
112
0
#define XPATH_MAX_RECURSION_DEPTH 500
113
#elif defined(_WIN32)
114
/* Windows typically limits stack size to 1MB. */
115
#define XPATH_MAX_RECURSION_DEPTH 1000
116
#else
117
#define XPATH_MAX_RECURSION_DEPTH 5000
118
#endif
119
120
/*
121
 * TODO:
122
 * There are a few spots where some tests are done which depend upon ascii
123
 * data.  These should be enhanced for full UTF8 support (see particularly
124
 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
125
 */
126
127
#if defined(LIBXML_XPATH_ENABLED)
128
129
static void
130
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
131
132
static const struct {
133
    const char *name;
134
    xmlXPathFunction func;
135
} xmlXPathStandardFunctions[] = {
136
    { "boolean", xmlXPathBooleanFunction },
137
    { "ceiling", xmlXPathCeilingFunction },
138
    { "count", xmlXPathCountFunction },
139
    { "concat", xmlXPathConcatFunction },
140
    { "contains", xmlXPathContainsFunction },
141
    { "id", xmlXPathIdFunction },
142
    { "false", xmlXPathFalseFunction },
143
    { "floor", xmlXPathFloorFunction },
144
    { "last", xmlXPathLastFunction },
145
    { "lang", xmlXPathLangFunction },
146
    { "local-name", xmlXPathLocalNameFunction },
147
    { "not", xmlXPathNotFunction },
148
    { "name", xmlXPathNameFunction },
149
    { "namespace-uri", xmlXPathNamespaceURIFunction },
150
    { "normalize-space", xmlXPathNormalizeFunction },
151
    { "number", xmlXPathNumberFunction },
152
    { "position", xmlXPathPositionFunction },
153
    { "round", xmlXPathRoundFunction },
154
    { "string", xmlXPathStringFunction },
155
    { "string-length", xmlXPathStringLengthFunction },
156
    { "starts-with", xmlXPathStartsWithFunction },
157
    { "substring", xmlXPathSubstringFunction },
158
    { "substring-before", xmlXPathSubstringBeforeFunction },
159
    { "substring-after", xmlXPathSubstringAfterFunction },
160
    { "sum", xmlXPathSumFunction },
161
    { "true", xmlXPathTrueFunction },
162
    { "translate", xmlXPathTranslateFunction }
163
};
164
165
#define NUM_STANDARD_FUNCTIONS \
166
28
    (sizeof(xmlXPathStandardFunctions) / sizeof(xmlXPathStandardFunctions[0]))
167
168
99
#define SF_HASH_SIZE 64
169
170
static unsigned char xmlXPathSFHash[SF_HASH_SIZE];
171
172
double xmlXPathNAN = 0.0;
173
double xmlXPathPINF = 0.0;
174
double xmlXPathNINF = 0.0;
175
176
/**
177
 * @deprecated Alias for #xmlInitParser.
178
 */
179
void
180
0
xmlXPathInit(void) {
181
0
    xmlInitParser();
182
0
}
183
184
ATTRIBUTE_NO_SANITIZE_INTEGER
185
static unsigned
186
27
xmlXPathSFComputeHash(const xmlChar *name) {
187
27
    unsigned hashValue = 5381;
188
27
    const xmlChar *ptr;
189
190
230
    for (ptr = name; *ptr; ptr++)
191
203
        hashValue = hashValue * 33 + *ptr;
192
193
27
    return(hashValue);
194
27
}
195
196
/**
197
 * Initialize the XPath environment
198
 */
199
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
200
void
201
1
xmlInitXPathInternal(void) {
202
1
    size_t i;
203
204
1
#if defined(NAN) && defined(INFINITY)
205
1
    xmlXPathNAN = NAN;
206
1
    xmlXPathPINF = INFINITY;
207
1
    xmlXPathNINF = -INFINITY;
208
#else
209
    /* MSVC doesn't allow division by zero in constant expressions. */
210
    double zero = 0.0;
211
    xmlXPathNAN = 0.0 / zero;
212
    xmlXPathPINF = 1.0 / zero;
213
    xmlXPathNINF = -xmlXPathPINF;
214
#endif
215
216
    /*
217
     * Initialize hash table for standard functions
218
     */
219
220
65
    for (i = 0; i < SF_HASH_SIZE; i++)
221
64
        xmlXPathSFHash[i] = UCHAR_MAX;
222
223
28
    for (i = 0; i < NUM_STANDARD_FUNCTIONS; i++) {
224
27
        const char *name = xmlXPathStandardFunctions[i].name;
225
27
        int bucketIndex = xmlXPathSFComputeHash(BAD_CAST name) % SF_HASH_SIZE;
226
227
34
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
228
7
            bucketIndex += 1;
229
7
            if (bucketIndex >= SF_HASH_SIZE)
230
0
                bucketIndex = 0;
231
7
        }
232
233
27
        xmlXPathSFHash[bucketIndex] = i;
234
27
    }
235
1
}
236
237
/************************************************************************
238
 *                  *
239
 *      Floating point stuff        *
240
 *                  *
241
 ************************************************************************/
242
243
/**
244
 * Checks whether a double is a NaN.
245
 *
246
 * @param val  a double value
247
 * @returns 1 if the value is a NaN, 0 otherwise
248
 */
249
int
250
0
xmlXPathIsNaN(double val) {
251
0
#ifdef isnan
252
0
    return isnan(val);
253
#else
254
    return !(val == val);
255
#endif
256
0
}
257
258
/**
259
 * Checks whether a double is an infinity.
260
 *
261
 * @param val  a double value
262
 * @returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
263
 */
264
int
265
0
xmlXPathIsInf(double val) {
266
0
#ifdef isinf
267
0
    return isinf(val) ? (val > 0 ? 1 : -1) : 0;
268
#else
269
    if (val >= xmlXPathPINF)
270
        return 1;
271
    if (val <= -xmlXPathPINF)
272
        return -1;
273
    return 0;
274
#endif
275
0
}
276
277
/*
278
 * TODO: when compatibility allows remove all "fake node libxslt" strings
279
 *       the test should just be name[0] = ' '
280
 */
281
282
static const xmlNs xmlXPathXMLNamespaceStruct = {
283
    NULL,
284
    XML_NAMESPACE_DECL,
285
    XML_XML_NAMESPACE,
286
    BAD_CAST "xml",
287
    NULL,
288
    NULL
289
};
290
static const xmlNs *const xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
291
292
static void
293
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
294
295
0
#define XML_NODE_SORT_VALUE(n) XML_PTR_TO_INT((n)->content)
296
297
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
298
299
/**
300
 * Compare two nodes w.r.t document order.
301
 * This one is optimized for handling of non-element nodes.
302
 *
303
 * @param node1  the first node
304
 * @param node2  the second node
305
 * @returns -2 in case of error 1 if first point < second point, 0 if
306
 *         it's the same node, -1 otherwise
307
 */
308
static int
309
0
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
310
0
    int depth1, depth2;
311
0
    int misc = 0, precedence1 = 0, precedence2 = 0;
312
0
    xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
313
0
    xmlNodePtr cur, root;
314
0
    XML_INTPTR_T l1, l2;
315
316
0
    if ((node1 == NULL) || (node2 == NULL))
317
0
  return(-2);
318
319
0
    if (node1 == node2)
320
0
  return(0);
321
322
    /*
323
     * a couple of optimizations which will avoid computations in most cases
324
     */
325
0
    switch (node1->type) {
326
0
  case XML_ELEMENT_NODE:
327
0
      if (node2->type == XML_ELEMENT_NODE) {
328
0
    if ((0 > XML_NODE_SORT_VALUE(node1)) &&
329
0
        (0 > XML_NODE_SORT_VALUE(node2)) &&
330
0
        (node1->doc == node2->doc))
331
0
    {
332
0
        l1 = -XML_NODE_SORT_VALUE(node1);
333
0
        l2 = -XML_NODE_SORT_VALUE(node2);
334
0
        if (l1 < l2)
335
0
      return(1);
336
0
        if (l1 > l2)
337
0
      return(-1);
338
0
    } else
339
0
        goto turtle_comparison;
340
0
      }
341
0
      break;
342
0
  case XML_ATTRIBUTE_NODE:
343
0
      precedence1 = 1; /* element is owner */
344
0
      miscNode1 = node1;
345
0
      node1 = node1->parent;
346
0
      misc = 1;
347
0
      break;
348
0
  case XML_TEXT_NODE:
349
0
  case XML_CDATA_SECTION_NODE:
350
0
  case XML_COMMENT_NODE:
351
0
  case XML_PI_NODE: {
352
0
      miscNode1 = node1;
353
      /*
354
      * Find nearest element node.
355
      */
356
0
      if (node1->prev != NULL) {
357
0
    do {
358
0
        node1 = node1->prev;
359
0
        if (node1->type == XML_ELEMENT_NODE) {
360
0
      precedence1 = 3; /* element in prev-sibl axis */
361
0
      break;
362
0
        }
363
0
        if (node1->prev == NULL) {
364
0
      precedence1 = 2; /* element is parent */
365
      /*
366
      * URGENT TODO: Are there any cases, where the
367
      * parent of such a node is not an element node?
368
      */
369
0
      node1 = node1->parent;
370
0
      break;
371
0
        }
372
0
    } while (1);
373
0
      } else {
374
0
    precedence1 = 2; /* element is parent */
375
0
    node1 = node1->parent;
376
0
      }
377
0
      if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
378
0
    (0 <= XML_NODE_SORT_VALUE(node1))) {
379
    /*
380
    * Fallback for whatever case.
381
    */
382
0
    node1 = miscNode1;
383
0
    precedence1 = 0;
384
0
      } else
385
0
    misc = 1;
386
0
  }
387
0
      break;
388
0
  case XML_NAMESPACE_DECL:
389
      /*
390
      * TODO: why do we return 1 for namespace nodes?
391
      */
392
0
      return(1);
393
0
  default:
394
0
      break;
395
0
    }
396
0
    switch (node2->type) {
397
0
  case XML_ELEMENT_NODE:
398
0
      break;
399
0
  case XML_ATTRIBUTE_NODE:
400
0
      precedence2 = 1; /* element is owner */
401
0
      miscNode2 = node2;
402
0
      node2 = node2->parent;
403
0
      misc = 1;
404
0
      break;
405
0
  case XML_TEXT_NODE:
406
0
  case XML_CDATA_SECTION_NODE:
407
0
  case XML_COMMENT_NODE:
408
0
  case XML_PI_NODE: {
409
0
      miscNode2 = node2;
410
0
      if (node2->prev != NULL) {
411
0
    do {
412
0
        node2 = node2->prev;
413
0
        if (node2->type == XML_ELEMENT_NODE) {
414
0
      precedence2 = 3; /* element in prev-sibl axis */
415
0
      break;
416
0
        }
417
0
        if (node2->prev == NULL) {
418
0
      precedence2 = 2; /* element is parent */
419
0
      node2 = node2->parent;
420
0
      break;
421
0
        }
422
0
    } while (1);
423
0
      } else {
424
0
    precedence2 = 2; /* element is parent */
425
0
    node2 = node2->parent;
426
0
      }
427
0
      if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
428
0
    (0 <= XML_NODE_SORT_VALUE(node2)))
429
0
      {
430
0
    node2 = miscNode2;
431
0
    precedence2 = 0;
432
0
      } else
433
0
    misc = 1;
434
0
  }
435
0
      break;
436
0
  case XML_NAMESPACE_DECL:
437
0
      return(1);
438
0
  default:
439
0
      break;
440
0
    }
441
0
    if (misc) {
442
0
  if (node1 == node2) {
443
0
      if (precedence1 == precedence2) {
444
    /*
445
    * The ugly case; but normally there aren't many
446
    * adjacent non-element nodes around.
447
    */
448
0
    cur = miscNode2->prev;
449
0
    while (cur != NULL) {
450
0
        if (cur == miscNode1)
451
0
      return(1);
452
0
        if (cur->type == XML_ELEMENT_NODE)
453
0
      return(-1);
454
0
        cur = cur->prev;
455
0
    }
456
0
    return (-1);
457
0
      } else {
458
    /*
459
    * Evaluate based on higher precedence wrt to the element.
460
    * TODO: This assumes attributes are sorted before content.
461
    *   Is this 100% correct?
462
    */
463
0
    if (precedence1 < precedence2)
464
0
        return(1);
465
0
    else
466
0
        return(-1);
467
0
      }
468
0
  }
469
  /*
470
  * Special case: One of the helper-elements is contained by the other.
471
  * <foo>
472
  *   <node2>
473
  *     <node1>Text-1(precedence1 == 2)</node1>
474
  *   </node2>
475
  *   Text-6(precedence2 == 3)
476
  * </foo>
477
  */
478
0
  if ((precedence2 == 3) && (precedence1 > 1)) {
479
0
      cur = node1->parent;
480
0
      while (cur) {
481
0
    if (cur == node2)
482
0
        return(1);
483
0
    cur = cur->parent;
484
0
      }
485
0
  }
486
0
  if ((precedence1 == 3) && (precedence2 > 1)) {
487
0
      cur = node2->parent;
488
0
      while (cur) {
489
0
    if (cur == node1)
490
0
        return(-1);
491
0
    cur = cur->parent;
492
0
      }
493
0
  }
494
0
    }
495
496
    /*
497
     * Speedup using document order if available.
498
     */
499
0
    if ((node1->type == XML_ELEMENT_NODE) &&
500
0
  (node2->type == XML_ELEMENT_NODE) &&
501
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
502
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
503
0
  (node1->doc == node2->doc)) {
504
505
0
  l1 = -XML_NODE_SORT_VALUE(node1);
506
0
  l2 = -XML_NODE_SORT_VALUE(node2);
507
0
  if (l1 < l2)
508
0
      return(1);
509
0
  if (l1 > l2)
510
0
      return(-1);
511
0
    }
512
513
0
turtle_comparison:
514
515
0
    if (node1 == node2->prev)
516
0
  return(1);
517
0
    if (node1 == node2->next)
518
0
  return(-1);
519
    /*
520
     * compute depth to root
521
     */
522
0
    for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
523
0
  if (cur->parent == node1)
524
0
      return(1);
525
0
  depth2++;
526
0
    }
527
0
    root = cur;
528
0
    for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
529
0
  if (cur->parent == node2)
530
0
      return(-1);
531
0
  depth1++;
532
0
    }
533
    /*
534
     * Distinct document (or distinct entities :-( ) case.
535
     */
536
0
    if (root != cur) {
537
0
  return(-2);
538
0
    }
539
    /*
540
     * get the nearest common ancestor.
541
     */
542
0
    while (depth1 > depth2) {
543
0
  depth1--;
544
0
  node1 = node1->parent;
545
0
    }
546
0
    while (depth2 > depth1) {
547
0
  depth2--;
548
0
  node2 = node2->parent;
549
0
    }
550
0
    while (node1->parent != node2->parent) {
551
0
  node1 = node1->parent;
552
0
  node2 = node2->parent;
553
  /* should not happen but just in case ... */
554
0
  if ((node1 == NULL) || (node2 == NULL))
555
0
      return(-2);
556
0
    }
557
    /*
558
     * Find who's first.
559
     */
560
0
    if (node1 == node2->prev)
561
0
  return(1);
562
0
    if (node1 == node2->next)
563
0
  return(-1);
564
    /*
565
     * Speedup using document order if available.
566
     */
567
0
    if ((node1->type == XML_ELEMENT_NODE) &&
568
0
  (node2->type == XML_ELEMENT_NODE) &&
569
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
570
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
571
0
  (node1->doc == node2->doc)) {
572
573
0
  l1 = -XML_NODE_SORT_VALUE(node1);
574
0
  l2 = -XML_NODE_SORT_VALUE(node2);
575
0
  if (l1 < l2)
576
0
      return(1);
577
0
  if (l1 > l2)
578
0
      return(-1);
579
0
    }
580
581
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
582
0
  if (cur == node2)
583
0
      return(1);
584
0
    return(-1); /* assume there is no sibling list corruption */
585
0
}
586
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
587
588
/*
589
 * Wrapper for the Timsort algorithm from timsort.h
590
 */
591
#ifdef WITH_TIM_SORT
592
#define SORT_NAME libxml_domnode
593
0
#define SORT_TYPE xmlNodePtr
594
/**
595
 * Comparison function for the Timsort implementation
596
 *
597
 * @param x  a node
598
 * @param y  another node
599
 * @returns -2 in case of error -1 if first point < second point, 0 if
600
 *         it's the same node, +1 otherwise
601
 */
602
static
603
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
604
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
605
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
606
0
    {
607
0
        int res = xmlXPathCmpNodesExt(x, y);
608
0
        return res == -2 ? res : -res;
609
0
    }
610
#else
611
    static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
612
    {
613
        int res = xmlXPathCmpNodes(x, y);
614
        return res == -2 ? res : -res;
615
    }
616
#endif
617
0
#define SORT_CMP(x, y)  (wrap_cmp(x, y))
618
#include "timsort.h"
619
#endif /* WITH_TIM_SORT */
620
621
/************************************************************************
622
 *                  *
623
 *      Error handling routines       *
624
 *                  *
625
 ************************************************************************/
626
627
/**
628
 * Macro to raise an XPath error and return NULL.
629
 *
630
 * @param X  the error code
631
 */
632
#define XP_ERRORNULL(X)             \
633
0
    { xmlXPathErr(ctxt, X); return(NULL); }
634
635
/*
636
 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
637
 */
638
static const char* const xmlXPathErrorMessages[] = {
639
    "Ok\n",
640
    "Number encoding\n",
641
    "Unfinished literal\n",
642
    "Start of literal\n",
643
    "Expected $ for variable reference\n",
644
    "Undefined variable\n",
645
    "Invalid predicate\n",
646
    "Invalid expression\n",
647
    "Missing closing curly brace\n",
648
    "Unregistered function\n",
649
    "Invalid operand\n",
650
    "Invalid type\n",
651
    "Invalid number of arguments\n",
652
    "Invalid context size\n",
653
    "Invalid context position\n",
654
    "Memory allocation error\n",
655
    "Syntax error\n",
656
    "Resource error\n",
657
    "Sub resource error\n",
658
    "Undefined namespace prefix\n",
659
    "Encoding error\n",
660
    "Char out of XML range\n",
661
    "Invalid or incomplete context\n",
662
    "Stack usage error\n",
663
    "Forbidden variable\n",
664
    "Operation limit exceeded\n",
665
    "Recursion limit exceeded\n",
666
    "?? Unknown error ??\n" /* Must be last in the list! */
667
};
668
0
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) /  \
669
0
       sizeof(xmlXPathErrorMessages[0])) - 1)
670
/**
671
 * Handle a memory allocation failure.
672
 *
673
 * @param ctxt  an XPath context
674
 */
675
void
676
xmlXPathErrMemory(xmlXPathContext *ctxt)
677
0
{
678
0
    if (ctxt == NULL)
679
0
        return;
680
0
    xmlRaiseMemoryError(ctxt->error, NULL, ctxt->userData, XML_FROM_XPATH,
681
0
                        &ctxt->lastError);
682
0
}
683
684
/**
685
 * Handle a memory allocation failure.
686
 *
687
 * @param ctxt  an XPath parser context
688
 */
689
void
690
xmlXPathPErrMemory(xmlXPathParserContext *ctxt)
691
0
{
692
0
    if (ctxt == NULL)
693
0
        return;
694
0
    ctxt->error = XPATH_MEMORY_ERROR;
695
0
    xmlXPathErrMemory(ctxt->context);
696
0
}
697
698
/**
699
 * Handle an XPath error
700
 *
701
 * @param ctxt  a XPath parser context
702
 * @param code  the error code
703
 */
704
void
705
xmlXPathErr(xmlXPathParserContext *ctxt, int code)
706
0
{
707
0
    xmlStructuredErrorFunc schannel = NULL;
708
0
    xmlGenericErrorFunc channel = NULL;
709
0
    void *data = NULL;
710
0
    xmlNodePtr node = NULL;
711
0
    int res;
712
713
0
    if (ctxt == NULL)
714
0
        return;
715
0
    if ((code < 0) || (code > MAXERRNO))
716
0
  code = MAXERRNO;
717
    /* Only report the first error */
718
0
    if (ctxt->error != 0)
719
0
        return;
720
721
0
    ctxt->error = code;
722
723
0
    if (ctxt->context != NULL) {
724
0
        xmlErrorPtr err = &ctxt->context->lastError;
725
726
        /* Don't overwrite memory error. */
727
0
        if (err->code == XML_ERR_NO_MEMORY)
728
0
            return;
729
730
        /* cleanup current last error */
731
0
        xmlResetError(err);
732
733
0
        err->domain = XML_FROM_XPATH;
734
0
        err->code = code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK;
735
0
        err->level = XML_ERR_ERROR;
736
0
        if (ctxt->base != NULL) {
737
0
            err->str1 = (char *) xmlStrdup(ctxt->base);
738
0
            if (err->str1 == NULL) {
739
0
                xmlXPathPErrMemory(ctxt);
740
0
                return;
741
0
            }
742
0
        }
743
0
        err->int1 = ctxt->cur - ctxt->base;
744
0
        err->node = ctxt->context->debugNode;
745
746
0
        schannel = ctxt->context->error;
747
0
        data = ctxt->context->userData;
748
0
        node = ctxt->context->debugNode;
749
0
    }
750
751
0
    if (schannel == NULL) {
752
0
        channel = xmlGenericError;
753
0
        data = xmlGenericErrorContext;
754
0
    }
755
756
0
    res = xmlRaiseError(schannel, channel, data, NULL, node, XML_FROM_XPATH,
757
0
                        code + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
758
0
                        XML_ERR_ERROR, NULL, 0,
759
0
                        (const char *) ctxt->base, NULL, NULL,
760
0
                        ctxt->cur - ctxt->base, 0,
761
0
                        "%s", xmlXPathErrorMessages[code]);
762
0
    if (res < 0)
763
0
        xmlXPathPErrMemory(ctxt);
764
0
}
765
766
/**
767
 * Formats an error message.
768
 *
769
 * @param ctxt  the XPath Parser context
770
 * @param file  the file name
771
 * @param line  the line number
772
 * @param no  the error number
773
 */
774
void
775
xmlXPatherror(xmlXPathParserContext *ctxt, const char *file ATTRIBUTE_UNUSED,
776
0
              int line ATTRIBUTE_UNUSED, int no) {
777
0
    xmlXPathErr(ctxt, no);
778
0
}
779
780
/**
781
 * Adds opCount to the running total of operations and returns -1 if the
782
 * operation limit is exceeded. Returns 0 otherwise.
783
 *
784
 * @param ctxt  the XPath Parser context
785
 * @param opCount  the number of operations to be added
786
 */
787
static int
788
0
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
789
0
    xmlXPathContextPtr xpctxt = ctxt->context;
790
791
0
    if ((opCount > xpctxt->opLimit) ||
792
0
        (xpctxt->opCount > xpctxt->opLimit - opCount)) {
793
0
        xpctxt->opCount = xpctxt->opLimit;
794
0
        xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
795
0
        return(-1);
796
0
    }
797
798
0
    xpctxt->opCount += opCount;
799
0
    return(0);
800
0
}
801
802
#define OP_LIMIT_EXCEEDED(ctxt, n) \
803
0
    ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
804
805
/************************************************************************
806
 *                  *
807
 *      Parser Types          *
808
 *                  *
809
 ************************************************************************/
810
811
/*
812
 * Types are private:
813
 */
814
815
typedef enum {
816
    XPATH_OP_END=0,
817
    XPATH_OP_AND,
818
    XPATH_OP_OR,
819
    XPATH_OP_EQUAL,
820
    XPATH_OP_CMP,
821
    XPATH_OP_PLUS,
822
    XPATH_OP_MULT,
823
    XPATH_OP_UNION,
824
    XPATH_OP_ROOT,
825
    XPATH_OP_NODE,
826
    XPATH_OP_COLLECT,
827
    XPATH_OP_VALUE, /* 11 */
828
    XPATH_OP_VARIABLE,
829
    XPATH_OP_FUNCTION,
830
    XPATH_OP_ARG,
831
    XPATH_OP_PREDICATE,
832
    XPATH_OP_FILTER, /* 16 */
833
    XPATH_OP_SORT /* 17 */
834
} xmlXPathOp;
835
836
typedef enum {
837
    AXIS_ANCESTOR = 1,
838
    AXIS_ANCESTOR_OR_SELF,
839
    AXIS_ATTRIBUTE,
840
    AXIS_CHILD,
841
    AXIS_DESCENDANT,
842
    AXIS_DESCENDANT_OR_SELF,
843
    AXIS_FOLLOWING,
844
    AXIS_FOLLOWING_SIBLING,
845
    AXIS_NAMESPACE,
846
    AXIS_PARENT,
847
    AXIS_PRECEDING,
848
    AXIS_PRECEDING_SIBLING,
849
    AXIS_SELF
850
} xmlXPathAxisVal;
851
852
typedef enum {
853
    NODE_TEST_NONE = 0,
854
    NODE_TEST_TYPE = 1,
855
    NODE_TEST_PI = 2,
856
    NODE_TEST_ALL = 3,
857
    NODE_TEST_NS = 4,
858
    NODE_TEST_NAME = 5
859
} xmlXPathTestVal;
860
861
typedef enum {
862
    NODE_TYPE_NODE = 0,
863
    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
864
    NODE_TYPE_TEXT = XML_TEXT_NODE,
865
    NODE_TYPE_PI = XML_PI_NODE
866
} xmlXPathTypeVal;
867
868
typedef struct _xmlXPathStepOp xmlXPathStepOp;
869
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
870
struct _xmlXPathStepOp {
871
    xmlXPathOp op;    /* The identifier of the operation */
872
    int ch1;      /* First child */
873
    int ch2;      /* Second child */
874
    int value;
875
    int value2;
876
    int value3;
877
    void *value4;
878
    void *value5;
879
    xmlXPathFunction cache;
880
    void *cacheURI;
881
};
882
883
struct _xmlXPathCompExpr {
884
    int nbStep;     /* Number of steps in this expression */
885
    int maxStep;    /* Maximum number of steps allocated */
886
    xmlXPathStepOp *steps;  /* ops for computation of this expression */
887
    int last;     /* index of last step in expression */
888
    xmlChar *expr;    /* the expression being computed */
889
    xmlDictPtr dict;    /* the dictionary to use if any */
890
#ifdef XPATH_STREAMING
891
    xmlPatternPtr stream;
892
#endif
893
};
894
895
/************************************************************************
896
 *                  *
897
 *      Forward declarations        *
898
 *                  *
899
 ************************************************************************/
900
901
static void
902
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
903
static int
904
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
905
                        xmlXPathStepOpPtr op, xmlNodePtr *first);
906
static int
907
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
908
          xmlXPathStepOpPtr op,
909
          int isPredicate);
910
static void
911
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
912
913
/************************************************************************
914
 *                  *
915
 *      Parser Type functions       *
916
 *                  *
917
 ************************************************************************/
918
919
/**
920
 * Create a new Xpath component
921
 *
922
 * @returns the newly allocated xmlXPathCompExpr or NULL in case of error
923
 */
924
static xmlXPathCompExprPtr
925
0
xmlXPathNewCompExpr(void) {
926
0
    xmlXPathCompExprPtr cur;
927
928
0
    cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
929
0
    if (cur == NULL)
930
0
  return(NULL);
931
0
    memset(cur, 0, sizeof(xmlXPathCompExpr));
932
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
933
0
    cur->maxStep = 1;
934
#else
935
    cur->maxStep = 10;
936
#endif
937
0
    cur->nbStep = 0;
938
0
    cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
939
0
                                     sizeof(xmlXPathStepOp));
940
0
    if (cur->steps == NULL) {
941
0
  xmlFree(cur);
942
0
  return(NULL);
943
0
    }
944
0
    memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
945
0
    cur->last = -1;
946
0
    return(cur);
947
0
}
948
949
/**
950
 * Free up the memory allocated by `comp`
951
 *
952
 * @param comp  an XPATH comp
953
 */
954
void
955
xmlXPathFreeCompExpr(xmlXPathCompExpr *comp)
956
0
{
957
0
    xmlXPathStepOpPtr op;
958
0
    int i;
959
960
0
    if (comp == NULL)
961
0
        return;
962
0
    if (comp->dict == NULL) {
963
0
  for (i = 0; i < comp->nbStep; i++) {
964
0
      op = &comp->steps[i];
965
0
      if (op->value4 != NULL) {
966
0
    if (op->op == XPATH_OP_VALUE)
967
0
        xmlXPathFreeObject(op->value4);
968
0
    else
969
0
        xmlFree(op->value4);
970
0
      }
971
0
      if (op->value5 != NULL)
972
0
    xmlFree(op->value5);
973
0
  }
974
0
    } else {
975
0
  for (i = 0; i < comp->nbStep; i++) {
976
0
      op = &comp->steps[i];
977
0
      if (op->value4 != NULL) {
978
0
    if (op->op == XPATH_OP_VALUE)
979
0
        xmlXPathFreeObject(op->value4);
980
0
      }
981
0
  }
982
0
        xmlDictFree(comp->dict);
983
0
    }
984
0
    if (comp->steps != NULL) {
985
0
        xmlFree(comp->steps);
986
0
    }
987
#ifdef XPATH_STREAMING
988
    if (comp->stream != NULL) {
989
        xmlFreePatternList(comp->stream);
990
    }
991
#endif
992
0
    if (comp->expr != NULL) {
993
0
        xmlFree(comp->expr);
994
0
    }
995
996
0
    xmlFree(comp);
997
0
}
998
999
/**
1000
 * Add a step to an XPath Compiled Expression
1001
 *
1002
 * @param ctxt  XPath parser context
1003
 * @param ch1  first child index
1004
 * @param ch2  second child index
1005
 * @param op  an op
1006
 * @param value  the first int value
1007
 * @param value2  the second int value
1008
 * @param value3  the third int value
1009
 * @param value4  the first string value
1010
 * @param value5  the second string value
1011
 * @returns -1 in case of failure, the index otherwise
1012
 */
1013
static int
1014
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1015
   xmlXPathOp op, int value,
1016
0
   int value2, int value3, void *value4, void *value5) {
1017
0
    xmlXPathCompExprPtr comp = ctxt->comp;
1018
0
    if (comp->nbStep >= comp->maxStep) {
1019
0
  xmlXPathStepOp *real;
1020
0
        int newSize;
1021
1022
0
        newSize = xmlGrowCapacity(comp->maxStep, sizeof(real[0]),
1023
0
                                  10, XPATH_MAX_STEPS);
1024
0
        if (newSize < 0) {
1025
0
      xmlXPathPErrMemory(ctxt);
1026
0
      return(-1);
1027
0
        }
1028
0
  real = xmlRealloc(comp->steps, newSize * sizeof(real[0]));
1029
0
  if (real == NULL) {
1030
0
      xmlXPathPErrMemory(ctxt);
1031
0
      return(-1);
1032
0
  }
1033
0
  comp->steps = real;
1034
0
  comp->maxStep = newSize;
1035
0
    }
1036
0
    comp->last = comp->nbStep;
1037
0
    comp->steps[comp->nbStep].ch1 = ch1;
1038
0
    comp->steps[comp->nbStep].ch2 = ch2;
1039
0
    comp->steps[comp->nbStep].op = op;
1040
0
    comp->steps[comp->nbStep].value = value;
1041
0
    comp->steps[comp->nbStep].value2 = value2;
1042
0
    comp->steps[comp->nbStep].value3 = value3;
1043
0
    if ((comp->dict != NULL) &&
1044
0
        ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1045
0
   (op == XPATH_OP_COLLECT))) {
1046
0
        if (value4 != NULL) {
1047
0
      comp->steps[comp->nbStep].value4 = (xmlChar *)
1048
0
          (void *)xmlDictLookup(comp->dict, value4, -1);
1049
0
      xmlFree(value4);
1050
0
  } else
1051
0
      comp->steps[comp->nbStep].value4 = NULL;
1052
0
        if (value5 != NULL) {
1053
0
      comp->steps[comp->nbStep].value5 = (xmlChar *)
1054
0
          (void *)xmlDictLookup(comp->dict, value5, -1);
1055
0
      xmlFree(value5);
1056
0
  } else
1057
0
      comp->steps[comp->nbStep].value5 = NULL;
1058
0
    } else {
1059
0
  comp->steps[comp->nbStep].value4 = value4;
1060
0
  comp->steps[comp->nbStep].value5 = value5;
1061
0
    }
1062
0
    comp->steps[comp->nbStep].cache = NULL;
1063
0
    return(comp->nbStep++);
1064
0
}
1065
1066
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1067
0
    xmlXPathCompExprAdd(ctxt, (op1), (op2),     \
1068
0
                  (op), (val), (val2), (val3), (val4), (val5))
1069
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5)     \
1070
0
    xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1,   \
1071
0
                  (op), (val), (val2), (val3), (val4), (val5))
1072
1073
0
#define PUSH_LEAVE_EXPR(op, val, val2)          \
1074
0
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1075
1076
0
#define PUSH_UNARY_EXPR(op, ch, val, val2)        \
1077
0
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1078
1079
0
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2)     \
1080
0
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op),     \
1081
0
      (val), (val2), 0 ,NULL ,NULL)
1082
1083
/************************************************************************
1084
 *                  *
1085
 *    XPath object cache structures       *
1086
 *                  *
1087
 ************************************************************************/
1088
1089
/* #define XP_DEFAULT_CACHE_ON */
1090
1091
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1092
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1093
struct _xmlXPathContextCache {
1094
    xmlXPathObjectPtr nodesetObjs;  /* stringval points to next */
1095
    xmlXPathObjectPtr miscObjs;     /* stringval points to next */
1096
    int numNodeset;
1097
    int maxNodeset;
1098
    int numMisc;
1099
    int maxMisc;
1100
};
1101
1102
/************************************************************************
1103
 *                  *
1104
 *    Debugging related functions       *
1105
 *                  *
1106
 ************************************************************************/
1107
1108
#ifdef LIBXML_DEBUG_ENABLED
1109
static void
1110
0
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1111
0
    int i;
1112
0
    char shift[100];
1113
1114
0
    for (i = 0;((i < depth) && (i < 25));i++)
1115
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1116
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1117
0
    if (cur == NULL) {
1118
0
  fprintf(output, "%s", shift);
1119
0
  fprintf(output, "Node is NULL !\n");
1120
0
  return;
1121
1122
0
    }
1123
1124
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
1125
0
       (cur->type == XML_HTML_DOCUMENT_NODE)) {
1126
0
  fprintf(output, "%s", shift);
1127
0
  fprintf(output, " /\n");
1128
0
    } else if (cur->type == XML_ATTRIBUTE_NODE)
1129
0
  xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1130
0
    else
1131
0
  xmlDebugDumpOneNode(output, cur, depth);
1132
0
}
1133
static void
1134
0
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1135
0
    xmlNodePtr tmp;
1136
0
    int i;
1137
0
    char shift[100];
1138
1139
0
    for (i = 0;((i < depth) && (i < 25));i++)
1140
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1141
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1142
0
    if (cur == NULL) {
1143
0
  fprintf(output, "%s", shift);
1144
0
  fprintf(output, "Node is NULL !\n");
1145
0
  return;
1146
1147
0
    }
1148
1149
0
    while (cur != NULL) {
1150
0
  tmp = cur;
1151
0
  cur = cur->next;
1152
0
  xmlDebugDumpOneNode(output, tmp, depth);
1153
0
    }
1154
0
}
1155
1156
static void
1157
0
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1158
0
    int i;
1159
0
    char shift[100];
1160
1161
0
    for (i = 0;((i < depth) && (i < 25));i++)
1162
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1163
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1164
1165
0
    if (cur == NULL) {
1166
0
  fprintf(output, "%s", shift);
1167
0
  fprintf(output, "NodeSet is NULL !\n");
1168
0
  return;
1169
1170
0
    }
1171
1172
0
    if (cur != NULL) {
1173
0
  fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1174
0
  for (i = 0;i < cur->nodeNr;i++) {
1175
0
      fprintf(output, "%s", shift);
1176
0
      fprintf(output, "%d", i + 1);
1177
0
      xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1178
0
  }
1179
0
    }
1180
0
}
1181
1182
static void
1183
0
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1184
0
    int i;
1185
0
    char shift[100];
1186
1187
0
    for (i = 0;((i < depth) && (i < 25));i++)
1188
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1189
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1190
1191
0
    if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1192
0
  fprintf(output, "%s", shift);
1193
0
  fprintf(output, "Value Tree is NULL !\n");
1194
0
  return;
1195
1196
0
    }
1197
1198
0
    fprintf(output, "%s", shift);
1199
0
    fprintf(output, "%d", i + 1);
1200
0
    xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1201
0
}
1202
1203
/**
1204
 * Dump the content of the object for debugging purposes
1205
 *
1206
 * @param output  the FILE * to dump the output
1207
 * @param cur  the object to inspect
1208
 * @param depth  indentation level
1209
 */
1210
void
1211
0
xmlXPathDebugDumpObject(FILE *output, xmlXPathObject *cur, int depth) {
1212
0
    int i;
1213
0
    char shift[100];
1214
1215
0
    if (output == NULL) return;
1216
1217
0
    for (i = 0;((i < depth) && (i < 25));i++)
1218
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1219
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1220
1221
1222
0
    fprintf(output, "%s", shift);
1223
1224
0
    if (cur == NULL) {
1225
0
        fprintf(output, "Object is empty (NULL)\n");
1226
0
  return;
1227
0
    }
1228
0
    switch(cur->type) {
1229
0
        case XPATH_UNDEFINED:
1230
0
      fprintf(output, "Object is uninitialized\n");
1231
0
      break;
1232
0
        case XPATH_NODESET:
1233
0
      fprintf(output, "Object is a Node Set :\n");
1234
0
      xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1235
0
      break;
1236
0
  case XPATH_XSLT_TREE:
1237
0
      fprintf(output, "Object is an XSLT value tree :\n");
1238
0
      xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1239
0
      break;
1240
0
        case XPATH_BOOLEAN:
1241
0
      fprintf(output, "Object is a Boolean : ");
1242
0
      if (cur->boolval) fprintf(output, "true\n");
1243
0
      else fprintf(output, "false\n");
1244
0
      break;
1245
0
        case XPATH_NUMBER:
1246
0
      switch (xmlXPathIsInf(cur->floatval)) {
1247
0
      case 1:
1248
0
    fprintf(output, "Object is a number : Infinity\n");
1249
0
    break;
1250
0
      case -1:
1251
0
    fprintf(output, "Object is a number : -Infinity\n");
1252
0
    break;
1253
0
      default:
1254
0
    if (xmlXPathIsNaN(cur->floatval)) {
1255
0
        fprintf(output, "Object is a number : NaN\n");
1256
0
    } else if (cur->floatval == 0) {
1257
                    /* Omit sign for negative zero. */
1258
0
        fprintf(output, "Object is a number : 0\n");
1259
0
    } else {
1260
0
        fprintf(output, "Object is a number : %0g\n", cur->floatval);
1261
0
    }
1262
0
      }
1263
0
      break;
1264
0
        case XPATH_STRING:
1265
0
      fprintf(output, "Object is a string : ");
1266
0
      xmlDebugDumpString(output, cur->stringval);
1267
0
      fprintf(output, "\n");
1268
0
      break;
1269
0
  case XPATH_USERS:
1270
0
      fprintf(output, "Object is user defined\n");
1271
0
      break;
1272
0
    }
1273
0
}
1274
1275
static void
1276
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1277
0
                       xmlXPathStepOpPtr op, int depth) {
1278
0
    int i;
1279
0
    char shift[100];
1280
1281
0
    for (i = 0;((i < depth) && (i < 25));i++)
1282
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1283
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1284
1285
0
    fprintf(output, "%s", shift);
1286
0
    if (op == NULL) {
1287
0
  fprintf(output, "Step is NULL\n");
1288
0
  return;
1289
0
    }
1290
0
    switch (op->op) {
1291
0
        case XPATH_OP_END:
1292
0
      fprintf(output, "END"); break;
1293
0
        case XPATH_OP_AND:
1294
0
      fprintf(output, "AND"); break;
1295
0
        case XPATH_OP_OR:
1296
0
      fprintf(output, "OR"); break;
1297
0
        case XPATH_OP_EQUAL:
1298
0
       if (op->value)
1299
0
     fprintf(output, "EQUAL =");
1300
0
       else
1301
0
     fprintf(output, "EQUAL !=");
1302
0
       break;
1303
0
        case XPATH_OP_CMP:
1304
0
       if (op->value)
1305
0
     fprintf(output, "CMP <");
1306
0
       else
1307
0
     fprintf(output, "CMP >");
1308
0
       if (!op->value2)
1309
0
     fprintf(output, "=");
1310
0
       break;
1311
0
        case XPATH_OP_PLUS:
1312
0
       if (op->value == 0)
1313
0
     fprintf(output, "PLUS -");
1314
0
       else if (op->value == 1)
1315
0
     fprintf(output, "PLUS +");
1316
0
       else if (op->value == 2)
1317
0
     fprintf(output, "PLUS unary -");
1318
0
       else if (op->value == 3)
1319
0
     fprintf(output, "PLUS unary - -");
1320
0
       break;
1321
0
        case XPATH_OP_MULT:
1322
0
       if (op->value == 0)
1323
0
     fprintf(output, "MULT *");
1324
0
       else if (op->value == 1)
1325
0
     fprintf(output, "MULT div");
1326
0
       else
1327
0
     fprintf(output, "MULT mod");
1328
0
       break;
1329
0
        case XPATH_OP_UNION:
1330
0
       fprintf(output, "UNION"); break;
1331
0
        case XPATH_OP_ROOT:
1332
0
       fprintf(output, "ROOT"); break;
1333
0
        case XPATH_OP_NODE:
1334
0
       fprintf(output, "NODE"); break;
1335
0
        case XPATH_OP_SORT:
1336
0
       fprintf(output, "SORT"); break;
1337
0
        case XPATH_OP_COLLECT: {
1338
0
      xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1339
0
      xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1340
0
      xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1341
0
      const xmlChar *prefix = op->value4;
1342
0
      const xmlChar *name = op->value5;
1343
1344
0
      fprintf(output, "COLLECT ");
1345
0
      switch (axis) {
1346
0
    case AXIS_ANCESTOR:
1347
0
        fprintf(output, " 'ancestors' "); break;
1348
0
    case AXIS_ANCESTOR_OR_SELF:
1349
0
        fprintf(output, " 'ancestors-or-self' "); break;
1350
0
    case AXIS_ATTRIBUTE:
1351
0
        fprintf(output, " 'attributes' "); break;
1352
0
    case AXIS_CHILD:
1353
0
        fprintf(output, " 'child' "); break;
1354
0
    case AXIS_DESCENDANT:
1355
0
        fprintf(output, " 'descendant' "); break;
1356
0
    case AXIS_DESCENDANT_OR_SELF:
1357
0
        fprintf(output, " 'descendant-or-self' "); break;
1358
0
    case AXIS_FOLLOWING:
1359
0
        fprintf(output, " 'following' "); break;
1360
0
    case AXIS_FOLLOWING_SIBLING:
1361
0
        fprintf(output, " 'following-siblings' "); break;
1362
0
    case AXIS_NAMESPACE:
1363
0
        fprintf(output, " 'namespace' "); break;
1364
0
    case AXIS_PARENT:
1365
0
        fprintf(output, " 'parent' "); break;
1366
0
    case AXIS_PRECEDING:
1367
0
        fprintf(output, " 'preceding' "); break;
1368
0
    case AXIS_PRECEDING_SIBLING:
1369
0
        fprintf(output, " 'preceding-sibling' "); break;
1370
0
    case AXIS_SELF:
1371
0
        fprintf(output, " 'self' "); break;
1372
0
      }
1373
0
      switch (test) {
1374
0
                case NODE_TEST_NONE:
1375
0
        fprintf(output, "'none' "); break;
1376
0
                case NODE_TEST_TYPE:
1377
0
        fprintf(output, "'type' "); break;
1378
0
                case NODE_TEST_PI:
1379
0
        fprintf(output, "'PI' "); break;
1380
0
                case NODE_TEST_ALL:
1381
0
        fprintf(output, "'all' "); break;
1382
0
                case NODE_TEST_NS:
1383
0
        fprintf(output, "'namespace' "); break;
1384
0
                case NODE_TEST_NAME:
1385
0
        fprintf(output, "'name' "); break;
1386
0
      }
1387
0
      switch (type) {
1388
0
                case NODE_TYPE_NODE:
1389
0
        fprintf(output, "'node' "); break;
1390
0
                case NODE_TYPE_COMMENT:
1391
0
        fprintf(output, "'comment' "); break;
1392
0
                case NODE_TYPE_TEXT:
1393
0
        fprintf(output, "'text' "); break;
1394
0
                case NODE_TYPE_PI:
1395
0
        fprintf(output, "'PI' "); break;
1396
0
      }
1397
0
      if (prefix != NULL)
1398
0
    fprintf(output, "%s:", prefix);
1399
0
      if (name != NULL)
1400
0
    fprintf(output, "%s", (const char *) name);
1401
0
      break;
1402
1403
0
        }
1404
0
  case XPATH_OP_VALUE: {
1405
0
      xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1406
1407
0
      fprintf(output, "ELEM ");
1408
0
      xmlXPathDebugDumpObject(output, object, 0);
1409
0
      goto finish;
1410
0
  }
1411
0
  case XPATH_OP_VARIABLE: {
1412
0
      const xmlChar *prefix = op->value5;
1413
0
      const xmlChar *name = op->value4;
1414
1415
0
      if (prefix != NULL)
1416
0
    fprintf(output, "VARIABLE %s:%s", prefix, name);
1417
0
      else
1418
0
    fprintf(output, "VARIABLE %s", name);
1419
0
      break;
1420
0
  }
1421
0
  case XPATH_OP_FUNCTION: {
1422
0
      int nbargs = op->value;
1423
0
      const xmlChar *prefix = op->value5;
1424
0
      const xmlChar *name = op->value4;
1425
1426
0
      if (prefix != NULL)
1427
0
    fprintf(output, "FUNCTION %s:%s(%d args)",
1428
0
      prefix, name, nbargs);
1429
0
      else
1430
0
    fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1431
0
      break;
1432
0
  }
1433
0
        case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1434
0
        case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1435
0
        case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1436
0
  default:
1437
0
        fprintf(output, "UNKNOWN %d\n", op->op); return;
1438
0
    }
1439
0
    fprintf(output, "\n");
1440
0
finish:
1441
    /* OP_VALUE has invalid ch1. */
1442
0
    if (op->op == XPATH_OP_VALUE)
1443
0
        return;
1444
1445
0
    if (op->ch1 >= 0)
1446
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1447
0
    if (op->ch2 >= 0)
1448
0
  xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1449
0
}
1450
1451
/**
1452
 * Dumps the tree of the compiled XPath expression.
1453
 *
1454
 * @param output  the FILE * for the output
1455
 * @param comp  the precompiled XPath expression
1456
 * @param depth  the indentation level.
1457
 */
1458
void
1459
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExpr *comp,
1460
0
                    int depth) {
1461
0
    int i;
1462
0
    char shift[100];
1463
1464
0
    if ((output == NULL) || (comp == NULL)) return;
1465
1466
0
    for (i = 0;((i < depth) && (i < 25));i++)
1467
0
        shift[2 * i] = shift[2 * i + 1] = ' ';
1468
0
    shift[2 * i] = shift[2 * i + 1] = 0;
1469
1470
0
    fprintf(output, "%s", shift);
1471
1472
#ifdef XPATH_STREAMING
1473
    if (comp->stream) {
1474
        fprintf(output, "Streaming Expression\n");
1475
    } else
1476
#endif
1477
0
    {
1478
0
        fprintf(output, "Compiled Expression : %d elements\n",
1479
0
                comp->nbStep);
1480
0
        i = comp->last;
1481
0
        xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1482
0
    }
1483
0
}
1484
1485
#endif /* LIBXML_DEBUG_ENABLED */
1486
1487
/************************************************************************
1488
 *                  *
1489
 *      XPath object caching        *
1490
 *                  *
1491
 ************************************************************************/
1492
1493
/**
1494
 * Create a new object cache
1495
 *
1496
 * @returns the xmlXPathCache just allocated.
1497
 */
1498
static xmlXPathContextCachePtr
1499
xmlXPathNewCache(void)
1500
0
{
1501
0
    xmlXPathContextCachePtr ret;
1502
1503
0
    ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1504
0
    if (ret == NULL)
1505
0
  return(NULL);
1506
0
    memset(ret, 0 , sizeof(xmlXPathContextCache));
1507
0
    ret->maxNodeset = 100;
1508
0
    ret->maxMisc = 100;
1509
0
    return(ret);
1510
0
}
1511
1512
static void
1513
xmlXPathCacheFreeObjectList(xmlXPathObjectPtr list)
1514
0
{
1515
0
    while (list != NULL) {
1516
0
        xmlXPathObjectPtr next;
1517
1518
0
        next = (void *) list->stringval;
1519
1520
0
  if (list->nodesetval != NULL) {
1521
0
      if (list->nodesetval->nodeTab != NULL)
1522
0
    xmlFree(list->nodesetval->nodeTab);
1523
0
      xmlFree(list->nodesetval);
1524
0
  }
1525
0
  xmlFree(list);
1526
1527
0
        list = next;
1528
0
    }
1529
0
}
1530
1531
static void
1532
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1533
0
{
1534
0
    if (cache == NULL)
1535
0
  return;
1536
0
    if (cache->nodesetObjs)
1537
0
  xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1538
0
    if (cache->miscObjs)
1539
0
  xmlXPathCacheFreeObjectList(cache->miscObjs);
1540
0
    xmlFree(cache);
1541
0
}
1542
1543
/**
1544
 * Creates/frees an object cache on the XPath context.
1545
 * If activates XPath objects (xmlXPathObject) will be cached internally
1546
 * to be reused.
1547
 *
1548
 * `options` must be set to 0 to enable XPath object caching.
1549
 * Other values for `options` have currently no effect.
1550
 *
1551
 * `value` sets the maximum number of XPath objects to be cached per slot.
1552
 * There are two slots for node-set and misc objects.
1553
 * Use <0 for the default number (100).
1554
 *
1555
 * @param ctxt  the XPath context
1556
 * @param active  enables/disables (creates/frees) the cache
1557
 * @param value  a value with semantics dependent on `options`
1558
 * @param options  options (currently only the value 0 is used)
1559
 * @returns 0 if the setting succeeded, and -1 on API or internal errors.
1560
 */
1561
int
1562
xmlXPathContextSetCache(xmlXPathContext *ctxt,
1563
      int active,
1564
      int value,
1565
      int options)
1566
0
{
1567
0
    if (ctxt == NULL)
1568
0
  return(-1);
1569
0
    if (active) {
1570
0
  xmlXPathContextCachePtr cache;
1571
1572
0
  if (ctxt->cache == NULL) {
1573
0
      ctxt->cache = xmlXPathNewCache();
1574
0
      if (ctxt->cache == NULL) {
1575
0
                xmlXPathErrMemory(ctxt);
1576
0
    return(-1);
1577
0
            }
1578
0
  }
1579
0
  cache = (xmlXPathContextCachePtr) ctxt->cache;
1580
0
  if (options == 0) {
1581
0
      if (value < 0)
1582
0
    value = 100;
1583
0
      cache->maxNodeset = value;
1584
0
      cache->maxMisc = value;
1585
0
  }
1586
0
    } else if (ctxt->cache != NULL) {
1587
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1588
0
  ctxt->cache = NULL;
1589
0
    }
1590
0
    return(0);
1591
0
}
1592
1593
/**
1594
 * This is the cached version of #xmlXPathWrapNodeSet.
1595
 * Wrap the Nodeset `val` in a new xmlXPathObject
1596
 *
1597
 * In case of error the node set is destroyed and NULL is returned.
1598
 *
1599
 * @param pctxt  the XPath context
1600
 * @param val  the NodePtr value
1601
 * @returns the created or reused object.
1602
 */
1603
static xmlXPathObjectPtr
1604
xmlXPathCacheWrapNodeSet(xmlXPathParserContextPtr pctxt, xmlNodeSetPtr val)
1605
0
{
1606
0
    xmlXPathObjectPtr ret;
1607
0
    xmlXPathContextPtr ctxt = pctxt->context;
1608
1609
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1610
0
  xmlXPathContextCachePtr cache =
1611
0
      (xmlXPathContextCachePtr) ctxt->cache;
1612
1613
0
  if (cache->miscObjs != NULL) {
1614
0
      ret = cache->miscObjs;
1615
0
            cache->miscObjs = (void *) ret->stringval;
1616
0
            cache->numMisc -= 1;
1617
0
            ret->stringval = NULL;
1618
0
      ret->type = XPATH_NODESET;
1619
0
      ret->nodesetval = val;
1620
0
      return(ret);
1621
0
  }
1622
0
    }
1623
1624
0
    ret = xmlXPathWrapNodeSet(val);
1625
0
    if (ret == NULL)
1626
0
        xmlXPathPErrMemory(pctxt);
1627
0
    return(ret);
1628
0
}
1629
1630
/**
1631
 * This is the cached version of #xmlXPathWrapString.
1632
 * Wraps the `val` string into an XPath object.
1633
 *
1634
 * @param pctxt  the XPath context
1635
 * @param val  the xmlChar * value
1636
 * @returns the created or reused object.
1637
 */
1638
static xmlXPathObjectPtr
1639
xmlXPathCacheWrapString(xmlXPathParserContextPtr pctxt, xmlChar *val)
1640
0
{
1641
0
    xmlXPathObjectPtr ret;
1642
0
    xmlXPathContextPtr ctxt = pctxt->context;
1643
1644
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1645
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1646
1647
0
  if (cache->miscObjs != NULL) {
1648
0
      ret = cache->miscObjs;
1649
0
            cache->miscObjs = (void *) ret->stringval;
1650
0
            cache->numMisc -= 1;
1651
0
      ret->type = XPATH_STRING;
1652
0
      ret->stringval = val;
1653
0
      return(ret);
1654
0
  }
1655
0
    }
1656
1657
0
    ret = xmlXPathWrapString(val);
1658
0
    if (ret == NULL)
1659
0
        xmlXPathPErrMemory(pctxt);
1660
0
    return(ret);
1661
0
}
1662
1663
/**
1664
 * This is the cached version of #xmlXPathNewNodeSet.
1665
 * Acquire an xmlXPathObject of type NodeSet and initialize
1666
 * it with the single Node `val`
1667
 *
1668
 * @param pctxt  the XPath context
1669
 * @param val  the NodePtr value
1670
 * @returns the created or reused object.
1671
 */
1672
static xmlXPathObjectPtr
1673
xmlXPathCacheNewNodeSet(xmlXPathParserContextPtr pctxt, xmlNodePtr val)
1674
0
{
1675
0
    xmlXPathObjectPtr ret;
1676
0
    xmlXPathContextPtr ctxt = pctxt->context;
1677
1678
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1679
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1680
1681
0
  if (cache->nodesetObjs != NULL) {
1682
      /*
1683
      * Use the nodeset-cache.
1684
      */
1685
0
      ret = cache->nodesetObjs;
1686
0
            cache->nodesetObjs = (void *) ret->stringval;
1687
0
            cache->numNodeset -= 1;
1688
0
            ret->stringval = NULL;
1689
0
      ret->type = XPATH_NODESET;
1690
0
      ret->boolval = 0;
1691
0
      if (val) {
1692
0
    if ((ret->nodesetval->nodeMax == 0) ||
1693
0
        (val->type == XML_NAMESPACE_DECL))
1694
0
    {
1695
0
        if (xmlXPathNodeSetAddUnique(ret->nodesetval, val) < 0)
1696
0
                        xmlXPathPErrMemory(pctxt);
1697
0
    } else {
1698
0
        ret->nodesetval->nodeTab[0] = val;
1699
0
        ret->nodesetval->nodeNr = 1;
1700
0
    }
1701
0
      }
1702
0
      return(ret);
1703
0
  } else if (cache->miscObjs != NULL) {
1704
0
            xmlNodeSetPtr set;
1705
      /*
1706
      * Fallback to misc-cache.
1707
      */
1708
1709
0
      set = xmlXPathNodeSetCreate(val);
1710
0
      if (set == NULL) {
1711
0
                xmlXPathPErrMemory(pctxt);
1712
0
    return(NULL);
1713
0
      }
1714
1715
0
      ret = cache->miscObjs;
1716
0
            cache->miscObjs = (void *) ret->stringval;
1717
0
            cache->numMisc -= 1;
1718
0
            ret->stringval = NULL;
1719
0
      ret->type = XPATH_NODESET;
1720
0
      ret->boolval = 0;
1721
0
      ret->nodesetval = set;
1722
0
      return(ret);
1723
0
  }
1724
0
    }
1725
0
    ret = xmlXPathNewNodeSet(val);
1726
0
    if (ret == NULL)
1727
0
        xmlXPathPErrMemory(pctxt);
1728
0
    return(ret);
1729
0
}
1730
1731
/**
1732
 * This is the cached version of #xmlXPathNewString.
1733
 * Acquire an xmlXPathObject of type string and of value `val`
1734
 *
1735
 * @param pctxt  the XPath context
1736
 * @param val  the xmlChar * value
1737
 * @returns the created or reused object.
1738
 */
1739
static xmlXPathObjectPtr
1740
xmlXPathCacheNewString(xmlXPathParserContextPtr pctxt, const xmlChar *val)
1741
0
{
1742
0
    xmlXPathObjectPtr ret;
1743
0
    xmlXPathContextPtr ctxt = pctxt->context;
1744
1745
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1746
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1747
1748
0
  if (cache->miscObjs != NULL) {
1749
0
            xmlChar *copy;
1750
1751
0
            if (val == NULL)
1752
0
                val = BAD_CAST "";
1753
0
            copy = xmlStrdup(val);
1754
0
            if (copy == NULL) {
1755
0
                xmlXPathPErrMemory(pctxt);
1756
0
                return(NULL);
1757
0
            }
1758
1759
0
      ret = cache->miscObjs;
1760
0
            cache->miscObjs = (void *) ret->stringval;
1761
0
            cache->numMisc -= 1;
1762
0
      ret->type = XPATH_STRING;
1763
0
            ret->stringval = copy;
1764
0
      return(ret);
1765
0
  }
1766
0
    }
1767
1768
0
    ret = xmlXPathNewString(val);
1769
0
    if (ret == NULL)
1770
0
        xmlXPathPErrMemory(pctxt);
1771
0
    return(ret);
1772
0
}
1773
1774
/**
1775
 * This is the cached version of #xmlXPathNewCString.
1776
 * Acquire an xmlXPathObject of type string and of value `val`
1777
 *
1778
 * @param pctxt  the XPath context
1779
 * @param val  the char * value
1780
 * @returns the created or reused object.
1781
 */
1782
static xmlXPathObjectPtr
1783
xmlXPathCacheNewCString(xmlXPathParserContextPtr pctxt, const char *val)
1784
0
{
1785
0
    return xmlXPathCacheNewString(pctxt, BAD_CAST val);
1786
0
}
1787
1788
/**
1789
 * This is the cached version of #xmlXPathNewBoolean.
1790
 * Acquires an xmlXPathObject of type boolean and of value `val`
1791
 *
1792
 * @param pctxt  the XPath context
1793
 * @param val  the boolean value
1794
 * @returns the created or reused object.
1795
 */
1796
static xmlXPathObjectPtr
1797
xmlXPathCacheNewBoolean(xmlXPathParserContextPtr pctxt, int val)
1798
0
{
1799
0
    xmlXPathObjectPtr ret;
1800
0
    xmlXPathContextPtr ctxt = pctxt->context;
1801
1802
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1803
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1804
1805
0
  if (cache->miscObjs != NULL) {
1806
0
      ret = cache->miscObjs;
1807
0
            cache->miscObjs = (void *) ret->stringval;
1808
0
            cache->numMisc -= 1;
1809
0
            ret->stringval = NULL;
1810
0
      ret->type = XPATH_BOOLEAN;
1811
0
      ret->boolval = (val != 0);
1812
0
      return(ret);
1813
0
  }
1814
0
    }
1815
1816
0
    ret = xmlXPathNewBoolean(val);
1817
0
    if (ret == NULL)
1818
0
        xmlXPathPErrMemory(pctxt);
1819
0
    return(ret);
1820
0
}
1821
1822
/**
1823
 * This is the cached version of #xmlXPathNewFloat.
1824
 * Acquires an xmlXPathObject of type double and of value `val`
1825
 *
1826
 * @param pctxt  the XPath context
1827
 * @param val  the double value
1828
 * @returns the created or reused object.
1829
 */
1830
static xmlXPathObjectPtr
1831
xmlXPathCacheNewFloat(xmlXPathParserContextPtr pctxt, double val)
1832
0
{
1833
0
    xmlXPathObjectPtr ret;
1834
0
    xmlXPathContextPtr ctxt = pctxt->context;
1835
1836
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1837
0
  xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1838
1839
0
  if (cache->miscObjs != NULL) {
1840
0
      ret = cache->miscObjs;
1841
0
            cache->miscObjs = (void *) ret->stringval;
1842
0
            cache->numMisc -= 1;
1843
0
            ret->stringval = NULL;
1844
0
      ret->type = XPATH_NUMBER;
1845
0
      ret->floatval = val;
1846
0
      return(ret);
1847
0
  }
1848
0
    }
1849
1850
0
    ret = xmlXPathNewFloat(val);
1851
0
    if (ret == NULL)
1852
0
        xmlXPathPErrMemory(pctxt);
1853
0
    return(ret);
1854
0
}
1855
1856
/**
1857
 * This is the cached version of #xmlXPathObjectCopy.
1858
 * Acquire a copy of a given object
1859
 *
1860
 * @param pctxt  the XPath context
1861
 * @param val  the original object
1862
 * @returns a created or reused created object.
1863
 */
1864
static xmlXPathObjectPtr
1865
xmlXPathCacheObjectCopy(xmlXPathParserContextPtr pctxt, xmlXPathObjectPtr val)
1866
0
{
1867
0
    xmlXPathObjectPtr ret;
1868
0
    xmlXPathContextPtr ctxt = pctxt->context;
1869
1870
0
    if (val == NULL)
1871
0
  return(NULL);
1872
1873
0
    if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1874
0
  switch (val->type) {
1875
0
            case XPATH_NODESET: {
1876
0
                xmlNodeSetPtr set;
1877
1878
0
                set = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1879
0
                if (set == NULL) {
1880
0
                    xmlXPathPErrMemory(pctxt);
1881
0
                    return(NULL);
1882
0
                }
1883
0
                return(xmlXPathCacheWrapNodeSet(pctxt, set));
1884
0
            }
1885
0
      case XPATH_STRING:
1886
0
    return(xmlXPathCacheNewString(pctxt, val->stringval));
1887
0
      case XPATH_BOOLEAN:
1888
0
    return(xmlXPathCacheNewBoolean(pctxt, val->boolval));
1889
0
      case XPATH_NUMBER:
1890
0
    return(xmlXPathCacheNewFloat(pctxt, val->floatval));
1891
0
      default:
1892
0
    break;
1893
0
  }
1894
0
    }
1895
0
    ret = xmlXPathObjectCopy(val);
1896
0
    if (ret == NULL)
1897
0
        xmlXPathPErrMemory(pctxt);
1898
0
    return(ret);
1899
0
}
1900
1901
/************************************************************************
1902
 *                  *
1903
 *    Parser stacks related functions and macros    *
1904
 *                  *
1905
 ************************************************************************/
1906
1907
/**
1908
 * Converts an XPath object to its number value
1909
 *
1910
 * @param ctxt  parser context
1911
 * @param val  an XPath object
1912
 * @returns the number value
1913
 */
1914
static double
1915
xmlXPathCastToNumberInternal(xmlXPathParserContextPtr ctxt,
1916
0
                             xmlXPathObjectPtr val) {
1917
0
    double ret = 0.0;
1918
1919
0
    if (val == NULL)
1920
0
  return(xmlXPathNAN);
1921
0
    switch (val->type) {
1922
0
    case XPATH_UNDEFINED:
1923
0
  ret = xmlXPathNAN;
1924
0
  break;
1925
0
    case XPATH_NODESET:
1926
0
    case XPATH_XSLT_TREE: {
1927
0
        xmlChar *str;
1928
1929
0
  str = xmlXPathCastNodeSetToString(val->nodesetval);
1930
0
        if (str == NULL) {
1931
0
            xmlXPathPErrMemory(ctxt);
1932
0
            ret = xmlXPathNAN;
1933
0
        } else {
1934
0
      ret = xmlXPathCastStringToNumber(str);
1935
0
            xmlFree(str);
1936
0
        }
1937
0
  break;
1938
0
    }
1939
0
    case XPATH_STRING:
1940
0
  ret = xmlXPathCastStringToNumber(val->stringval);
1941
0
  break;
1942
0
    case XPATH_NUMBER:
1943
0
  ret = val->floatval;
1944
0
  break;
1945
0
    case XPATH_BOOLEAN:
1946
0
  ret = xmlXPathCastBooleanToNumber(val->boolval);
1947
0
  break;
1948
0
    case XPATH_USERS:
1949
  /* TODO */
1950
0
  ret = xmlXPathNAN;
1951
0
  break;
1952
0
    }
1953
0
    return(ret);
1954
0
}
1955
1956
/**
1957
 * Pops the top XPath object from the value stack
1958
 *
1959
 * @param ctxt  an XPath evaluation context
1960
 * @returns the XPath object just removed
1961
 */
1962
xmlXPathObject *
1963
xmlXPathValuePop(xmlXPathParserContext *ctxt)
1964
0
{
1965
0
    xmlXPathObjectPtr ret;
1966
1967
0
    if ((ctxt == NULL) || (ctxt->valueNr <= 0))
1968
0
        return (NULL);
1969
1970
0
    ctxt->valueNr--;
1971
0
    if (ctxt->valueNr > 0)
1972
0
        ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
1973
0
    else
1974
0
        ctxt->value = NULL;
1975
0
    ret = ctxt->valueTab[ctxt->valueNr];
1976
0
    ctxt->valueTab[ctxt->valueNr] = NULL;
1977
0
    return (ret);
1978
0
}
1979
1980
/**
1981
 * Pushes a new XPath object on top of the value stack. If value is NULL,
1982
 * a memory error is recorded in the parser context.
1983
 *
1984
 * The object is destroyed in case of error.
1985
 *
1986
 * @param ctxt  an XPath evaluation context
1987
 * @param value  the XPath object
1988
 * @returns the number of items on the value stack, or -1 in case of error.
1989
 */
1990
int
1991
xmlXPathValuePush(xmlXPathParserContext *ctxt, xmlXPathObject *value)
1992
0
{
1993
0
    if (ctxt == NULL) return(-1);
1994
0
    if (value == NULL) {
1995
        /*
1996
         * A NULL value typically indicates that a memory allocation failed.
1997
         */
1998
0
        xmlXPathPErrMemory(ctxt);
1999
0
        return(-1);
2000
0
    }
2001
0
    if (ctxt->valueNr >= ctxt->valueMax) {
2002
0
        xmlXPathObjectPtr *tmp;
2003
0
        int newSize;
2004
2005
0
        newSize = xmlGrowCapacity(ctxt->valueMax, sizeof(tmp[0]),
2006
0
                                  10, XPATH_MAX_STACK_DEPTH);
2007
0
        if (newSize < 0) {
2008
0
            xmlXPathPErrMemory(ctxt);
2009
0
            xmlXPathFreeObject(value);
2010
0
            return (-1);
2011
0
        }
2012
0
        tmp = xmlRealloc(ctxt->valueTab, newSize * sizeof(tmp[0]));
2013
0
        if (tmp == NULL) {
2014
0
            xmlXPathPErrMemory(ctxt);
2015
0
            xmlXPathFreeObject(value);
2016
0
            return (-1);
2017
0
        }
2018
0
  ctxt->valueTab = tmp;
2019
0
        ctxt->valueMax = newSize;
2020
0
    }
2021
0
    ctxt->valueTab[ctxt->valueNr] = value;
2022
0
    ctxt->value = value;
2023
0
    return (ctxt->valueNr++);
2024
0
}
2025
2026
/**
2027
 * Pops a boolean from the stack, handling conversion if needed.
2028
 * Check error with xmlXPathCheckError.
2029
 *
2030
 * @param ctxt  an XPath parser context
2031
 * @returns the boolean
2032
 */
2033
int
2034
0
xmlXPathPopBoolean (xmlXPathParserContext *ctxt) {
2035
0
    xmlXPathObjectPtr obj;
2036
0
    int ret;
2037
2038
0
    obj = xmlXPathValuePop(ctxt);
2039
0
    if (obj == NULL) {
2040
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2041
0
  return(0);
2042
0
    }
2043
0
    if (obj->type != XPATH_BOOLEAN)
2044
0
  ret = xmlXPathCastToBoolean(obj);
2045
0
    else
2046
0
        ret = obj->boolval;
2047
0
    xmlXPathReleaseObject(ctxt->context, obj);
2048
0
    return(ret);
2049
0
}
2050
2051
/**
2052
 * Pops a number from the stack, handling conversion if needed.
2053
 * Check error with xmlXPathCheckError.
2054
 *
2055
 * @param ctxt  an XPath parser context
2056
 * @returns the number
2057
 */
2058
double
2059
0
xmlXPathPopNumber (xmlXPathParserContext *ctxt) {
2060
0
    xmlXPathObjectPtr obj;
2061
0
    double ret;
2062
2063
0
    obj = xmlXPathValuePop(ctxt);
2064
0
    if (obj == NULL) {
2065
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2066
0
  return(0);
2067
0
    }
2068
0
    if (obj->type != XPATH_NUMBER)
2069
0
  ret = xmlXPathCastToNumberInternal(ctxt, obj);
2070
0
    else
2071
0
        ret = obj->floatval;
2072
0
    xmlXPathReleaseObject(ctxt->context, obj);
2073
0
    return(ret);
2074
0
}
2075
2076
/**
2077
 * Pops a string from the stack, handling conversion if needed.
2078
 * Check error with xmlXPathCheckError.
2079
 *
2080
 * @param ctxt  an XPath parser context
2081
 * @returns the string
2082
 */
2083
xmlChar *
2084
0
xmlXPathPopString (xmlXPathParserContext *ctxt) {
2085
0
    xmlXPathObjectPtr obj;
2086
0
    xmlChar * ret;
2087
2088
0
    obj = xmlXPathValuePop(ctxt);
2089
0
    if (obj == NULL) {
2090
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2091
0
  return(NULL);
2092
0
    }
2093
0
    ret = xmlXPathCastToString(obj);
2094
0
    if (ret == NULL)
2095
0
        xmlXPathPErrMemory(ctxt);
2096
0
    xmlXPathReleaseObject(ctxt->context, obj);
2097
0
    return(ret);
2098
0
}
2099
2100
/**
2101
 * Pops a node-set from the stack, handling conversion if needed.
2102
 * Check error with xmlXPathCheckError.
2103
 *
2104
 * @param ctxt  an XPath parser context
2105
 * @returns the node-set
2106
 */
2107
xmlNodeSet *
2108
0
xmlXPathPopNodeSet (xmlXPathParserContext *ctxt) {
2109
0
    xmlXPathObjectPtr obj;
2110
0
    xmlNodeSetPtr ret;
2111
2112
0
    if (ctxt == NULL) return(NULL);
2113
0
    if (ctxt->value == NULL) {
2114
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2115
0
  return(NULL);
2116
0
    }
2117
0
    if (!xmlXPathStackIsNodeSet(ctxt)) {
2118
0
  xmlXPathSetTypeError(ctxt);
2119
0
  return(NULL);
2120
0
    }
2121
0
    obj = xmlXPathValuePop(ctxt);
2122
0
    ret = obj->nodesetval;
2123
0
    obj->nodesetval = NULL;
2124
0
    xmlXPathReleaseObject(ctxt->context, obj);
2125
0
    return(ret);
2126
0
}
2127
2128
/**
2129
 * Pops an external object from the stack, handling conversion if needed.
2130
 * Check error with xmlXPathCheckError.
2131
 *
2132
 * @param ctxt  an XPath parser context
2133
 * @returns the object
2134
 */
2135
void *
2136
0
xmlXPathPopExternal (xmlXPathParserContext *ctxt) {
2137
0
    xmlXPathObjectPtr obj;
2138
0
    void * ret;
2139
2140
0
    if ((ctxt == NULL) || (ctxt->value == NULL)) {
2141
0
  xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2142
0
  return(NULL);
2143
0
    }
2144
0
    if (ctxt->value->type != XPATH_USERS) {
2145
0
  xmlXPathSetTypeError(ctxt);
2146
0
  return(NULL);
2147
0
    }
2148
0
    obj = xmlXPathValuePop(ctxt);
2149
0
    ret = obj->user;
2150
0
    obj->user = NULL;
2151
0
    xmlXPathReleaseObject(ctxt->context, obj);
2152
0
    return(ret);
2153
0
}
2154
2155
/*
2156
 * Macros for accessing the content. Those should be used only by the parser,
2157
 * and not exported.
2158
 *
2159
 * Dirty macros, i.e. one need to make assumption on the context to use them
2160
 *
2161
 *   CUR_PTR return the current pointer to the xmlChar to be parsed.
2162
 *   CUR     returns the current xmlChar value, i.e. a 8 bit value
2163
 *           in ISO-Latin or UTF-8.
2164
 *           This should be used internally by the parser
2165
 *           only to compare to ASCII values otherwise it would break when
2166
 *           running with UTF-8 encoding.
2167
 *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
2168
 *           to compare on ASCII based substring.
2169
 *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2170
 *           strings within the parser.
2171
 *   CURRENT Returns the current char value, with the full decoding of
2172
 *           UTF-8 if we are using this mode. It returns an int.
2173
 *   NEXT    Skip to the next character, this does the proper decoding
2174
 *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
2175
 *           It returns the pointer to the current xmlChar.
2176
 */
2177
2178
0
#define CUR (*ctxt->cur)
2179
0
#define SKIP(val) ctxt->cur += (val)
2180
0
#define NXT(val) ctxt->cur[(val)]
2181
0
#define CUR_PTR ctxt->cur
2182
2183
#define SKIP_BLANKS             \
2184
0
    while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2185
2186
#define CURRENT (*ctxt->cur)
2187
0
#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
2188
2189
2190
#ifndef DBL_DIG
2191
#define DBL_DIG 16
2192
#endif
2193
#ifndef DBL_EPSILON
2194
#define DBL_EPSILON 1E-9
2195
#endif
2196
2197
0
#define UPPER_DOUBLE 1E9
2198
0
#define LOWER_DOUBLE 1E-5
2199
#define LOWER_DOUBLE_EXP 5
2200
2201
#define INTEGER_DIGITS DBL_DIG
2202
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2203
0
#define EXPONENT_DIGITS (3 + 2)
2204
2205
/**
2206
 * Convert the number into a string representation.
2207
 *
2208
 * @param number  number to format
2209
 * @param buffer  output buffer
2210
 * @param buffersize  size of output buffer
2211
 */
2212
static void
2213
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2214
0
{
2215
0
    switch (xmlXPathIsInf(number)) {
2216
0
    case 1:
2217
0
  if (buffersize > (int)sizeof("Infinity"))
2218
0
      snprintf(buffer, buffersize, "Infinity");
2219
0
  break;
2220
0
    case -1:
2221
0
  if (buffersize > (int)sizeof("-Infinity"))
2222
0
      snprintf(buffer, buffersize, "-Infinity");
2223
0
  break;
2224
0
    default:
2225
0
  if (xmlXPathIsNaN(number)) {
2226
0
      if (buffersize > (int)sizeof("NaN"))
2227
0
    snprintf(buffer, buffersize, "NaN");
2228
0
  } else if (number == 0) {
2229
            /* Omit sign for negative zero. */
2230
0
      snprintf(buffer, buffersize, "0");
2231
0
  } else if ((number > INT_MIN) && (number < INT_MAX) &&
2232
0
                   (number == (int) number)) {
2233
0
      char work[30];
2234
0
      char *ptr, *cur;
2235
0
      int value = (int) number;
2236
2237
0
            ptr = &buffer[0];
2238
0
      if (value == 0) {
2239
0
    *ptr++ = '0';
2240
0
      } else {
2241
0
    snprintf(work, 29, "%d", value);
2242
0
    cur = &work[0];
2243
0
    while ((*cur) && (ptr - buffer < buffersize)) {
2244
0
        *ptr++ = *cur++;
2245
0
    }
2246
0
      }
2247
0
      if (ptr - buffer < buffersize) {
2248
0
    *ptr = 0;
2249
0
      } else if (buffersize > 0) {
2250
0
    ptr--;
2251
0
    *ptr = 0;
2252
0
      }
2253
0
  } else {
2254
      /*
2255
        For the dimension of work,
2256
            DBL_DIG is number of significant digits
2257
      EXPONENT is only needed for "scientific notation"
2258
            3 is sign, decimal point, and terminating zero
2259
      LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2260
        Note that this dimension is slightly (a few characters)
2261
        larger than actually necessary.
2262
      */
2263
0
      char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2264
0
      int integer_place, fraction_place;
2265
0
      char *ptr;
2266
0
      char *after_fraction;
2267
0
      double absolute_value;
2268
0
      int size;
2269
2270
0
      absolute_value = fabs(number);
2271
2272
      /*
2273
       * First choose format - scientific or regular floating point.
2274
       * In either case, result is in work, and after_fraction points
2275
       * just past the fractional part.
2276
      */
2277
0
      if ( ((absolute_value > UPPER_DOUBLE) ||
2278
0
      (absolute_value < LOWER_DOUBLE)) &&
2279
0
     (absolute_value != 0.0) ) {
2280
    /* Use scientific notation */
2281
0
    integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2282
0
    fraction_place = DBL_DIG - 1;
2283
0
    size = snprintf(work, sizeof(work),"%*.*e",
2284
0
       integer_place, fraction_place, number);
2285
0
    while ((size > 0) && (work[size] != 'e')) size--;
2286
2287
0
      }
2288
0
      else {
2289
    /* Use regular notation */
2290
0
    if (absolute_value > 0.0) {
2291
0
        integer_place = (int)log10(absolute_value);
2292
0
        if (integer_place > 0)
2293
0
            fraction_place = DBL_DIG - integer_place - 1;
2294
0
        else
2295
0
            fraction_place = DBL_DIG - integer_place;
2296
0
    } else {
2297
0
        fraction_place = 1;
2298
0
    }
2299
0
    size = snprintf(work, sizeof(work), "%0.*f",
2300
0
        fraction_place, number);
2301
0
      }
2302
2303
      /* Remove leading spaces sometimes inserted by snprintf */
2304
0
      while (work[0] == ' ') {
2305
0
          for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2306
0
    size--;
2307
0
      }
2308
2309
      /* Remove fractional trailing zeroes */
2310
0
      after_fraction = work + size;
2311
0
      ptr = after_fraction;
2312
0
      while (*(--ptr) == '0')
2313
0
    ;
2314
0
      if (*ptr != '.')
2315
0
          ptr++;
2316
0
      while ((*ptr++ = *after_fraction++) != 0);
2317
2318
      /* Finally copy result back to caller */
2319
0
      size = strlen(work) + 1;
2320
0
      if (size > buffersize) {
2321
0
    work[buffersize - 1] = 0;
2322
0
    size = buffersize;
2323
0
      }
2324
0
      memmove(buffer, work, size);
2325
0
  }
2326
0
  break;
2327
0
    }
2328
0
}
2329
2330
2331
/************************************************************************
2332
 *                  *
2333
 *      Routines to handle NodeSets     *
2334
 *                  *
2335
 ************************************************************************/
2336
2337
/**
2338
 * Call this routine to speed up XPath computation on static documents.
2339
 * This stamps all the element nodes with the document order
2340
 * Like for line information, the order is kept in the element->content
2341
 * field, the value stored is actually - the node number (starting at -1)
2342
 * to be able to differentiate from line numbers.
2343
 *
2344
 * @param doc  an input document
2345
 * @returns the number of elements found in the document or -1 in case
2346
 *    of error.
2347
 */
2348
long
2349
0
xmlXPathOrderDocElems(xmlDoc *doc) {
2350
0
    XML_INTPTR_T count = 0;
2351
0
    xmlNodePtr cur;
2352
2353
0
    if (doc == NULL)
2354
0
  return(-1);
2355
0
    cur = doc->children;
2356
0
    while (cur != NULL) {
2357
0
  if (cur->type == XML_ELEMENT_NODE) {
2358
0
            count += 1;
2359
0
            cur->content = XML_INT_TO_PTR(-count);
2360
0
      if (cur->children != NULL) {
2361
0
    cur = cur->children;
2362
0
    continue;
2363
0
      }
2364
0
  }
2365
0
  if (cur->next != NULL) {
2366
0
      cur = cur->next;
2367
0
      continue;
2368
0
  }
2369
0
  do {
2370
0
      cur = cur->parent;
2371
0
      if (cur == NULL)
2372
0
    break;
2373
0
      if (cur == (xmlNodePtr) doc) {
2374
0
    cur = NULL;
2375
0
    break;
2376
0
      }
2377
0
      if (cur->next != NULL) {
2378
0
    cur = cur->next;
2379
0
    break;
2380
0
      }
2381
0
  } while (cur != NULL);
2382
0
    }
2383
0
    return(count);
2384
0
}
2385
2386
/**
2387
 * Compare two nodes w.r.t document order
2388
 *
2389
 * @param node1  the first node
2390
 * @param node2  the second node
2391
 * @returns -2 in case of error 1 if first point < second point, 0 if
2392
 *         it's the same node, -1 otherwise
2393
 */
2394
int
2395
0
xmlXPathCmpNodes(xmlNode *node1, xmlNode *node2) {
2396
0
    int depth1, depth2;
2397
0
    int attr1 = 0, attr2 = 0;
2398
0
    xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2399
0
    xmlNodePtr cur, root;
2400
2401
0
    if ((node1 == NULL) || (node2 == NULL))
2402
0
  return(-2);
2403
    /*
2404
     * a couple of optimizations which will avoid computations in most cases
2405
     */
2406
0
    if (node1 == node2)   /* trivial case */
2407
0
  return(0);
2408
0
    if (node1->type == XML_ATTRIBUTE_NODE) {
2409
0
  attr1 = 1;
2410
0
  attrNode1 = node1;
2411
0
  node1 = node1->parent;
2412
0
    }
2413
0
    if (node2->type == XML_ATTRIBUTE_NODE) {
2414
0
  attr2 = 1;
2415
0
  attrNode2 = node2;
2416
0
  node2 = node2->parent;
2417
0
    }
2418
0
    if (node1 == node2) {
2419
0
  if (attr1 == attr2) {
2420
      /* not required, but we keep attributes in order */
2421
0
      if (attr1 != 0) {
2422
0
          cur = attrNode2->prev;
2423
0
    while (cur != NULL) {
2424
0
        if (cur == attrNode1)
2425
0
            return (1);
2426
0
        cur = cur->prev;
2427
0
    }
2428
0
    return (-1);
2429
0
      }
2430
0
      return(0);
2431
0
  }
2432
0
  if (attr2 == 1)
2433
0
      return(1);
2434
0
  return(-1);
2435
0
    }
2436
0
    if ((node1->type == XML_NAMESPACE_DECL) ||
2437
0
        (node2->type == XML_NAMESPACE_DECL))
2438
0
  return(1);
2439
0
    if (node1 == node2->prev)
2440
0
  return(1);
2441
0
    if (node1 == node2->next)
2442
0
  return(-1);
2443
2444
    /*
2445
     * Speedup using document order if available.
2446
     */
2447
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2448
0
  (node2->type == XML_ELEMENT_NODE) &&
2449
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2450
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2451
0
  (node1->doc == node2->doc)) {
2452
0
  XML_INTPTR_T l1, l2;
2453
2454
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2455
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2456
0
  if (l1 < l2)
2457
0
      return(1);
2458
0
  if (l1 > l2)
2459
0
      return(-1);
2460
0
    }
2461
2462
    /*
2463
     * compute depth to root
2464
     */
2465
0
    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2466
0
  if (cur->parent == node1)
2467
0
      return(1);
2468
0
  depth2++;
2469
0
    }
2470
0
    root = cur;
2471
0
    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2472
0
  if (cur->parent == node2)
2473
0
      return(-1);
2474
0
  depth1++;
2475
0
    }
2476
    /*
2477
     * Distinct document (or distinct entities :-( ) case.
2478
     */
2479
0
    if (root != cur) {
2480
0
  return(-2);
2481
0
    }
2482
    /*
2483
     * get the nearest common ancestor.
2484
     */
2485
0
    while (depth1 > depth2) {
2486
0
  depth1--;
2487
0
  node1 = node1->parent;
2488
0
    }
2489
0
    while (depth2 > depth1) {
2490
0
  depth2--;
2491
0
  node2 = node2->parent;
2492
0
    }
2493
0
    while (node1->parent != node2->parent) {
2494
0
  node1 = node1->parent;
2495
0
  node2 = node2->parent;
2496
  /* should not happen but just in case ... */
2497
0
  if ((node1 == NULL) || (node2 == NULL))
2498
0
      return(-2);
2499
0
    }
2500
    /*
2501
     * Find who's first.
2502
     */
2503
0
    if (node1 == node2->prev)
2504
0
  return(1);
2505
0
    if (node1 == node2->next)
2506
0
  return(-1);
2507
    /*
2508
     * Speedup using document order if available.
2509
     */
2510
0
    if ((node1->type == XML_ELEMENT_NODE) &&
2511
0
  (node2->type == XML_ELEMENT_NODE) &&
2512
0
  (0 > XML_NODE_SORT_VALUE(node1)) &&
2513
0
  (0 > XML_NODE_SORT_VALUE(node2)) &&
2514
0
  (node1->doc == node2->doc)) {
2515
0
  XML_INTPTR_T l1, l2;
2516
2517
0
  l1 = -XML_NODE_SORT_VALUE(node1);
2518
0
  l2 = -XML_NODE_SORT_VALUE(node2);
2519
0
  if (l1 < l2)
2520
0
      return(1);
2521
0
  if (l1 > l2)
2522
0
      return(-1);
2523
0
    }
2524
2525
0
    for (cur = node1->next;cur != NULL;cur = cur->next)
2526
0
  if (cur == node2)
2527
0
      return(1);
2528
0
    return(-1); /* assume there is no sibling list corruption */
2529
0
}
2530
2531
/**
2532
 * Sort the node set in document order
2533
 *
2534
 * @param set  the node set
2535
 */
2536
void
2537
0
xmlXPathNodeSetSort(xmlNodeSet *set) {
2538
#ifndef WITH_TIM_SORT
2539
    int i, j, incr, len;
2540
    xmlNodePtr tmp;
2541
#endif
2542
2543
0
    if (set == NULL)
2544
0
  return;
2545
2546
#ifndef WITH_TIM_SORT
2547
    /*
2548
     * Use the old Shell's sort implementation to sort the node-set
2549
     * Timsort ought to be quite faster
2550
     */
2551
    len = set->nodeNr;
2552
    for (incr = len / 2; incr > 0; incr /= 2) {
2553
  for (i = incr; i < len; i++) {
2554
      j = i - incr;
2555
      while (j >= 0) {
2556
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2557
    if (xmlXPathCmpNodesExt(set->nodeTab[j],
2558
      set->nodeTab[j + incr]) == -1)
2559
#else
2560
    if (xmlXPathCmpNodes(set->nodeTab[j],
2561
      set->nodeTab[j + incr]) == -1)
2562
#endif
2563
    {
2564
        tmp = set->nodeTab[j];
2565
        set->nodeTab[j] = set->nodeTab[j + incr];
2566
        set->nodeTab[j + incr] = tmp;
2567
        j -= incr;
2568
    } else
2569
        break;
2570
      }
2571
  }
2572
    }
2573
#else /* WITH_TIM_SORT */
2574
0
    libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2575
0
#endif /* WITH_TIM_SORT */
2576
0
}
2577
2578
0
#define XML_NODESET_DEFAULT 10
2579
/**
2580
 * Namespace node in libxml don't match the XPath semantic. In a node set
2581
 * the namespace nodes are duplicated and the next pointer is set to the
2582
 * parent node in the XPath semantic.
2583
 *
2584
 * @param node  the parent node of the namespace XPath node
2585
 * @param ns  the libxml namespace declaration node.
2586
 * @returns the newly created object.
2587
 */
2588
static xmlNodePtr
2589
0
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2590
0
    xmlNsPtr cur;
2591
2592
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2593
0
  return(NULL);
2594
0
    if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2595
0
  return((xmlNodePtr) ns);
2596
2597
    /*
2598
     * Allocate a new Namespace and fill the fields.
2599
     */
2600
0
    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2601
0
    if (cur == NULL)
2602
0
  return(NULL);
2603
0
    memset(cur, 0, sizeof(xmlNs));
2604
0
    cur->type = XML_NAMESPACE_DECL;
2605
0
    if (ns->href != NULL) {
2606
0
  cur->href = xmlStrdup(ns->href);
2607
0
        if (cur->href == NULL) {
2608
0
            xmlFree(cur);
2609
0
            return(NULL);
2610
0
        }
2611
0
    }
2612
0
    if (ns->prefix != NULL) {
2613
0
  cur->prefix = xmlStrdup(ns->prefix);
2614
0
        if (cur->prefix == NULL) {
2615
0
            xmlFree((xmlChar *) cur->href);
2616
0
            xmlFree(cur);
2617
0
            return(NULL);
2618
0
        }
2619
0
    }
2620
0
    cur->next = (xmlNsPtr) node;
2621
0
    return((xmlNodePtr) cur);
2622
0
}
2623
2624
/**
2625
 * Namespace nodes in libxml don't match the XPath semantic. In a node set
2626
 * the namespace nodes are duplicated and the next pointer is set to the
2627
 * parent node in the XPath semantic. Check if such a node needs to be freed
2628
 *
2629
 * @param ns  the XPath namespace node found in a nodeset.
2630
 */
2631
void
2632
0
xmlXPathNodeSetFreeNs(xmlNs *ns) {
2633
0
    if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2634
0
  return;
2635
2636
0
    if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2637
0
  if (ns->href != NULL)
2638
0
      xmlFree((xmlChar *)ns->href);
2639
0
  if (ns->prefix != NULL)
2640
0
      xmlFree((xmlChar *)ns->prefix);
2641
0
  xmlFree(ns);
2642
0
    }
2643
0
}
2644
2645
/**
2646
 * Create a new xmlNodeSet of type double and of value `val`
2647
 *
2648
 * @param val  an initial xmlNode, or NULL
2649
 * @returns the newly created object.
2650
 */
2651
xmlNodeSet *
2652
0
xmlXPathNodeSetCreate(xmlNode *val) {
2653
0
    xmlNodeSetPtr ret;
2654
2655
0
    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2656
0
    if (ret == NULL)
2657
0
  return(NULL);
2658
0
    memset(ret, 0 , sizeof(xmlNodeSet));
2659
0
    if (val != NULL) {
2660
0
        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2661
0
               sizeof(xmlNodePtr));
2662
0
  if (ret->nodeTab == NULL) {
2663
0
      xmlFree(ret);
2664
0
      return(NULL);
2665
0
  }
2666
0
  memset(ret->nodeTab, 0 ,
2667
0
         XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2668
0
        ret->nodeMax = XML_NODESET_DEFAULT;
2669
0
  if (val->type == XML_NAMESPACE_DECL) {
2670
0
      xmlNsPtr ns = (xmlNsPtr) val;
2671
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2672
2673
0
            if (nsNode == NULL) {
2674
0
                xmlXPathFreeNodeSet(ret);
2675
0
                return(NULL);
2676
0
            }
2677
0
      ret->nodeTab[ret->nodeNr++] = nsNode;
2678
0
  } else
2679
0
      ret->nodeTab[ret->nodeNr++] = val;
2680
0
    }
2681
0
    return(ret);
2682
0
}
2683
2684
/**
2685
 * checks whether `cur` contains `val`
2686
 *
2687
 * @param cur  the node-set
2688
 * @param val  the node
2689
 * @returns true (1) if `cur` contains `val`, false (0) otherwise
2690
 */
2691
int
2692
0
xmlXPathNodeSetContains (xmlNodeSet *cur, xmlNode *val) {
2693
0
    int i;
2694
2695
0
    if ((cur == NULL) || (val == NULL)) return(0);
2696
0
    if (val->type == XML_NAMESPACE_DECL) {
2697
0
  for (i = 0; i < cur->nodeNr; i++) {
2698
0
      if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2699
0
    xmlNsPtr ns1, ns2;
2700
2701
0
    ns1 = (xmlNsPtr) val;
2702
0
    ns2 = (xmlNsPtr) cur->nodeTab[i];
2703
0
    if (ns1 == ns2)
2704
0
        return(1);
2705
0
    if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
2706
0
              (xmlStrEqual(ns1->prefix, ns2->prefix)))
2707
0
        return(1);
2708
0
      }
2709
0
  }
2710
0
    } else {
2711
0
  for (i = 0; i < cur->nodeNr; i++) {
2712
0
      if (cur->nodeTab[i] == val)
2713
0
    return(1);
2714
0
  }
2715
0
    }
2716
0
    return(0);
2717
0
}
2718
2719
static int
2720
0
xmlXPathNodeSetGrow(xmlNodeSetPtr cur) {
2721
0
    xmlNodePtr *temp;
2722
0
    int newSize;
2723
2724
0
    newSize = xmlGrowCapacity(cur->nodeMax, sizeof(temp[0]),
2725
0
                              XML_NODESET_DEFAULT, XPATH_MAX_NODESET_LENGTH);
2726
0
    if (newSize < 0)
2727
0
        return(-1);
2728
0
    temp = xmlRealloc(cur->nodeTab, newSize * sizeof(temp[0]));
2729
0
    if (temp == NULL)
2730
0
        return(-1);
2731
0
    cur->nodeMax = newSize;
2732
0
    cur->nodeTab = temp;
2733
2734
0
    return(0);
2735
0
}
2736
2737
/**
2738
 * add a new namespace node to an existing NodeSet
2739
 *
2740
 * @param cur  the initial node set
2741
 * @param node  the hosting node
2742
 * @param ns  a the namespace node
2743
 * @returns 0 in case of success and -1 in case of error
2744
 */
2745
int
2746
0
xmlXPathNodeSetAddNs(xmlNodeSet *cur, xmlNode *node, xmlNs *ns) {
2747
0
    int i;
2748
0
    xmlNodePtr nsNode;
2749
2750
0
    if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
2751
0
        (ns->type != XML_NAMESPACE_DECL) ||
2752
0
  (node->type != XML_ELEMENT_NODE))
2753
0
  return(-1);
2754
2755
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2756
    /*
2757
     * prevent duplicates
2758
     */
2759
0
    for (i = 0;i < cur->nodeNr;i++) {
2760
0
        if ((cur->nodeTab[i] != NULL) &&
2761
0
      (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
2762
0
      (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
2763
0
      (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
2764
0
      return(0);
2765
0
    }
2766
2767
    /*
2768
     * grow the nodeTab if needed
2769
     */
2770
0
    if (cur->nodeNr >= cur->nodeMax) {
2771
0
        if (xmlXPathNodeSetGrow(cur) < 0)
2772
0
            return(-1);
2773
0
    }
2774
0
    nsNode = xmlXPathNodeSetDupNs(node, ns);
2775
0
    if(nsNode == NULL)
2776
0
        return(-1);
2777
0
    cur->nodeTab[cur->nodeNr++] = nsNode;
2778
0
    return(0);
2779
0
}
2780
2781
/**
2782
 * add a new xmlNode to an existing NodeSet
2783
 *
2784
 * @param cur  the initial node set
2785
 * @param val  a new xmlNode
2786
 * @returns 0 in case of success, and -1 in case of error
2787
 */
2788
int
2789
0
xmlXPathNodeSetAdd(xmlNodeSet *cur, xmlNode *val) {
2790
0
    int i;
2791
2792
0
    if ((cur == NULL) || (val == NULL)) return(-1);
2793
2794
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2795
    /*
2796
     * prevent duplicates
2797
     */
2798
0
    for (i = 0;i < cur->nodeNr;i++)
2799
0
        if (cur->nodeTab[i] == val) return(0);
2800
2801
    /*
2802
     * grow the nodeTab if needed
2803
     */
2804
0
    if (cur->nodeNr >= cur->nodeMax) {
2805
0
        if (xmlXPathNodeSetGrow(cur) < 0)
2806
0
            return(-1);
2807
0
    }
2808
2809
0
    if (val->type == XML_NAMESPACE_DECL) {
2810
0
  xmlNsPtr ns = (xmlNsPtr) val;
2811
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2812
2813
0
        if (nsNode == NULL)
2814
0
            return(-1);
2815
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2816
0
    } else
2817
0
  cur->nodeTab[cur->nodeNr++] = val;
2818
0
    return(0);
2819
0
}
2820
2821
/**
2822
 * add a new xmlNode to an existing NodeSet, optimized version
2823
 * when we are sure the node is not already in the set.
2824
 *
2825
 * @param cur  the initial node set
2826
 * @param val  a new xmlNode
2827
 * @returns 0 in case of success and -1 in case of failure
2828
 */
2829
int
2830
0
xmlXPathNodeSetAddUnique(xmlNodeSet *cur, xmlNode *val) {
2831
0
    if ((cur == NULL) || (val == NULL)) return(-1);
2832
2833
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2834
    /*
2835
     * grow the nodeTab if needed
2836
     */
2837
0
    if (cur->nodeNr >= cur->nodeMax) {
2838
0
        if (xmlXPathNodeSetGrow(cur) < 0)
2839
0
            return(-1);
2840
0
    }
2841
2842
0
    if (val->type == XML_NAMESPACE_DECL) {
2843
0
  xmlNsPtr ns = (xmlNsPtr) val;
2844
0
        xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2845
2846
0
        if (nsNode == NULL)
2847
0
            return(-1);
2848
0
  cur->nodeTab[cur->nodeNr++] = nsNode;
2849
0
    } else
2850
0
  cur->nodeTab[cur->nodeNr++] = val;
2851
0
    return(0);
2852
0
}
2853
2854
/**
2855
 * Merges two nodesets, all nodes from `val2` are added to `val1`
2856
 * if `val1` is NULL, a new set is created and copied from `val2`
2857
 *
2858
 * Frees `val1` in case of error.
2859
 *
2860
 * @param val1  the first NodeSet or NULL
2861
 * @param val2  the second NodeSet
2862
 * @returns `val1` once extended or NULL in case of error.
2863
 */
2864
xmlNodeSet *
2865
0
xmlXPathNodeSetMerge(xmlNodeSet *val1, xmlNodeSet *val2) {
2866
0
    int i, j, initNr, skip;
2867
0
    xmlNodePtr n1, n2;
2868
2869
0
    if (val1 == NULL) {
2870
0
  val1 = xmlXPathNodeSetCreate(NULL);
2871
0
        if (val1 == NULL)
2872
0
            return (NULL);
2873
0
    }
2874
0
    if (val2 == NULL)
2875
0
        return(val1);
2876
2877
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
2878
0
    initNr = val1->nodeNr;
2879
2880
0
    for (i = 0;i < val2->nodeNr;i++) {
2881
0
  n2 = val2->nodeTab[i];
2882
  /*
2883
   * check against duplicates
2884
   */
2885
0
  skip = 0;
2886
0
  for (j = 0; j < initNr; j++) {
2887
0
      n1 = val1->nodeTab[j];
2888
0
      if (n1 == n2) {
2889
0
    skip = 1;
2890
0
    break;
2891
0
      } else if ((n1->type == XML_NAMESPACE_DECL) &&
2892
0
           (n2->type == XML_NAMESPACE_DECL)) {
2893
0
    if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2894
0
        (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2895
0
      ((xmlNsPtr) n2)->prefix)))
2896
0
    {
2897
0
        skip = 1;
2898
0
        break;
2899
0
    }
2900
0
      }
2901
0
  }
2902
0
  if (skip)
2903
0
      continue;
2904
2905
  /*
2906
   * grow the nodeTab if needed
2907
   */
2908
0
        if (val1->nodeNr >= val1->nodeMax) {
2909
0
            if (xmlXPathNodeSetGrow(val1) < 0)
2910
0
                goto error;
2911
0
        }
2912
0
  if (n2->type == XML_NAMESPACE_DECL) {
2913
0
      xmlNsPtr ns = (xmlNsPtr) n2;
2914
0
            xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
2915
2916
0
            if (nsNode == NULL)
2917
0
                goto error;
2918
0
      val1->nodeTab[val1->nodeNr++] = nsNode;
2919
0
  } else
2920
0
      val1->nodeTab[val1->nodeNr++] = n2;
2921
0
    }
2922
2923
0
    return(val1);
2924
2925
0
error:
2926
0
    xmlXPathFreeNodeSet(val1);
2927
0
    return(NULL);
2928
0
}
2929
2930
2931
/**
2932
 * Merges two nodesets, all nodes from `set2` are added to `set1`.
2933
 * Checks for duplicate nodes. Clears set2.
2934
 *
2935
 * Frees `set1` in case of error.
2936
 *
2937
 * @param set1  the first NodeSet or NULL
2938
 * @param set2  the second NodeSet
2939
 * @returns `set1` once extended or NULL in case of error.
2940
 */
2941
static xmlNodeSetPtr
2942
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
2943
0
{
2944
0
    {
2945
0
  int i, j, initNbSet1;
2946
0
  xmlNodePtr n1, n2;
2947
2948
0
  initNbSet1 = set1->nodeNr;
2949
0
  for (i = 0;i < set2->nodeNr;i++) {
2950
0
      n2 = set2->nodeTab[i];
2951
      /*
2952
      * Skip duplicates.
2953
      */
2954
0
      for (j = 0; j < initNbSet1; j++) {
2955
0
    n1 = set1->nodeTab[j];
2956
0
    if (n1 == n2) {
2957
0
        goto skip_node;
2958
0
    } else if ((n1->type == XML_NAMESPACE_DECL) &&
2959
0
        (n2->type == XML_NAMESPACE_DECL))
2960
0
    {
2961
0
        if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
2962
0
      (xmlStrEqual(((xmlNsPtr) n1)->prefix,
2963
0
      ((xmlNsPtr) n2)->prefix)))
2964
0
        {
2965
      /*
2966
      * Free the namespace node.
2967
      */
2968
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
2969
0
      goto skip_node;
2970
0
        }
2971
0
    }
2972
0
      }
2973
      /*
2974
      * grow the nodeTab if needed
2975
      */
2976
0
            if (set1->nodeNr >= set1->nodeMax) {
2977
0
                if (xmlXPathNodeSetGrow(set1) < 0)
2978
0
                    goto error;
2979
0
            }
2980
0
      set1->nodeTab[set1->nodeNr++] = n2;
2981
0
skip_node:
2982
0
            set2->nodeTab[i] = NULL;
2983
0
  }
2984
0
    }
2985
0
    set2->nodeNr = 0;
2986
0
    return(set1);
2987
2988
0
error:
2989
0
    xmlXPathFreeNodeSet(set1);
2990
0
    xmlXPathNodeSetClear(set2, 1);
2991
0
    return(NULL);
2992
0
}
2993
2994
/**
2995
 * Merges two nodesets, all nodes from `set2` are added to `set1`.
2996
 * Doesn't check for duplicate nodes. Clears set2.
2997
 *
2998
 * Frees `set1` in case of error.
2999
 *
3000
 * @param set1  the first NodeSet or NULL
3001
 * @param set2  the second NodeSet
3002
 * @returns `set1` once extended or NULL in case of error.
3003
 */
3004
static xmlNodeSetPtr
3005
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3006
0
{
3007
0
    {
3008
0
  int i;
3009
0
  xmlNodePtr n2;
3010
3011
0
  for (i = 0;i < set2->nodeNr;i++) {
3012
0
      n2 = set2->nodeTab[i];
3013
0
            if (set1->nodeNr >= set1->nodeMax) {
3014
0
                if (xmlXPathNodeSetGrow(set1) < 0)
3015
0
                    goto error;
3016
0
            }
3017
0
      set1->nodeTab[set1->nodeNr++] = n2;
3018
0
            set2->nodeTab[i] = NULL;
3019
0
  }
3020
0
    }
3021
0
    set2->nodeNr = 0;
3022
0
    return(set1);
3023
3024
0
error:
3025
0
    xmlXPathFreeNodeSet(set1);
3026
0
    xmlXPathNodeSetClear(set2, 1);
3027
0
    return(NULL);
3028
0
}
3029
3030
/**
3031
 * Removes an xmlNode from an existing NodeSet
3032
 *
3033
 * @param cur  the initial node set
3034
 * @param val  an xmlNode
3035
 */
3036
void
3037
0
xmlXPathNodeSetDel(xmlNodeSet *cur, xmlNode *val) {
3038
0
    int i;
3039
3040
0
    if (cur == NULL) return;
3041
0
    if (val == NULL) return;
3042
3043
    /*
3044
     * find node in nodeTab
3045
     */
3046
0
    for (i = 0;i < cur->nodeNr;i++)
3047
0
        if (cur->nodeTab[i] == val) break;
3048
3049
0
    if (i >= cur->nodeNr) { /* not found */
3050
0
        return;
3051
0
    }
3052
0
    if ((cur->nodeTab[i] != NULL) &&
3053
0
  (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3054
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3055
0
    cur->nodeNr--;
3056
0
    for (;i < cur->nodeNr;i++)
3057
0
        cur->nodeTab[i] = cur->nodeTab[i + 1];
3058
0
    cur->nodeTab[cur->nodeNr] = NULL;
3059
0
}
3060
3061
/**
3062
 * Removes an entry from an existing NodeSet list.
3063
 *
3064
 * @param cur  the initial node set
3065
 * @param val  the index to remove
3066
 */
3067
void
3068
0
xmlXPathNodeSetRemove(xmlNodeSet *cur, int val) {
3069
0
    if (cur == NULL) return;
3070
0
    if (val >= cur->nodeNr) return;
3071
0
    if ((cur->nodeTab[val] != NULL) &&
3072
0
  (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3073
0
  xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3074
0
    cur->nodeNr--;
3075
0
    for (;val < cur->nodeNr;val++)
3076
0
        cur->nodeTab[val] = cur->nodeTab[val + 1];
3077
0
    cur->nodeTab[cur->nodeNr] = NULL;
3078
0
}
3079
3080
/**
3081
 * Free the NodeSet compound (not the actual nodes !).
3082
 *
3083
 * @param obj  the xmlNodeSet to free
3084
 */
3085
void
3086
0
xmlXPathFreeNodeSet(xmlNodeSet *obj) {
3087
0
    if (obj == NULL) return;
3088
0
    if (obj->nodeTab != NULL) {
3089
0
  int i;
3090
3091
  /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3092
0
  for (i = 0;i < obj->nodeNr;i++)
3093
0
      if ((obj->nodeTab[i] != NULL) &&
3094
0
    (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3095
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3096
0
  xmlFree(obj->nodeTab);
3097
0
    }
3098
0
    xmlFree(obj);
3099
0
}
3100
3101
/**
3102
 * Clears the list from temporary XPath objects (e.g. namespace nodes
3103
 * are feed) starting with the entry at `pos`, but does *not* free the list
3104
 * itself. Sets the length of the list to `pos`.
3105
 *
3106
 * @param set  the node set to be cleared
3107
 * @param pos  the start position to clear from
3108
 * @param hasNsNodes  the node set might contain namespace nodes
3109
 */
3110
static void
3111
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3112
0
{
3113
0
    if ((set == NULL) || (pos >= set->nodeNr))
3114
0
  return;
3115
0
    else if ((hasNsNodes)) {
3116
0
  int i;
3117
0
  xmlNodePtr node;
3118
3119
0
  for (i = pos; i < set->nodeNr; i++) {
3120
0
      node = set->nodeTab[i];
3121
0
      if ((node != NULL) &&
3122
0
    (node->type == XML_NAMESPACE_DECL))
3123
0
    xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3124
0
  }
3125
0
    }
3126
0
    set->nodeNr = pos;
3127
0
}
3128
3129
/**
3130
 * Clears the list from all temporary XPath objects (e.g. namespace nodes
3131
 * are feed), but does *not* free the list itself. Sets the length of the
3132
 * list to 0.
3133
 *
3134
 * @param set  the node set to clear
3135
 * @param hasNsNodes  the node set might contain namespace nodes
3136
 */
3137
static void
3138
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3139
0
{
3140
0
    xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3141
0
}
3142
3143
/**
3144
 * Move the last node to the first position and clear temporary XPath objects
3145
 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
3146
 * to 1.
3147
 *
3148
 * @param set  the node set to be cleared
3149
 */
3150
static void
3151
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3152
0
{
3153
0
    int i;
3154
0
    xmlNodePtr node;
3155
3156
0
    if ((set == NULL) || (set->nodeNr <= 1))
3157
0
  return;
3158
0
    for (i = 0; i < set->nodeNr - 1; i++) {
3159
0
        node = set->nodeTab[i];
3160
0
        if ((node != NULL) &&
3161
0
            (node->type == XML_NAMESPACE_DECL))
3162
0
            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3163
0
    }
3164
0
    set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3165
0
    set->nodeNr = 1;
3166
0
}
3167
3168
/**
3169
 * Create a new xmlXPathObject of type NodeSet and initialize
3170
 * it with the single Node `val`
3171
 *
3172
 * @param val  the NodePtr value
3173
 * @returns the newly created object.
3174
 */
3175
xmlXPathObject *
3176
0
xmlXPathNewNodeSet(xmlNode *val) {
3177
0
    xmlXPathObjectPtr ret;
3178
3179
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3180
0
    if (ret == NULL)
3181
0
  return(NULL);
3182
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3183
0
    ret->type = XPATH_NODESET;
3184
0
    ret->boolval = 0;
3185
0
    ret->nodesetval = xmlXPathNodeSetCreate(val);
3186
0
    if (ret->nodesetval == NULL) {
3187
0
        xmlFree(ret);
3188
0
        return(NULL);
3189
0
    }
3190
    /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3191
0
    return(ret);
3192
0
}
3193
3194
/**
3195
 * Create a new xmlXPathObject of type Value Tree (XSLT) and initialize
3196
 * it with the tree root `val`
3197
 *
3198
 * @param val  the NodePtr value
3199
 * @returns the newly created object.
3200
 */
3201
xmlXPathObject *
3202
0
xmlXPathNewValueTree(xmlNode *val) {
3203
0
    xmlXPathObjectPtr ret;
3204
3205
0
    ret = xmlXPathNewNodeSet(val);
3206
0
    if (ret == NULL)
3207
0
  return(NULL);
3208
0
    ret->type = XPATH_XSLT_TREE;
3209
3210
0
    return(ret);
3211
0
}
3212
3213
/**
3214
 * Create a new xmlXPathObject of type NodeSet and initialize
3215
 * it with the Nodeset `val`
3216
 *
3217
 * @param val  an existing NodeSet
3218
 * @returns the newly created object.
3219
 */
3220
xmlXPathObject *
3221
xmlXPathNewNodeSetList(xmlNodeSet *val)
3222
0
{
3223
0
    xmlXPathObjectPtr ret;
3224
3225
0
    if (val == NULL)
3226
0
        ret = NULL;
3227
0
    else if (val->nodeTab == NULL)
3228
0
        ret = xmlXPathNewNodeSet(NULL);
3229
0
    else {
3230
0
        ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3231
0
        if (ret) {
3232
0
            ret->nodesetval = xmlXPathNodeSetMerge(NULL, val);
3233
0
            if (ret->nodesetval == NULL) {
3234
0
                xmlFree(ret);
3235
0
                return(NULL);
3236
0
            }
3237
0
        }
3238
0
    }
3239
3240
0
    return (ret);
3241
0
}
3242
3243
/**
3244
 * Wrap the Nodeset `val` in a new xmlXPathObject
3245
 *
3246
 * In case of error the node set is destroyed and NULL is returned.
3247
 *
3248
 * @param val  the NodePtr value
3249
 * @returns the newly created object.
3250
 */
3251
xmlXPathObject *
3252
0
xmlXPathWrapNodeSet(xmlNodeSet *val) {
3253
0
    xmlXPathObjectPtr ret;
3254
3255
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3256
0
    if (ret == NULL) {
3257
0
        xmlXPathFreeNodeSet(val);
3258
0
  return(NULL);
3259
0
    }
3260
0
    memset(ret, 0 , sizeof(xmlXPathObject));
3261
0
    ret->type = XPATH_NODESET;
3262
0
    ret->nodesetval = val;
3263
0
    return(ret);
3264
0
}
3265
3266
/**
3267
 * Free up the xmlXPathObject `obj` but don't deallocate the objects in
3268
 * the list contrary to #xmlXPathFreeObject.
3269
 *
3270
 * @param obj  an existing NodeSetList object
3271
 */
3272
void
3273
0
xmlXPathFreeNodeSetList(xmlXPathObject *obj) {
3274
0
    if (obj == NULL) return;
3275
0
    xmlFree(obj);
3276
0
}
3277
3278
/**
3279
 * Implements the EXSLT - Sets difference() function:
3280
 *    node-set set:difference (node-set, node-set)
3281
 *
3282
 * @param nodes1  a node-set
3283
 * @param nodes2  a node-set
3284
 * @returns the difference between the two node sets, or nodes1 if
3285
 *         nodes2 is empty
3286
 */
3287
xmlNodeSet *
3288
0
xmlXPathDifference (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3289
0
    xmlNodeSetPtr ret;
3290
0
    int i, l1;
3291
0
    xmlNodePtr cur;
3292
3293
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3294
0
  return(nodes1);
3295
3296
0
    ret = xmlXPathNodeSetCreate(NULL);
3297
0
    if (ret == NULL)
3298
0
        return(NULL);
3299
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3300
0
  return(ret);
3301
3302
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3303
3304
0
    for (i = 0; i < l1; i++) {
3305
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3306
0
  if (!xmlXPathNodeSetContains(nodes2, cur)) {
3307
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3308
0
                xmlXPathFreeNodeSet(ret);
3309
0
          return(NULL);
3310
0
            }
3311
0
  }
3312
0
    }
3313
0
    return(ret);
3314
0
}
3315
3316
/**
3317
 * Implements the EXSLT - Sets intersection() function:
3318
 *    node-set set:intersection (node-set, node-set)
3319
 *
3320
 * @param nodes1  a node-set
3321
 * @param nodes2  a node-set
3322
 * @returns a node set comprising the nodes that are within both the
3323
 *         node sets passed as arguments
3324
 */
3325
xmlNodeSet *
3326
0
xmlXPathIntersection (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3327
0
    xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3328
0
    int i, l1;
3329
0
    xmlNodePtr cur;
3330
3331
0
    if (ret == NULL)
3332
0
        return(ret);
3333
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3334
0
  return(ret);
3335
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3336
0
  return(ret);
3337
3338
0
    l1 = xmlXPathNodeSetGetLength(nodes1);
3339
3340
0
    for (i = 0; i < l1; i++) {
3341
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3342
0
  if (xmlXPathNodeSetContains(nodes2, cur)) {
3343
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3344
0
                xmlXPathFreeNodeSet(ret);
3345
0
          return(NULL);
3346
0
            }
3347
0
  }
3348
0
    }
3349
0
    return(ret);
3350
0
}
3351
3352
/**
3353
 * Implements the EXSLT - Sets distinct() function:
3354
 *    node-set set:distinct (node-set)
3355
 *
3356
 * @param nodes  a node-set, sorted by document order
3357
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3358
 *         it is empty
3359
 */
3360
xmlNodeSet *
3361
0
xmlXPathDistinctSorted (xmlNodeSet *nodes) {
3362
0
    xmlNodeSetPtr ret;
3363
0
    xmlHashTablePtr hash;
3364
0
    int i, l;
3365
0
    xmlChar * strval;
3366
0
    xmlNodePtr cur;
3367
3368
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3369
0
  return(nodes);
3370
3371
0
    ret = xmlXPathNodeSetCreate(NULL);
3372
0
    if (ret == NULL)
3373
0
        return(ret);
3374
0
    l = xmlXPathNodeSetGetLength(nodes);
3375
0
    hash = xmlHashCreate (l);
3376
0
    for (i = 0; i < l; i++) {
3377
0
  cur = xmlXPathNodeSetItem(nodes, i);
3378
0
  strval = xmlXPathCastNodeToString(cur);
3379
0
  if (xmlHashLookup(hash, strval) == NULL) {
3380
0
      if (xmlHashAddEntry(hash, strval, strval) < 0) {
3381
0
                xmlFree(strval);
3382
0
                goto error;
3383
0
            }
3384
0
      if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3385
0
          goto error;
3386
0
  } else {
3387
0
      xmlFree(strval);
3388
0
  }
3389
0
    }
3390
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3391
0
    return(ret);
3392
3393
0
error:
3394
0
    xmlHashFree(hash, xmlHashDefaultDeallocator);
3395
0
    xmlXPathFreeNodeSet(ret);
3396
0
    return(NULL);
3397
0
}
3398
3399
/**
3400
 * Implements the EXSLT - Sets distinct() function:
3401
 *    node-set set:distinct (node-set)
3402
 * `nodes` is sorted by document order, then exslSetsDistinctSorted
3403
 * is called with the sorted node-set
3404
 *
3405
 * @param nodes  a node-set
3406
 * @returns a subset of the nodes contained in `nodes`, or `nodes` if
3407
 *         it is empty
3408
 */
3409
xmlNodeSet *
3410
0
xmlXPathDistinct (xmlNodeSet *nodes) {
3411
0
    if (xmlXPathNodeSetIsEmpty(nodes))
3412
0
  return(nodes);
3413
3414
0
    xmlXPathNodeSetSort(nodes);
3415
0
    return(xmlXPathDistinctSorted(nodes));
3416
0
}
3417
3418
/**
3419
 * Implements the EXSLT - Sets has-same-nodes function:
3420
 *    boolean set:has-same-node(node-set, node-set)
3421
 *
3422
 * @param nodes1  a node-set
3423
 * @param nodes2  a node-set
3424
 * @returns true (1) if `nodes1` shares any node with `nodes2`, false (0)
3425
 *         otherwise
3426
 */
3427
int
3428
0
xmlXPathHasSameNodes (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3429
0
    int i, l;
3430
0
    xmlNodePtr cur;
3431
3432
0
    if (xmlXPathNodeSetIsEmpty(nodes1) ||
3433
0
  xmlXPathNodeSetIsEmpty(nodes2))
3434
0
  return(0);
3435
3436
0
    l = xmlXPathNodeSetGetLength(nodes1);
3437
0
    for (i = 0; i < l; i++) {
3438
0
  cur = xmlXPathNodeSetItem(nodes1, i);
3439
0
  if (xmlXPathNodeSetContains(nodes2, cur))
3440
0
      return(1);
3441
0
    }
3442
0
    return(0);
3443
0
}
3444
3445
/**
3446
 * Implements the EXSLT - Sets leading() function:
3447
 *    node-set set:leading (node-set, node-set)
3448
 *
3449
 * @param nodes  a node-set, sorted by document order
3450
 * @param node  a node
3451
 * @returns the nodes in `nodes` that precede `node` in document order,
3452
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3453
 *         doesn't contain `node`
3454
 */
3455
xmlNodeSet *
3456
0
xmlXPathNodeLeadingSorted (xmlNodeSet *nodes, xmlNode *node) {
3457
0
    int i, l;
3458
0
    xmlNodePtr cur;
3459
0
    xmlNodeSetPtr ret;
3460
3461
0
    if (node == NULL)
3462
0
  return(nodes);
3463
3464
0
    ret = xmlXPathNodeSetCreate(NULL);
3465
0
    if (ret == NULL)
3466
0
        return(ret);
3467
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3468
0
  (!xmlXPathNodeSetContains(nodes, node)))
3469
0
  return(ret);
3470
3471
0
    l = xmlXPathNodeSetGetLength(nodes);
3472
0
    for (i = 0; i < l; i++) {
3473
0
  cur = xmlXPathNodeSetItem(nodes, i);
3474
0
  if (cur == node)
3475
0
      break;
3476
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3477
0
            xmlXPathFreeNodeSet(ret);
3478
0
      return(NULL);
3479
0
        }
3480
0
    }
3481
0
    return(ret);
3482
0
}
3483
3484
/**
3485
 * Implements the EXSLT - Sets leading() function:
3486
 *    node-set set:leading (node-set, node-set)
3487
 * `nodes` is sorted by document order, then exslSetsNodeLeadingSorted
3488
 * is called.
3489
 *
3490
 * @param nodes  a node-set
3491
 * @param node  a node
3492
 * @returns the nodes in `nodes` that precede `node` in document order,
3493
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3494
 *         doesn't contain `node`
3495
 */
3496
xmlNodeSet *
3497
0
xmlXPathNodeLeading (xmlNodeSet *nodes, xmlNode *node) {
3498
0
    xmlXPathNodeSetSort(nodes);
3499
0
    return(xmlXPathNodeLeadingSorted(nodes, node));
3500
0
}
3501
3502
/**
3503
 * Implements the EXSLT - Sets leading() function:
3504
 *    node-set set:leading (node-set, node-set)
3505
 *
3506
 * @param nodes1  a node-set, sorted by document order
3507
 * @param nodes2  a node-set, sorted by document order
3508
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3509
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3510
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3511
 */
3512
xmlNodeSet *
3513
0
xmlXPathLeadingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3514
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3515
0
  return(nodes1);
3516
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3517
0
             xmlXPathNodeSetItem(nodes2, 1)));
3518
0
}
3519
3520
/**
3521
 * Implements the EXSLT - Sets leading() function:
3522
 *    node-set set:leading (node-set, node-set)
3523
 * `nodes1` and `nodes2` are sorted by document order, then
3524
 * exslSetsLeadingSorted is called.
3525
 *
3526
 * @param nodes1  a node-set
3527
 * @param nodes2  a node-set
3528
 * @returns the nodes in `nodes1` that precede the first node in `nodes2`
3529
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3530
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3531
 */
3532
xmlNodeSet *
3533
0
xmlXPathLeading (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3534
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3535
0
  return(nodes1);
3536
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3537
0
  return(xmlXPathNodeSetCreate(NULL));
3538
0
    xmlXPathNodeSetSort(nodes1);
3539
0
    xmlXPathNodeSetSort(nodes2);
3540
0
    return(xmlXPathNodeLeadingSorted(nodes1,
3541
0
             xmlXPathNodeSetItem(nodes2, 1)));
3542
0
}
3543
3544
/**
3545
 * Implements the EXSLT - Sets trailing() function:
3546
 *    node-set set:trailing (node-set, node-set)
3547
 *
3548
 * @param nodes  a node-set, sorted by document order
3549
 * @param node  a node
3550
 * @returns the nodes in `nodes` that follow `node` in document order,
3551
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3552
 *         doesn't contain `node`
3553
 */
3554
xmlNodeSet *
3555
0
xmlXPathNodeTrailingSorted (xmlNodeSet *nodes, xmlNode *node) {
3556
0
    int i, l;
3557
0
    xmlNodePtr cur;
3558
0
    xmlNodeSetPtr ret;
3559
3560
0
    if (node == NULL)
3561
0
  return(nodes);
3562
3563
0
    ret = xmlXPathNodeSetCreate(NULL);
3564
0
    if (ret == NULL)
3565
0
        return(ret);
3566
0
    if (xmlXPathNodeSetIsEmpty(nodes) ||
3567
0
  (!xmlXPathNodeSetContains(nodes, node)))
3568
0
  return(ret);
3569
3570
0
    l = xmlXPathNodeSetGetLength(nodes);
3571
0
    for (i = l - 1; i >= 0; i--) {
3572
0
  cur = xmlXPathNodeSetItem(nodes, i);
3573
0
  if (cur == node)
3574
0
      break;
3575
0
  if (xmlXPathNodeSetAddUnique(ret, cur) < 0) {
3576
0
            xmlXPathFreeNodeSet(ret);
3577
0
      return(NULL);
3578
0
        }
3579
0
    }
3580
0
    xmlXPathNodeSetSort(ret); /* bug 413451 */
3581
0
    return(ret);
3582
0
}
3583
3584
/**
3585
 * Implements the EXSLT - Sets trailing() function:
3586
 *    node-set set:trailing (node-set, node-set)
3587
 * `nodes` is sorted by document order, then #xmlXPathNodeTrailingSorted
3588
 * is called.
3589
 *
3590
 * @param nodes  a node-set
3591
 * @param node  a node
3592
 * @returns the nodes in `nodes` that follow `node` in document order,
3593
 *         `nodes` if `node` is NULL or an empty node-set if `nodes`
3594
 *         doesn't contain `node`
3595
 */
3596
xmlNodeSet *
3597
0
xmlXPathNodeTrailing (xmlNodeSet *nodes, xmlNode *node) {
3598
0
    xmlXPathNodeSetSort(nodes);
3599
0
    return(xmlXPathNodeTrailingSorted(nodes, node));
3600
0
}
3601
3602
/**
3603
 * Implements the EXSLT - Sets trailing() function:
3604
 *    node-set set:trailing (node-set, node-set)
3605
 *
3606
 * @param nodes1  a node-set, sorted by document order
3607
 * @param nodes2  a node-set, sorted by document order
3608
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3609
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3610
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3611
 */
3612
xmlNodeSet *
3613
0
xmlXPathTrailingSorted (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3614
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3615
0
  return(nodes1);
3616
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3617
0
              xmlXPathNodeSetItem(nodes2, 0)));
3618
0
}
3619
3620
/**
3621
 * Implements the EXSLT - Sets trailing() function:
3622
 *    node-set set:trailing (node-set, node-set)
3623
 * `nodes1` and `nodes2` are sorted by document order, then
3624
 * #xmlXPathTrailingSorted is called.
3625
 *
3626
 * @param nodes1  a node-set
3627
 * @param nodes2  a node-set
3628
 * @returns the nodes in `nodes1` that follow the first node in `nodes2`
3629
 *         in document order, `nodes1` if `nodes2` is NULL or empty or
3630
 *         an empty node-set if `nodes1` doesn't contain `nodes2`
3631
 */
3632
xmlNodeSet *
3633
0
xmlXPathTrailing (xmlNodeSet *nodes1, xmlNodeSet *nodes2) {
3634
0
    if (xmlXPathNodeSetIsEmpty(nodes2))
3635
0
  return(nodes1);
3636
0
    if (xmlXPathNodeSetIsEmpty(nodes1))
3637
0
  return(xmlXPathNodeSetCreate(NULL));
3638
0
    xmlXPathNodeSetSort(nodes1);
3639
0
    xmlXPathNodeSetSort(nodes2);
3640
0
    return(xmlXPathNodeTrailingSorted(nodes1,
3641
0
              xmlXPathNodeSetItem(nodes2, 0)));
3642
0
}
3643
3644
/************************************************************************
3645
 *                  *
3646
 *    Routines to handle extra functions      *
3647
 *                  *
3648
 ************************************************************************/
3649
3650
/**
3651
 * Register a new function. If `f` is NULL it unregisters the function
3652
 *
3653
 * @param ctxt  the XPath context
3654
 * @param name  the function name
3655
 * @param f  the function implementation or NULL
3656
 * @returns 0 in case of success, -1 in case of error
3657
 */
3658
int
3659
xmlXPathRegisterFunc(xmlXPathContext *ctxt, const xmlChar *name,
3660
0
         xmlXPathFunction f) {
3661
0
    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
3662
0
}
3663
3664
/**
3665
 * Register a new function. If `f` is NULL it unregisters the function
3666
 *
3667
 * @param ctxt  the XPath context
3668
 * @param name  the function name
3669
 * @param ns_uri  the function namespace URI
3670
 * @param f  the function implementation or NULL
3671
 * @returns 0 in case of success, -1 in case of error
3672
 */
3673
int
3674
xmlXPathRegisterFuncNS(xmlXPathContext *ctxt, const xmlChar *name,
3675
0
           const xmlChar *ns_uri, xmlXPathFunction f) {
3676
0
    int ret;
3677
0
    void *payload;
3678
3679
0
    if (ctxt == NULL)
3680
0
  return(-1);
3681
0
    if (name == NULL)
3682
0
  return(-1);
3683
3684
0
    if (ctxt->funcHash == NULL)
3685
0
  ctxt->funcHash = xmlHashCreate(0);
3686
0
    if (ctxt->funcHash == NULL) {
3687
0
        xmlXPathErrMemory(ctxt);
3688
0
  return(-1);
3689
0
    }
3690
0
    if (f == NULL)
3691
0
        return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
3692
0
    memcpy(&payload, &f, sizeof(f));
3693
0
    ret = xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, payload);
3694
0
    if (ret < 0) {
3695
0
        xmlXPathErrMemory(ctxt);
3696
0
        return(-1);
3697
0
    }
3698
3699
0
    return(0);
3700
0
}
3701
3702
/**
3703
 * Registers an external mechanism to do function lookup.
3704
 *
3705
 * @param ctxt  the XPath context
3706
 * @param f  the lookup function
3707
 * @param funcCtxt  the lookup data
3708
 */
3709
void
3710
xmlXPathRegisterFuncLookup (xmlXPathContext *ctxt,
3711
          xmlXPathFuncLookupFunc f,
3712
0
          void *funcCtxt) {
3713
0
    if (ctxt == NULL)
3714
0
  return;
3715
0
    ctxt->funcLookupFunc = f;
3716
0
    ctxt->funcLookupData = funcCtxt;
3717
0
}
3718
3719
/**
3720
 * Search in the Function array of the context for the given
3721
 * function.
3722
 *
3723
 * @param ctxt  the XPath context
3724
 * @param name  the function name
3725
 * @returns the xmlXPathFunction or NULL if not found
3726
 */
3727
xmlXPathFunction
3728
0
xmlXPathFunctionLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3729
0
    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
3730
0
}
3731
3732
/**
3733
 * Search in the Function array of the context for the given
3734
 * function.
3735
 *
3736
 * @param ctxt  the XPath context
3737
 * @param name  the function name
3738
 * @param ns_uri  the function namespace URI
3739
 * @returns the xmlXPathFunction or NULL if not found
3740
 */
3741
xmlXPathFunction
3742
xmlXPathFunctionLookupNS(xmlXPathContext *ctxt, const xmlChar *name,
3743
0
       const xmlChar *ns_uri) {
3744
0
    xmlXPathFunction ret;
3745
0
    void *payload;
3746
3747
0
    if (ctxt == NULL)
3748
0
  return(NULL);
3749
0
    if (name == NULL)
3750
0
  return(NULL);
3751
3752
0
    if (ns_uri == NULL) {
3753
0
        int bucketIndex = xmlXPathSFComputeHash(name) % SF_HASH_SIZE;
3754
3755
0
        while (xmlXPathSFHash[bucketIndex] != UCHAR_MAX) {
3756
0
            int funcIndex = xmlXPathSFHash[bucketIndex];
3757
3758
0
            if (strcmp(xmlXPathStandardFunctions[funcIndex].name,
3759
0
                       (char *) name) == 0)
3760
0
                return(xmlXPathStandardFunctions[funcIndex].func);
3761
3762
0
            bucketIndex += 1;
3763
0
            if (bucketIndex >= SF_HASH_SIZE)
3764
0
                bucketIndex = 0;
3765
0
        }
3766
0
    }
3767
3768
0
    if (ctxt->funcLookupFunc != NULL) {
3769
0
  xmlXPathFuncLookupFunc f;
3770
3771
0
  f = ctxt->funcLookupFunc;
3772
0
  ret = f(ctxt->funcLookupData, name, ns_uri);
3773
0
  if (ret != NULL)
3774
0
      return(ret);
3775
0
    }
3776
3777
0
    if (ctxt->funcHash == NULL)
3778
0
  return(NULL);
3779
3780
0
    payload = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
3781
0
    memcpy(&ret, &payload, sizeof(payload));
3782
3783
0
    return(ret);
3784
0
}
3785
3786
/**
3787
 * Cleanup the XPath context data associated to registered functions
3788
 *
3789
 * @param ctxt  the XPath context
3790
 */
3791
void
3792
0
xmlXPathRegisteredFuncsCleanup(xmlXPathContext *ctxt) {
3793
0
    if (ctxt == NULL)
3794
0
  return;
3795
3796
0
    xmlHashFree(ctxt->funcHash, NULL);
3797
0
    ctxt->funcHash = NULL;
3798
0
}
3799
3800
/************************************************************************
3801
 *                  *
3802
 *      Routines to handle Variables      *
3803
 *                  *
3804
 ************************************************************************/
3805
3806
/**
3807
 * Register a new variable value. If `value` is NULL it unregisters
3808
 * the variable
3809
 *
3810
 * @param ctxt  the XPath context
3811
 * @param name  the variable name
3812
 * @param value  the variable value or NULL
3813
 * @returns 0 in case of success, -1 in case of error
3814
 */
3815
int
3816
xmlXPathRegisterVariable(xmlXPathContext *ctxt, const xmlChar *name,
3817
0
       xmlXPathObject *value) {
3818
0
    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
3819
0
}
3820
3821
/**
3822
 * Register a new variable value. If `value` is NULL it unregisters
3823
 * the variable
3824
 *
3825
 * @param ctxt  the XPath context
3826
 * @param name  the variable name
3827
 * @param ns_uri  the variable namespace URI
3828
 * @param value  the variable value or NULL
3829
 * @returns 0 in case of success, -1 in case of error
3830
 */
3831
int
3832
xmlXPathRegisterVariableNS(xmlXPathContext *ctxt, const xmlChar *name,
3833
         const xmlChar *ns_uri,
3834
0
         xmlXPathObject *value) {
3835
0
    if (ctxt == NULL)
3836
0
  return(-1);
3837
0
    if (name == NULL)
3838
0
  return(-1);
3839
3840
0
    if (ctxt->varHash == NULL)
3841
0
  ctxt->varHash = xmlHashCreate(0);
3842
0
    if (ctxt->varHash == NULL)
3843
0
  return(-1);
3844
0
    if (value == NULL)
3845
0
        return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
3846
0
                             xmlXPathFreeObjectEntry));
3847
0
    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
3848
0
             (void *) value, xmlXPathFreeObjectEntry));
3849
0
}
3850
3851
/**
3852
 * register an external mechanism to do variable lookup
3853
 *
3854
 * @param ctxt  the XPath context
3855
 * @param f  the lookup function
3856
 * @param data  the lookup data
3857
 */
3858
void
3859
xmlXPathRegisterVariableLookup(xmlXPathContext *ctxt,
3860
0
   xmlXPathVariableLookupFunc f, void *data) {
3861
0
    if (ctxt == NULL)
3862
0
  return;
3863
0
    ctxt->varLookupFunc = f;
3864
0
    ctxt->varLookupData = data;
3865
0
}
3866
3867
/**
3868
 * Search in the Variable array of the context for the given
3869
 * variable value.
3870
 *
3871
 * @param ctxt  the XPath context
3872
 * @param name  the variable name
3873
 * @returns a copy of the value or NULL if not found
3874
 */
3875
xmlXPathObject *
3876
0
xmlXPathVariableLookup(xmlXPathContext *ctxt, const xmlChar *name) {
3877
0
    if (ctxt == NULL)
3878
0
  return(NULL);
3879
3880
0
    if (ctxt->varLookupFunc != NULL) {
3881
0
  xmlXPathObjectPtr ret;
3882
3883
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3884
0
          (ctxt->varLookupData, name, NULL);
3885
0
  return(ret);
3886
0
    }
3887
0
    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
3888
0
}
3889
3890
/**
3891
 * Search in the Variable array of the context for the given
3892
 * variable value.
3893
 *
3894
 * @param ctxt  the XPath context
3895
 * @param name  the variable name
3896
 * @param ns_uri  the variable namespace URI
3897
 * @returns the a copy of the value or NULL if not found
3898
 */
3899
xmlXPathObject *
3900
xmlXPathVariableLookupNS(xmlXPathContext *ctxt, const xmlChar *name,
3901
0
       const xmlChar *ns_uri) {
3902
0
    if (ctxt == NULL)
3903
0
  return(NULL);
3904
3905
0
    if (ctxt->varLookupFunc != NULL) {
3906
0
  xmlXPathObjectPtr ret;
3907
3908
0
  ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
3909
0
          (ctxt->varLookupData, name, ns_uri);
3910
0
  if (ret != NULL) return(ret);
3911
0
    }
3912
3913
0
    if (ctxt->varHash == NULL)
3914
0
  return(NULL);
3915
0
    if (name == NULL)
3916
0
  return(NULL);
3917
3918
0
    return(xmlXPathObjectCopy(xmlHashLookup2(ctxt->varHash, name, ns_uri)));
3919
0
}
3920
3921
/**
3922
 * Cleanup the XPath context data associated to registered variables
3923
 *
3924
 * @param ctxt  the XPath context
3925
 */
3926
void
3927
0
xmlXPathRegisteredVariablesCleanup(xmlXPathContext *ctxt) {
3928
0
    if (ctxt == NULL)
3929
0
  return;
3930
3931
0
    xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
3932
0
    ctxt->varHash = NULL;
3933
0
}
3934
3935
/**
3936
 * Register a new namespace. If `ns_uri` is NULL it unregisters
3937
 * the namespace
3938
 *
3939
 * @param ctxt  the XPath context
3940
 * @param prefix  the namespace prefix cannot be NULL or empty string
3941
 * @param ns_uri  the namespace name
3942
 * @returns 0 in case of success, -1 in case of error
3943
 */
3944
int
3945
xmlXPathRegisterNs(xmlXPathContext *ctxt, const xmlChar *prefix,
3946
0
         const xmlChar *ns_uri) {
3947
0
    xmlChar *copy;
3948
3949
0
    if (ctxt == NULL)
3950
0
  return(-1);
3951
0
    if (prefix == NULL)
3952
0
  return(-1);
3953
0
    if (prefix[0] == 0)
3954
0
  return(-1);
3955
3956
0
    if (ctxt->nsHash == NULL)
3957
0
  ctxt->nsHash = xmlHashCreate(10);
3958
0
    if (ctxt->nsHash == NULL) {
3959
0
        xmlXPathErrMemory(ctxt);
3960
0
  return(-1);
3961
0
    }
3962
0
    if (ns_uri == NULL)
3963
0
        return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
3964
0
                            xmlHashDefaultDeallocator));
3965
3966
0
    copy = xmlStrdup(ns_uri);
3967
0
    if (copy == NULL) {
3968
0
        xmlXPathErrMemory(ctxt);
3969
0
        return(-1);
3970
0
    }
3971
0
    if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
3972
0
                           xmlHashDefaultDeallocator) < 0) {
3973
0
        xmlXPathErrMemory(ctxt);
3974
0
        xmlFree(copy);
3975
0
        return(-1);
3976
0
    }
3977
3978
0
    return(0);
3979
0
}
3980
3981
/**
3982
 * Search in the namespace declaration array of the context for the given
3983
 * namespace name associated to the given prefix
3984
 *
3985
 * @param ctxt  the XPath context
3986
 * @param prefix  the namespace prefix value
3987
 * @returns the value or NULL if not found
3988
 */
3989
const xmlChar *
3990
0
xmlXPathNsLookup(xmlXPathContext *ctxt, const xmlChar *prefix) {
3991
0
    if (ctxt == NULL)
3992
0
  return(NULL);
3993
0
    if (prefix == NULL)
3994
0
  return(NULL);
3995
3996
0
    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
3997
0
  return(XML_XML_NAMESPACE);
3998
3999
0
    if (ctxt->namespaces != NULL) {
4000
0
  int i;
4001
4002
0
  for (i = 0;i < ctxt->nsNr;i++) {
4003
0
      if ((ctxt->namespaces[i] != NULL) &&
4004
0
    (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4005
0
    return(ctxt->namespaces[i]->href);
4006
0
  }
4007
0
    }
4008
4009
0
    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4010
0
}
4011
4012
/**
4013
 * Cleanup the XPath context data associated to registered variables
4014
 *
4015
 * @param ctxt  the XPath context
4016
 */
4017
void
4018
0
xmlXPathRegisteredNsCleanup(xmlXPathContext *ctxt) {
4019
0
    if (ctxt == NULL)
4020
0
  return;
4021
4022
0
    xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4023
0
    ctxt->nsHash = NULL;
4024
0
}
4025
4026
/************************************************************************
4027
 *                  *
4028
 *      Routines to handle Values     *
4029
 *                  *
4030
 ************************************************************************/
4031
4032
/* Allocations are terrible, one needs to optimize all this !!! */
4033
4034
/**
4035
 * Create a new xmlXPathObject of type double and of value `val`
4036
 *
4037
 * @param val  the double value
4038
 * @returns the newly created object.
4039
 */
4040
xmlXPathObject *
4041
0
xmlXPathNewFloat(double val) {
4042
0
    xmlXPathObjectPtr ret;
4043
4044
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4045
0
    if (ret == NULL)
4046
0
  return(NULL);
4047
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4048
0
    ret->type = XPATH_NUMBER;
4049
0
    ret->floatval = val;
4050
0
    return(ret);
4051
0
}
4052
4053
/**
4054
 * Create a new xmlXPathObject of type boolean and of value `val`
4055
 *
4056
 * @param val  the boolean value
4057
 * @returns the newly created object.
4058
 */
4059
xmlXPathObject *
4060
0
xmlXPathNewBoolean(int val) {
4061
0
    xmlXPathObjectPtr ret;
4062
4063
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4064
0
    if (ret == NULL)
4065
0
  return(NULL);
4066
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4067
0
    ret->type = XPATH_BOOLEAN;
4068
0
    ret->boolval = (val != 0);
4069
0
    return(ret);
4070
0
}
4071
4072
/**
4073
 * Create a new xmlXPathObject of type string and of value `val`
4074
 *
4075
 * @param val  the xmlChar * value
4076
 * @returns the newly created object.
4077
 */
4078
xmlXPathObject *
4079
0
xmlXPathNewString(const xmlChar *val) {
4080
0
    xmlXPathObjectPtr ret;
4081
4082
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4083
0
    if (ret == NULL)
4084
0
  return(NULL);
4085
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4086
0
    ret->type = XPATH_STRING;
4087
0
    if (val == NULL)
4088
0
        val = BAD_CAST "";
4089
0
    ret->stringval = xmlStrdup(val);
4090
0
    if (ret->stringval == NULL) {
4091
0
        xmlFree(ret);
4092
0
        return(NULL);
4093
0
    }
4094
0
    return(ret);
4095
0
}
4096
4097
/**
4098
 * Wraps the `val` string into an XPath object.
4099
 *
4100
 * Frees `val` in case of error.
4101
 *
4102
 * @param val  the xmlChar * value
4103
 * @returns the newly created object.
4104
 */
4105
xmlXPathObject *
4106
0
xmlXPathWrapString (xmlChar *val) {
4107
0
    xmlXPathObjectPtr ret;
4108
4109
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4110
0
    if (ret == NULL) {
4111
0
        xmlFree(val);
4112
0
  return(NULL);
4113
0
    }
4114
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4115
0
    ret->type = XPATH_STRING;
4116
0
    ret->stringval = val;
4117
0
    return(ret);
4118
0
}
4119
4120
/**
4121
 * Create a new xmlXPathObject of type string and of value `val`
4122
 *
4123
 * @param val  the char * value
4124
 * @returns the newly created object.
4125
 */
4126
xmlXPathObject *
4127
0
xmlXPathNewCString(const char *val) {
4128
0
    return(xmlXPathNewString(BAD_CAST val));
4129
0
}
4130
4131
/**
4132
 * Wraps a string into an XPath object.
4133
 *
4134
 * @param val  the char * value
4135
 * @returns the newly created object.
4136
 */
4137
xmlXPathObject *
4138
0
xmlXPathWrapCString (char * val) {
4139
0
    return(xmlXPathWrapString((xmlChar *)(val)));
4140
0
}
4141
4142
/**
4143
 * Wraps the `val` data into an XPath object.
4144
 *
4145
 * @param val  the user data
4146
 * @returns the newly created object.
4147
 */
4148
xmlXPathObject *
4149
0
xmlXPathWrapExternal (void *val) {
4150
0
    xmlXPathObjectPtr ret;
4151
4152
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4153
0
    if (ret == NULL)
4154
0
  return(NULL);
4155
0
    memset(ret, 0 , sizeof(xmlXPathObject));
4156
0
    ret->type = XPATH_USERS;
4157
0
    ret->user = val;
4158
0
    return(ret);
4159
0
}
4160
4161
/**
4162
 * allocate a new copy of a given object
4163
 *
4164
 * @param val  the original object
4165
 * @returns the newly created object.
4166
 */
4167
xmlXPathObject *
4168
0
xmlXPathObjectCopy(xmlXPathObject *val) {
4169
0
    xmlXPathObjectPtr ret;
4170
4171
0
    if (val == NULL)
4172
0
  return(NULL);
4173
4174
0
    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4175
0
    if (ret == NULL)
4176
0
  return(NULL);
4177
0
    memcpy(ret, val , sizeof(xmlXPathObject));
4178
0
    switch (val->type) {
4179
0
  case XPATH_BOOLEAN:
4180
0
  case XPATH_NUMBER:
4181
0
      break;
4182
0
  case XPATH_STRING:
4183
0
      ret->stringval = xmlStrdup(val->stringval);
4184
0
            if (ret->stringval == NULL) {
4185
0
                xmlFree(ret);
4186
0
                return(NULL);
4187
0
            }
4188
0
      break;
4189
0
  case XPATH_XSLT_TREE:
4190
0
  case XPATH_NODESET:
4191
0
      ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4192
0
            if (ret->nodesetval == NULL) {
4193
0
                xmlFree(ret);
4194
0
                return(NULL);
4195
0
            }
4196
      /* Do not deallocate the copied tree value */
4197
0
      ret->boolval = 0;
4198
0
      break;
4199
0
        case XPATH_USERS:
4200
0
      ret->user = val->user;
4201
0
      break;
4202
0
        default:
4203
0
            xmlFree(ret);
4204
0
            ret = NULL;
4205
0
      break;
4206
0
    }
4207
0
    return(ret);
4208
0
}
4209
4210
/**
4211
 * Free up an xmlXPathObject object.
4212
 *
4213
 * @param obj  the object to free
4214
 */
4215
void
4216
0
xmlXPathFreeObject(xmlXPathObject *obj) {
4217
0
    if (obj == NULL) return;
4218
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4219
0
        if (obj->nodesetval != NULL)
4220
0
            xmlXPathFreeNodeSet(obj->nodesetval);
4221
0
    } else if (obj->type == XPATH_STRING) {
4222
0
  if (obj->stringval != NULL)
4223
0
      xmlFree(obj->stringval);
4224
0
    }
4225
0
    xmlFree(obj);
4226
0
}
4227
4228
static void
4229
0
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4230
0
    xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4231
0
}
4232
4233
/**
4234
 * Depending on the state of the cache this frees the given
4235
 * XPath object or stores it in the cache.
4236
 *
4237
 * @param ctxt  XPath context
4238
 * @param obj  the xmlXPathObject to free or to cache
4239
 */
4240
static void
4241
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4242
0
{
4243
0
    if (obj == NULL)
4244
0
  return;
4245
0
    if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4246
0
   xmlXPathFreeObject(obj);
4247
0
    } else {
4248
0
  xmlXPathContextCachePtr cache =
4249
0
      (xmlXPathContextCachePtr) ctxt->cache;
4250
4251
0
  switch (obj->type) {
4252
0
      case XPATH_NODESET:
4253
0
      case XPATH_XSLT_TREE:
4254
0
    if (obj->nodesetval != NULL) {
4255
0
        if ((obj->nodesetval->nodeMax <= 40) &&
4256
0
      (cache->numNodeset < cache->maxNodeset)) {
4257
0
                        obj->stringval = (void *) cache->nodesetObjs;
4258
0
                        cache->nodesetObjs = obj;
4259
0
                        cache->numNodeset += 1;
4260
0
      goto obj_cached;
4261
0
        } else {
4262
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4263
0
      obj->nodesetval = NULL;
4264
0
        }
4265
0
    }
4266
0
    break;
4267
0
      case XPATH_STRING:
4268
0
    if (obj->stringval != NULL)
4269
0
        xmlFree(obj->stringval);
4270
0
                obj->stringval = NULL;
4271
0
    break;
4272
0
      case XPATH_BOOLEAN:
4273
0
      case XPATH_NUMBER:
4274
0
    break;
4275
0
      default:
4276
0
    goto free_obj;
4277
0
  }
4278
4279
  /*
4280
  * Fallback to adding to the misc-objects slot.
4281
  */
4282
0
        if (cache->numMisc >= cache->maxMisc)
4283
0
      goto free_obj;
4284
0
        obj->stringval = (void *) cache->miscObjs;
4285
0
        cache->miscObjs = obj;
4286
0
        cache->numMisc += 1;
4287
4288
0
obj_cached:
4289
0
        obj->boolval = 0;
4290
0
  if (obj->nodesetval != NULL) {
4291
0
      xmlNodeSetPtr tmpset = obj->nodesetval;
4292
4293
      /*
4294
      * Due to those nasty ns-nodes, we need to traverse
4295
      * the list and free the ns-nodes.
4296
      */
4297
0
      if (tmpset->nodeNr > 0) {
4298
0
    int i;
4299
0
    xmlNodePtr node;
4300
4301
0
    for (i = 0; i < tmpset->nodeNr; i++) {
4302
0
        node = tmpset->nodeTab[i];
4303
0
        if ((node != NULL) &&
4304
0
      (node->type == XML_NAMESPACE_DECL))
4305
0
        {
4306
0
      xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4307
0
        }
4308
0
    }
4309
0
      }
4310
0
      tmpset->nodeNr = 0;
4311
0
        }
4312
4313
0
  return;
4314
4315
0
free_obj:
4316
  /*
4317
  * Cache is full; free the object.
4318
  */
4319
0
  if (obj->nodesetval != NULL)
4320
0
      xmlXPathFreeNodeSet(obj->nodesetval);
4321
0
  xmlFree(obj);
4322
0
    }
4323
0
}
4324
4325
4326
/************************************************************************
4327
 *                  *
4328
 *      Type Casting Routines       *
4329
 *                  *
4330
 ************************************************************************/
4331
4332
/**
4333
 * Converts a boolean to its string value.
4334
 *
4335
 * @param val  a boolean
4336
 * @returns a newly allocated string.
4337
 */
4338
xmlChar *
4339
0
xmlXPathCastBooleanToString (int val) {
4340
0
    xmlChar *ret;
4341
0
    if (val)
4342
0
  ret = xmlStrdup((const xmlChar *) "true");
4343
0
    else
4344
0
  ret = xmlStrdup((const xmlChar *) "false");
4345
0
    return(ret);
4346
0
}
4347
4348
/**
4349
 * Converts a number to its string value.
4350
 *
4351
 * @param val  a number
4352
 * @returns a newly allocated string.
4353
 */
4354
xmlChar *
4355
0
xmlXPathCastNumberToString (double val) {
4356
0
    xmlChar *ret;
4357
0
    switch (xmlXPathIsInf(val)) {
4358
0
    case 1:
4359
0
  ret = xmlStrdup((const xmlChar *) "Infinity");
4360
0
  break;
4361
0
    case -1:
4362
0
  ret = xmlStrdup((const xmlChar *) "-Infinity");
4363
0
  break;
4364
0
    default:
4365
0
  if (xmlXPathIsNaN(val)) {
4366
0
      ret = xmlStrdup((const xmlChar *) "NaN");
4367
0
  } else if (val == 0) {
4368
            /* Omit sign for negative zero. */
4369
0
      ret = xmlStrdup((const xmlChar *) "0");
4370
0
  } else {
4371
      /* could be improved */
4372
0
      char buf[100];
4373
0
      xmlXPathFormatNumber(val, buf, 99);
4374
0
      buf[99] = 0;
4375
0
      ret = xmlStrdup((const xmlChar *) buf);
4376
0
  }
4377
0
    }
4378
0
    return(ret);
4379
0
}
4380
4381
/**
4382
 * Converts a node to its string value.
4383
 *
4384
 * @param node  a node
4385
 * @returns a newly allocated string.
4386
 */
4387
xmlChar *
4388
0
xmlXPathCastNodeToString (xmlNode *node) {
4389
0
    return(xmlNodeGetContent(node));
4390
0
}
4391
4392
/**
4393
 * Converts a node-set to its string value.
4394
 *
4395
 * @param ns  a node-set
4396
 * @returns a newly allocated string.
4397
 */
4398
xmlChar *
4399
0
xmlXPathCastNodeSetToString (xmlNodeSet *ns) {
4400
0
    if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
4401
0
  return(xmlStrdup((const xmlChar *) ""));
4402
4403
0
    if (ns->nodeNr > 1)
4404
0
  xmlXPathNodeSetSort(ns);
4405
0
    return(xmlXPathCastNodeToString(ns->nodeTab[0]));
4406
0
}
4407
4408
/**
4409
 * Converts an existing object to its string() equivalent
4410
 *
4411
 * @param val  an XPath object
4412
 * @returns the allocated string value of the object, NULL in case of error.
4413
 *         It's up to the caller to free the string memory with #xmlFree.
4414
 */
4415
xmlChar *
4416
0
xmlXPathCastToString(xmlXPathObject *val) {
4417
0
    xmlChar *ret = NULL;
4418
4419
0
    if (val == NULL)
4420
0
  return(xmlStrdup((const xmlChar *) ""));
4421
0
    switch (val->type) {
4422
0
  case XPATH_UNDEFINED:
4423
0
      ret = xmlStrdup((const xmlChar *) "");
4424
0
      break;
4425
0
        case XPATH_NODESET:
4426
0
        case XPATH_XSLT_TREE:
4427
0
      ret = xmlXPathCastNodeSetToString(val->nodesetval);
4428
0
      break;
4429
0
  case XPATH_STRING:
4430
0
      return(xmlStrdup(val->stringval));
4431
0
        case XPATH_BOOLEAN:
4432
0
      ret = xmlXPathCastBooleanToString(val->boolval);
4433
0
      break;
4434
0
  case XPATH_NUMBER: {
4435
0
      ret = xmlXPathCastNumberToString(val->floatval);
4436
0
      break;
4437
0
  }
4438
0
  case XPATH_USERS:
4439
      /* TODO */
4440
0
      ret = xmlStrdup((const xmlChar *) "");
4441
0
      break;
4442
0
    }
4443
0
    return(ret);
4444
0
}
4445
4446
/**
4447
 * Converts an existing object to its string() equivalent
4448
 *
4449
 * @param val  an XPath object
4450
 * @returns the new object, the old one is freed (or the operation
4451
 *         is done directly on `val`)
4452
 */
4453
xmlXPathObject *
4454
0
xmlXPathConvertString(xmlXPathObject *val) {
4455
0
    xmlChar *res = NULL;
4456
4457
0
    if (val == NULL)
4458
0
  return(xmlXPathNewCString(""));
4459
4460
0
    switch (val->type) {
4461
0
    case XPATH_UNDEFINED:
4462
0
  break;
4463
0
    case XPATH_NODESET:
4464
0
    case XPATH_XSLT_TREE:
4465
0
  res = xmlXPathCastNodeSetToString(val->nodesetval);
4466
0
  break;
4467
0
    case XPATH_STRING:
4468
0
  return(val);
4469
0
    case XPATH_BOOLEAN:
4470
0
  res = xmlXPathCastBooleanToString(val->boolval);
4471
0
  break;
4472
0
    case XPATH_NUMBER:
4473
0
  res = xmlXPathCastNumberToString(val->floatval);
4474
0
  break;
4475
0
    case XPATH_USERS:
4476
  /* TODO */
4477
0
  break;
4478
0
    }
4479
0
    xmlXPathFreeObject(val);
4480
0
    if (res == NULL)
4481
0
  return(xmlXPathNewCString(""));
4482
0
    return(xmlXPathWrapString(res));
4483
0
}
4484
4485
/**
4486
 * Converts a boolean to its number value
4487
 *
4488
 * @param val  a boolean
4489
 * @returns the number value
4490
 */
4491
double
4492
0
xmlXPathCastBooleanToNumber(int val) {
4493
0
    if (val)
4494
0
  return(1.0);
4495
0
    return(0.0);
4496
0
}
4497
4498
/**
4499
 * Converts a string to its number value
4500
 *
4501
 * @param val  a string
4502
 * @returns the number value
4503
 */
4504
double
4505
0
xmlXPathCastStringToNumber(const xmlChar * val) {
4506
0
    return(xmlXPathStringEvalNumber(val));
4507
0
}
4508
4509
/**
4510
 * Converts a node to its number value
4511
 *
4512
 * @param ctxt  XPath parser context
4513
 * @param node  a node
4514
 * @returns the number value
4515
 */
4516
static double
4517
0
xmlXPathNodeToNumberInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr node) {
4518
0
    xmlChar *strval;
4519
0
    double ret;
4520
4521
0
    if (node == NULL)
4522
0
  return(xmlXPathNAN);
4523
0
    strval = xmlXPathCastNodeToString(node);
4524
0
    if (strval == NULL) {
4525
0
        xmlXPathPErrMemory(ctxt);
4526
0
  return(xmlXPathNAN);
4527
0
    }
4528
0
    ret = xmlXPathCastStringToNumber(strval);
4529
0
    xmlFree(strval);
4530
4531
0
    return(ret);
4532
0
}
4533
4534
/**
4535
 * Converts a node to its number value
4536
 *
4537
 * @param node  a node
4538
 * @returns the number value
4539
 */
4540
double
4541
0
xmlXPathCastNodeToNumber (xmlNode *node) {
4542
0
    return(xmlXPathNodeToNumberInternal(NULL, node));
4543
0
}
4544
4545
/**
4546
 * Converts a node-set to its number value
4547
 *
4548
 * @param ns  a node-set
4549
 * @returns the number value
4550
 */
4551
double
4552
0
xmlXPathCastNodeSetToNumber (xmlNodeSet *ns) {
4553
0
    xmlChar *str;
4554
0
    double ret;
4555
4556
0
    if (ns == NULL)
4557
0
  return(xmlXPathNAN);
4558
0
    str = xmlXPathCastNodeSetToString(ns);
4559
0
    ret = xmlXPathCastStringToNumber(str);
4560
0
    xmlFree(str);
4561
0
    return(ret);
4562
0
}
4563
4564
/**
4565
 * Converts an XPath object to its number value
4566
 *
4567
 * @param val  an XPath object
4568
 * @returns the number value
4569
 */
4570
double
4571
0
xmlXPathCastToNumber(xmlXPathObject *val) {
4572
0
    return(xmlXPathCastToNumberInternal(NULL, val));
4573
0
}
4574
4575
/**
4576
 * Converts an existing object to its number() equivalent
4577
 *
4578
 * @param val  an XPath object
4579
 * @returns the new object, the old one is freed (or the operation
4580
 *         is done directly on `val`)
4581
 */
4582
xmlXPathObject *
4583
0
xmlXPathConvertNumber(xmlXPathObject *val) {
4584
0
    xmlXPathObjectPtr ret;
4585
4586
0
    if (val == NULL)
4587
0
  return(xmlXPathNewFloat(0.0));
4588
0
    if (val->type == XPATH_NUMBER)
4589
0
  return(val);
4590
0
    ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
4591
0
    xmlXPathFreeObject(val);
4592
0
    return(ret);
4593
0
}
4594
4595
/**
4596
 * Converts a number to its boolean value
4597
 *
4598
 * @param val  a number
4599
 * @returns the boolean value
4600
 */
4601
int
4602
0
xmlXPathCastNumberToBoolean (double val) {
4603
0
     if (xmlXPathIsNaN(val) || (val == 0.0))
4604
0
   return(0);
4605
0
     return(1);
4606
0
}
4607
4608
/**
4609
 * Converts a string to its boolean value
4610
 *
4611
 * @param val  a string
4612
 * @returns the boolean value
4613
 */
4614
int
4615
0
xmlXPathCastStringToBoolean (const xmlChar *val) {
4616
0
    if ((val == NULL) || (xmlStrlen(val) == 0))
4617
0
  return(0);
4618
0
    return(1);
4619
0
}
4620
4621
/**
4622
 * Converts a node-set to its boolean value
4623
 *
4624
 * @param ns  a node-set
4625
 * @returns the boolean value
4626
 */
4627
int
4628
0
xmlXPathCastNodeSetToBoolean (xmlNodeSet *ns) {
4629
0
    if ((ns == NULL) || (ns->nodeNr == 0))
4630
0
  return(0);
4631
0
    return(1);
4632
0
}
4633
4634
/**
4635
 * Converts an XPath object to its boolean value
4636
 *
4637
 * @param val  an XPath object
4638
 * @returns the boolean value
4639
 */
4640
int
4641
0
xmlXPathCastToBoolean (xmlXPathObject *val) {
4642
0
    int ret = 0;
4643
4644
0
    if (val == NULL)
4645
0
  return(0);
4646
0
    switch (val->type) {
4647
0
    case XPATH_UNDEFINED:
4648
0
  ret = 0;
4649
0
  break;
4650
0
    case XPATH_NODESET:
4651
0
    case XPATH_XSLT_TREE:
4652
0
  ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
4653
0
  break;
4654
0
    case XPATH_STRING:
4655
0
  ret = xmlXPathCastStringToBoolean(val->stringval);
4656
0
  break;
4657
0
    case XPATH_NUMBER:
4658
0
  ret = xmlXPathCastNumberToBoolean(val->floatval);
4659
0
  break;
4660
0
    case XPATH_BOOLEAN:
4661
0
  ret = val->boolval;
4662
0
  break;
4663
0
    case XPATH_USERS:
4664
  /* TODO */
4665
0
  ret = 0;
4666
0
  break;
4667
0
    }
4668
0
    return(ret);
4669
0
}
4670
4671
4672
/**
4673
 * Converts an existing object to its boolean() equivalent
4674
 *
4675
 * @param val  an XPath object
4676
 * @returns the new object, the old one is freed (or the operation
4677
 *         is done directly on `val`)
4678
 */
4679
xmlXPathObject *
4680
0
xmlXPathConvertBoolean(xmlXPathObject *val) {
4681
0
    xmlXPathObjectPtr ret;
4682
4683
0
    if (val == NULL)
4684
0
  return(xmlXPathNewBoolean(0));
4685
0
    if (val->type == XPATH_BOOLEAN)
4686
0
  return(val);
4687
0
    ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
4688
0
    xmlXPathFreeObject(val);
4689
0
    return(ret);
4690
0
}
4691
4692
/************************************************************************
4693
 *                  *
4694
 *    Routines to handle XPath contexts     *
4695
 *                  *
4696
 ************************************************************************/
4697
4698
/**
4699
 * Create a new xmlXPathContext
4700
 *
4701
 * @param doc  the XML document
4702
 * @returns the xmlXPathContext just allocated. The caller will need to free it.
4703
 */
4704
xmlXPathContext *
4705
0
xmlXPathNewContext(xmlDoc *doc) {
4706
0
    xmlXPathContextPtr ret;
4707
4708
0
    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
4709
0
    if (ret == NULL)
4710
0
  return(NULL);
4711
0
    memset(ret, 0 , sizeof(xmlXPathContext));
4712
0
    ret->doc = doc;
4713
0
    ret->node = NULL;
4714
4715
0
    ret->varHash = NULL;
4716
4717
0
    ret->nb_types = 0;
4718
0
    ret->max_types = 0;
4719
0
    ret->types = NULL;
4720
4721
0
    ret->nb_axis = 0;
4722
0
    ret->max_axis = 0;
4723
0
    ret->axis = NULL;
4724
4725
0
    ret->nsHash = NULL;
4726
0
    ret->user = NULL;
4727
4728
0
    ret->contextSize = -1;
4729
0
    ret->proximityPosition = -1;
4730
4731
#ifdef XP_DEFAULT_CACHE_ON
4732
    if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
4733
  xmlXPathFreeContext(ret);
4734
  return(NULL);
4735
    }
4736
#endif
4737
4738
0
    return(ret);
4739
0
}
4740
4741
/**
4742
 * Free up an xmlXPathContext
4743
 *
4744
 * @param ctxt  the context to free
4745
 */
4746
void
4747
0
xmlXPathFreeContext(xmlXPathContext *ctxt) {
4748
0
    if (ctxt == NULL) return;
4749
4750
0
    if (ctxt->cache != NULL)
4751
0
  xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
4752
0
    xmlXPathRegisteredNsCleanup(ctxt);
4753
0
    xmlXPathRegisteredFuncsCleanup(ctxt);
4754
0
    xmlXPathRegisteredVariablesCleanup(ctxt);
4755
0
    xmlResetError(&ctxt->lastError);
4756
0
    xmlFree(ctxt);
4757
0
}
4758
4759
/**
4760
 * Register a callback function that will be called on errors and
4761
 * warnings. If handler is NULL, the error handler will be deactivated.
4762
 *
4763
 * @since 2.13.0
4764
 * @param ctxt  the XPath context
4765
 * @param handler  error handler
4766
 * @param data  user data which will be passed to the handler
4767
 */
4768
void
4769
xmlXPathSetErrorHandler(xmlXPathContext *ctxt,
4770
0
                        xmlStructuredErrorFunc handler, void *data) {
4771
0
    if (ctxt == NULL)
4772
0
        return;
4773
4774
0
    ctxt->error = handler;
4775
0
    ctxt->userData = data;
4776
0
}
4777
4778
/************************************************************************
4779
 *                  *
4780
 *    Routines to handle XPath parser contexts    *
4781
 *                  *
4782
 ************************************************************************/
4783
4784
/**
4785
 * Create a new xmlXPathParserContext
4786
 *
4787
 * @param str  the XPath expression
4788
 * @param ctxt  the XPath context
4789
 * @returns the xmlXPathParserContext just allocated.
4790
 */
4791
xmlXPathParserContext *
4792
0
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContext *ctxt) {
4793
0
    xmlXPathParserContextPtr ret;
4794
4795
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4796
0
    if (ret == NULL) {
4797
0
        xmlXPathErrMemory(ctxt);
4798
0
  return(NULL);
4799
0
    }
4800
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4801
0
    ret->cur = ret->base = str;
4802
0
    ret->context = ctxt;
4803
4804
0
    ret->comp = xmlXPathNewCompExpr();
4805
0
    if (ret->comp == NULL) {
4806
0
        xmlXPathErrMemory(ctxt);
4807
0
  xmlFree(ret->valueTab);
4808
0
  xmlFree(ret);
4809
0
  return(NULL);
4810
0
    }
4811
0
    if ((ctxt != NULL) && (ctxt->dict != NULL)) {
4812
0
        ret->comp->dict = ctxt->dict;
4813
0
  xmlDictReference(ret->comp->dict);
4814
0
    }
4815
4816
0
    return(ret);
4817
0
}
4818
4819
/**
4820
 * Create a new xmlXPathParserContext when processing a compiled expression
4821
 *
4822
 * @param comp  the XPath compiled expression
4823
 * @param ctxt  the XPath context
4824
 * @returns the xmlXPathParserContext just allocated.
4825
 */
4826
static xmlXPathParserContextPtr
4827
0
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
4828
0
    xmlXPathParserContextPtr ret;
4829
4830
0
    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
4831
0
    if (ret == NULL) {
4832
0
        xmlXPathErrMemory(ctxt);
4833
0
  return(NULL);
4834
0
    }
4835
0
    memset(ret, 0 , sizeof(xmlXPathParserContext));
4836
4837
    /* Allocate the value stack */
4838
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4839
0
    ret->valueMax = 1;
4840
#else
4841
    ret->valueMax = 10;
4842
#endif
4843
0
    ret->valueTab = xmlMalloc(ret->valueMax * sizeof(xmlXPathObjectPtr));
4844
0
    if (ret->valueTab == NULL) {
4845
0
  xmlFree(ret);
4846
0
  xmlXPathErrMemory(ctxt);
4847
0
  return(NULL);
4848
0
    }
4849
0
    ret->valueNr = 0;
4850
0
    ret->value = NULL;
4851
4852
0
    ret->context = ctxt;
4853
0
    ret->comp = comp;
4854
4855
0
    return(ret);
4856
0
}
4857
4858
/**
4859
 * Free up an xmlXPathParserContext
4860
 *
4861
 * @param ctxt  the context to free
4862
 */
4863
void
4864
0
xmlXPathFreeParserContext(xmlXPathParserContext *ctxt) {
4865
0
    int i;
4866
4867
0
    if (ctxt == NULL)
4868
0
        return;
4869
4870
0
    if (ctxt->valueTab != NULL) {
4871
0
        for (i = 0; i < ctxt->valueNr; i++) {
4872
0
            if (ctxt->context)
4873
0
                xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
4874
0
            else
4875
0
                xmlXPathFreeObject(ctxt->valueTab[i]);
4876
0
        }
4877
0
        xmlFree(ctxt->valueTab);
4878
0
    }
4879
0
    if (ctxt->comp != NULL) {
4880
#ifdef XPATH_STREAMING
4881
  if (ctxt->comp->stream != NULL) {
4882
      xmlFreePatternList(ctxt->comp->stream);
4883
      ctxt->comp->stream = NULL;
4884
  }
4885
#endif
4886
0
  xmlXPathFreeCompExpr(ctxt->comp);
4887
0
    }
4888
0
    xmlFree(ctxt);
4889
0
}
4890
4891
/************************************************************************
4892
 *                  *
4893
 *    The implicit core function library      *
4894
 *                  *
4895
 ************************************************************************/
4896
4897
/**
4898
 * Function computing the beginning of the string value of the node,
4899
 * used to speed up comparisons
4900
 *
4901
 * @param node  a node pointer
4902
 * @returns an int usable as a hash
4903
 */
4904
static unsigned int
4905
0
xmlXPathNodeValHash(xmlNodePtr node) {
4906
0
    int len = 2;
4907
0
    const xmlChar * string = NULL;
4908
0
    xmlNodePtr tmp = NULL;
4909
0
    unsigned int ret = 0;
4910
4911
0
    if (node == NULL)
4912
0
  return(0);
4913
4914
0
    if (node->type == XML_DOCUMENT_NODE) {
4915
0
  tmp = xmlDocGetRootElement((xmlDocPtr) node);
4916
0
  if (tmp == NULL)
4917
0
      node = node->children;
4918
0
  else
4919
0
      node = tmp;
4920
4921
0
  if (node == NULL)
4922
0
      return(0);
4923
0
    }
4924
4925
0
    switch (node->type) {
4926
0
  case XML_COMMENT_NODE:
4927
0
  case XML_PI_NODE:
4928
0
  case XML_CDATA_SECTION_NODE:
4929
0
  case XML_TEXT_NODE:
4930
0
      string = node->content;
4931
0
      if (string == NULL)
4932
0
    return(0);
4933
0
      if (string[0] == 0)
4934
0
    return(0);
4935
0
      return(string[0] + (string[1] << 8));
4936
0
  case XML_NAMESPACE_DECL:
4937
0
      string = ((xmlNsPtr)node)->href;
4938
0
      if (string == NULL)
4939
0
    return(0);
4940
0
      if (string[0] == 0)
4941
0
    return(0);
4942
0
      return(string[0] + (string[1] << 8));
4943
0
  case XML_ATTRIBUTE_NODE:
4944
0
      tmp = ((xmlAttrPtr) node)->children;
4945
0
      break;
4946
0
  case XML_ELEMENT_NODE:
4947
0
      tmp = node->children;
4948
0
      break;
4949
0
  default:
4950
0
      return(0);
4951
0
    }
4952
0
    while (tmp != NULL) {
4953
0
  switch (tmp->type) {
4954
0
      case XML_CDATA_SECTION_NODE:
4955
0
      case XML_TEXT_NODE:
4956
0
    string = tmp->content;
4957
0
    break;
4958
0
      default:
4959
0
                string = NULL;
4960
0
    break;
4961
0
  }
4962
0
  if ((string != NULL) && (string[0] != 0)) {
4963
0
      if (len == 1) {
4964
0
    return(ret + (string[0] << 8));
4965
0
      }
4966
0
      if (string[1] == 0) {
4967
0
    len = 1;
4968
0
    ret = string[0];
4969
0
      } else {
4970
0
    return(string[0] + (string[1] << 8));
4971
0
      }
4972
0
  }
4973
  /*
4974
   * Skip to next node
4975
   */
4976
0
        if ((tmp->children != NULL) &&
4977
0
            (tmp->type != XML_DTD_NODE) &&
4978
0
            (tmp->type != XML_ENTITY_REF_NODE) &&
4979
0
            (tmp->children->type != XML_ENTITY_DECL)) {
4980
0
            tmp = tmp->children;
4981
0
            continue;
4982
0
  }
4983
0
  if (tmp == node)
4984
0
      break;
4985
4986
0
  if (tmp->next != NULL) {
4987
0
      tmp = tmp->next;
4988
0
      continue;
4989
0
  }
4990
4991
0
  do {
4992
0
      tmp = tmp->parent;
4993
0
      if (tmp == NULL)
4994
0
    break;
4995
0
      if (tmp == node) {
4996
0
    tmp = NULL;
4997
0
    break;
4998
0
      }
4999
0
      if (tmp->next != NULL) {
5000
0
    tmp = tmp->next;
5001
0
    break;
5002
0
      }
5003
0
  } while (tmp != NULL);
5004
0
    }
5005
0
    return(ret);
5006
0
}
5007
5008
/**
5009
 * Function computing the beginning of the string value of the node,
5010
 * used to speed up comparisons
5011
 *
5012
 * @param string  a string
5013
 * @returns an int usable as a hash
5014
 */
5015
static unsigned int
5016
0
xmlXPathStringHash(const xmlChar * string) {
5017
0
    if (string == NULL)
5018
0
  return(0);
5019
0
    if (string[0] == 0)
5020
0
  return(0);
5021
0
    return(string[0] + (string[1] << 8));
5022
0
}
5023
5024
/**
5025
 * Implement the compare operation between a nodeset and a number
5026
 *     `ns` < `val`    (1, 1, ...
5027
 *     `ns` <= `val`   (1, 0, ...
5028
 *     `ns` > `val`    (0, 1, ...
5029
 *     `ns` >= `val`   (0, 0, ...
5030
 *
5031
 * If one object to be compared is a node-set and the other is a number,
5032
 * then the comparison will be true if and only if there is a node in the
5033
 * node-set such that the result of performing the comparison on the number
5034
 * to be compared and on the result of converting the string-value of that
5035
 * node to a number using the number function is true.
5036
 *
5037
 * @param ctxt  the XPath Parser context
5038
 * @param inf  less than (1) or greater than (0)
5039
 * @param strict  is the comparison strict
5040
 * @param arg  the node set
5041
 * @param f  the value
5042
 * @returns 0 or 1 depending on the results of the test.
5043
 */
5044
static int
5045
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5046
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5047
0
    int i, ret = 0;
5048
0
    xmlNodeSetPtr ns;
5049
0
    xmlChar *str2;
5050
5051
0
    if ((f == NULL) || (arg == NULL) ||
5052
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5053
0
  xmlXPathReleaseObject(ctxt->context, arg);
5054
0
  xmlXPathReleaseObject(ctxt->context, f);
5055
0
        return(0);
5056
0
    }
5057
0
    ns = arg->nodesetval;
5058
0
    if (ns != NULL) {
5059
0
  for (i = 0;i < ns->nodeNr;i++) {
5060
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5061
0
       if (str2 != NULL) {
5062
0
     xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5063
0
     xmlFree(str2);
5064
0
     xmlXPathNumberFunction(ctxt, 1);
5065
0
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, f));
5066
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5067
0
     if (ret)
5068
0
         break;
5069
0
       } else {
5070
0
                 xmlXPathPErrMemory(ctxt);
5071
0
             }
5072
0
  }
5073
0
    }
5074
0
    xmlXPathReleaseObject(ctxt->context, arg);
5075
0
    xmlXPathReleaseObject(ctxt->context, f);
5076
0
    return(ret);
5077
0
}
5078
5079
/**
5080
 * Implement the compare operation between a nodeset and a string
5081
 *     `ns` < `val`    (1, 1, ...
5082
 *     `ns` <= `val`   (1, 0, ...
5083
 *     `ns` > `val`    (0, 1, ...
5084
 *     `ns` >= `val`   (0, 0, ...
5085
 *
5086
 * If one object to be compared is a node-set and the other is a string,
5087
 * then the comparison will be true if and only if there is a node in
5088
 * the node-set such that the result of performing the comparison on the
5089
 * string-value of the node and the other string is true.
5090
 *
5091
 * @param ctxt  the XPath Parser context
5092
 * @param inf  less than (1) or greater than (0)
5093
 * @param strict  is the comparison strict
5094
 * @param arg  the node set
5095
 * @param s  the value
5096
 * @returns 0 or 1 depending on the results of the test.
5097
 */
5098
static int
5099
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5100
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5101
0
    int i, ret = 0;
5102
0
    xmlNodeSetPtr ns;
5103
0
    xmlChar *str2;
5104
5105
0
    if ((s == NULL) || (arg == NULL) ||
5106
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5107
0
  xmlXPathReleaseObject(ctxt->context, arg);
5108
0
  xmlXPathReleaseObject(ctxt->context, s);
5109
0
        return(0);
5110
0
    }
5111
0
    ns = arg->nodesetval;
5112
0
    if (ns != NULL) {
5113
0
  for (i = 0;i < ns->nodeNr;i++) {
5114
0
       str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5115
0
       if (str2 != NULL) {
5116
0
     xmlXPathValuePush(ctxt,
5117
0
         xmlXPathCacheNewString(ctxt, str2));
5118
0
     xmlFree(str2);
5119
0
     xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, s));
5120
0
     ret = xmlXPathCompareValues(ctxt, inf, strict);
5121
0
     if (ret)
5122
0
         break;
5123
0
       } else {
5124
0
                 xmlXPathPErrMemory(ctxt);
5125
0
             }
5126
0
  }
5127
0
    }
5128
0
    xmlXPathReleaseObject(ctxt->context, arg);
5129
0
    xmlXPathReleaseObject(ctxt->context, s);
5130
0
    return(ret);
5131
0
}
5132
5133
/**
5134
 * Implement the compare operation on nodesets:
5135
 *
5136
 * If both objects to be compared are node-sets, then the comparison
5137
 * will be true if and only if there is a node in the first node-set
5138
 * and a node in the second node-set such that the result of performing
5139
 * the comparison on the string-values of the two nodes is true.
5140
 * ....
5141
 * When neither object to be compared is a node-set and the operator
5142
 * is <=, <, >= or >, then the objects are compared by converting both
5143
 * objects to numbers and comparing the numbers according to IEEE 754.
5144
 * ....
5145
 * The number function converts its argument to a number as follows:
5146
 *  - a string that consists of optional whitespace followed by an
5147
 *    optional minus sign followed by a Number followed by whitespace
5148
 *    is converted to the IEEE 754 number that is nearest (according
5149
 *    to the IEEE 754 round-to-nearest rule) to the mathematical value
5150
 *    represented by the string; any other string is converted to NaN
5151
 *
5152
 * Conclusion all nodes need to be converted first to their string value
5153
 * and then the comparison must be done when possible
5154
 *
5155
 * @param ctxt  XPath parser context
5156
 * @param inf  less than (1) or greater than (0)
5157
 * @param strict  is the comparison strict
5158
 * @param arg1  the first node set object
5159
 * @param arg2  the second node set object
5160
 */
5161
static int
5162
xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
5163
0
                  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5164
0
    int i, j, init = 0;
5165
0
    double val1;
5166
0
    double *values2;
5167
0
    int ret = 0;
5168
0
    xmlNodeSetPtr ns1;
5169
0
    xmlNodeSetPtr ns2;
5170
5171
0
    if ((arg1 == NULL) ||
5172
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5173
0
  xmlXPathFreeObject(arg2);
5174
0
        return(0);
5175
0
    }
5176
0
    if ((arg2 == NULL) ||
5177
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5178
0
  xmlXPathFreeObject(arg1);
5179
0
  xmlXPathFreeObject(arg2);
5180
0
        return(0);
5181
0
    }
5182
5183
0
    ns1 = arg1->nodesetval;
5184
0
    ns2 = arg2->nodesetval;
5185
5186
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5187
0
  xmlXPathFreeObject(arg1);
5188
0
  xmlXPathFreeObject(arg2);
5189
0
  return(0);
5190
0
    }
5191
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5192
0
  xmlXPathFreeObject(arg1);
5193
0
  xmlXPathFreeObject(arg2);
5194
0
  return(0);
5195
0
    }
5196
5197
0
    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5198
0
    if (values2 == NULL) {
5199
0
        xmlXPathPErrMemory(ctxt);
5200
0
  xmlXPathFreeObject(arg1);
5201
0
  xmlXPathFreeObject(arg2);
5202
0
  return(0);
5203
0
    }
5204
0
    for (i = 0;i < ns1->nodeNr;i++) {
5205
0
  val1 = xmlXPathNodeToNumberInternal(ctxt, ns1->nodeTab[i]);
5206
0
  if (xmlXPathIsNaN(val1))
5207
0
      continue;
5208
0
  for (j = 0;j < ns2->nodeNr;j++) {
5209
0
      if (init == 0) {
5210
0
    values2[j] = xmlXPathNodeToNumberInternal(ctxt,
5211
0
                                                          ns2->nodeTab[j]);
5212
0
      }
5213
0
      if (xmlXPathIsNaN(values2[j]))
5214
0
    continue;
5215
0
      if (inf && strict)
5216
0
    ret = (val1 < values2[j]);
5217
0
      else if (inf && !strict)
5218
0
    ret = (val1 <= values2[j]);
5219
0
      else if (!inf && strict)
5220
0
    ret = (val1 > values2[j]);
5221
0
      else if (!inf && !strict)
5222
0
    ret = (val1 >= values2[j]);
5223
0
      if (ret)
5224
0
    break;
5225
0
  }
5226
0
  if (ret)
5227
0
      break;
5228
0
  init = 1;
5229
0
    }
5230
0
    xmlFree(values2);
5231
0
    xmlXPathFreeObject(arg1);
5232
0
    xmlXPathFreeObject(arg2);
5233
0
    return(ret);
5234
0
}
5235
5236
/**
5237
 * Implement the compare operation between a nodeset and a value
5238
 *     `ns` < `val`    (1, 1, ...
5239
 *     `ns` <= `val`   (1, 0, ...
5240
 *     `ns` > `val`    (0, 1, ...
5241
 *     `ns` >= `val`   (0, 0, ...
5242
 *
5243
 * If one object to be compared is a node-set and the other is a boolean,
5244
 * then the comparison will be true if and only if the result of performing
5245
 * the comparison on the boolean and on the result of converting
5246
 * the node-set to a boolean using the boolean function is true.
5247
 *
5248
 * @param ctxt  the XPath Parser context
5249
 * @param inf  less than (1) or greater than (0)
5250
 * @param strict  is the comparison strict
5251
 * @param arg  the node set
5252
 * @param val  the value
5253
 * @returns 0 or 1 depending on the results of the test.
5254
 */
5255
static int
5256
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
5257
0
                      xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
5258
0
    if ((val == NULL) || (arg == NULL) ||
5259
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5260
0
        return(0);
5261
5262
0
    switch(val->type) {
5263
0
        case XPATH_NUMBER:
5264
0
      return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
5265
0
        case XPATH_NODESET:
5266
0
        case XPATH_XSLT_TREE:
5267
0
      return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
5268
0
        case XPATH_STRING:
5269
0
      return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
5270
0
        case XPATH_BOOLEAN:
5271
0
      xmlXPathValuePush(ctxt, arg);
5272
0
      xmlXPathBooleanFunction(ctxt, 1);
5273
0
      xmlXPathValuePush(ctxt, val);
5274
0
      return(xmlXPathCompareValues(ctxt, inf, strict));
5275
0
  default:
5276
0
            xmlXPathReleaseObject(ctxt->context, arg);
5277
0
            xmlXPathReleaseObject(ctxt->context, val);
5278
0
            XP_ERROR0(XPATH_INVALID_TYPE);
5279
0
    }
5280
0
    return(0);
5281
0
}
5282
5283
/**
5284
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5285
 * If one object to be compared is a node-set and the other is a string,
5286
 * then the comparison will be true if and only if there is a node in
5287
 * the node-set such that the result of performing the comparison on the
5288
 * string-value of the node and the other string is true.
5289
 *
5290
 * @param ctxt  XPath parser context
5291
 * @param arg  the nodeset object argument
5292
 * @param str  the string to compare to.
5293
 * @param neq  flag to show whether for '=' (0) or '!=' (1)
5294
 * @returns 0 or 1 depending on the results of the test.
5295
 */
5296
static int
5297
xmlXPathEqualNodeSetString(xmlXPathParserContextPtr ctxt,
5298
                           xmlXPathObjectPtr arg, const xmlChar * str, int neq)
5299
0
{
5300
0
    int i;
5301
0
    xmlNodeSetPtr ns;
5302
0
    xmlChar *str2;
5303
0
    unsigned int hash;
5304
5305
0
    if ((str == NULL) || (arg == NULL) ||
5306
0
        ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5307
0
        return (0);
5308
0
    ns = arg->nodesetval;
5309
    /*
5310
     * A NULL nodeset compared with a string is always false
5311
     * (since there is no node equal, and no node not equal)
5312
     */
5313
0
    if ((ns == NULL) || (ns->nodeNr <= 0) )
5314
0
        return (0);
5315
0
    hash = xmlXPathStringHash(str);
5316
0
    for (i = 0; i < ns->nodeNr; i++) {
5317
0
        if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
5318
0
            str2 = xmlNodeGetContent(ns->nodeTab[i]);
5319
0
            if (str2 == NULL) {
5320
0
                xmlXPathPErrMemory(ctxt);
5321
0
                return(0);
5322
0
            }
5323
0
            if (xmlStrEqual(str, str2)) {
5324
0
                xmlFree(str2);
5325
0
    if (neq)
5326
0
        continue;
5327
0
                return (1);
5328
0
            } else if (neq) {
5329
0
    xmlFree(str2);
5330
0
    return (1);
5331
0
      }
5332
0
            xmlFree(str2);
5333
0
        } else if (neq)
5334
0
      return (1);
5335
0
    }
5336
0
    return (0);
5337
0
}
5338
5339
/**
5340
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5341
 * If one object to be compared is a node-set and the other is a number,
5342
 * then the comparison will be true if and only if there is a node in
5343
 * the node-set such that the result of performing the comparison on the
5344
 * number to be compared and on the result of converting the string-value
5345
 * of that node to a number using the number function is true.
5346
 *
5347
 * @param ctxt  XPath parser context
5348
 * @param arg  the nodeset object argument
5349
 * @param f  the float to compare to
5350
 * @param neq  flag to show whether to compare '=' (0) or '!=' (1)
5351
 * @returns 0 or 1 depending on the results of the test.
5352
 */
5353
static int
5354
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
5355
0
    xmlXPathObjectPtr arg, double f, int neq) {
5356
0
  int i, ret=0;
5357
0
  xmlNodeSetPtr ns;
5358
0
  xmlChar *str2;
5359
0
  xmlXPathObjectPtr val;
5360
0
  double v;
5361
5362
0
    if ((arg == NULL) ||
5363
0
  ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
5364
0
        return(0);
5365
5366
0
    ns = arg->nodesetval;
5367
0
    if (ns != NULL) {
5368
0
  for (i=0;i<ns->nodeNr;i++) {
5369
0
      str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5370
0
      if (str2 != NULL) {
5371
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, str2));
5372
0
    xmlFree(str2);
5373
0
    xmlXPathNumberFunction(ctxt, 1);
5374
0
                CHECK_ERROR0;
5375
0
    val = xmlXPathValuePop(ctxt);
5376
0
    v = val->floatval;
5377
0
    xmlXPathReleaseObject(ctxt->context, val);
5378
0
    if (!xmlXPathIsNaN(v)) {
5379
0
        if ((!neq) && (v==f)) {
5380
0
      ret = 1;
5381
0
      break;
5382
0
        } else if ((neq) && (v!=f)) {
5383
0
      ret = 1;
5384
0
      break;
5385
0
        }
5386
0
    } else { /* NaN is unequal to any value */
5387
0
        if (neq)
5388
0
      ret = 1;
5389
0
    }
5390
0
      } else {
5391
0
                xmlXPathPErrMemory(ctxt);
5392
0
            }
5393
0
  }
5394
0
    }
5395
5396
0
    return(ret);
5397
0
}
5398
5399
5400
/**
5401
 * Implement the equal / not equal operation on XPath nodesets:
5402
 * `arg1` == `arg2`  or  `arg1` != `arg2`
5403
 * If both objects to be compared are node-sets, then the comparison
5404
 * will be true if and only if there is a node in the first node-set and
5405
 * a node in the second node-set such that the result of performing the
5406
 * comparison on the string-values of the two nodes is true.
5407
 *
5408
 * (needless to say, this is a costly operation)
5409
 *
5410
 * @param ctxt  XPath parser context
5411
 * @param arg1  first nodeset object argument
5412
 * @param arg2  second nodeset object argument
5413
 * @param neq  flag to show whether to test '=' (0) or '!=' (1)
5414
 * @returns 0 or 1 depending on the results of the test.
5415
 */
5416
static int
5417
xmlXPathEqualNodeSets(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr arg1,
5418
0
                      xmlXPathObjectPtr arg2, int neq) {
5419
0
    int i, j;
5420
0
    unsigned int *hashs1;
5421
0
    unsigned int *hashs2;
5422
0
    xmlChar **values1;
5423
0
    xmlChar **values2;
5424
0
    int ret = 0;
5425
0
    xmlNodeSetPtr ns1;
5426
0
    xmlNodeSetPtr ns2;
5427
5428
0
    if ((arg1 == NULL) ||
5429
0
  ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
5430
0
        return(0);
5431
0
    if ((arg2 == NULL) ||
5432
0
  ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
5433
0
        return(0);
5434
5435
0
    ns1 = arg1->nodesetval;
5436
0
    ns2 = arg2->nodesetval;
5437
5438
0
    if ((ns1 == NULL) || (ns1->nodeNr <= 0))
5439
0
  return(0);
5440
0
    if ((ns2 == NULL) || (ns2->nodeNr <= 0))
5441
0
  return(0);
5442
5443
    /*
5444
     * for equal, check if there is a node pertaining to both sets
5445
     */
5446
0
    if (neq == 0)
5447
0
  for (i = 0;i < ns1->nodeNr;i++)
5448
0
      for (j = 0;j < ns2->nodeNr;j++)
5449
0
    if (ns1->nodeTab[i] == ns2->nodeTab[j])
5450
0
        return(1);
5451
5452
0
    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
5453
0
    if (values1 == NULL) {
5454
0
        xmlXPathPErrMemory(ctxt);
5455
0
  return(0);
5456
0
    }
5457
0
    hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
5458
0
    if (hashs1 == NULL) {
5459
0
        xmlXPathPErrMemory(ctxt);
5460
0
  xmlFree(values1);
5461
0
  return(0);
5462
0
    }
5463
0
    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
5464
0
    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
5465
0
    if (values2 == NULL) {
5466
0
        xmlXPathPErrMemory(ctxt);
5467
0
  xmlFree(hashs1);
5468
0
  xmlFree(values1);
5469
0
  return(0);
5470
0
    }
5471
0
    hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
5472
0
    if (hashs2 == NULL) {
5473
0
        xmlXPathPErrMemory(ctxt);
5474
0
  xmlFree(hashs1);
5475
0
  xmlFree(values1);
5476
0
  xmlFree(values2);
5477
0
  return(0);
5478
0
    }
5479
0
    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
5480
0
    for (i = 0;i < ns1->nodeNr;i++) {
5481
0
  hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
5482
0
  for (j = 0;j < ns2->nodeNr;j++) {
5483
0
      if (i == 0)
5484
0
    hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
5485
0
      if (hashs1[i] != hashs2[j]) {
5486
0
    if (neq) {
5487
0
        ret = 1;
5488
0
        break;
5489
0
    }
5490
0
      }
5491
0
      else {
5492
0
    if (values1[i] == NULL) {
5493
0
        values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
5494
0
                    if (values1[i] == NULL)
5495
0
                        xmlXPathPErrMemory(ctxt);
5496
0
                }
5497
0
    if (values2[j] == NULL) {
5498
0
        values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
5499
0
                    if (values2[j] == NULL)
5500
0
                        xmlXPathPErrMemory(ctxt);
5501
0
                }
5502
0
    ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
5503
0
    if (ret)
5504
0
        break;
5505
0
      }
5506
0
  }
5507
0
  if (ret)
5508
0
      break;
5509
0
    }
5510
0
    for (i = 0;i < ns1->nodeNr;i++)
5511
0
  if (values1[i] != NULL)
5512
0
      xmlFree(values1[i]);
5513
0
    for (j = 0;j < ns2->nodeNr;j++)
5514
0
  if (values2[j] != NULL)
5515
0
      xmlFree(values2[j]);
5516
0
    xmlFree(values1);
5517
0
    xmlFree(values2);
5518
0
    xmlFree(hashs1);
5519
0
    xmlFree(hashs2);
5520
0
    return(ret);
5521
0
}
5522
5523
static int
5524
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
5525
0
  xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5526
0
    int ret = 0;
5527
    /*
5528
     *At this point we are assured neither arg1 nor arg2
5529
     *is a nodeset, so we can just pick the appropriate routine.
5530
     */
5531
0
    switch (arg1->type) {
5532
0
        case XPATH_UNDEFINED:
5533
0
      break;
5534
0
        case XPATH_BOOLEAN:
5535
0
      switch (arg2->type) {
5536
0
          case XPATH_UNDEFINED:
5537
0
        break;
5538
0
    case XPATH_BOOLEAN:
5539
0
        ret = (arg1->boolval == arg2->boolval);
5540
0
        break;
5541
0
    case XPATH_NUMBER:
5542
0
        ret = (arg1->boolval ==
5543
0
         xmlXPathCastNumberToBoolean(arg2->floatval));
5544
0
        break;
5545
0
    case XPATH_STRING:
5546
0
        if ((arg2->stringval == NULL) ||
5547
0
      (arg2->stringval[0] == 0)) ret = 0;
5548
0
        else
5549
0
      ret = 1;
5550
0
        ret = (arg1->boolval == ret);
5551
0
        break;
5552
0
    case XPATH_USERS:
5553
        /* TODO */
5554
0
        break;
5555
0
    case XPATH_NODESET:
5556
0
    case XPATH_XSLT_TREE:
5557
0
        break;
5558
0
      }
5559
0
      break;
5560
0
        case XPATH_NUMBER:
5561
0
      switch (arg2->type) {
5562
0
          case XPATH_UNDEFINED:
5563
0
        break;
5564
0
    case XPATH_BOOLEAN:
5565
0
        ret = (arg2->boolval==
5566
0
         xmlXPathCastNumberToBoolean(arg1->floatval));
5567
0
        break;
5568
0
    case XPATH_STRING:
5569
0
        xmlXPathValuePush(ctxt, arg2);
5570
0
        xmlXPathNumberFunction(ctxt, 1);
5571
0
        arg2 = xmlXPathValuePop(ctxt);
5572
0
                    if (ctxt->error)
5573
0
                        break;
5574
                    /* Falls through. */
5575
0
    case XPATH_NUMBER:
5576
        /* Hand check NaN and Infinity equalities */
5577
0
        if (xmlXPathIsNaN(arg1->floatval) ||
5578
0
          xmlXPathIsNaN(arg2->floatval)) {
5579
0
            ret = 0;
5580
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5581
0
            if (xmlXPathIsInf(arg2->floatval) == 1)
5582
0
          ret = 1;
5583
0
      else
5584
0
          ret = 0;
5585
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5586
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
5587
0
          ret = 1;
5588
0
      else
5589
0
          ret = 0;
5590
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5591
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
5592
0
          ret = 1;
5593
0
      else
5594
0
          ret = 0;
5595
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5596
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5597
0
          ret = 1;
5598
0
      else
5599
0
          ret = 0;
5600
0
        } else {
5601
0
            ret = (arg1->floatval == arg2->floatval);
5602
0
        }
5603
0
        break;
5604
0
    case XPATH_USERS:
5605
        /* TODO */
5606
0
        break;
5607
0
    case XPATH_NODESET:
5608
0
    case XPATH_XSLT_TREE:
5609
0
        break;
5610
0
      }
5611
0
      break;
5612
0
        case XPATH_STRING:
5613
0
      switch (arg2->type) {
5614
0
          case XPATH_UNDEFINED:
5615
0
        break;
5616
0
    case XPATH_BOOLEAN:
5617
0
        if ((arg1->stringval == NULL) ||
5618
0
      (arg1->stringval[0] == 0)) ret = 0;
5619
0
        else
5620
0
      ret = 1;
5621
0
        ret = (arg2->boolval == ret);
5622
0
        break;
5623
0
    case XPATH_STRING:
5624
0
        ret = xmlStrEqual(arg1->stringval, arg2->stringval);
5625
0
        break;
5626
0
    case XPATH_NUMBER:
5627
0
        xmlXPathValuePush(ctxt, arg1);
5628
0
        xmlXPathNumberFunction(ctxt, 1);
5629
0
        arg1 = xmlXPathValuePop(ctxt);
5630
0
                    if (ctxt->error)
5631
0
                        break;
5632
        /* Hand check NaN and Infinity equalities */
5633
0
        if (xmlXPathIsNaN(arg1->floatval) ||
5634
0
          xmlXPathIsNaN(arg2->floatval)) {
5635
0
            ret = 0;
5636
0
        } else if (xmlXPathIsInf(arg1->floatval) == 1) {
5637
0
      if (xmlXPathIsInf(arg2->floatval) == 1)
5638
0
          ret = 1;
5639
0
      else
5640
0
          ret = 0;
5641
0
        } else if (xmlXPathIsInf(arg1->floatval) == -1) {
5642
0
      if (xmlXPathIsInf(arg2->floatval) == -1)
5643
0
          ret = 1;
5644
0
      else
5645
0
          ret = 0;
5646
0
        } else if (xmlXPathIsInf(arg2->floatval) == 1) {
5647
0
      if (xmlXPathIsInf(arg1->floatval) == 1)
5648
0
          ret = 1;
5649
0
      else
5650
0
          ret = 0;
5651
0
        } else if (xmlXPathIsInf(arg2->floatval) == -1) {
5652
0
      if (xmlXPathIsInf(arg1->floatval) == -1)
5653
0
          ret = 1;
5654
0
      else
5655
0
          ret = 0;
5656
0
        } else {
5657
0
            ret = (arg1->floatval == arg2->floatval);
5658
0
        }
5659
0
        break;
5660
0
    case XPATH_USERS:
5661
        /* TODO */
5662
0
        break;
5663
0
    case XPATH_NODESET:
5664
0
    case XPATH_XSLT_TREE:
5665
0
        break;
5666
0
      }
5667
0
      break;
5668
0
        case XPATH_USERS:
5669
      /* TODO */
5670
0
      break;
5671
0
  case XPATH_NODESET:
5672
0
  case XPATH_XSLT_TREE:
5673
0
      break;
5674
0
    }
5675
0
    xmlXPathReleaseObject(ctxt->context, arg1);
5676
0
    xmlXPathReleaseObject(ctxt->context, arg2);
5677
0
    return(ret);
5678
0
}
5679
5680
/**
5681
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5682
 *
5683
 * @param ctxt  the XPath Parser context
5684
 * @returns 0 or 1 depending on the results of the test.
5685
 */
5686
int
5687
0
xmlXPathEqualValues(xmlXPathParserContext *ctxt) {
5688
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
5689
0
    int ret = 0;
5690
5691
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5692
0
    arg2 = xmlXPathValuePop(ctxt);
5693
0
    arg1 = xmlXPathValuePop(ctxt);
5694
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
5695
0
  if (arg1 != NULL)
5696
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5697
0
  else
5698
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5699
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5700
0
    }
5701
5702
0
    if (arg1 == arg2) {
5703
0
  xmlXPathFreeObject(arg1);
5704
0
        return(1);
5705
0
    }
5706
5707
    /*
5708
     *If either argument is a nodeset, it's a 'special case'
5709
     */
5710
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5711
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5712
  /*
5713
   *Hack it to assure arg1 is the nodeset
5714
   */
5715
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5716
0
    argtmp = arg2;
5717
0
    arg2 = arg1;
5718
0
    arg1 = argtmp;
5719
0
  }
5720
0
  switch (arg2->type) {
5721
0
      case XPATH_UNDEFINED:
5722
0
    break;
5723
0
      case XPATH_NODESET:
5724
0
      case XPATH_XSLT_TREE:
5725
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 0);
5726
0
    break;
5727
0
      case XPATH_BOOLEAN:
5728
0
    if ((arg1->nodesetval == NULL) ||
5729
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5730
0
    else
5731
0
        ret = 1;
5732
0
    ret = (ret == arg2->boolval);
5733
0
    break;
5734
0
      case XPATH_NUMBER:
5735
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
5736
0
    break;
5737
0
      case XPATH_STRING:
5738
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5739
0
                                                 arg2->stringval, 0);
5740
0
    break;
5741
0
      case XPATH_USERS:
5742
    /* TODO */
5743
0
    break;
5744
0
  }
5745
0
  xmlXPathReleaseObject(ctxt->context, arg1);
5746
0
  xmlXPathReleaseObject(ctxt->context, arg2);
5747
0
  return(ret);
5748
0
    }
5749
5750
0
    return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5751
0
}
5752
5753
/**
5754
 * Implement the equal operation on XPath objects content: `arg1` == `arg2`
5755
 *
5756
 * @param ctxt  the XPath Parser context
5757
 * @returns 0 or 1 depending on the results of the test.
5758
 */
5759
int
5760
0
xmlXPathNotEqualValues(xmlXPathParserContext *ctxt) {
5761
0
    xmlXPathObjectPtr arg1, arg2, argtmp;
5762
0
    int ret = 0;
5763
5764
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5765
0
    arg2 = xmlXPathValuePop(ctxt);
5766
0
    arg1 = xmlXPathValuePop(ctxt);
5767
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
5768
0
  if (arg1 != NULL)
5769
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5770
0
  else
5771
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5772
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5773
0
    }
5774
5775
0
    if (arg1 == arg2) {
5776
0
  xmlXPathReleaseObject(ctxt->context, arg1);
5777
0
        return(0);
5778
0
    }
5779
5780
    /*
5781
     *If either argument is a nodeset, it's a 'special case'
5782
     */
5783
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5784
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5785
  /*
5786
   *Hack it to assure arg1 is the nodeset
5787
   */
5788
0
  if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
5789
0
    argtmp = arg2;
5790
0
    arg2 = arg1;
5791
0
    arg1 = argtmp;
5792
0
  }
5793
0
  switch (arg2->type) {
5794
0
      case XPATH_UNDEFINED:
5795
0
    break;
5796
0
      case XPATH_NODESET:
5797
0
      case XPATH_XSLT_TREE:
5798
0
    ret = xmlXPathEqualNodeSets(ctxt, arg1, arg2, 1);
5799
0
    break;
5800
0
      case XPATH_BOOLEAN:
5801
0
    if ((arg1->nodesetval == NULL) ||
5802
0
      (arg1->nodesetval->nodeNr == 0)) ret = 0;
5803
0
    else
5804
0
        ret = 1;
5805
0
    ret = (ret != arg2->boolval);
5806
0
    break;
5807
0
      case XPATH_NUMBER:
5808
0
    ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
5809
0
    break;
5810
0
      case XPATH_STRING:
5811
0
    ret = xmlXPathEqualNodeSetString(ctxt, arg1,
5812
0
                                                 arg2->stringval, 1);
5813
0
    break;
5814
0
      case XPATH_USERS:
5815
    /* TODO */
5816
0
    break;
5817
0
  }
5818
0
  xmlXPathReleaseObject(ctxt->context, arg1);
5819
0
  xmlXPathReleaseObject(ctxt->context, arg2);
5820
0
  return(ret);
5821
0
    }
5822
5823
0
    return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
5824
0
}
5825
5826
/**
5827
 * Implement the compare operation on XPath objects:
5828
 *     `arg1` < `arg2`    (1, 1, ...
5829
 *     `arg1` <= `arg2`   (1, 0, ...
5830
 *     `arg1` > `arg2`    (0, 1, ...
5831
 *     `arg1` >= `arg2`   (0, 0, ...
5832
 *
5833
 * When neither object to be compared is a node-set and the operator is
5834
 * <=, <, >=, >, then the objects are compared by converted both objects
5835
 * to numbers and comparing the numbers according to IEEE 754. The <
5836
 * comparison will be true if and only if the first number is less than the
5837
 * second number. The <= comparison will be true if and only if the first
5838
 * number is less than or equal to the second number. The > comparison
5839
 * will be true if and only if the first number is greater than the second
5840
 * number. The >= comparison will be true if and only if the first number
5841
 * is greater than or equal to the second number.
5842
 *
5843
 * @param ctxt  the XPath Parser context
5844
 * @param inf  less than (1) or greater than (0)
5845
 * @param strict  is the comparison strict
5846
 * @returns 1 if the comparison succeeded, 0 if it failed
5847
 */
5848
int
5849
0
xmlXPathCompareValues(xmlXPathParserContext *ctxt, int inf, int strict) {
5850
0
    int ret = 0, arg1i = 0, arg2i = 0;
5851
0
    xmlXPathObjectPtr arg1, arg2;
5852
5853
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
5854
0
    arg2 = xmlXPathValuePop(ctxt);
5855
0
    arg1 = xmlXPathValuePop(ctxt);
5856
0
    if ((arg1 == NULL) || (arg2 == NULL)) {
5857
0
  if (arg1 != NULL)
5858
0
      xmlXPathReleaseObject(ctxt->context, arg1);
5859
0
  else
5860
0
      xmlXPathReleaseObject(ctxt->context, arg2);
5861
0
  XP_ERROR0(XPATH_INVALID_OPERAND);
5862
0
    }
5863
5864
0
    if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
5865
0
      (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5866
  /*
5867
   * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
5868
   * are not freed from within this routine; they will be freed from the
5869
   * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
5870
   */
5871
0
  if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
5872
0
    ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
5873
0
      ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
5874
0
  } else {
5875
0
      if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
5876
0
    ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
5877
0
                                arg1, arg2);
5878
0
      } else {
5879
0
    ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
5880
0
                                arg2, arg1);
5881
0
      }
5882
0
  }
5883
0
  return(ret);
5884
0
    }
5885
5886
0
    if (arg1->type != XPATH_NUMBER) {
5887
0
  xmlXPathValuePush(ctxt, arg1);
5888
0
  xmlXPathNumberFunction(ctxt, 1);
5889
0
  arg1 = xmlXPathValuePop(ctxt);
5890
0
    }
5891
0
    if (arg2->type != XPATH_NUMBER) {
5892
0
  xmlXPathValuePush(ctxt, arg2);
5893
0
  xmlXPathNumberFunction(ctxt, 1);
5894
0
  arg2 = xmlXPathValuePop(ctxt);
5895
0
    }
5896
0
    if (ctxt->error)
5897
0
        goto error;
5898
    /*
5899
     * Add tests for infinity and nan
5900
     * => feedback on 3.4 for Inf and NaN
5901
     */
5902
    /* Hand check NaN and Infinity comparisons */
5903
0
    if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
5904
0
  ret=0;
5905
0
    } else {
5906
0
  arg1i=xmlXPathIsInf(arg1->floatval);
5907
0
  arg2i=xmlXPathIsInf(arg2->floatval);
5908
0
  if (inf && strict) {
5909
0
      if ((arg1i == -1 && arg2i != -1) ||
5910
0
    (arg2i == 1 && arg1i != 1)) {
5911
0
    ret = 1;
5912
0
      } else if (arg1i == 0 && arg2i == 0) {
5913
0
    ret = (arg1->floatval < arg2->floatval);
5914
0
      } else {
5915
0
    ret = 0;
5916
0
      }
5917
0
  }
5918
0
  else if (inf && !strict) {
5919
0
      if (arg1i == -1 || arg2i == 1) {
5920
0
    ret = 1;
5921
0
      } else if (arg1i == 0 && arg2i == 0) {
5922
0
    ret = (arg1->floatval <= arg2->floatval);
5923
0
      } else {
5924
0
    ret = 0;
5925
0
      }
5926
0
  }
5927
0
  else if (!inf && strict) {
5928
0
      if ((arg1i == 1 && arg2i != 1) ||
5929
0
    (arg2i == -1 && arg1i != -1)) {
5930
0
    ret = 1;
5931
0
      } else if (arg1i == 0 && arg2i == 0) {
5932
0
    ret = (arg1->floatval > arg2->floatval);
5933
0
      } else {
5934
0
    ret = 0;
5935
0
      }
5936
0
  }
5937
0
  else if (!inf && !strict) {
5938
0
      if (arg1i == 1 || arg2i == -1) {
5939
0
    ret = 1;
5940
0
      } else if (arg1i == 0 && arg2i == 0) {
5941
0
    ret = (arg1->floatval >= arg2->floatval);
5942
0
      } else {
5943
0
    ret = 0;
5944
0
      }
5945
0
  }
5946
0
    }
5947
0
error:
5948
0
    xmlXPathReleaseObject(ctxt->context, arg1);
5949
0
    xmlXPathReleaseObject(ctxt->context, arg2);
5950
0
    return(ret);
5951
0
}
5952
5953
/**
5954
 * Implement the unary - operation on an XPath object
5955
 * The numeric operators convert their operands to numbers as if
5956
 * by calling the number function.
5957
 *
5958
 * @param ctxt  the XPath Parser context
5959
 */
5960
void
5961
0
xmlXPathValueFlipSign(xmlXPathParserContext *ctxt) {
5962
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return;
5963
0
    CAST_TO_NUMBER;
5964
0
    CHECK_TYPE(XPATH_NUMBER);
5965
0
    ctxt->value->floatval = -ctxt->value->floatval;
5966
0
}
5967
5968
/**
5969
 * Implement the add operation on XPath objects:
5970
 * The numeric operators convert their operands to numbers as if
5971
 * by calling the number function.
5972
 *
5973
 * @param ctxt  the XPath Parser context
5974
 */
5975
void
5976
0
xmlXPathAddValues(xmlXPathParserContext *ctxt) {
5977
0
    xmlXPathObjectPtr arg;
5978
0
    double val;
5979
5980
0
    arg = xmlXPathValuePop(ctxt);
5981
0
    if (arg == NULL)
5982
0
  XP_ERROR(XPATH_INVALID_OPERAND);
5983
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
5984
0
    xmlXPathReleaseObject(ctxt->context, arg);
5985
0
    CAST_TO_NUMBER;
5986
0
    CHECK_TYPE(XPATH_NUMBER);
5987
0
    ctxt->value->floatval += val;
5988
0
}
5989
5990
/**
5991
 * Implement the subtraction operation on XPath objects:
5992
 * The numeric operators convert their operands to numbers as if
5993
 * by calling the number function.
5994
 *
5995
 * @param ctxt  the XPath Parser context
5996
 */
5997
void
5998
0
xmlXPathSubValues(xmlXPathParserContext *ctxt) {
5999
0
    xmlXPathObjectPtr arg;
6000
0
    double val;
6001
6002
0
    arg = xmlXPathValuePop(ctxt);
6003
0
    if (arg == NULL)
6004
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6005
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6006
0
    xmlXPathReleaseObject(ctxt->context, arg);
6007
0
    CAST_TO_NUMBER;
6008
0
    CHECK_TYPE(XPATH_NUMBER);
6009
0
    ctxt->value->floatval -= val;
6010
0
}
6011
6012
/**
6013
 * Implement the multiply operation on XPath objects:
6014
 * The numeric operators convert their operands to numbers as if
6015
 * by calling the number function.
6016
 *
6017
 * @param ctxt  the XPath Parser context
6018
 */
6019
void
6020
0
xmlXPathMultValues(xmlXPathParserContext *ctxt) {
6021
0
    xmlXPathObjectPtr arg;
6022
0
    double val;
6023
6024
0
    arg = xmlXPathValuePop(ctxt);
6025
0
    if (arg == NULL)
6026
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6027
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6028
0
    xmlXPathReleaseObject(ctxt->context, arg);
6029
0
    CAST_TO_NUMBER;
6030
0
    CHECK_TYPE(XPATH_NUMBER);
6031
0
    ctxt->value->floatval *= val;
6032
0
}
6033
6034
/**
6035
 * Implement the div operation on XPath objects `arg1` / `arg2`.
6036
 * The numeric operators convert their operands to numbers as if
6037
 * by calling the number function.
6038
 *
6039
 * @param ctxt  the XPath Parser context
6040
 */
6041
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6042
void
6043
0
xmlXPathDivValues(xmlXPathParserContext *ctxt) {
6044
0
    xmlXPathObjectPtr arg;
6045
0
    double val;
6046
6047
0
    arg = xmlXPathValuePop(ctxt);
6048
0
    if (arg == NULL)
6049
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6050
0
    val = xmlXPathCastToNumberInternal(ctxt, arg);
6051
0
    xmlXPathReleaseObject(ctxt->context, arg);
6052
0
    CAST_TO_NUMBER;
6053
0
    CHECK_TYPE(XPATH_NUMBER);
6054
0
    ctxt->value->floatval /= val;
6055
0
}
6056
6057
/**
6058
 * Implement the mod operation on XPath objects: `arg1` / `arg2`
6059
 * The numeric operators convert their operands to numbers as if
6060
 * by calling the number function.
6061
 *
6062
 * @param ctxt  the XPath Parser context
6063
 */
6064
void
6065
0
xmlXPathModValues(xmlXPathParserContext *ctxt) {
6066
0
    xmlXPathObjectPtr arg;
6067
0
    double arg1, arg2;
6068
6069
0
    arg = xmlXPathValuePop(ctxt);
6070
0
    if (arg == NULL)
6071
0
  XP_ERROR(XPATH_INVALID_OPERAND);
6072
0
    arg2 = xmlXPathCastToNumberInternal(ctxt, arg);
6073
0
    xmlXPathReleaseObject(ctxt->context, arg);
6074
0
    CAST_TO_NUMBER;
6075
0
    CHECK_TYPE(XPATH_NUMBER);
6076
0
    arg1 = ctxt->value->floatval;
6077
0
    if (arg2 == 0)
6078
0
  ctxt->value->floatval = xmlXPathNAN;
6079
0
    else {
6080
0
  ctxt->value->floatval = fmod(arg1, arg2);
6081
0
    }
6082
0
}
6083
6084
/************************************************************************
6085
 *                  *
6086
 *    The traversal functions         *
6087
 *                  *
6088
 ************************************************************************/
6089
6090
/*
6091
 * A traversal function enumerates nodes along an axis.
6092
 * Initially it must be called with NULL, and it indicates
6093
 * termination on the axis by returning NULL.
6094
 */
6095
typedef xmlNode *(*xmlXPathTraversalFunction)
6096
                    (xmlXPathParserContext *ctxt, xmlNode *cur);
6097
6098
/*
6099
 * A traversal function enumerates nodes along an axis.
6100
 * Initially it must be called with NULL, and it indicates
6101
 * termination on the axis by returning NULL.
6102
 * The context node of the traversal is specified via `contextNode`.
6103
 */
6104
typedef xmlNode *(*xmlXPathTraversalFunctionExt)
6105
                    (xmlNode *cur, xmlNode *contextNode);
6106
6107
/*
6108
 * Used for merging node sets in #xmlXPathCollectAndTest.
6109
 */
6110
typedef xmlNodeSet *(*xmlXPathNodeSetMergeFunction)
6111
        (xmlNodeSet *, xmlNodeSet *);
6112
6113
6114
/**
6115
 * Traversal function for the "self" direction
6116
 * The self axis contains just the context node itself
6117
 *
6118
 * @param ctxt  the XPath Parser context
6119
 * @param cur  the current node in the traversal
6120
 * @returns the next element following that axis
6121
 */
6122
xmlNode *
6123
0
xmlXPathNextSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6124
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6125
0
    if (cur == NULL)
6126
0
        return(ctxt->context->node);
6127
0
    return(NULL);
6128
0
}
6129
6130
/**
6131
 * Traversal function for the "child" direction
6132
 * The child axis contains the children of the context node in document order.
6133
 *
6134
 * @param ctxt  the XPath Parser context
6135
 * @param cur  the current node in the traversal
6136
 * @returns the next element following that axis
6137
 */
6138
xmlNode *
6139
0
xmlXPathNextChild(xmlXPathParserContext *ctxt, xmlNode *cur) {
6140
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6141
0
    if (cur == NULL) {
6142
0
  if (ctxt->context->node == NULL) return(NULL);
6143
0
  switch (ctxt->context->node->type) {
6144
0
            case XML_ELEMENT_NODE:
6145
0
            case XML_TEXT_NODE:
6146
0
            case XML_CDATA_SECTION_NODE:
6147
0
            case XML_ENTITY_REF_NODE:
6148
0
            case XML_ENTITY_NODE:
6149
0
            case XML_PI_NODE:
6150
0
            case XML_COMMENT_NODE:
6151
0
            case XML_NOTATION_NODE:
6152
0
            case XML_DTD_NODE:
6153
0
    return(ctxt->context->node->children);
6154
0
            case XML_DOCUMENT_NODE:
6155
0
            case XML_DOCUMENT_TYPE_NODE:
6156
0
            case XML_DOCUMENT_FRAG_NODE:
6157
0
            case XML_HTML_DOCUMENT_NODE:
6158
0
    return(((xmlDocPtr) ctxt->context->node)->children);
6159
0
      case XML_ELEMENT_DECL:
6160
0
      case XML_ATTRIBUTE_DECL:
6161
0
      case XML_ENTITY_DECL:
6162
0
            case XML_ATTRIBUTE_NODE:
6163
0
      case XML_NAMESPACE_DECL:
6164
0
      case XML_XINCLUDE_START:
6165
0
      case XML_XINCLUDE_END:
6166
0
    return(NULL);
6167
0
  }
6168
0
  return(NULL);
6169
0
    }
6170
0
    if ((cur->type == XML_DOCUMENT_NODE) ||
6171
0
        (cur->type == XML_HTML_DOCUMENT_NODE))
6172
0
  return(NULL);
6173
0
    return(cur->next);
6174
0
}
6175
6176
/**
6177
 * Traversal function for the "child" direction and nodes of type element.
6178
 * The child axis contains the children of the context node in document order.
6179
 *
6180
 * @param ctxt  the XPath Parser context
6181
 * @param cur  the current node in the traversal
6182
 * @returns the next element following that axis
6183
 */
6184
static xmlNodePtr
6185
0
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6186
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6187
0
    if (cur == NULL) {
6188
0
  cur = ctxt->context->node;
6189
0
  if (cur == NULL) return(NULL);
6190
  /*
6191
  * Get the first element child.
6192
  */
6193
0
  switch (cur->type) {
6194
0
            case XML_ELEMENT_NODE:
6195
0
      case XML_DOCUMENT_FRAG_NODE:
6196
0
      case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
6197
0
            case XML_ENTITY_NODE:
6198
0
    cur = cur->children;
6199
0
    if (cur != NULL) {
6200
0
        if (cur->type == XML_ELEMENT_NODE)
6201
0
      return(cur);
6202
0
        do {
6203
0
      cur = cur->next;
6204
0
        } while ((cur != NULL) &&
6205
0
      (cur->type != XML_ELEMENT_NODE));
6206
0
        return(cur);
6207
0
    }
6208
0
    return(NULL);
6209
0
            case XML_DOCUMENT_NODE:
6210
0
            case XML_HTML_DOCUMENT_NODE:
6211
0
    return(xmlDocGetRootElement((xmlDocPtr) cur));
6212
0
      default:
6213
0
    return(NULL);
6214
0
  }
6215
0
  return(NULL);
6216
0
    }
6217
    /*
6218
    * Get the next sibling element node.
6219
    */
6220
0
    switch (cur->type) {
6221
0
  case XML_ELEMENT_NODE:
6222
0
  case XML_TEXT_NODE:
6223
0
  case XML_ENTITY_REF_NODE:
6224
0
  case XML_ENTITY_NODE:
6225
0
  case XML_CDATA_SECTION_NODE:
6226
0
  case XML_PI_NODE:
6227
0
  case XML_COMMENT_NODE:
6228
0
  case XML_XINCLUDE_END:
6229
0
      break;
6230
  /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
6231
0
  default:
6232
0
      return(NULL);
6233
0
    }
6234
0
    if (cur->next != NULL) {
6235
0
  if (cur->next->type == XML_ELEMENT_NODE)
6236
0
      return(cur->next);
6237
0
  cur = cur->next;
6238
0
  do {
6239
0
      cur = cur->next;
6240
0
  } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
6241
0
  return(cur);
6242
0
    }
6243
0
    return(NULL);
6244
0
}
6245
6246
/**
6247
 * Traversal function for the "descendant" direction
6248
 * the descendant axis contains the descendants of the context node in document
6249
 * order; a descendant is a child or a child of a child and so on.
6250
 *
6251
 * @param ctxt  the XPath Parser context
6252
 * @param cur  the current node in the traversal
6253
 * @returns the next element following that axis
6254
 */
6255
xmlNode *
6256
0
xmlXPathNextDescendant(xmlXPathParserContext *ctxt, xmlNode *cur) {
6257
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6258
0
    if (cur == NULL) {
6259
0
  if (ctxt->context->node == NULL)
6260
0
      return(NULL);
6261
0
  if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6262
0
      (ctxt->context->node->type == XML_NAMESPACE_DECL))
6263
0
      return(NULL);
6264
6265
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6266
0
      return(ctxt->context->doc->children);
6267
0
        return(ctxt->context->node->children);
6268
0
    }
6269
6270
0
    if (cur->type == XML_NAMESPACE_DECL)
6271
0
        return(NULL);
6272
0
    if (cur->children != NULL) {
6273
  /*
6274
   * Do not descend on entities declarations
6275
   */
6276
0
  if (cur->children->type != XML_ENTITY_DECL) {
6277
0
      cur = cur->children;
6278
      /*
6279
       * Skip DTDs
6280
       */
6281
0
      if (cur->type != XML_DTD_NODE)
6282
0
    return(cur);
6283
0
  }
6284
0
    }
6285
6286
0
    if (cur == ctxt->context->node) return(NULL);
6287
6288
0
    while (cur->next != NULL) {
6289
0
  cur = cur->next;
6290
0
  if ((cur->type != XML_ENTITY_DECL) &&
6291
0
      (cur->type != XML_DTD_NODE))
6292
0
      return(cur);
6293
0
    }
6294
6295
0
    do {
6296
0
        cur = cur->parent;
6297
0
  if (cur == NULL) break;
6298
0
  if (cur == ctxt->context->node) return(NULL);
6299
0
  if (cur->next != NULL) {
6300
0
      cur = cur->next;
6301
0
      return(cur);
6302
0
  }
6303
0
    } while (cur != NULL);
6304
0
    return(cur);
6305
0
}
6306
6307
/**
6308
 * Traversal function for the "descendant-or-self" direction
6309
 * the descendant-or-self axis contains the context node and the descendants
6310
 * of the context node in document order; thus the context node is the first
6311
 * node on the axis, and the first child of the context node is the second node
6312
 * on the axis
6313
 *
6314
 * @param ctxt  the XPath Parser context
6315
 * @param cur  the current node in the traversal
6316
 * @returns the next element following that axis
6317
 */
6318
xmlNode *
6319
0
xmlXPathNextDescendantOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6320
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6321
0
    if (cur == NULL)
6322
0
        return(ctxt->context->node);
6323
6324
0
    if (ctxt->context->node == NULL)
6325
0
        return(NULL);
6326
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6327
0
        (ctxt->context->node->type == XML_NAMESPACE_DECL))
6328
0
        return(NULL);
6329
6330
0
    return(xmlXPathNextDescendant(ctxt, cur));
6331
0
}
6332
6333
/**
6334
 * Traversal function for the "parent" direction
6335
 * The parent axis contains the parent of the context node, if there is one.
6336
 *
6337
 * @param ctxt  the XPath Parser context
6338
 * @param cur  the current node in the traversal
6339
 * @returns the next element following that axis
6340
 */
6341
xmlNode *
6342
0
xmlXPathNextParent(xmlXPathParserContext *ctxt, xmlNode *cur) {
6343
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6344
    /*
6345
     * the parent of an attribute or namespace node is the element
6346
     * to which the attribute or namespace node is attached
6347
     * Namespace handling !!!
6348
     */
6349
0
    if (cur == NULL) {
6350
0
  if (ctxt->context->node == NULL) return(NULL);
6351
0
  switch (ctxt->context->node->type) {
6352
0
            case XML_ELEMENT_NODE:
6353
0
            case XML_TEXT_NODE:
6354
0
            case XML_CDATA_SECTION_NODE:
6355
0
            case XML_ENTITY_REF_NODE:
6356
0
            case XML_ENTITY_NODE:
6357
0
            case XML_PI_NODE:
6358
0
            case XML_COMMENT_NODE:
6359
0
            case XML_NOTATION_NODE:
6360
0
            case XML_DTD_NODE:
6361
0
      case XML_ELEMENT_DECL:
6362
0
      case XML_ATTRIBUTE_DECL:
6363
0
      case XML_XINCLUDE_START:
6364
0
      case XML_XINCLUDE_END:
6365
0
      case XML_ENTITY_DECL:
6366
0
    if (ctxt->context->node->parent == NULL)
6367
0
        return((xmlNodePtr) ctxt->context->doc);
6368
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6369
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6370
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6371
0
         BAD_CAST "fake node libxslt"))))
6372
0
        return(NULL);
6373
0
    return(ctxt->context->node->parent);
6374
0
            case XML_ATTRIBUTE_NODE: {
6375
0
    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
6376
6377
0
    return(att->parent);
6378
0
      }
6379
0
            case XML_DOCUMENT_NODE:
6380
0
            case XML_DOCUMENT_TYPE_NODE:
6381
0
            case XML_DOCUMENT_FRAG_NODE:
6382
0
            case XML_HTML_DOCUMENT_NODE:
6383
0
                return(NULL);
6384
0
      case XML_NAMESPACE_DECL: {
6385
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6386
6387
0
    if ((ns->next != NULL) &&
6388
0
        (ns->next->type != XML_NAMESPACE_DECL))
6389
0
        return((xmlNodePtr) ns->next);
6390
0
                return(NULL);
6391
0
      }
6392
0
  }
6393
0
    }
6394
0
    return(NULL);
6395
0
}
6396
6397
/**
6398
 * Traversal function for the "ancestor" direction
6399
 * the ancestor axis contains the ancestors of the context node; the ancestors
6400
 * of the context node consist of the parent of context node and the parent's
6401
 * parent and so on; the nodes are ordered in reverse document order; thus the
6402
 * parent is the first node on the axis, and the parent's parent is the second
6403
 * node on the axis
6404
 *
6405
 * @param ctxt  the XPath Parser context
6406
 * @param cur  the current node in the traversal
6407
 * @returns the next element following that axis
6408
 */
6409
xmlNode *
6410
0
xmlXPathNextAncestor(xmlXPathParserContext *ctxt, xmlNode *cur) {
6411
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6412
    /*
6413
     * the parent of an attribute or namespace node is the element
6414
     * to which the attribute or namespace node is attached
6415
     * !!!!!!!!!!!!!
6416
     */
6417
0
    if (cur == NULL) {
6418
0
  if (ctxt->context->node == NULL) return(NULL);
6419
0
  switch (ctxt->context->node->type) {
6420
0
            case XML_ELEMENT_NODE:
6421
0
            case XML_TEXT_NODE:
6422
0
            case XML_CDATA_SECTION_NODE:
6423
0
            case XML_ENTITY_REF_NODE:
6424
0
            case XML_ENTITY_NODE:
6425
0
            case XML_PI_NODE:
6426
0
            case XML_COMMENT_NODE:
6427
0
      case XML_DTD_NODE:
6428
0
      case XML_ELEMENT_DECL:
6429
0
      case XML_ATTRIBUTE_DECL:
6430
0
      case XML_ENTITY_DECL:
6431
0
            case XML_NOTATION_NODE:
6432
0
      case XML_XINCLUDE_START:
6433
0
      case XML_XINCLUDE_END:
6434
0
    if (ctxt->context->node->parent == NULL)
6435
0
        return((xmlNodePtr) ctxt->context->doc);
6436
0
    if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
6437
0
        ((ctxt->context->node->parent->name[0] == ' ') ||
6438
0
         (xmlStrEqual(ctxt->context->node->parent->name,
6439
0
         BAD_CAST "fake node libxslt"))))
6440
0
        return(NULL);
6441
0
    return(ctxt->context->node->parent);
6442
0
            case XML_ATTRIBUTE_NODE: {
6443
0
    xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
6444
6445
0
    return(tmp->parent);
6446
0
      }
6447
0
            case XML_DOCUMENT_NODE:
6448
0
            case XML_DOCUMENT_TYPE_NODE:
6449
0
            case XML_DOCUMENT_FRAG_NODE:
6450
0
            case XML_HTML_DOCUMENT_NODE:
6451
0
                return(NULL);
6452
0
      case XML_NAMESPACE_DECL: {
6453
0
    xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
6454
6455
0
    if ((ns->next != NULL) &&
6456
0
        (ns->next->type != XML_NAMESPACE_DECL))
6457
0
        return((xmlNodePtr) ns->next);
6458
    /* Bad, how did that namespace end up here ? */
6459
0
                return(NULL);
6460
0
      }
6461
0
  }
6462
0
  return(NULL);
6463
0
    }
6464
0
    if (cur == ctxt->context->doc->children)
6465
0
  return((xmlNodePtr) ctxt->context->doc);
6466
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6467
0
  return(NULL);
6468
0
    switch (cur->type) {
6469
0
  case XML_ELEMENT_NODE:
6470
0
  case XML_TEXT_NODE:
6471
0
  case XML_CDATA_SECTION_NODE:
6472
0
  case XML_ENTITY_REF_NODE:
6473
0
  case XML_ENTITY_NODE:
6474
0
  case XML_PI_NODE:
6475
0
  case XML_COMMENT_NODE:
6476
0
  case XML_NOTATION_NODE:
6477
0
  case XML_DTD_NODE:
6478
0
        case XML_ELEMENT_DECL:
6479
0
        case XML_ATTRIBUTE_DECL:
6480
0
        case XML_ENTITY_DECL:
6481
0
  case XML_XINCLUDE_START:
6482
0
  case XML_XINCLUDE_END:
6483
0
      if (cur->parent == NULL)
6484
0
    return(NULL);
6485
0
      if ((cur->parent->type == XML_ELEMENT_NODE) &&
6486
0
    ((cur->parent->name[0] == ' ') ||
6487
0
     (xmlStrEqual(cur->parent->name,
6488
0
            BAD_CAST "fake node libxslt"))))
6489
0
    return(NULL);
6490
0
      return(cur->parent);
6491
0
  case XML_ATTRIBUTE_NODE: {
6492
0
      xmlAttrPtr att = (xmlAttrPtr) cur;
6493
6494
0
      return(att->parent);
6495
0
  }
6496
0
  case XML_NAMESPACE_DECL: {
6497
0
      xmlNsPtr ns = (xmlNsPtr) cur;
6498
6499
0
      if ((ns->next != NULL) &&
6500
0
          (ns->next->type != XML_NAMESPACE_DECL))
6501
0
          return((xmlNodePtr) ns->next);
6502
      /* Bad, how did that namespace end up here ? */
6503
0
            return(NULL);
6504
0
  }
6505
0
  case XML_DOCUMENT_NODE:
6506
0
  case XML_DOCUMENT_TYPE_NODE:
6507
0
  case XML_DOCUMENT_FRAG_NODE:
6508
0
  case XML_HTML_DOCUMENT_NODE:
6509
0
      return(NULL);
6510
0
    }
6511
0
    return(NULL);
6512
0
}
6513
6514
/**
6515
 * Traversal function for the "ancestor-or-self" direction
6516
 * he ancestor-or-self axis contains the context node and ancestors of
6517
 * the context node in reverse document order; thus the context node is
6518
 * the first node on the axis, and the context node's parent the second;
6519
 * parent here is defined the same as with the parent axis.
6520
 *
6521
 * @param ctxt  the XPath Parser context
6522
 * @param cur  the current node in the traversal
6523
 * @returns the next element following that axis
6524
 */
6525
xmlNode *
6526
0
xmlXPathNextAncestorOrSelf(xmlXPathParserContext *ctxt, xmlNode *cur) {
6527
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6528
0
    if (cur == NULL)
6529
0
        return(ctxt->context->node);
6530
0
    return(xmlXPathNextAncestor(ctxt, cur));
6531
0
}
6532
6533
/**
6534
 * Traversal function for the "following-sibling" direction
6535
 * The following-sibling axis contains the following siblings of the context
6536
 * node in document order.
6537
 *
6538
 * @param ctxt  the XPath Parser context
6539
 * @param cur  the current node in the traversal
6540
 * @returns the next element following that axis
6541
 */
6542
xmlNode *
6543
0
xmlXPathNextFollowingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6544
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6545
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6546
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6547
0
  return(NULL);
6548
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6549
0
        return(NULL);
6550
0
    if (cur == NULL)
6551
0
        return(ctxt->context->node->next);
6552
0
    return(cur->next);
6553
0
}
6554
6555
/**
6556
 * Traversal function for the "preceding-sibling" direction
6557
 * The preceding-sibling axis contains the preceding siblings of the context
6558
 * node in reverse document order; the first preceding sibling is first on the
6559
 * axis; the sibling preceding that node is the second on the axis and so on.
6560
 *
6561
 * @param ctxt  the XPath Parser context
6562
 * @param cur  the current node in the traversal
6563
 * @returns the next element following that axis
6564
 */
6565
xmlNode *
6566
0
xmlXPathNextPrecedingSibling(xmlXPathParserContext *ctxt, xmlNode *cur) {
6567
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6568
0
    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
6569
0
  (ctxt->context->node->type == XML_NAMESPACE_DECL))
6570
0
  return(NULL);
6571
0
    if (cur == (xmlNodePtr) ctxt->context->doc)
6572
0
        return(NULL);
6573
0
    if (cur == NULL)
6574
0
        return(ctxt->context->node->prev);
6575
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
6576
0
  cur = cur->prev;
6577
0
  if (cur == NULL)
6578
0
      return(ctxt->context->node->prev);
6579
0
    }
6580
0
    return(cur->prev);
6581
0
}
6582
6583
/**
6584
 * Traversal function for the "following" direction
6585
 * The following axis contains all nodes in the same document as the context
6586
 * node that are after the context node in document order, excluding any
6587
 * descendants and excluding attribute nodes and namespace nodes; the nodes
6588
 * are ordered in document order
6589
 *
6590
 * @param ctxt  the XPath Parser context
6591
 * @param cur  the current node in the traversal
6592
 * @returns the next element following that axis
6593
 */
6594
xmlNode *
6595
0
xmlXPathNextFollowing(xmlXPathParserContext *ctxt, xmlNode *cur) {
6596
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6597
0
    if ((cur != NULL) && (cur->type  != XML_ATTRIBUTE_NODE) &&
6598
0
        (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
6599
0
        return(cur->children);
6600
6601
0
    if (cur == NULL) {
6602
0
        cur = ctxt->context->node;
6603
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6604
0
            cur = cur->parent;
6605
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6606
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6607
6608
0
            if ((ns->next == NULL) ||
6609
0
                (ns->next->type == XML_NAMESPACE_DECL))
6610
0
                return (NULL);
6611
0
            cur = (xmlNodePtr) ns->next;
6612
0
        }
6613
0
    }
6614
0
    if (cur == NULL) return(NULL) ; /* ERROR */
6615
0
    if (cur->next != NULL) return(cur->next) ;
6616
0
    do {
6617
0
        cur = cur->parent;
6618
0
        if (cur == NULL) break;
6619
0
        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
6620
0
        if (cur->next != NULL) return(cur->next);
6621
0
    } while (cur != NULL);
6622
0
    return(cur);
6623
0
}
6624
6625
/*
6626
 * @param ancestor  the ancestor node
6627
 * @param node  the current node
6628
 *
6629
 * Check that `ancestor` is a `node`'s ancestor
6630
 *
6631
 * @returns 1 if `ancestor` is a `node`'s ancestor, 0 otherwise.
6632
 */
6633
static int
6634
0
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
6635
0
    if ((ancestor == NULL) || (node == NULL)) return(0);
6636
0
    if (node->type == XML_NAMESPACE_DECL)
6637
0
        return(0);
6638
0
    if (ancestor->type == XML_NAMESPACE_DECL)
6639
0
        return(0);
6640
    /* nodes need to be in the same document */
6641
0
    if (ancestor->doc != node->doc) return(0);
6642
    /* avoid searching if ancestor or node is the root node */
6643
0
    if (ancestor == (xmlNodePtr) node->doc) return(1);
6644
0
    if (node == (xmlNodePtr) ancestor->doc) return(0);
6645
0
    while (node->parent != NULL) {
6646
0
        if (node->parent == ancestor)
6647
0
            return(1);
6648
0
  node = node->parent;
6649
0
    }
6650
0
    return(0);
6651
0
}
6652
6653
/**
6654
 * Traversal function for the "preceding" direction
6655
 * the preceding axis contains all nodes in the same document as the context
6656
 * node that are before the context node in document order, excluding any
6657
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6658
 * ordered in reverse document order
6659
 *
6660
 * @param ctxt  the XPath Parser context
6661
 * @param cur  the current node in the traversal
6662
 * @returns the next element following that axis
6663
 */
6664
xmlNode *
6665
xmlXPathNextPreceding(xmlXPathParserContext *ctxt, xmlNode *cur)
6666
0
{
6667
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6668
0
    if (cur == NULL) {
6669
0
        cur = ctxt->context->node;
6670
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6671
0
            cur = cur->parent;
6672
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6673
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6674
6675
0
            if ((ns->next == NULL) ||
6676
0
                (ns->next->type == XML_NAMESPACE_DECL))
6677
0
                return (NULL);
6678
0
            cur = (xmlNodePtr) ns->next;
6679
0
        }
6680
0
    }
6681
0
    if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
6682
0
  return (NULL);
6683
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6684
0
  cur = cur->prev;
6685
0
    do {
6686
0
        if (cur->prev != NULL) {
6687
0
            for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
6688
0
            return (cur);
6689
0
        }
6690
6691
0
        cur = cur->parent;
6692
0
        if (cur == NULL)
6693
0
            return (NULL);
6694
0
        if (cur == ctxt->context->doc->children)
6695
0
            return (NULL);
6696
0
    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
6697
0
    return (cur);
6698
0
}
6699
6700
/**
6701
 * Traversal function for the "preceding" direction
6702
 * the preceding axis contains all nodes in the same document as the context
6703
 * node that are before the context node in document order, excluding any
6704
 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
6705
 * ordered in reverse document order
6706
 * This is a faster implementation but internal only since it requires a
6707
 * state kept in the parser context: ctxt->ancestor.
6708
 *
6709
 * @param ctxt  the XPath Parser context
6710
 * @param cur  the current node in the traversal
6711
 * @returns the next element following that axis
6712
 */
6713
static xmlNodePtr
6714
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
6715
                              xmlNodePtr cur)
6716
0
{
6717
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6718
0
    if (cur == NULL) {
6719
0
        cur = ctxt->context->node;
6720
0
        if (cur == NULL)
6721
0
            return (NULL);
6722
0
        if (cur->type == XML_ATTRIBUTE_NODE) {
6723
0
            cur = cur->parent;
6724
0
        } else if (cur->type == XML_NAMESPACE_DECL) {
6725
0
            xmlNsPtr ns = (xmlNsPtr) cur;
6726
6727
0
            if ((ns->next == NULL) ||
6728
0
                (ns->next->type == XML_NAMESPACE_DECL))
6729
0
                return (NULL);
6730
0
            cur = (xmlNodePtr) ns->next;
6731
0
        }
6732
0
        ctxt->ancestor = cur->parent;
6733
0
    }
6734
0
    if (cur->type == XML_NAMESPACE_DECL)
6735
0
        return(NULL);
6736
0
    if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
6737
0
  cur = cur->prev;
6738
0
    while (cur->prev == NULL) {
6739
0
        cur = cur->parent;
6740
0
        if (cur == NULL)
6741
0
            return (NULL);
6742
0
        if (cur == ctxt->context->doc->children)
6743
0
            return (NULL);
6744
0
        if (cur != ctxt->ancestor)
6745
0
            return (cur);
6746
0
        ctxt->ancestor = cur->parent;
6747
0
    }
6748
0
    cur = cur->prev;
6749
0
    while (cur->last != NULL)
6750
0
        cur = cur->last;
6751
0
    return (cur);
6752
0
}
6753
6754
/**
6755
 * Traversal function for the "namespace" direction
6756
 * the namespace axis contains the namespace nodes of the context node;
6757
 * the order of nodes on this axis is implementation-defined; the axis will
6758
 * be empty unless the context node is an element
6759
 *
6760
 * We keep the XML namespace node at the end of the list.
6761
 *
6762
 * @param ctxt  the XPath Parser context
6763
 * @param cur  the current attribute in the traversal
6764
 * @returns the next element following that axis
6765
 */
6766
xmlNode *
6767
0
xmlXPathNextNamespace(xmlXPathParserContext *ctxt, xmlNode *cur) {
6768
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6769
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
6770
0
    if (cur == NULL) {
6771
0
        if (ctxt->context->tmpNsList != NULL)
6772
0
      xmlFree(ctxt->context->tmpNsList);
6773
0
  ctxt->context->tmpNsNr = 0;
6774
0
        if (xmlGetNsListSafe(ctxt->context->doc, ctxt->context->node,
6775
0
                             &ctxt->context->tmpNsList) < 0) {
6776
0
            xmlXPathPErrMemory(ctxt);
6777
0
            return(NULL);
6778
0
        }
6779
0
        if (ctxt->context->tmpNsList != NULL) {
6780
0
            while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
6781
0
                ctxt->context->tmpNsNr++;
6782
0
            }
6783
0
        }
6784
0
  return((xmlNodePtr) xmlXPathXMLNamespace);
6785
0
    }
6786
0
    if (ctxt->context->tmpNsNr > 0) {
6787
0
  return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
6788
0
    } else {
6789
0
  if (ctxt->context->tmpNsList != NULL)
6790
0
      xmlFree(ctxt->context->tmpNsList);
6791
0
  ctxt->context->tmpNsList = NULL;
6792
0
  return(NULL);
6793
0
    }
6794
0
}
6795
6796
/**
6797
 * Traversal function for the "attribute" direction
6798
 * TODO: support DTD inherited default attributes
6799
 *
6800
 * @param ctxt  the XPath Parser context
6801
 * @param cur  the current attribute in the traversal
6802
 * @returns the next element following that axis
6803
 */
6804
xmlNode *
6805
0
xmlXPathNextAttribute(xmlXPathParserContext *ctxt, xmlNode *cur) {
6806
0
    if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6807
0
    if (ctxt->context->node == NULL)
6808
0
  return(NULL);
6809
0
    if (ctxt->context->node->type != XML_ELEMENT_NODE)
6810
0
  return(NULL);
6811
0
    if (cur == NULL) {
6812
0
        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
6813
0
      return(NULL);
6814
0
        return((xmlNodePtr)ctxt->context->node->properties);
6815
0
    }
6816
0
    return((xmlNodePtr)cur->next);
6817
0
}
6818
6819
/************************************************************************
6820
 *                  *
6821
 *    NodeTest Functions          *
6822
 *                  *
6823
 ************************************************************************/
6824
6825
#define IS_FUNCTION     200
6826
6827
6828
/************************************************************************
6829
 *                  *
6830
 *    Implicit tree core function library     *
6831
 *                  *
6832
 ************************************************************************/
6833
6834
/**
6835
 * Initialize the context to the root of the document
6836
 *
6837
 * @param ctxt  the XPath Parser context
6838
 */
6839
void
6840
0
xmlXPathRoot(xmlXPathParserContext *ctxt) {
6841
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
6842
0
  return;
6843
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
6844
0
                                            (xmlNodePtr) ctxt->context->doc));
6845
0
}
6846
6847
/************************************************************************
6848
 *                  *
6849
 *    The explicit core function library      *
6850
 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
6851
 *                  *
6852
 ************************************************************************/
6853
6854
6855
/**
6856
 * Implement the last() XPath function
6857
 *    number last()
6858
 * The last function returns the number of nodes in the context node list.
6859
 *
6860
 * @param ctxt  the XPath Parser context
6861
 * @param nargs  the number of arguments
6862
 */
6863
void
6864
0
xmlXPathLastFunction(xmlXPathParserContext *ctxt, int nargs) {
6865
0
    CHECK_ARITY(0);
6866
0
    if (ctxt->context->contextSize >= 0) {
6867
0
  xmlXPathValuePush(ctxt,
6868
0
      xmlXPathCacheNewFloat(ctxt, (double) ctxt->context->contextSize));
6869
0
    } else {
6870
0
  XP_ERROR(XPATH_INVALID_CTXT_SIZE);
6871
0
    }
6872
0
}
6873
6874
/**
6875
 * Implement the position() XPath function
6876
 *    number position()
6877
 * The position function returns the position of the context node in the
6878
 * context node list. The first position is 1, and so the last position
6879
 * will be equal to last().
6880
 *
6881
 * @param ctxt  the XPath Parser context
6882
 * @param nargs  the number of arguments
6883
 */
6884
void
6885
0
xmlXPathPositionFunction(xmlXPathParserContext *ctxt, int nargs) {
6886
0
    CHECK_ARITY(0);
6887
0
    if (ctxt->context->proximityPosition >= 0) {
6888
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6889
0
            (double) ctxt->context->proximityPosition));
6890
0
    } else {
6891
0
  XP_ERROR(XPATH_INVALID_CTXT_POSITION);
6892
0
    }
6893
0
}
6894
6895
/**
6896
 * Implement the count() XPath function
6897
 *    number count(node-set)
6898
 *
6899
 * @param ctxt  the XPath Parser context
6900
 * @param nargs  the number of arguments
6901
 */
6902
void
6903
0
xmlXPathCountFunction(xmlXPathParserContext *ctxt, int nargs) {
6904
0
    xmlXPathObjectPtr cur;
6905
6906
0
    CHECK_ARITY(1);
6907
0
    if ((ctxt->value == NULL) ||
6908
0
  ((ctxt->value->type != XPATH_NODESET) &&
6909
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
6910
0
  XP_ERROR(XPATH_INVALID_TYPE);
6911
0
    cur = xmlXPathValuePop(ctxt);
6912
6913
0
    if ((cur == NULL) || (cur->nodesetval == NULL))
6914
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
6915
0
    else
6916
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
6917
0
      (double) cur->nodesetval->nodeNr));
6918
0
    xmlXPathReleaseObject(ctxt->context, cur);
6919
0
}
6920
6921
/**
6922
 * Selects elements by their unique ID.
6923
 *
6924
 * @param doc  the document
6925
 * @param ids  a whitespace separated list of IDs
6926
 * @returns a node-set of selected elements.
6927
 */
6928
static xmlNodeSetPtr
6929
0
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
6930
0
    xmlNodeSetPtr ret;
6931
0
    const xmlChar *cur = ids;
6932
0
    xmlChar *ID;
6933
0
    xmlAttrPtr attr;
6934
0
    xmlNodePtr elem = NULL;
6935
6936
0
    if (ids == NULL) return(NULL);
6937
6938
0
    ret = xmlXPathNodeSetCreate(NULL);
6939
0
    if (ret == NULL)
6940
0
        return(ret);
6941
6942
0
    while (IS_BLANK_CH(*cur)) cur++;
6943
0
    while (*cur != 0) {
6944
0
  while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
6945
0
      cur++;
6946
6947
0
        ID = xmlStrndup(ids, cur - ids);
6948
0
  if (ID == NULL) {
6949
0
            xmlXPathFreeNodeSet(ret);
6950
0
            return(NULL);
6951
0
        }
6952
        /*
6953
         * We used to check the fact that the value passed
6954
         * was an NCName, but this generated much troubles for
6955
         * me and Aleksey Sanin, people blatantly violated that
6956
         * constraint, like Visa3D spec.
6957
         * if (xmlValidateNCName(ID, 1) == 0)
6958
         */
6959
0
        attr = xmlGetID(doc, ID);
6960
0
        xmlFree(ID);
6961
0
        if (attr != NULL) {
6962
0
            if (attr->type == XML_ATTRIBUTE_NODE)
6963
0
                elem = attr->parent;
6964
0
            else if (attr->type == XML_ELEMENT_NODE)
6965
0
                elem = (xmlNodePtr) attr;
6966
0
            else
6967
0
                elem = NULL;
6968
0
            if (elem != NULL) {
6969
0
                if (xmlXPathNodeSetAdd(ret, elem) < 0) {
6970
0
                    xmlXPathFreeNodeSet(ret);
6971
0
                    return(NULL);
6972
0
                }
6973
0
            }
6974
0
        }
6975
6976
0
  while (IS_BLANK_CH(*cur)) cur++;
6977
0
  ids = cur;
6978
0
    }
6979
0
    return(ret);
6980
0
}
6981
6982
/**
6983
 * Implement the id() XPath function
6984
 *    node-set id(object)
6985
 * The id function selects elements by their unique ID
6986
 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
6987
 * then the result is the union of the result of applying id to the
6988
 * string value of each of the nodes in the argument node-set. When the
6989
 * argument to id is of any other type, the argument is converted to a
6990
 * string as if by a call to the string function; the string is split
6991
 * into a whitespace-separated list of tokens (whitespace is any sequence
6992
 * of characters matching the production S); the result is a node-set
6993
 * containing the elements in the same document as the context node that
6994
 * have a unique ID equal to any of the tokens in the list.
6995
 *
6996
 * @param ctxt  the XPath Parser context
6997
 * @param nargs  the number of arguments
6998
 */
6999
void
7000
0
xmlXPathIdFunction(xmlXPathParserContext *ctxt, int nargs) {
7001
0
    xmlChar *tokens;
7002
0
    xmlNodeSetPtr ret;
7003
0
    xmlXPathObjectPtr obj;
7004
7005
0
    CHECK_ARITY(1);
7006
0
    obj = xmlXPathValuePop(ctxt);
7007
0
    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7008
0
    if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7009
0
  xmlNodeSetPtr ns;
7010
0
  int i;
7011
7012
0
  ret = xmlXPathNodeSetCreate(NULL);
7013
0
        if (ret == NULL)
7014
0
            xmlXPathPErrMemory(ctxt);
7015
7016
0
  if (obj->nodesetval != NULL) {
7017
0
      for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7018
0
    tokens =
7019
0
        xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7020
0
                if (tokens == NULL)
7021
0
                    xmlXPathPErrMemory(ctxt);
7022
0
    ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7023
0
                if (ns == NULL)
7024
0
                    xmlXPathPErrMemory(ctxt);
7025
0
    ret = xmlXPathNodeSetMerge(ret, ns);
7026
0
                if (ret == NULL)
7027
0
                    xmlXPathPErrMemory(ctxt);
7028
0
    xmlXPathFreeNodeSet(ns);
7029
0
    if (tokens != NULL)
7030
0
        xmlFree(tokens);
7031
0
      }
7032
0
  }
7033
0
  xmlXPathReleaseObject(ctxt->context, obj);
7034
0
  xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7035
0
  return;
7036
0
    }
7037
0
    tokens = xmlXPathCastToString(obj);
7038
0
    if (tokens == NULL)
7039
0
        xmlXPathPErrMemory(ctxt);
7040
0
    xmlXPathReleaseObject(ctxt->context, obj);
7041
0
    ret = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7042
0
    if (ret == NULL)
7043
0
        xmlXPathPErrMemory(ctxt);
7044
0
    xmlFree(tokens);
7045
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, ret));
7046
0
}
7047
7048
/**
7049
 * Implement the local-name() XPath function
7050
 *    string local-name(node-set?)
7051
 * The local-name function returns a string containing the local part
7052
 * of the name of the node in the argument node-set that is first in
7053
 * document order. If the node-set is empty or the first node has no
7054
 * name, an empty string is returned. If the argument is omitted it
7055
 * defaults to the context node.
7056
 *
7057
 * @param ctxt  the XPath Parser context
7058
 * @param nargs  the number of arguments
7059
 */
7060
void
7061
0
xmlXPathLocalNameFunction(xmlXPathParserContext *ctxt, int nargs) {
7062
0
    xmlXPathObjectPtr cur;
7063
7064
0
    if (ctxt == NULL) return;
7065
7066
0
    if (nargs == 0) {
7067
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7068
0
  nargs = 1;
7069
0
    }
7070
7071
0
    CHECK_ARITY(1);
7072
0
    if ((ctxt->value == NULL) ||
7073
0
  ((ctxt->value->type != XPATH_NODESET) &&
7074
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7075
0
  XP_ERROR(XPATH_INVALID_TYPE);
7076
0
    cur = xmlXPathValuePop(ctxt);
7077
7078
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7079
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7080
0
    } else {
7081
0
  int i = 0; /* Should be first in document order !!!!! */
7082
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7083
0
  case XML_ELEMENT_NODE:
7084
0
  case XML_ATTRIBUTE_NODE:
7085
0
  case XML_PI_NODE:
7086
0
      if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7087
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7088
0
      else
7089
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7090
0
      cur->nodesetval->nodeTab[i]->name));
7091
0
      break;
7092
0
  case XML_NAMESPACE_DECL:
7093
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7094
0
      ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7095
0
      break;
7096
0
  default:
7097
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7098
0
  }
7099
0
    }
7100
0
    xmlXPathReleaseObject(ctxt->context, cur);
7101
0
}
7102
7103
/**
7104
 * Implement the namespace-uri() XPath function
7105
 *    string namespace-uri(node-set?)
7106
 * The namespace-uri function returns a string containing the
7107
 * namespace URI of the expanded name of the node in the argument
7108
 * node-set that is first in document order. If the node-set is empty,
7109
 * the first node has no name, or the expanded name has no namespace
7110
 * URI, an empty string is returned. If the argument is omitted it
7111
 * defaults to the context node.
7112
 *
7113
 * @param ctxt  the XPath Parser context
7114
 * @param nargs  the number of arguments
7115
 */
7116
void
7117
0
xmlXPathNamespaceURIFunction(xmlXPathParserContext *ctxt, int nargs) {
7118
0
    xmlXPathObjectPtr cur;
7119
7120
0
    if (ctxt == NULL) return;
7121
7122
0
    if (nargs == 0) {
7123
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7124
0
  nargs = 1;
7125
0
    }
7126
0
    CHECK_ARITY(1);
7127
0
    if ((ctxt->value == NULL) ||
7128
0
  ((ctxt->value->type != XPATH_NODESET) &&
7129
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7130
0
  XP_ERROR(XPATH_INVALID_TYPE);
7131
0
    cur = xmlXPathValuePop(ctxt);
7132
7133
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7134
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7135
0
    } else {
7136
0
  int i = 0; /* Should be first in document order !!!!! */
7137
0
  switch (cur->nodesetval->nodeTab[i]->type) {
7138
0
  case XML_ELEMENT_NODE:
7139
0
  case XML_ATTRIBUTE_NODE:
7140
0
      if (cur->nodesetval->nodeTab[i]->ns == NULL)
7141
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7142
0
      else
7143
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7144
0
        cur->nodesetval->nodeTab[i]->ns->href));
7145
0
      break;
7146
0
  default:
7147
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7148
0
  }
7149
0
    }
7150
0
    xmlXPathReleaseObject(ctxt->context, cur);
7151
0
}
7152
7153
/**
7154
 * Implement the name() XPath function
7155
 *    string name(node-set?)
7156
 * The name function returns a string containing a QName representing
7157
 * the name of the node in the argument node-set that is first in document
7158
 * order. The QName must represent the name with respect to the namespace
7159
 * declarations in effect on the node whose name is being represented.
7160
 * Typically, this will be the form in which the name occurred in the XML
7161
 * source. This need not be the case if there are namespace declarations
7162
 * in effect on the node that associate multiple prefixes with the same
7163
 * namespace. However, an implementation may include information about
7164
 * the original prefix in its representation of nodes; in this case, an
7165
 * implementation can ensure that the returned string is always the same
7166
 * as the QName used in the XML source. If the argument it omitted it
7167
 * defaults to the context node.
7168
 * Libxml keep the original prefix so the "real qualified name" used is
7169
 * returned.
7170
 *
7171
 * @param ctxt  the XPath Parser context
7172
 * @param nargs  the number of arguments
7173
 */
7174
static void
7175
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
7176
0
{
7177
0
    xmlXPathObjectPtr cur;
7178
7179
0
    if (nargs == 0) {
7180
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt, ctxt->context->node));
7181
0
        nargs = 1;
7182
0
    }
7183
7184
0
    CHECK_ARITY(1);
7185
0
    if ((ctxt->value == NULL) ||
7186
0
        ((ctxt->value->type != XPATH_NODESET) &&
7187
0
         (ctxt->value->type != XPATH_XSLT_TREE)))
7188
0
        XP_ERROR(XPATH_INVALID_TYPE);
7189
0
    cur = xmlXPathValuePop(ctxt);
7190
7191
0
    if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7192
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7193
0
    } else {
7194
0
        int i = 0;              /* Should be first in document order !!!!! */
7195
7196
0
        switch (cur->nodesetval->nodeTab[i]->type) {
7197
0
            case XML_ELEMENT_NODE:
7198
0
            case XML_ATTRIBUTE_NODE:
7199
0
    if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7200
0
        xmlXPathValuePush(ctxt,
7201
0
      xmlXPathCacheNewCString(ctxt, ""));
7202
0
    else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
7203
0
                         (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
7204
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt,
7205
0
          cur->nodesetval->nodeTab[i]->name));
7206
0
    } else {
7207
0
        xmlChar *fullname;
7208
7209
0
        fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
7210
0
             cur->nodesetval->nodeTab[i]->ns->prefix,
7211
0
             NULL, 0);
7212
0
        if (fullname == cur->nodesetval->nodeTab[i]->name)
7213
0
      fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
7214
0
        if (fullname == NULL)
7215
0
                        xmlXPathPErrMemory(ctxt);
7216
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, fullname));
7217
0
                }
7218
0
                break;
7219
0
            default:
7220
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
7221
0
        cur->nodesetval->nodeTab[i]));
7222
0
                xmlXPathLocalNameFunction(ctxt, 1);
7223
0
        }
7224
0
    }
7225
0
    xmlXPathReleaseObject(ctxt->context, cur);
7226
0
}
7227
7228
7229
/**
7230
 * Implement the string() XPath function
7231
 *    string string(object?)
7232
 * The string function converts an object to a string as follows:
7233
 *    - A node-set is converted to a string by returning the value of
7234
 *      the node in the node-set that is first in document order.
7235
 *      If the node-set is empty, an empty string is returned.
7236
 *    - A number is converted to a string as follows
7237
 *      + NaN is converted to the string NaN
7238
 *      + positive zero is converted to the string 0
7239
 *      + negative zero is converted to the string 0
7240
 *      + positive infinity is converted to the string Infinity
7241
 *      + negative infinity is converted to the string -Infinity
7242
 *      + if the number is an integer, the number is represented in
7243
 *        decimal form as a Number with no decimal point and no leading
7244
 *        zeros, preceded by a minus sign (-) if the number is negative
7245
 *      + otherwise, the number is represented in decimal form as a
7246
 *        Number including a decimal point with at least one digit
7247
 *        before the decimal point and at least one digit after the
7248
 *        decimal point, preceded by a minus sign (-) if the number
7249
 *        is negative; there must be no leading zeros before the decimal
7250
 *        point apart possibly from the one required digit immediately
7251
 *        before the decimal point; beyond the one required digit
7252
 *        after the decimal point there must be as many, but only as
7253
 *        many, more digits as are needed to uniquely distinguish the
7254
 *        number from all other IEEE 754 numeric values.
7255
 *    - The boolean false value is converted to the string false.
7256
 *      The boolean true value is converted to the string true.
7257
 *
7258
 * If the argument is omitted, it defaults to a node-set with the
7259
 * context node as its only member.
7260
 *
7261
 * @param ctxt  the XPath Parser context
7262
 * @param nargs  the number of arguments
7263
 */
7264
void
7265
0
xmlXPathStringFunction(xmlXPathParserContext *ctxt, int nargs) {
7266
0
    xmlXPathObjectPtr cur;
7267
0
    xmlChar *stringval;
7268
7269
0
    if (ctxt == NULL) return;
7270
0
    if (nargs == 0) {
7271
0
        stringval = xmlXPathCastNodeToString(ctxt->context->node);
7272
0
        if (stringval == NULL)
7273
0
            xmlXPathPErrMemory(ctxt);
7274
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, stringval));
7275
0
  return;
7276
0
    }
7277
7278
0
    CHECK_ARITY(1);
7279
0
    cur = xmlXPathValuePop(ctxt);
7280
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7281
0
    if (cur->type != XPATH_STRING) {
7282
0
        stringval = xmlXPathCastToString(cur);
7283
0
        if (stringval == NULL)
7284
0
            xmlXPathPErrMemory(ctxt);
7285
0
        xmlXPathReleaseObject(ctxt->context, cur);
7286
0
        cur = xmlXPathCacheWrapString(ctxt, stringval);
7287
0
    }
7288
0
    xmlXPathValuePush(ctxt, cur);
7289
0
}
7290
7291
/**
7292
 * Implement the string-length() XPath function
7293
 *    number string-length(string?)
7294
 * The string-length returns the number of characters in the string
7295
 * (see [3.6 Strings]). If the argument is omitted, it defaults to
7296
 * the context node converted to a string, in other words the value
7297
 * of the context node.
7298
 *
7299
 * @param ctxt  the XPath Parser context
7300
 * @param nargs  the number of arguments
7301
 */
7302
void
7303
0
xmlXPathStringLengthFunction(xmlXPathParserContext *ctxt, int nargs) {
7304
0
    xmlXPathObjectPtr cur;
7305
7306
0
    if (nargs == 0) {
7307
0
        if ((ctxt == NULL) || (ctxt->context == NULL))
7308
0
      return;
7309
0
  if (ctxt->context->node == NULL) {
7310
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0));
7311
0
  } else {
7312
0
      xmlChar *content;
7313
7314
0
      content = xmlXPathCastNodeToString(ctxt->context->node);
7315
0
            if (content == NULL)
7316
0
                xmlXPathPErrMemory(ctxt);
7317
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7318
0
    xmlUTF8Strlen(content)));
7319
0
      xmlFree(content);
7320
0
  }
7321
0
  return;
7322
0
    }
7323
0
    CHECK_ARITY(1);
7324
0
    CAST_TO_STRING;
7325
0
    CHECK_TYPE(XPATH_STRING);
7326
0
    cur = xmlXPathValuePop(ctxt);
7327
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt,
7328
0
  xmlUTF8Strlen(cur->stringval)));
7329
0
    xmlXPathReleaseObject(ctxt->context, cur);
7330
0
}
7331
7332
/**
7333
 * Implement the concat() XPath function
7334
 *    string concat(string, string, string*)
7335
 * The concat function returns the concatenation of its arguments.
7336
 *
7337
 * @param ctxt  the XPath Parser context
7338
 * @param nargs  the number of arguments
7339
 */
7340
void
7341
0
xmlXPathConcatFunction(xmlXPathParserContext *ctxt, int nargs) {
7342
0
    xmlXPathObjectPtr cur, newobj;
7343
0
    xmlChar *tmp;
7344
7345
0
    if (ctxt == NULL) return;
7346
0
    if (nargs < 2) {
7347
0
  CHECK_ARITY(2);
7348
0
    }
7349
7350
0
    CAST_TO_STRING;
7351
0
    cur = xmlXPathValuePop(ctxt);
7352
0
    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
7353
0
  xmlXPathReleaseObject(ctxt->context, cur);
7354
0
  return;
7355
0
    }
7356
0
    nargs--;
7357
7358
0
    while (nargs > 0) {
7359
0
  CAST_TO_STRING;
7360
0
  newobj = xmlXPathValuePop(ctxt);
7361
0
  if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
7362
0
      xmlXPathReleaseObject(ctxt->context, newobj);
7363
0
      xmlXPathReleaseObject(ctxt->context, cur);
7364
0
      XP_ERROR(XPATH_INVALID_TYPE);
7365
0
  }
7366
0
  tmp = xmlStrcat(newobj->stringval, cur->stringval);
7367
0
        if (tmp == NULL)
7368
0
            xmlXPathPErrMemory(ctxt);
7369
0
  newobj->stringval = cur->stringval;
7370
0
  cur->stringval = tmp;
7371
0
  xmlXPathReleaseObject(ctxt->context, newobj);
7372
0
  nargs--;
7373
0
    }
7374
0
    xmlXPathValuePush(ctxt, cur);
7375
0
}
7376
7377
/**
7378
 * Implement the contains() XPath function
7379
 *    boolean contains(string, string)
7380
 * The contains function returns true if the first argument string
7381
 * contains the second argument string, and otherwise returns false.
7382
 *
7383
 * @param ctxt  the XPath Parser context
7384
 * @param nargs  the number of arguments
7385
 */
7386
void
7387
0
xmlXPathContainsFunction(xmlXPathParserContext *ctxt, int nargs) {
7388
0
    xmlXPathObjectPtr hay, needle;
7389
7390
0
    CHECK_ARITY(2);
7391
0
    CAST_TO_STRING;
7392
0
    CHECK_TYPE(XPATH_STRING);
7393
0
    needle = xmlXPathValuePop(ctxt);
7394
0
    CAST_TO_STRING;
7395
0
    hay = xmlXPathValuePop(ctxt);
7396
7397
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7398
0
  xmlXPathReleaseObject(ctxt->context, hay);
7399
0
  xmlXPathReleaseObject(ctxt->context, needle);
7400
0
  XP_ERROR(XPATH_INVALID_TYPE);
7401
0
    }
7402
0
    if (xmlStrstr(hay->stringval, needle->stringval))
7403
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7404
0
    else
7405
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7406
0
    xmlXPathReleaseObject(ctxt->context, hay);
7407
0
    xmlXPathReleaseObject(ctxt->context, needle);
7408
0
}
7409
7410
/**
7411
 * Implement the starts-with() XPath function
7412
 *    boolean starts-with(string, string)
7413
 * The starts-with function returns true if the first argument string
7414
 * starts with the second argument string, and otherwise returns false.
7415
 *
7416
 * @param ctxt  the XPath Parser context
7417
 * @param nargs  the number of arguments
7418
 */
7419
void
7420
0
xmlXPathStartsWithFunction(xmlXPathParserContext *ctxt, int nargs) {
7421
0
    xmlXPathObjectPtr hay, needle;
7422
0
    int n;
7423
7424
0
    CHECK_ARITY(2);
7425
0
    CAST_TO_STRING;
7426
0
    CHECK_TYPE(XPATH_STRING);
7427
0
    needle = xmlXPathValuePop(ctxt);
7428
0
    CAST_TO_STRING;
7429
0
    hay = xmlXPathValuePop(ctxt);
7430
7431
0
    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
7432
0
  xmlXPathReleaseObject(ctxt->context, hay);
7433
0
  xmlXPathReleaseObject(ctxt->context, needle);
7434
0
  XP_ERROR(XPATH_INVALID_TYPE);
7435
0
    }
7436
0
    n = xmlStrlen(needle->stringval);
7437
0
    if (xmlStrncmp(hay->stringval, needle->stringval, n))
7438
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7439
0
    else
7440
0
        xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7441
0
    xmlXPathReleaseObject(ctxt->context, hay);
7442
0
    xmlXPathReleaseObject(ctxt->context, needle);
7443
0
}
7444
7445
/**
7446
 * Implement the substring() XPath function
7447
 *    string substring(string, number, number?)
7448
 * The substring function returns the substring of the first argument
7449
 * starting at the position specified in the second argument with
7450
 * length specified in the third argument. For example,
7451
 * substring("12345",2,3) returns "234". If the third argument is not
7452
 * specified, it returns the substring starting at the position specified
7453
 * in the second argument and continuing to the end of the string. For
7454
 * example, substring("12345",2) returns "2345".  More precisely, each
7455
 * character in the string (see [3.6 Strings]) is considered to have a
7456
 * numeric position: the position of the first character is 1, the position
7457
 * of the second character is 2 and so on. The returned substring contains
7458
 * those characters for which the position of the character is greater than
7459
 * or equal to the second argument and, if the third argument is specified,
7460
 * less than the sum of the second and third arguments; the comparisons
7461
 * and addition used for the above follow the standard IEEE 754 rules. Thus:
7462
 *  - substring("12345", 1.5, 2.6) returns "234"
7463
 *  - substring("12345", 0, 3) returns "12"
7464
 *  - substring("12345", 0 div 0, 3) returns ""
7465
 *  - substring("12345", 1, 0 div 0) returns ""
7466
 *  - substring("12345", -42, 1 div 0) returns "12345"
7467
 *  - substring("12345", -1 div 0, 1 div 0) returns ""
7468
 *
7469
 * @param ctxt  the XPath Parser context
7470
 * @param nargs  the number of arguments
7471
 */
7472
void
7473
0
xmlXPathSubstringFunction(xmlXPathParserContext *ctxt, int nargs) {
7474
0
    xmlXPathObjectPtr str, start, len;
7475
0
    double le=0, in;
7476
0
    int i = 1, j = INT_MAX;
7477
7478
0
    if (nargs < 2) {
7479
0
  CHECK_ARITY(2);
7480
0
    }
7481
0
    if (nargs > 3) {
7482
0
  CHECK_ARITY(3);
7483
0
    }
7484
    /*
7485
     * take care of possible last (position) argument
7486
    */
7487
0
    if (nargs == 3) {
7488
0
  CAST_TO_NUMBER;
7489
0
  CHECK_TYPE(XPATH_NUMBER);
7490
0
  len = xmlXPathValuePop(ctxt);
7491
0
  le = len->floatval;
7492
0
  xmlXPathReleaseObject(ctxt->context, len);
7493
0
    }
7494
7495
0
    CAST_TO_NUMBER;
7496
0
    CHECK_TYPE(XPATH_NUMBER);
7497
0
    start = xmlXPathValuePop(ctxt);
7498
0
    in = start->floatval;
7499
0
    xmlXPathReleaseObject(ctxt->context, start);
7500
0
    CAST_TO_STRING;
7501
0
    CHECK_TYPE(XPATH_STRING);
7502
0
    str = xmlXPathValuePop(ctxt);
7503
7504
0
    if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
7505
0
        i = INT_MAX;
7506
0
    } else if (in >= 1.0) {
7507
0
        i = (int)in;
7508
0
        if (in - floor(in) >= 0.5)
7509
0
            i += 1;
7510
0
    }
7511
7512
0
    if (nargs == 3) {
7513
0
        double rin, rle, end;
7514
7515
0
        rin = floor(in);
7516
0
        if (in - rin >= 0.5)
7517
0
            rin += 1.0;
7518
7519
0
        rle = floor(le);
7520
0
        if (le - rle >= 0.5)
7521
0
            rle += 1.0;
7522
7523
0
        end = rin + rle;
7524
0
        if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
7525
0
            j = 1;
7526
0
        } else if (end < INT_MAX) {
7527
0
            j = (int)end;
7528
0
        }
7529
0
    }
7530
7531
0
    i -= 1;
7532
0
    j -= 1;
7533
7534
0
    if ((i < j) && (i < xmlUTF8Strlen(str->stringval))) {
7535
0
        xmlChar *ret = xmlUTF8Strsub(str->stringval, i, j - i);
7536
0
        if (ret == NULL)
7537
0
            xmlXPathPErrMemory(ctxt);
7538
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewString(ctxt, ret));
7539
0
  xmlFree(ret);
7540
0
    } else {
7541
0
  xmlXPathValuePush(ctxt, xmlXPathCacheNewCString(ctxt, ""));
7542
0
    }
7543
7544
0
    xmlXPathReleaseObject(ctxt->context, str);
7545
0
}
7546
7547
/**
7548
 * Implement the substring-before() XPath function
7549
 *    string substring-before(string, string)
7550
 * The substring-before function returns the substring of the first
7551
 * argument string that precedes the first occurrence of the second
7552
 * argument string in the first argument string, or the empty string
7553
 * if the first argument string does not contain the second argument
7554
 * string. For example, substring-before("1999/04/01","/") returns 1999.
7555
 *
7556
 * @param ctxt  the XPath Parser context
7557
 * @param nargs  the number of arguments
7558
 */
7559
void
7560
0
xmlXPathSubstringBeforeFunction(xmlXPathParserContext *ctxt, int nargs) {
7561
0
    xmlXPathObjectPtr str = NULL;
7562
0
    xmlXPathObjectPtr find = NULL;
7563
0
    const xmlChar *point;
7564
0
    xmlChar *result;
7565
7566
0
    CHECK_ARITY(2);
7567
0
    CAST_TO_STRING;
7568
0
    find = xmlXPathValuePop(ctxt);
7569
0
    CAST_TO_STRING;
7570
0
    str = xmlXPathValuePop(ctxt);
7571
0
    if (ctxt->error != 0)
7572
0
        goto error;
7573
7574
0
    point = xmlStrstr(str->stringval, find->stringval);
7575
0
    if (point == NULL) {
7576
0
        result = xmlStrdup(BAD_CAST "");
7577
0
    } else {
7578
0
        result = xmlStrndup(str->stringval, point - str->stringval);
7579
0
    }
7580
0
    if (result == NULL) {
7581
0
        xmlXPathPErrMemory(ctxt);
7582
0
        goto error;
7583
0
    }
7584
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7585
7586
0
error:
7587
0
    xmlXPathReleaseObject(ctxt->context, str);
7588
0
    xmlXPathReleaseObject(ctxt->context, find);
7589
0
}
7590
7591
/**
7592
 * Implement the substring-after() XPath function
7593
 *    string substring-after(string, string)
7594
 * The substring-after function returns the substring of the first
7595
 * argument string that follows the first occurrence of the second
7596
 * argument string in the first argument string, or the empty string
7597
 * if the first argument string does not contain the second argument
7598
 * string. For example, substring-after("1999/04/01","/") returns 04/01,
7599
 * and substring-after("1999/04/01","19") returns 99/04/01.
7600
 *
7601
 * @param ctxt  the XPath Parser context
7602
 * @param nargs  the number of arguments
7603
 */
7604
void
7605
0
xmlXPathSubstringAfterFunction(xmlXPathParserContext *ctxt, int nargs) {
7606
0
    xmlXPathObjectPtr str = NULL;
7607
0
    xmlXPathObjectPtr find = NULL;
7608
0
    const xmlChar *point;
7609
0
    xmlChar *result;
7610
7611
0
    CHECK_ARITY(2);
7612
0
    CAST_TO_STRING;
7613
0
    find = xmlXPathValuePop(ctxt);
7614
0
    CAST_TO_STRING;
7615
0
    str = xmlXPathValuePop(ctxt);
7616
0
    if (ctxt->error != 0)
7617
0
        goto error;
7618
7619
0
    point = xmlStrstr(str->stringval, find->stringval);
7620
0
    if (point == NULL) {
7621
0
        result = xmlStrdup(BAD_CAST "");
7622
0
    } else {
7623
0
        result = xmlStrdup(point + xmlStrlen(find->stringval));
7624
0
    }
7625
0
    if (result == NULL) {
7626
0
        xmlXPathPErrMemory(ctxt);
7627
0
        goto error;
7628
0
    }
7629
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, result));
7630
7631
0
error:
7632
0
    xmlXPathReleaseObject(ctxt->context, str);
7633
0
    xmlXPathReleaseObject(ctxt->context, find);
7634
0
}
7635
7636
/**
7637
 * Implement the normalize-space() XPath function
7638
 *    string normalize-space(string?)
7639
 * The normalize-space function returns the argument string with white
7640
 * space normalized by stripping leading and trailing whitespace
7641
 * and replacing sequences of whitespace characters by a single
7642
 * space. Whitespace characters are the same allowed by the S production
7643
 * in XML. If the argument is omitted, it defaults to the context
7644
 * node converted to a string, in other words the value of the context node.
7645
 *
7646
 * @param ctxt  the XPath Parser context
7647
 * @param nargs  the number of arguments
7648
 */
7649
void
7650
0
xmlXPathNormalizeFunction(xmlXPathParserContext *ctxt, int nargs) {
7651
0
    xmlChar *source, *target;
7652
0
    int blank;
7653
7654
0
    if (ctxt == NULL) return;
7655
0
    if (nargs == 0) {
7656
        /* Use current context node */
7657
0
        source = xmlXPathCastNodeToString(ctxt->context->node);
7658
0
        if (source == NULL)
7659
0
            xmlXPathPErrMemory(ctxt);
7660
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, source));
7661
0
        nargs = 1;
7662
0
    }
7663
7664
0
    CHECK_ARITY(1);
7665
0
    CAST_TO_STRING;
7666
0
    CHECK_TYPE(XPATH_STRING);
7667
0
    source = ctxt->value->stringval;
7668
0
    if (source == NULL)
7669
0
        return;
7670
0
    target = source;
7671
7672
    /* Skip leading whitespaces */
7673
0
    while (IS_BLANK_CH(*source))
7674
0
        source++;
7675
7676
    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
7677
0
    blank = 0;
7678
0
    while (*source) {
7679
0
        if (IS_BLANK_CH(*source)) {
7680
0
      blank = 1;
7681
0
        } else {
7682
0
            if (blank) {
7683
0
                *target++ = 0x20;
7684
0
                blank = 0;
7685
0
            }
7686
0
            *target++ = *source;
7687
0
        }
7688
0
        source++;
7689
0
    }
7690
0
    *target = 0;
7691
0
}
7692
7693
/**
7694
 * Implement the translate() XPath function
7695
 *    string translate(string, string, string)
7696
 * The translate function returns the first argument string with
7697
 * occurrences of characters in the second argument string replaced
7698
 * by the character at the corresponding position in the third argument
7699
 * string. For example, translate("bar","abc","ABC") returns the string
7700
 * BAr. If there is a character in the second argument string with no
7701
 * character at a corresponding position in the third argument string
7702
 * (because the second argument string is longer than the third argument
7703
 * string), then occurrences of that character in the first argument
7704
 * string are removed. For example,
7705
 * translate("--aaa--","abc-","ABC") returns "AAA".
7706
 * If a character occurs more than once in second
7707
 * argument string, then the first occurrence determines the replacement
7708
 * character. If the third argument string is longer than the second
7709
 * argument string, then excess characters are ignored.
7710
 *
7711
 * @param ctxt  the XPath Parser context
7712
 * @param nargs  the number of arguments
7713
 */
7714
void
7715
0
xmlXPathTranslateFunction(xmlXPathParserContext *ctxt, int nargs) {
7716
0
    xmlXPathObjectPtr str = NULL;
7717
0
    xmlXPathObjectPtr from = NULL;
7718
0
    xmlXPathObjectPtr to = NULL;
7719
0
    xmlBufPtr target;
7720
0
    int offset, max;
7721
0
    int ch;
7722
0
    const xmlChar *point;
7723
0
    xmlChar *cptr, *content;
7724
7725
0
    CHECK_ARITY(3);
7726
7727
0
    CAST_TO_STRING;
7728
0
    to = xmlXPathValuePop(ctxt);
7729
0
    CAST_TO_STRING;
7730
0
    from = xmlXPathValuePop(ctxt);
7731
0
    CAST_TO_STRING;
7732
0
    str = xmlXPathValuePop(ctxt);
7733
0
    if (ctxt->error != 0)
7734
0
        goto error;
7735
7736
    /*
7737
     * Account for quadratic runtime
7738
     */
7739
0
    if (ctxt->context->opLimit != 0) {
7740
0
        unsigned long f1 = xmlStrlen(from->stringval);
7741
0
        unsigned long f2 = xmlStrlen(str->stringval);
7742
7743
0
        if ((f1 > 0) && (f2 > 0)) {
7744
0
            unsigned long p;
7745
7746
0
            f1 = f1 / 10 + 1;
7747
0
            f2 = f2 / 10 + 1;
7748
0
            p = f1 > ULONG_MAX / f2 ? ULONG_MAX : f1 * f2;
7749
0
            if (xmlXPathCheckOpLimit(ctxt, p) < 0)
7750
0
                goto error;
7751
0
        }
7752
0
    }
7753
7754
0
    target = xmlBufCreate(50);
7755
0
    if (target == NULL) {
7756
0
        xmlXPathPErrMemory(ctxt);
7757
0
        goto error;
7758
0
    }
7759
7760
0
    max = xmlUTF8Strlen(to->stringval);
7761
0
    for (cptr = str->stringval; (ch=*cptr); ) {
7762
0
        offset = xmlUTF8Strloc(from->stringval, cptr);
7763
0
        if (offset >= 0) {
7764
0
            if (offset < max) {
7765
0
                point = xmlUTF8Strpos(to->stringval, offset);
7766
0
                if (point)
7767
0
                    xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
7768
0
            }
7769
0
        } else
7770
0
            xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
7771
7772
        /* Step to next character in input */
7773
0
        cptr++;
7774
0
        if ( ch & 0x80 ) {
7775
            /* if not simple ascii, verify proper format */
7776
0
            if ( (ch & 0xc0) != 0xc0 ) {
7777
0
                xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7778
0
                break;
7779
0
            }
7780
            /* then skip over remaining bytes for this char */
7781
0
            while ( (ch <<= 1) & 0x80 )
7782
0
                if ( (*cptr++ & 0xc0) != 0x80 ) {
7783
0
                    xmlXPathErr(ctxt, XPATH_INVALID_CHAR_ERROR);
7784
0
                    break;
7785
0
                }
7786
0
            if (ch & 0x80) /* must have had error encountered */
7787
0
                break;
7788
0
        }
7789
0
    }
7790
7791
0
    content = xmlBufDetach(target);
7792
0
    if (content == NULL)
7793
0
        xmlXPathPErrMemory(ctxt);
7794
0
    else
7795
0
        xmlXPathValuePush(ctxt, xmlXPathCacheWrapString(ctxt, content));
7796
0
    xmlBufFree(target);
7797
0
error:
7798
0
    xmlXPathReleaseObject(ctxt->context, str);
7799
0
    xmlXPathReleaseObject(ctxt->context, from);
7800
0
    xmlXPathReleaseObject(ctxt->context, to);
7801
0
}
7802
7803
/**
7804
 * Implement the boolean() XPath function
7805
 *    boolean boolean(object)
7806
 * The boolean function converts its argument to a boolean as follows:
7807
 *    - a number is true if and only if it is neither positive or
7808
 *      negative zero nor NaN
7809
 *    - a node-set is true if and only if it is non-empty
7810
 *    - a string is true if and only if its length is non-zero
7811
 *
7812
 * @param ctxt  the XPath Parser context
7813
 * @param nargs  the number of arguments
7814
 */
7815
void
7816
0
xmlXPathBooleanFunction(xmlXPathParserContext *ctxt, int nargs) {
7817
0
    xmlXPathObjectPtr cur;
7818
7819
0
    CHECK_ARITY(1);
7820
0
    cur = xmlXPathValuePop(ctxt);
7821
0
    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7822
0
    if (cur->type != XPATH_BOOLEAN) {
7823
0
        int boolval = xmlXPathCastToBoolean(cur);
7824
7825
0
        xmlXPathReleaseObject(ctxt->context, cur);
7826
0
        cur = xmlXPathCacheNewBoolean(ctxt, boolval);
7827
0
    }
7828
0
    xmlXPathValuePush(ctxt, cur);
7829
0
}
7830
7831
/**
7832
 * Implement the not() XPath function
7833
 *    boolean not(boolean)
7834
 * The not function returns true if its argument is false,
7835
 * and false otherwise.
7836
 *
7837
 * @param ctxt  the XPath Parser context
7838
 * @param nargs  the number of arguments
7839
 */
7840
void
7841
0
xmlXPathNotFunction(xmlXPathParserContext *ctxt, int nargs) {
7842
0
    CHECK_ARITY(1);
7843
0
    CAST_TO_BOOLEAN;
7844
0
    CHECK_TYPE(XPATH_BOOLEAN);
7845
0
    ctxt->value->boolval = ! ctxt->value->boolval;
7846
0
}
7847
7848
/**
7849
 * Implement the true() XPath function
7850
 *    boolean true()
7851
 *
7852
 * @param ctxt  the XPath Parser context
7853
 * @param nargs  the number of arguments
7854
 */
7855
void
7856
0
xmlXPathTrueFunction(xmlXPathParserContext *ctxt, int nargs) {
7857
0
    CHECK_ARITY(0);
7858
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 1));
7859
0
}
7860
7861
/**
7862
 * Implement the false() XPath function
7863
 *    boolean false()
7864
 *
7865
 * @param ctxt  the XPath Parser context
7866
 * @param nargs  the number of arguments
7867
 */
7868
void
7869
0
xmlXPathFalseFunction(xmlXPathParserContext *ctxt, int nargs) {
7870
0
    CHECK_ARITY(0);
7871
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, 0));
7872
0
}
7873
7874
/**
7875
 * Implement the lang() XPath function
7876
 *    boolean lang(string)
7877
 * The lang function returns true or false depending on whether the
7878
 * language of the context node as specified by xml:lang attributes
7879
 * is the same as or is a sublanguage of the language specified by
7880
 * the argument string. The language of the context node is determined
7881
 * by the value of the xml:lang attribute on the context node, or, if
7882
 * the context node has no xml:lang attribute, by the value of the
7883
 * xml:lang attribute on the nearest ancestor of the context node that
7884
 * has an xml:lang attribute. If there is no such attribute, then
7885
 * lang returns false. If there is such an attribute, then lang returns
7886
 * true if the attribute value is equal to the argument ignoring case,
7887
 * or if there is some suffix starting with - such that the attribute
7888
 * value is equal to the argument ignoring that suffix of the attribute
7889
 * value and ignoring case.
7890
 *
7891
 * @param ctxt  the XPath Parser context
7892
 * @param nargs  the number of arguments
7893
 */
7894
void
7895
0
xmlXPathLangFunction(xmlXPathParserContext *ctxt, int nargs) {
7896
0
    xmlXPathObjectPtr val;
7897
0
    xmlNodePtr cur;
7898
0
    xmlChar *theLang;
7899
0
    const xmlChar *lang;
7900
0
    int ret = 0;
7901
0
    int i;
7902
7903
0
    CHECK_ARITY(1);
7904
0
    CAST_TO_STRING;
7905
0
    CHECK_TYPE(XPATH_STRING);
7906
0
    val = xmlXPathValuePop(ctxt);
7907
0
    lang = val->stringval;
7908
0
    cur = ctxt->context->node;
7909
0
    while (cur != NULL) {
7910
0
        if (xmlNodeGetAttrValue(cur, BAD_CAST "lang", XML_XML_NAMESPACE,
7911
0
                                &theLang) < 0)
7912
0
            xmlXPathPErrMemory(ctxt);
7913
0
        if (theLang != NULL)
7914
0
            break;
7915
0
        cur = cur->parent;
7916
0
    }
7917
0
    if ((theLang != NULL) && (lang != NULL)) {
7918
0
        for (i = 0;lang[i] != 0;i++)
7919
0
            if (toupper(lang[i]) != toupper(theLang[i]))
7920
0
                goto not_equal;
7921
0
        if ((theLang[i] == 0) || (theLang[i] == '-'))
7922
0
            ret = 1;
7923
0
    }
7924
0
not_equal:
7925
0
    if (theLang != NULL)
7926
0
  xmlFree((void *)theLang);
7927
7928
0
    xmlXPathReleaseObject(ctxt->context, val);
7929
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
7930
0
}
7931
7932
/**
7933
 * Implement the number() XPath function
7934
 *    number number(object?)
7935
 *
7936
 * @param ctxt  the XPath Parser context
7937
 * @param nargs  the number of arguments
7938
 */
7939
void
7940
0
xmlXPathNumberFunction(xmlXPathParserContext *ctxt, int nargs) {
7941
0
    xmlXPathObjectPtr cur;
7942
0
    double res;
7943
7944
0
    if (ctxt == NULL) return;
7945
0
    if (nargs == 0) {
7946
0
  if (ctxt->context->node == NULL) {
7947
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, 0.0));
7948
0
  } else {
7949
0
      xmlChar* content = xmlNodeGetContent(ctxt->context->node);
7950
0
            if (content == NULL)
7951
0
                xmlXPathPErrMemory(ctxt);
7952
7953
0
      res = xmlXPathStringEvalNumber(content);
7954
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
7955
0
      xmlFree(content);
7956
0
  }
7957
0
  return;
7958
0
    }
7959
7960
0
    CHECK_ARITY(1);
7961
0
    cur = xmlXPathValuePop(ctxt);
7962
0
    if (cur->type != XPATH_NUMBER) {
7963
0
        double floatval;
7964
7965
0
        floatval = xmlXPathCastToNumberInternal(ctxt, cur);
7966
0
        xmlXPathReleaseObject(ctxt->context, cur);
7967
0
        cur = xmlXPathCacheNewFloat(ctxt, floatval);
7968
0
    }
7969
0
    xmlXPathValuePush(ctxt, cur);
7970
0
}
7971
7972
/**
7973
 * Implement the sum() XPath function
7974
 *    number sum(node-set)
7975
 * The sum function returns the sum of the values of the nodes in
7976
 * the argument node-set.
7977
 *
7978
 * @param ctxt  the XPath Parser context
7979
 * @param nargs  the number of arguments
7980
 */
7981
void
7982
0
xmlXPathSumFunction(xmlXPathParserContext *ctxt, int nargs) {
7983
0
    xmlXPathObjectPtr cur;
7984
0
    int i;
7985
0
    double res = 0.0;
7986
7987
0
    CHECK_ARITY(1);
7988
0
    if ((ctxt->value == NULL) ||
7989
0
  ((ctxt->value->type != XPATH_NODESET) &&
7990
0
   (ctxt->value->type != XPATH_XSLT_TREE)))
7991
0
  XP_ERROR(XPATH_INVALID_TYPE);
7992
0
    cur = xmlXPathValuePop(ctxt);
7993
7994
0
    if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
7995
0
  for (i = 0; i < cur->nodesetval->nodeNr; i++) {
7996
0
      res += xmlXPathNodeToNumberInternal(ctxt,
7997
0
                                                cur->nodesetval->nodeTab[i]);
7998
0
  }
7999
0
    }
8000
0
    xmlXPathValuePush(ctxt, xmlXPathCacheNewFloat(ctxt, res));
8001
0
    xmlXPathReleaseObject(ctxt->context, cur);
8002
0
}
8003
8004
/**
8005
 * Implement the floor() XPath function
8006
 *    number floor(number)
8007
 * The floor function returns the largest (closest to positive infinity)
8008
 * number that is not greater than the argument and that is an integer.
8009
 *
8010
 * @param ctxt  the XPath Parser context
8011
 * @param nargs  the number of arguments
8012
 */
8013
void
8014
0
xmlXPathFloorFunction(xmlXPathParserContext *ctxt, int nargs) {
8015
0
    CHECK_ARITY(1);
8016
0
    CAST_TO_NUMBER;
8017
0
    CHECK_TYPE(XPATH_NUMBER);
8018
8019
0
    ctxt->value->floatval = floor(ctxt->value->floatval);
8020
0
}
8021
8022
/**
8023
 * Implement the ceiling() XPath function
8024
 *    number ceiling(number)
8025
 * The ceiling function returns the smallest (closest to negative infinity)
8026
 * number that is not less than the argument and that is an integer.
8027
 *
8028
 * @param ctxt  the XPath Parser context
8029
 * @param nargs  the number of arguments
8030
 */
8031
void
8032
0
xmlXPathCeilingFunction(xmlXPathParserContext *ctxt, int nargs) {
8033
0
    CHECK_ARITY(1);
8034
0
    CAST_TO_NUMBER;
8035
0
    CHECK_TYPE(XPATH_NUMBER);
8036
8037
#ifdef _AIX
8038
    /* Work around buggy ceil() function on AIX */
8039
    ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8040
#else
8041
0
    ctxt->value->floatval = ceil(ctxt->value->floatval);
8042
0
#endif
8043
0
}
8044
8045
/**
8046
 * Implement the round() XPath function
8047
 *    number round(number)
8048
 * The round function returns the number that is closest to the
8049
 * argument and that is an integer. If there are two such numbers,
8050
 * then the one that is closest to positive infinity is returned.
8051
 *
8052
 * @param ctxt  the XPath Parser context
8053
 * @param nargs  the number of arguments
8054
 */
8055
void
8056
0
xmlXPathRoundFunction(xmlXPathParserContext *ctxt, int nargs) {
8057
0
    double f;
8058
8059
0
    CHECK_ARITY(1);
8060
0
    CAST_TO_NUMBER;
8061
0
    CHECK_TYPE(XPATH_NUMBER);
8062
8063
0
    f = ctxt->value->floatval;
8064
8065
0
    if ((f >= -0.5) && (f < 0.5)) {
8066
        /* Handles negative zero. */
8067
0
        ctxt->value->floatval *= 0.0;
8068
0
    }
8069
0
    else {
8070
0
        double rounded = floor(f);
8071
0
        if (f - rounded >= 0.5)
8072
0
            rounded += 1.0;
8073
0
        ctxt->value->floatval = rounded;
8074
0
    }
8075
0
}
8076
8077
/************************************************************************
8078
 *                  *
8079
 *      The Parser          *
8080
 *                  *
8081
 ************************************************************************/
8082
8083
/*
8084
 * a few forward declarations since we use a recursive call based
8085
 * implementation.
8086
 */
8087
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8088
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8089
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8090
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8091
8092
/**
8093
 * Parse an XML non-colonized name.
8094
 *
8095
 * @param ctxt  the XPath Parser context
8096
 * @returns the nc name or NULL
8097
 */
8098
8099
xmlChar *
8100
0
xmlXPathParseNCName(xmlXPathParserContext *ctxt) {
8101
0
    const xmlChar *end;
8102
0
    xmlChar *ret;
8103
8104
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8105
8106
0
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, XML_SCAN_NC);
8107
0
    if (end == NULL) {
8108
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8109
0
    }
8110
0
    if (end == ctxt->cur)
8111
0
        return(NULL);
8112
8113
0
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8114
0
    if (ret == NULL)
8115
0
        xmlXPathPErrMemory(ctxt);
8116
0
    ctxt->cur = end;
8117
0
    return(ret);
8118
0
}
8119
8120
8121
/**
8122
 * Parse an XML qualified name
8123
 *
8124
 * @param ctxt  the XPath Parser context
8125
 * @param prefix  a xmlChar **
8126
 * @returns the function returns the local part, and prefix is updated
8127
 *   to get the Prefix if any.
8128
 */
8129
8130
static xmlChar *
8131
0
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
8132
0
    xmlChar *ret = NULL;
8133
8134
0
    *prefix = NULL;
8135
0
    ret = xmlXPathParseNCName(ctxt);
8136
0
    if (ret && CUR == ':') {
8137
0
        *prefix = ret;
8138
0
  NEXT;
8139
0
  ret = xmlXPathParseNCName(ctxt);
8140
0
    }
8141
0
    return(ret);
8142
0
}
8143
8144
/**
8145
 * parse an XML name
8146
 *
8147
 * @param ctxt  the XPath Parser context
8148
 * @returns the name or NULL
8149
 */
8150
8151
xmlChar *
8152
0
xmlXPathParseName(xmlXPathParserContext *ctxt) {
8153
0
    const xmlChar *end;
8154
0
    xmlChar *ret;
8155
8156
0
    if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
8157
8158
0
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8159
0
    if (end == NULL) {
8160
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8161
0
    }
8162
0
    if (end == ctxt->cur)
8163
0
        return(NULL);
8164
8165
0
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8166
0
    if (ret == NULL)
8167
0
        xmlXPathPErrMemory(ctxt);
8168
0
    ctxt->cur = end;
8169
0
    return(ret);
8170
0
}
8171
8172
0
#define MAX_FRAC 20
8173
8174
/**
8175
 *  [30a]  Float  ::= Number ('e' Digits?)?
8176
 *
8177
 *  [30]   Number ::=   Digits ('.' Digits?)?
8178
 *                    | '.' Digits
8179
 *  [31]   Digits ::=   [0-9]+
8180
 *
8181
 * Compile a Number in the string
8182
 * In complement of the Number expression, this function also handles
8183
 * negative values : '-' Number.
8184
 *
8185
 * @param str  A string to scan
8186
 * @returns the double value.
8187
 */
8188
double
8189
0
xmlXPathStringEvalNumber(const xmlChar *str) {
8190
0
    const xmlChar *cur = str;
8191
0
    double ret;
8192
0
    int ok = 0;
8193
0
    int isneg = 0;
8194
0
    int exponent = 0;
8195
0
    int is_exponent_negative = 0;
8196
0
#ifdef __GNUC__
8197
0
    unsigned long tmp = 0;
8198
0
    double temp;
8199
0
#endif
8200
0
    if (cur == NULL) return(0);
8201
0
    while (IS_BLANK_CH(*cur)) cur++;
8202
0
    if (*cur == '-') {
8203
0
  isneg = 1;
8204
0
  cur++;
8205
0
    }
8206
0
    if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
8207
0
        return(xmlXPathNAN);
8208
0
    }
8209
8210
0
#ifdef __GNUC__
8211
    /*
8212
     * tmp/temp is a workaround against a gcc compiler bug
8213
     * http://veillard.com/gcc.bug
8214
     */
8215
0
    ret = 0;
8216
0
    while ((*cur >= '0') && (*cur <= '9')) {
8217
0
  ret = ret * 10;
8218
0
  tmp = (*cur - '0');
8219
0
  ok = 1;
8220
0
  cur++;
8221
0
  temp = (double) tmp;
8222
0
  ret = ret + temp;
8223
0
    }
8224
#else
8225
    ret = 0;
8226
    while ((*cur >= '0') && (*cur <= '9')) {
8227
  ret = ret * 10 + (*cur - '0');
8228
  ok = 1;
8229
  cur++;
8230
    }
8231
#endif
8232
8233
0
    if (*cur == '.') {
8234
0
  int v, frac = 0, max;
8235
0
  double fraction = 0;
8236
8237
0
        cur++;
8238
0
  if (((*cur < '0') || (*cur > '9')) && (!ok)) {
8239
0
      return(xmlXPathNAN);
8240
0
  }
8241
0
        while (*cur == '0') {
8242
0
      frac = frac + 1;
8243
0
      cur++;
8244
0
        }
8245
0
        max = frac + MAX_FRAC;
8246
0
  while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
8247
0
      v = (*cur - '0');
8248
0
      fraction = fraction * 10 + v;
8249
0
      frac = frac + 1;
8250
0
      cur++;
8251
0
  }
8252
0
  fraction /= pow(10.0, frac);
8253
0
  ret = ret + fraction;
8254
0
  while ((*cur >= '0') && (*cur <= '9'))
8255
0
      cur++;
8256
0
    }
8257
0
    if ((*cur == 'e') || (*cur == 'E')) {
8258
0
      cur++;
8259
0
      if (*cur == '-') {
8260
0
  is_exponent_negative = 1;
8261
0
  cur++;
8262
0
      } else if (*cur == '+') {
8263
0
        cur++;
8264
0
      }
8265
0
      while ((*cur >= '0') && (*cur <= '9')) {
8266
0
        if (exponent < 1000000)
8267
0
    exponent = exponent * 10 + (*cur - '0');
8268
0
  cur++;
8269
0
      }
8270
0
    }
8271
0
    while (IS_BLANK_CH(*cur)) cur++;
8272
0
    if (*cur != 0) return(xmlXPathNAN);
8273
0
    if (isneg) ret = -ret;
8274
0
    if (is_exponent_negative) exponent = -exponent;
8275
0
    ret *= pow(10.0, (double)exponent);
8276
0
    return(ret);
8277
0
}
8278
8279
/**
8280
 *  [30]   Number ::=   Digits ('.' Digits?)?
8281
 *                    | '.' Digits
8282
 *  [31]   Digits ::=   [0-9]+
8283
 *
8284
 * Compile a Number, then push it on the stack
8285
 *
8286
 * @param ctxt  the XPath Parser context
8287
 */
8288
static void
8289
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
8290
0
{
8291
0
    double ret = 0.0;
8292
0
    int ok = 0;
8293
0
    int exponent = 0;
8294
0
    int is_exponent_negative = 0;
8295
0
    xmlXPathObjectPtr num;
8296
0
#ifdef __GNUC__
8297
0
    unsigned long tmp = 0;
8298
0
    double temp;
8299
0
#endif
8300
8301
0
    CHECK_ERROR;
8302
0
    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
8303
0
        XP_ERROR(XPATH_NUMBER_ERROR);
8304
0
    }
8305
0
#ifdef __GNUC__
8306
    /*
8307
     * tmp/temp is a workaround against a gcc compiler bug
8308
     * http://veillard.com/gcc.bug
8309
     */
8310
0
    ret = 0;
8311
0
    while ((CUR >= '0') && (CUR <= '9')) {
8312
0
  ret = ret * 10;
8313
0
  tmp = (CUR - '0');
8314
0
        ok = 1;
8315
0
        NEXT;
8316
0
  temp = (double) tmp;
8317
0
  ret = ret + temp;
8318
0
    }
8319
#else
8320
    ret = 0;
8321
    while ((CUR >= '0') && (CUR <= '9')) {
8322
  ret = ret * 10 + (CUR - '0');
8323
  ok = 1;
8324
  NEXT;
8325
    }
8326
#endif
8327
0
    if (CUR == '.') {
8328
0
  int v, frac = 0, max;
8329
0
  double fraction = 0;
8330
8331
0
        NEXT;
8332
0
        if (((CUR < '0') || (CUR > '9')) && (!ok)) {
8333
0
            XP_ERROR(XPATH_NUMBER_ERROR);
8334
0
        }
8335
0
        while (CUR == '0') {
8336
0
            frac = frac + 1;
8337
0
            NEXT;
8338
0
        }
8339
0
        max = frac + MAX_FRAC;
8340
0
        while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
8341
0
      v = (CUR - '0');
8342
0
      fraction = fraction * 10 + v;
8343
0
      frac = frac + 1;
8344
0
            NEXT;
8345
0
        }
8346
0
        fraction /= pow(10.0, frac);
8347
0
        ret = ret + fraction;
8348
0
        while ((CUR >= '0') && (CUR <= '9'))
8349
0
            NEXT;
8350
0
    }
8351
0
    if ((CUR == 'e') || (CUR == 'E')) {
8352
0
        NEXT;
8353
0
        if (CUR == '-') {
8354
0
            is_exponent_negative = 1;
8355
0
            NEXT;
8356
0
        } else if (CUR == '+') {
8357
0
      NEXT;
8358
0
  }
8359
0
        while ((CUR >= '0') && (CUR <= '9')) {
8360
0
            if (exponent < 1000000)
8361
0
                exponent = exponent * 10 + (CUR - '0');
8362
0
            NEXT;
8363
0
        }
8364
0
        if (is_exponent_negative)
8365
0
            exponent = -exponent;
8366
0
        ret *= pow(10.0, (double) exponent);
8367
0
    }
8368
0
    num = xmlXPathCacheNewFloat(ctxt, ret);
8369
0
    if (num == NULL) {
8370
0
  ctxt->error = XPATH_MEMORY_ERROR;
8371
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
8372
0
                              NULL) == -1) {
8373
0
        xmlXPathReleaseObject(ctxt->context, num);
8374
0
    }
8375
0
}
8376
8377
/**
8378
 * Parse a Literal
8379
 *
8380
 *  [29]   Literal ::=   '"' [^"]* '"'
8381
 *                    | "'" [^']* "'"
8382
 *
8383
 * @param ctxt  the XPath Parser context
8384
 * @returns the value found or NULL in case of error
8385
 */
8386
static xmlChar *
8387
0
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
8388
0
    const xmlChar *q;
8389
0
    xmlChar *ret = NULL;
8390
0
    int quote;
8391
8392
0
    if (CUR == '"') {
8393
0
        quote = '"';
8394
0
    } else if (CUR == '\'') {
8395
0
        quote = '\'';
8396
0
    } else {
8397
0
  XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
8398
0
    }
8399
8400
0
    NEXT;
8401
0
    q = CUR_PTR;
8402
0
    while (CUR != quote) {
8403
0
        int ch;
8404
0
        int len = 4;
8405
8406
0
        if (CUR == 0)
8407
0
            XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
8408
0
        ch = xmlGetUTF8Char(CUR_PTR, &len);
8409
0
        if ((ch < 0) || (IS_CHAR(ch) == 0))
8410
0
            XP_ERRORNULL(XPATH_INVALID_CHAR_ERROR);
8411
0
        CUR_PTR += len;
8412
0
    }
8413
0
    ret = xmlStrndup(q, CUR_PTR - q);
8414
0
    if (ret == NULL)
8415
0
        xmlXPathPErrMemory(ctxt);
8416
0
    NEXT;
8417
0
    return(ret);
8418
0
}
8419
8420
/**
8421
 * Parse a Literal and push it on the stack.
8422
 *
8423
 *  [29]   Literal ::=   '"' [^"]* '"'
8424
 *                    | "'" [^']* "'"
8425
 *
8426
 * TODO: Memory allocation could be improved.
8427
 *
8428
 * @param ctxt  the XPath Parser context
8429
 */
8430
static void
8431
0
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
8432
0
    xmlChar *ret = NULL;
8433
0
    xmlXPathObjectPtr lit;
8434
8435
0
    ret = xmlXPathParseLiteral(ctxt);
8436
0
    if (ret == NULL)
8437
0
        return;
8438
0
    lit = xmlXPathCacheNewString(ctxt, ret);
8439
0
    if (lit == NULL) {
8440
0
        ctxt->error = XPATH_MEMORY_ERROR;
8441
0
    } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
8442
0
                              NULL) == -1) {
8443
0
        xmlXPathReleaseObject(ctxt->context, lit);
8444
0
    }
8445
0
    xmlFree(ret);
8446
0
}
8447
8448
/**
8449
 * Parse a VariableReference, evaluate it and push it on the stack.
8450
 *
8451
 * The variable bindings consist of a mapping from variable names
8452
 * to variable values. The value of a variable is an object, which can be
8453
 * of any of the types that are possible for the value of an expression,
8454
 * and may also be of additional types not specified here.
8455
 *
8456
 * Early evaluation is possible since:
8457
 * The variable bindings [...] used to evaluate a subexpression are
8458
 * always the same as those used to evaluate the containing expression.
8459
 *
8460
 *  [36]   VariableReference ::=   '$' QName
8461
 * @param ctxt  the XPath Parser context
8462
 */
8463
static void
8464
0
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
8465
0
    xmlChar *name;
8466
0
    xmlChar *prefix;
8467
8468
0
    SKIP_BLANKS;
8469
0
    if (CUR != '$') {
8470
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8471
0
    }
8472
0
    NEXT;
8473
0
    name = xmlXPathParseQName(ctxt, &prefix);
8474
0
    if (name == NULL) {
8475
0
        xmlFree(prefix);
8476
0
  XP_ERROR(XPATH_VARIABLE_REF_ERROR);
8477
0
    }
8478
0
    ctxt->comp->last = -1;
8479
0
    if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
8480
0
        xmlFree(prefix);
8481
0
        xmlFree(name);
8482
0
    }
8483
0
    SKIP_BLANKS;
8484
0
    if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
8485
0
  XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
8486
0
    }
8487
0
}
8488
8489
/**
8490
 * Is the name given a NodeType one.
8491
 *
8492
 *  [38]   NodeType ::=   'comment'
8493
 *                    | 'text'
8494
 *                    | 'processing-instruction'
8495
 *                    | 'node'
8496
 *
8497
 * @param name  a name string
8498
 * @returns 1 if true 0 otherwise
8499
 */
8500
int
8501
0
xmlXPathIsNodeType(const xmlChar *name) {
8502
0
    if (name == NULL)
8503
0
  return(0);
8504
8505
0
    if (xmlStrEqual(name, BAD_CAST "node"))
8506
0
  return(1);
8507
0
    if (xmlStrEqual(name, BAD_CAST "text"))
8508
0
  return(1);
8509
0
    if (xmlStrEqual(name, BAD_CAST "comment"))
8510
0
  return(1);
8511
0
    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8512
0
  return(1);
8513
0
    return(0);
8514
0
}
8515
8516
/**
8517
 *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
8518
 *  [17]   Argument ::=   Expr
8519
 *
8520
 * Compile a function call, the evaluation of all arguments are
8521
 * pushed on the stack
8522
 *
8523
 * @param ctxt  the XPath Parser context
8524
 */
8525
static void
8526
0
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
8527
0
    xmlChar *name;
8528
0
    xmlChar *prefix;
8529
0
    int nbargs = 0;
8530
0
    int sort = 1;
8531
8532
0
    name = xmlXPathParseQName(ctxt, &prefix);
8533
0
    if (name == NULL) {
8534
0
  xmlFree(prefix);
8535
0
  XP_ERROR(XPATH_EXPR_ERROR);
8536
0
    }
8537
0
    SKIP_BLANKS;
8538
8539
0
    if (CUR != '(') {
8540
0
  xmlFree(name);
8541
0
  xmlFree(prefix);
8542
0
  XP_ERROR(XPATH_EXPR_ERROR);
8543
0
    }
8544
0
    NEXT;
8545
0
    SKIP_BLANKS;
8546
8547
    /*
8548
    * Optimization for count(): we don't need the node-set to be sorted.
8549
    */
8550
0
    if ((prefix == NULL) && (name[0] == 'c') &&
8551
0
  xmlStrEqual(name, BAD_CAST "count"))
8552
0
    {
8553
0
  sort = 0;
8554
0
    }
8555
0
    ctxt->comp->last = -1;
8556
0
    if (CUR != ')') {
8557
0
  while (CUR != 0) {
8558
0
      int op1 = ctxt->comp->last;
8559
0
      ctxt->comp->last = -1;
8560
0
      xmlXPathCompileExpr(ctxt, sort);
8561
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
8562
0
    xmlFree(name);
8563
0
    xmlFree(prefix);
8564
0
    return;
8565
0
      }
8566
0
      PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
8567
0
      nbargs++;
8568
0
      if (CUR == ')') break;
8569
0
      if (CUR != ',') {
8570
0
    xmlFree(name);
8571
0
    xmlFree(prefix);
8572
0
    XP_ERROR(XPATH_EXPR_ERROR);
8573
0
      }
8574
0
      NEXT;
8575
0
      SKIP_BLANKS;
8576
0
  }
8577
0
    }
8578
0
    if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
8579
0
        xmlFree(prefix);
8580
0
        xmlFree(name);
8581
0
    }
8582
0
    NEXT;
8583
0
    SKIP_BLANKS;
8584
0
}
8585
8586
/**
8587
 *  [15]   PrimaryExpr ::=   VariableReference
8588
 *                | '(' Expr ')'
8589
 *                | Literal
8590
 *                | Number
8591
 *                | FunctionCall
8592
 *
8593
 * Compile a primary expression.
8594
 *
8595
 * @param ctxt  the XPath Parser context
8596
 */
8597
static void
8598
0
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
8599
0
    SKIP_BLANKS;
8600
0
    if (CUR == '$') xmlXPathCompVariableReference(ctxt);
8601
0
    else if (CUR == '(') {
8602
0
  NEXT;
8603
0
  SKIP_BLANKS;
8604
0
  xmlXPathCompileExpr(ctxt, 1);
8605
0
  CHECK_ERROR;
8606
0
  if (CUR != ')') {
8607
0
      XP_ERROR(XPATH_EXPR_ERROR);
8608
0
  }
8609
0
  NEXT;
8610
0
  SKIP_BLANKS;
8611
0
    } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8612
0
  xmlXPathCompNumber(ctxt);
8613
0
    } else if ((CUR == '\'') || (CUR == '"')) {
8614
0
  xmlXPathCompLiteral(ctxt);
8615
0
    } else {
8616
0
  xmlXPathCompFunctionCall(ctxt);
8617
0
    }
8618
0
    SKIP_BLANKS;
8619
0
}
8620
8621
/**
8622
 *  [20]   FilterExpr ::=   PrimaryExpr
8623
 *               | FilterExpr Predicate
8624
 *
8625
 * Compile a filter expression.
8626
 * Square brackets are used to filter expressions in the same way that
8627
 * they are used in location paths. It is an error if the expression to
8628
 * be filtered does not evaluate to a node-set. The context node list
8629
 * used for evaluating the expression in square brackets is the node-set
8630
 * to be filtered listed in document order.
8631
 *
8632
 * @param ctxt  the XPath Parser context
8633
 */
8634
8635
static void
8636
0
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
8637
0
    xmlXPathCompPrimaryExpr(ctxt);
8638
0
    CHECK_ERROR;
8639
0
    SKIP_BLANKS;
8640
8641
0
    while (CUR == '[') {
8642
0
  xmlXPathCompPredicate(ctxt, 1);
8643
0
  SKIP_BLANKS;
8644
0
    }
8645
8646
8647
0
}
8648
8649
/**
8650
 * Trickery: parse an XML name but without consuming the input flow
8651
 * Needed to avoid insanity in the parser state.
8652
 *
8653
 * @param ctxt  the XPath Parser context
8654
 * @returns the Name parsed or NULL
8655
 */
8656
8657
static xmlChar *
8658
0
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
8659
0
    const xmlChar *end;
8660
0
    xmlChar *ret;
8661
8662
0
    end = xmlScanName(ctxt->cur, XML_MAX_NAME_LENGTH, 0);
8663
0
    if (end == NULL) {
8664
0
        XP_ERRORNULL(XPATH_EXPR_ERROR);
8665
0
    }
8666
0
    if (end == ctxt->cur)
8667
0
        return(NULL);
8668
8669
0
    ret = xmlStrndup(ctxt->cur, end - ctxt->cur);
8670
0
    if (ret == NULL)
8671
0
        xmlXPathPErrMemory(ctxt);
8672
0
    return(ret);
8673
0
}
8674
8675
/**
8676
 *  [19]   PathExpr ::=   LocationPath
8677
 *               | FilterExpr
8678
 *               | FilterExpr '/' RelativeLocationPath
8679
 *               | FilterExpr '//' RelativeLocationPath
8680
 *
8681
 * Compile a path expression.
8682
 *
8683
 * @param ctxt  the XPath Parser context
8684
 */
8685
8686
static void
8687
0
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
8688
0
    int lc = 1;           /* Should we branch to LocationPath ?         */
8689
0
    xmlChar *name = NULL; /* we may have to preparse a name to find out */
8690
8691
0
    SKIP_BLANKS;
8692
0
    if ((CUR == '$') || (CUR == '(') ||
8693
0
  (IS_ASCII_DIGIT(CUR)) ||
8694
0
        (CUR == '\'') || (CUR == '"') ||
8695
0
  (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
8696
0
  lc = 0;
8697
0
    } else if (CUR == '*') {
8698
  /* relative or absolute location path */
8699
0
  lc = 1;
8700
0
    } else if (CUR == '/') {
8701
  /* relative or absolute location path */
8702
0
  lc = 1;
8703
0
    } else if (CUR == '@') {
8704
  /* relative abbreviated attribute location path */
8705
0
  lc = 1;
8706
0
    } else if (CUR == '.') {
8707
  /* relative abbreviated attribute location path */
8708
0
  lc = 1;
8709
0
    } else {
8710
  /*
8711
   * Problem is finding if we have a name here whether it's:
8712
   *   - a nodetype
8713
   *   - a function call in which case it's followed by '('
8714
   *   - an axis in which case it's followed by ':'
8715
   *   - a element name
8716
   * We do an a priori analysis here rather than having to
8717
   * maintain parsed token content through the recursive function
8718
   * calls. This looks uglier but makes the code easier to
8719
   * read/write/debug.
8720
   */
8721
0
  SKIP_BLANKS;
8722
0
  name = xmlXPathScanName(ctxt);
8723
0
  if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
8724
0
      lc = 1;
8725
0
      xmlFree(name);
8726
0
  } else if (name != NULL) {
8727
0
      int len =xmlStrlen(name);
8728
8729
8730
0
      while (NXT(len) != 0) {
8731
0
    if (NXT(len) == '/') {
8732
        /* element name */
8733
0
        lc = 1;
8734
0
        break;
8735
0
    } else if (IS_BLANK_CH(NXT(len))) {
8736
        /* ignore blanks */
8737
0
        ;
8738
0
    } else if (NXT(len) == ':') {
8739
0
        lc = 1;
8740
0
        break;
8741
0
    } else if ((NXT(len) == '(')) {
8742
        /* Node Type or Function */
8743
0
        if (xmlXPathIsNodeType(name)) {
8744
0
      lc = 1;
8745
0
        } else {
8746
0
      lc = 0;
8747
0
        }
8748
0
                    break;
8749
0
    } else if ((NXT(len) == '[')) {
8750
        /* element name */
8751
0
        lc = 1;
8752
0
        break;
8753
0
    } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
8754
0
         (NXT(len) == '=')) {
8755
0
        lc = 1;
8756
0
        break;
8757
0
    } else {
8758
0
        lc = 1;
8759
0
        break;
8760
0
    }
8761
0
    len++;
8762
0
      }
8763
0
      if (NXT(len) == 0) {
8764
    /* element name */
8765
0
    lc = 1;
8766
0
      }
8767
0
      xmlFree(name);
8768
0
  } else {
8769
      /* make sure all cases are covered explicitly */
8770
0
      XP_ERROR(XPATH_EXPR_ERROR);
8771
0
  }
8772
0
    }
8773
8774
0
    if (lc) {
8775
0
  if (CUR == '/') {
8776
0
      PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8777
0
  } else {
8778
0
      PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8779
0
  }
8780
0
  xmlXPathCompLocationPath(ctxt);
8781
0
    } else {
8782
0
  xmlXPathCompFilterExpr(ctxt);
8783
0
  CHECK_ERROR;
8784
0
  if ((CUR == '/') && (NXT(1) == '/')) {
8785
0
      SKIP(2);
8786
0
      SKIP_BLANKS;
8787
8788
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8789
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8790
8791
0
      xmlXPathCompRelativeLocationPath(ctxt);
8792
0
  } else if (CUR == '/') {
8793
0
      xmlXPathCompRelativeLocationPath(ctxt);
8794
0
  }
8795
0
    }
8796
0
    SKIP_BLANKS;
8797
0
}
8798
8799
/**
8800
 *  [18]   UnionExpr ::=   PathExpr
8801
 *               | UnionExpr '|' PathExpr
8802
 *
8803
 * Compile an union expression.
8804
 *
8805
 * @param ctxt  the XPath Parser context
8806
 */
8807
8808
static void
8809
0
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8810
0
    xmlXPathCompPathExpr(ctxt);
8811
0
    CHECK_ERROR;
8812
0
    SKIP_BLANKS;
8813
0
    while (CUR == '|') {
8814
0
  int op1 = ctxt->comp->last;
8815
0
  PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8816
8817
0
  NEXT;
8818
0
  SKIP_BLANKS;
8819
0
  xmlXPathCompPathExpr(ctxt);
8820
8821
0
  PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8822
8823
0
  SKIP_BLANKS;
8824
0
    }
8825
0
}
8826
8827
/**
8828
 *  [27]   UnaryExpr ::=   UnionExpr
8829
 *                   | '-' UnaryExpr
8830
 *
8831
 * Compile an unary expression.
8832
 *
8833
 * @param ctxt  the XPath Parser context
8834
 */
8835
8836
static void
8837
0
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8838
0
    int minus = 0;
8839
0
    int found = 0;
8840
8841
0
    SKIP_BLANKS;
8842
0
    while (CUR == '-') {
8843
0
        minus = 1 - minus;
8844
0
  found = 1;
8845
0
  NEXT;
8846
0
  SKIP_BLANKS;
8847
0
    }
8848
8849
0
    xmlXPathCompUnionExpr(ctxt);
8850
0
    CHECK_ERROR;
8851
0
    if (found) {
8852
0
  if (minus)
8853
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8854
0
  else
8855
0
      PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8856
0
    }
8857
0
}
8858
8859
/**
8860
 *  [26]   MultiplicativeExpr ::=   UnaryExpr
8861
 *                   | MultiplicativeExpr MultiplyOperator UnaryExpr
8862
 *                   | MultiplicativeExpr 'div' UnaryExpr
8863
 *                   | MultiplicativeExpr 'mod' UnaryExpr
8864
 *  [34]   MultiplyOperator ::=   '*'
8865
 *
8866
 * Compile an Additive expression.
8867
 *
8868
 * @param ctxt  the XPath Parser context
8869
 */
8870
8871
static void
8872
0
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8873
0
    xmlXPathCompUnaryExpr(ctxt);
8874
0
    CHECK_ERROR;
8875
0
    SKIP_BLANKS;
8876
0
    while ((CUR == '*') ||
8877
0
           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8878
0
           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8879
0
  int op = -1;
8880
0
  int op1 = ctxt->comp->last;
8881
8882
0
        if (CUR == '*') {
8883
0
      op = 0;
8884
0
      NEXT;
8885
0
  } else if (CUR == 'd') {
8886
0
      op = 1;
8887
0
      SKIP(3);
8888
0
  } else if (CUR == 'm') {
8889
0
      op = 2;
8890
0
      SKIP(3);
8891
0
  }
8892
0
  SKIP_BLANKS;
8893
0
        xmlXPathCompUnaryExpr(ctxt);
8894
0
  CHECK_ERROR;
8895
0
  PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8896
0
  SKIP_BLANKS;
8897
0
    }
8898
0
}
8899
8900
/**
8901
 *  [25]   AdditiveExpr ::=   MultiplicativeExpr
8902
 *                   | AdditiveExpr '+' MultiplicativeExpr
8903
 *                   | AdditiveExpr '-' MultiplicativeExpr
8904
 *
8905
 * Compile an Additive expression.
8906
 *
8907
 * @param ctxt  the XPath Parser context
8908
 */
8909
8910
static void
8911
0
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8912
8913
0
    xmlXPathCompMultiplicativeExpr(ctxt);
8914
0
    CHECK_ERROR;
8915
0
    SKIP_BLANKS;
8916
0
    while ((CUR == '+') || (CUR == '-')) {
8917
0
  int plus;
8918
0
  int op1 = ctxt->comp->last;
8919
8920
0
        if (CUR == '+') plus = 1;
8921
0
  else plus = 0;
8922
0
  NEXT;
8923
0
  SKIP_BLANKS;
8924
0
        xmlXPathCompMultiplicativeExpr(ctxt);
8925
0
  CHECK_ERROR;
8926
0
  PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8927
0
  SKIP_BLANKS;
8928
0
    }
8929
0
}
8930
8931
/**
8932
 *  [24]   RelationalExpr ::=   AdditiveExpr
8933
 *                 | RelationalExpr '<' AdditiveExpr
8934
 *                 | RelationalExpr '>' AdditiveExpr
8935
 *                 | RelationalExpr '<=' AdditiveExpr
8936
 *                 | RelationalExpr '>=' AdditiveExpr
8937
 *
8938
 *  A <= B > C is allowed ? Answer from James, yes with
8939
 *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8940
 *  which is basically what got implemented.
8941
 *
8942
 * Compile a Relational expression, then push the result
8943
 * on the stack
8944
 *
8945
 * @param ctxt  the XPath Parser context
8946
 */
8947
8948
static void
8949
0
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8950
0
    xmlXPathCompAdditiveExpr(ctxt);
8951
0
    CHECK_ERROR;
8952
0
    SKIP_BLANKS;
8953
0
    while ((CUR == '<') || (CUR == '>')) {
8954
0
  int inf, strict;
8955
0
  int op1 = ctxt->comp->last;
8956
8957
0
        if (CUR == '<') inf = 1;
8958
0
  else inf = 0;
8959
0
  if (NXT(1) == '=') strict = 0;
8960
0
  else strict = 1;
8961
0
  NEXT;
8962
0
  if (!strict) NEXT;
8963
0
  SKIP_BLANKS;
8964
0
        xmlXPathCompAdditiveExpr(ctxt);
8965
0
  CHECK_ERROR;
8966
0
  PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8967
0
  SKIP_BLANKS;
8968
0
    }
8969
0
}
8970
8971
/**
8972
 *  [23]   EqualityExpr ::=   RelationalExpr
8973
 *                 | EqualityExpr '=' RelationalExpr
8974
 *                 | EqualityExpr '!=' RelationalExpr
8975
 *
8976
 *  A != B != C is allowed ? Answer from James, yes with
8977
 *  (RelationalExpr = RelationalExpr) = RelationalExpr
8978
 *  (RelationalExpr != RelationalExpr) != RelationalExpr
8979
 *  which is basically what got implemented.
8980
 *
8981
 * Compile an Equality expression.
8982
 *
8983
 * @param ctxt  the XPath Parser context
8984
 */
8985
static void
8986
0
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8987
0
    xmlXPathCompRelationalExpr(ctxt);
8988
0
    CHECK_ERROR;
8989
0
    SKIP_BLANKS;
8990
0
    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
8991
0
  int eq;
8992
0
  int op1 = ctxt->comp->last;
8993
8994
0
        if (CUR == '=') eq = 1;
8995
0
  else eq = 0;
8996
0
  NEXT;
8997
0
  if (!eq) NEXT;
8998
0
  SKIP_BLANKS;
8999
0
        xmlXPathCompRelationalExpr(ctxt);
9000
0
  CHECK_ERROR;
9001
0
  PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
9002
0
  SKIP_BLANKS;
9003
0
    }
9004
0
}
9005
9006
/**
9007
 *  [22]   AndExpr ::=   EqualityExpr
9008
 *                 | AndExpr 'and' EqualityExpr
9009
 *
9010
 * Compile an AND expression.
9011
 *
9012
 * @param ctxt  the XPath Parser context
9013
 */
9014
static void
9015
0
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
9016
0
    xmlXPathCompEqualityExpr(ctxt);
9017
0
    CHECK_ERROR;
9018
0
    SKIP_BLANKS;
9019
0
    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
9020
0
  int op1 = ctxt->comp->last;
9021
0
        SKIP(3);
9022
0
  SKIP_BLANKS;
9023
0
        xmlXPathCompEqualityExpr(ctxt);
9024
0
  CHECK_ERROR;
9025
0
  PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
9026
0
  SKIP_BLANKS;
9027
0
    }
9028
0
}
9029
9030
/**
9031
 *  [14]   Expr ::=   OrExpr
9032
 *  [21]   OrExpr ::=   AndExpr
9033
 *                 | OrExpr 'or' AndExpr
9034
 *
9035
 * Parse and compile an expression
9036
 *
9037
 * @param ctxt  the XPath Parser context
9038
 * @param sort  whether to sort the resulting node set
9039
 */
9040
static void
9041
0
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
9042
0
    xmlXPathContextPtr xpctxt = ctxt->context;
9043
9044
0
    if (xpctxt != NULL) {
9045
0
        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
9046
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9047
        /*
9048
         * Parsing a single '(' pushes about 10 functions on the call stack
9049
         * before recursing!
9050
         */
9051
0
        xpctxt->depth += 10;
9052
0
    }
9053
9054
0
    xmlXPathCompAndExpr(ctxt);
9055
0
    CHECK_ERROR;
9056
0
    SKIP_BLANKS;
9057
0
    while ((CUR == 'o') && (NXT(1) == 'r')) {
9058
0
  int op1 = ctxt->comp->last;
9059
0
        SKIP(2);
9060
0
  SKIP_BLANKS;
9061
0
        xmlXPathCompAndExpr(ctxt);
9062
0
  CHECK_ERROR;
9063
0
  PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
9064
0
  SKIP_BLANKS;
9065
0
    }
9066
0
    if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
9067
  /* more ops could be optimized too */
9068
  /*
9069
  * This is the main place to eliminate sorting for
9070
  * operations which don't require a sorted node-set.
9071
  * E.g. count().
9072
  */
9073
0
  PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
9074
0
    }
9075
9076
0
    if (xpctxt != NULL)
9077
0
        xpctxt->depth -= 10;
9078
0
}
9079
9080
/**
9081
 *  [8]   Predicate ::=   '[' PredicateExpr ']'
9082
 *  [9]   PredicateExpr ::=   Expr
9083
 *
9084
 * Compile a predicate expression
9085
 *
9086
 * @param ctxt  the XPath Parser context
9087
 * @param filter  act as a filter
9088
 */
9089
static void
9090
0
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
9091
0
    int op1 = ctxt->comp->last;
9092
9093
0
    SKIP_BLANKS;
9094
0
    if (CUR != '[') {
9095
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9096
0
    }
9097
0
    NEXT;
9098
0
    SKIP_BLANKS;
9099
9100
0
    ctxt->comp->last = -1;
9101
    /*
9102
    * This call to xmlXPathCompileExpr() will deactivate sorting
9103
    * of the predicate result.
9104
    * TODO: Sorting is still activated for filters, since I'm not
9105
    *  sure if needed. Normally sorting should not be needed, since
9106
    *  a filter can only diminish the number of items in a sequence,
9107
    *  but won't change its order; so if the initial sequence is sorted,
9108
    *  subsequent sorting is not needed.
9109
    */
9110
0
    if (! filter)
9111
0
  xmlXPathCompileExpr(ctxt, 0);
9112
0
    else
9113
0
  xmlXPathCompileExpr(ctxt, 1);
9114
0
    CHECK_ERROR;
9115
9116
0
    if (CUR != ']') {
9117
0
  XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
9118
0
    }
9119
9120
0
    if (filter)
9121
0
  PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
9122
0
    else
9123
0
  PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
9124
9125
0
    NEXT;
9126
0
    SKIP_BLANKS;
9127
0
}
9128
9129
/**
9130
 * ```
9131
 * [7] NodeTest ::=   NameTest
9132
 *        | NodeType '(' ')'
9133
 *        | 'processing-instruction' '(' Literal ')'
9134
 *
9135
 * [37] NameTest ::=  '*'
9136
 *        | NCName ':' '*'
9137
 *        | QName
9138
 * [38] NodeType ::= 'comment'
9139
 *       | 'text'
9140
 *       | 'processing-instruction'
9141
 *       | 'node'
9142
 * ```
9143
 *
9144
 * @param ctxt  the XPath Parser context
9145
 * @param test  pointer to a xmlXPathTestVal
9146
 * @param type  pointer to a xmlXPathTypeVal
9147
 * @param prefix  placeholder for a possible name prefix
9148
 * @param name  current name token (optional)
9149
 * @returns the name found and updates `test`, `type` and `prefix` appropriately
9150
 */
9151
static xmlChar *
9152
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
9153
               xmlXPathTypeVal *type, xmlChar **prefix,
9154
0
         xmlChar *name) {
9155
0
    int blanks;
9156
9157
0
    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
9158
0
  return(NULL);
9159
0
    }
9160
0
    *type = (xmlXPathTypeVal) 0;
9161
0
    *test = (xmlXPathTestVal) 0;
9162
0
    *prefix = NULL;
9163
0
    SKIP_BLANKS;
9164
9165
0
    if ((name == NULL) && (CUR == '*')) {
9166
  /*
9167
   * All elements
9168
   */
9169
0
  NEXT;
9170
0
  *test = NODE_TEST_ALL;
9171
0
  return(NULL);
9172
0
    }
9173
9174
0
    if (name == NULL)
9175
0
  name = xmlXPathParseNCName(ctxt);
9176
0
    if (name == NULL) {
9177
0
  XP_ERRORNULL(XPATH_EXPR_ERROR);
9178
0
    }
9179
9180
0
    blanks = IS_BLANK_CH(CUR);
9181
0
    SKIP_BLANKS;
9182
0
    if (CUR == '(') {
9183
0
  NEXT;
9184
  /*
9185
   * NodeType or PI search
9186
   */
9187
0
  if (xmlStrEqual(name, BAD_CAST "comment"))
9188
0
      *type = NODE_TYPE_COMMENT;
9189
0
  else if (xmlStrEqual(name, BAD_CAST "node"))
9190
0
      *type = NODE_TYPE_NODE;
9191
0
  else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9192
0
      *type = NODE_TYPE_PI;
9193
0
  else if (xmlStrEqual(name, BAD_CAST "text"))
9194
0
      *type = NODE_TYPE_TEXT;
9195
0
  else {
9196
0
      if (name != NULL)
9197
0
    xmlFree(name);
9198
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9199
0
  }
9200
9201
0
  *test = NODE_TEST_TYPE;
9202
9203
0
  SKIP_BLANKS;
9204
0
  if (*type == NODE_TYPE_PI) {
9205
      /*
9206
       * Specific case: search a PI by name.
9207
       */
9208
0
      if (name != NULL)
9209
0
    xmlFree(name);
9210
0
      name = NULL;
9211
0
      if (CUR != ')') {
9212
0
    name = xmlXPathParseLiteral(ctxt);
9213
0
    *test = NODE_TEST_PI;
9214
0
    SKIP_BLANKS;
9215
0
      }
9216
0
  }
9217
0
  if (CUR != ')') {
9218
0
      if (name != NULL)
9219
0
    xmlFree(name);
9220
0
      XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
9221
0
  }
9222
0
  NEXT;
9223
0
  return(name);
9224
0
    }
9225
0
    *test = NODE_TEST_NAME;
9226
0
    if ((!blanks) && (CUR == ':')) {
9227
0
  NEXT;
9228
9229
  /*
9230
   * Since currently the parser context don't have a
9231
   * namespace list associated:
9232
   * The namespace name for this prefix can be computed
9233
   * only at evaluation time. The compilation is done
9234
   * outside of any context.
9235
   */
9236
0
  *prefix = name;
9237
9238
0
  if (CUR == '*') {
9239
      /*
9240
       * All elements
9241
       */
9242
0
      NEXT;
9243
0
      *test = NODE_TEST_ALL;
9244
0
      return(NULL);
9245
0
  }
9246
9247
0
  name = xmlXPathParseNCName(ctxt);
9248
0
  if (name == NULL) {
9249
0
      XP_ERRORNULL(XPATH_EXPR_ERROR);
9250
0
  }
9251
0
    }
9252
0
    return(name);
9253
0
}
9254
9255
/**
9256
 * [6] AxisName ::=   'ancestor'
9257
 *                  | 'ancestor-or-self'
9258
 *                  | 'attribute'
9259
 *                  | 'child'
9260
 *                  | 'descendant'
9261
 *                  | 'descendant-or-self'
9262
 *                  | 'following'
9263
 *                  | 'following-sibling'
9264
 *                  | 'namespace'
9265
 *                  | 'parent'
9266
 *                  | 'preceding'
9267
 *                  | 'preceding-sibling'
9268
 *                  | 'self'
9269
 *
9270
 * @param name  a preparsed name token
9271
 * @returns the axis or 0
9272
 */
9273
static xmlXPathAxisVal
9274
0
xmlXPathIsAxisName(const xmlChar *name) {
9275
0
    xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
9276
0
    switch (name[0]) {
9277
0
  case 'a':
9278
0
      if (xmlStrEqual(name, BAD_CAST "ancestor"))
9279
0
    ret = AXIS_ANCESTOR;
9280
0
      if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
9281
0
    ret = AXIS_ANCESTOR_OR_SELF;
9282
0
      if (xmlStrEqual(name, BAD_CAST "attribute"))
9283
0
    ret = AXIS_ATTRIBUTE;
9284
0
      break;
9285
0
  case 'c':
9286
0
      if (xmlStrEqual(name, BAD_CAST "child"))
9287
0
    ret = AXIS_CHILD;
9288
0
      break;
9289
0
  case 'd':
9290
0
      if (xmlStrEqual(name, BAD_CAST "descendant"))
9291
0
    ret = AXIS_DESCENDANT;
9292
0
      if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
9293
0
    ret = AXIS_DESCENDANT_OR_SELF;
9294
0
      break;
9295
0
  case 'f':
9296
0
      if (xmlStrEqual(name, BAD_CAST "following"))
9297
0
    ret = AXIS_FOLLOWING;
9298
0
      if (xmlStrEqual(name, BAD_CAST "following-sibling"))
9299
0
    ret = AXIS_FOLLOWING_SIBLING;
9300
0
      break;
9301
0
  case 'n':
9302
0
      if (xmlStrEqual(name, BAD_CAST "namespace"))
9303
0
    ret = AXIS_NAMESPACE;
9304
0
      break;
9305
0
  case 'p':
9306
0
      if (xmlStrEqual(name, BAD_CAST "parent"))
9307
0
    ret = AXIS_PARENT;
9308
0
      if (xmlStrEqual(name, BAD_CAST "preceding"))
9309
0
    ret = AXIS_PRECEDING;
9310
0
      if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
9311
0
    ret = AXIS_PRECEDING_SIBLING;
9312
0
      break;
9313
0
  case 's':
9314
0
      if (xmlStrEqual(name, BAD_CAST "self"))
9315
0
    ret = AXIS_SELF;
9316
0
      break;
9317
0
    }
9318
0
    return(ret);
9319
0
}
9320
9321
/**
9322
 * [4] Step ::=   AxisSpecifier NodeTest Predicate*
9323
 *                  | AbbreviatedStep
9324
 *
9325
 * [12] AbbreviatedStep ::=   '.' | '..'
9326
 *
9327
 * [5] AxisSpecifier ::= AxisName '::'
9328
 *                  | AbbreviatedAxisSpecifier
9329
 *
9330
 * [13] AbbreviatedAxisSpecifier ::= '@'?
9331
 *
9332
 * Modified for XPtr range support as:
9333
 *
9334
 *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
9335
 *                     | AbbreviatedStep
9336
 *                     | 'range-to' '(' Expr ')' Predicate*
9337
 *
9338
 * Compile one step in a Location Path
9339
 *
9340
 * @param ctxt  the XPath Parser context
9341
 */
9342
static void
9343
0
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
9344
0
    SKIP_BLANKS;
9345
0
    if ((CUR == '.') && (NXT(1) == '.')) {
9346
0
  SKIP(2);
9347
0
  SKIP_BLANKS;
9348
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
9349
0
        NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9350
0
    } else if (CUR == '.') {
9351
0
  NEXT;
9352
0
  SKIP_BLANKS;
9353
0
    } else {
9354
0
  xmlChar *name = NULL;
9355
0
  xmlChar *prefix = NULL;
9356
0
  xmlXPathTestVal test = (xmlXPathTestVal) 0;
9357
0
  xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
9358
0
  xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
9359
0
  int op1;
9360
9361
0
  if (CUR == '*') {
9362
0
      axis = AXIS_CHILD;
9363
0
  } else {
9364
0
      if (name == NULL)
9365
0
    name = xmlXPathParseNCName(ctxt);
9366
0
      if (name != NULL) {
9367
0
    axis = xmlXPathIsAxisName(name);
9368
0
    if (axis != 0) {
9369
0
        SKIP_BLANKS;
9370
0
        if ((CUR == ':') && (NXT(1) == ':')) {
9371
0
      SKIP(2);
9372
0
      xmlFree(name);
9373
0
      name = NULL;
9374
0
        } else {
9375
      /* an element name can conflict with an axis one :-\ */
9376
0
      axis = AXIS_CHILD;
9377
0
        }
9378
0
    } else {
9379
0
        axis = AXIS_CHILD;
9380
0
    }
9381
0
      } else if (CUR == '@') {
9382
0
    NEXT;
9383
0
    axis = AXIS_ATTRIBUTE;
9384
0
      } else {
9385
0
    axis = AXIS_CHILD;
9386
0
      }
9387
0
  }
9388
9389
0
        if (ctxt->error != XPATH_EXPRESSION_OK) {
9390
0
            xmlFree(name);
9391
0
            return;
9392
0
        }
9393
9394
0
  name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
9395
0
  if (test == 0)
9396
0
      return;
9397
9398
0
        if ((prefix != NULL) && (ctxt->context != NULL) &&
9399
0
      (ctxt->context->flags & XML_XPATH_CHECKNS)) {
9400
0
      if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
9401
0
    xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
9402
0
      }
9403
0
  }
9404
9405
0
  op1 = ctxt->comp->last;
9406
0
  ctxt->comp->last = -1;
9407
9408
0
  SKIP_BLANKS;
9409
0
  while (CUR == '[') {
9410
0
      xmlXPathCompPredicate(ctxt, 0);
9411
0
  }
9412
9413
0
        if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
9414
0
                           test, type, (void *)prefix, (void *)name) == -1) {
9415
0
            xmlFree(prefix);
9416
0
            xmlFree(name);
9417
0
        }
9418
0
    }
9419
0
}
9420
9421
/**
9422
 *  [3]   RelativeLocationPath ::=   Step
9423
 *                     | RelativeLocationPath '/' Step
9424
 *                     | AbbreviatedRelativeLocationPath
9425
 *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step
9426
 *
9427
 * Compile a relative location path.
9428
 *
9429
 * @param ctxt  the XPath Parser context
9430
 */
9431
static void
9432
xmlXPathCompRelativeLocationPath
9433
0
(xmlXPathParserContextPtr ctxt) {
9434
0
    SKIP_BLANKS;
9435
0
    if ((CUR == '/') && (NXT(1) == '/')) {
9436
0
  SKIP(2);
9437
0
  SKIP_BLANKS;
9438
0
  PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9439
0
             NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9440
0
    } else if (CUR == '/') {
9441
0
      NEXT;
9442
0
  SKIP_BLANKS;
9443
0
    }
9444
0
    xmlXPathCompStep(ctxt);
9445
0
    CHECK_ERROR;
9446
0
    SKIP_BLANKS;
9447
0
    while (CUR == '/') {
9448
0
  if ((CUR == '/') && (NXT(1) == '/')) {
9449
0
      SKIP(2);
9450
0
      SKIP_BLANKS;
9451
0
      PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9452
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9453
0
      xmlXPathCompStep(ctxt);
9454
0
  } else if (CUR == '/') {
9455
0
      NEXT;
9456
0
      SKIP_BLANKS;
9457
0
      xmlXPathCompStep(ctxt);
9458
0
  }
9459
0
  SKIP_BLANKS;
9460
0
    }
9461
0
}
9462
9463
/**
9464
 *  [1]   LocationPath ::=   RelativeLocationPath
9465
 *                     | AbsoluteLocationPath
9466
 *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
9467
 *                     | AbbreviatedAbsoluteLocationPath
9468
 *  [10]   AbbreviatedAbsoluteLocationPath ::=
9469
 *                           '//' RelativeLocationPath
9470
 *
9471
 * Compile a location path
9472
 *
9473
 * @param ctxt  the XPath Parser context
9474
 */
9475
static void
9476
0
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
9477
0
    SKIP_BLANKS;
9478
0
    if (CUR != '/') {
9479
0
        xmlXPathCompRelativeLocationPath(ctxt);
9480
0
    } else {
9481
0
  while (CUR == '/') {
9482
0
      if ((CUR == '/') && (NXT(1) == '/')) {
9483
0
    SKIP(2);
9484
0
    SKIP_BLANKS;
9485
0
    PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9486
0
           NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9487
0
    xmlXPathCompRelativeLocationPath(ctxt);
9488
0
      } else if (CUR == '/') {
9489
0
    NEXT;
9490
0
    SKIP_BLANKS;
9491
0
    if ((CUR != 0) &&
9492
0
        ((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
9493
0
                     (CUR == '_') || (CUR == '.') ||
9494
0
         (CUR == '@') || (CUR == '*')))
9495
0
        xmlXPathCompRelativeLocationPath(ctxt);
9496
0
      }
9497
0
      CHECK_ERROR;
9498
0
  }
9499
0
    }
9500
0
}
9501
9502
/************************************************************************
9503
 *                  *
9504
 *    XPath precompiled expression evaluation     *
9505
 *                  *
9506
 ************************************************************************/
9507
9508
static int
9509
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
9510
9511
/**
9512
 * Filter a node set, keeping only nodes for which the predicate expression
9513
 * matches. Afterwards, keep only nodes between minPos and maxPos in the
9514
 * filtered result.
9515
 *
9516
 * @param ctxt  the XPath Parser context
9517
 * @param set  the node set to filter
9518
 * @param filterOpIndex  the index of the predicate/filter op
9519
 * @param minPos  minimum position in the filtered set (1-based)
9520
 * @param maxPos  maximum position in the filtered set (1-based)
9521
 * @param hasNsNodes  true if the node set may contain namespace nodes
9522
 */
9523
static void
9524
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
9525
          xmlNodeSetPtr set,
9526
          int filterOpIndex,
9527
                      int minPos, int maxPos,
9528
          int hasNsNodes)
9529
0
{
9530
0
    xmlXPathContextPtr xpctxt;
9531
0
    xmlNodePtr oldnode;
9532
0
    xmlDocPtr olddoc;
9533
0
    xmlXPathStepOpPtr filterOp;
9534
0
    int oldcs, oldpp;
9535
0
    int i, j, pos;
9536
9537
0
    if ((set == NULL) || (set->nodeNr == 0))
9538
0
        return;
9539
9540
    /*
9541
    * Check if the node set contains a sufficient number of nodes for
9542
    * the requested range.
9543
    */
9544
0
    if (set->nodeNr < minPos) {
9545
0
        xmlXPathNodeSetClear(set, hasNsNodes);
9546
0
        return;
9547
0
    }
9548
9549
0
    xpctxt = ctxt->context;
9550
0
    oldnode = xpctxt->node;
9551
0
    olddoc = xpctxt->doc;
9552
0
    oldcs = xpctxt->contextSize;
9553
0
    oldpp = xpctxt->proximityPosition;
9554
0
    filterOp = &ctxt->comp->steps[filterOpIndex];
9555
9556
0
    xpctxt->contextSize = set->nodeNr;
9557
9558
0
    for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
9559
0
        xmlNodePtr node = set->nodeTab[i];
9560
0
        int res;
9561
9562
0
        xpctxt->node = node;
9563
0
        xpctxt->proximityPosition = i + 1;
9564
9565
        /*
9566
        * Also set the xpath document in case things like
9567
        * key() are evaluated in the predicate.
9568
        *
9569
        * TODO: Get real doc for namespace nodes.
9570
        */
9571
0
        if ((node->type != XML_NAMESPACE_DECL) &&
9572
0
            (node->doc != NULL))
9573
0
            xpctxt->doc = node->doc;
9574
9575
0
        res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
9576
9577
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
9578
0
            break;
9579
0
        if (res < 0) {
9580
            /* Shouldn't happen */
9581
0
            xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
9582
0
            break;
9583
0
        }
9584
9585
0
        if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
9586
0
            if (i != j) {
9587
0
                set->nodeTab[j] = node;
9588
0
                set->nodeTab[i] = NULL;
9589
0
            }
9590
9591
0
            j += 1;
9592
0
        } else {
9593
            /* Remove the entry from the initial node set. */
9594
0
            set->nodeTab[i] = NULL;
9595
0
            if (node->type == XML_NAMESPACE_DECL)
9596
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9597
0
        }
9598
9599
0
        if (res != 0) {
9600
0
            if (pos == maxPos) {
9601
0
                i += 1;
9602
0
                break;
9603
0
            }
9604
9605
0
            pos += 1;
9606
0
        }
9607
0
    }
9608
9609
    /* Free remaining nodes. */
9610
0
    if (hasNsNodes) {
9611
0
        for (; i < set->nodeNr; i++) {
9612
0
            xmlNodePtr node = set->nodeTab[i];
9613
0
            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
9614
0
                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
9615
0
        }
9616
0
    }
9617
9618
0
    set->nodeNr = j;
9619
9620
    /* If too many elements were removed, shrink table to preserve memory. */
9621
0
    if ((set->nodeMax > XML_NODESET_DEFAULT) &&
9622
0
        (set->nodeNr < set->nodeMax / 2)) {
9623
0
        xmlNodePtr *tmp;
9624
0
        int nodeMax = set->nodeNr;
9625
9626
0
        if (nodeMax < XML_NODESET_DEFAULT)
9627
0
            nodeMax = XML_NODESET_DEFAULT;
9628
0
        tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
9629
0
                nodeMax * sizeof(xmlNodePtr));
9630
0
        if (tmp == NULL) {
9631
0
            xmlXPathPErrMemory(ctxt);
9632
0
        } else {
9633
0
            set->nodeTab = tmp;
9634
0
            set->nodeMax = nodeMax;
9635
0
        }
9636
0
    }
9637
9638
0
    xpctxt->node = oldnode;
9639
0
    xpctxt->doc = olddoc;
9640
0
    xpctxt->contextSize = oldcs;
9641
0
    xpctxt->proximityPosition = oldpp;
9642
0
}
9643
9644
/**
9645
 * Filter a node set, keeping only nodes for which the sequence of predicate
9646
 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
9647
 * in the filtered result.
9648
 *
9649
 * @param ctxt  the XPath Parser context
9650
 * @param op  the predicate op
9651
 * @param set  the node set to filter
9652
 * @param minPos  minimum position in the filtered set (1-based)
9653
 * @param maxPos  maximum position in the filtered set (1-based)
9654
 * @param hasNsNodes  true if the node set may contain namespace nodes
9655
 */
9656
static void
9657
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
9658
          xmlXPathStepOpPtr op,
9659
          xmlNodeSetPtr set,
9660
                            int minPos, int maxPos,
9661
          int hasNsNodes)
9662
0
{
9663
0
    if (op->ch1 != -1) {
9664
0
  xmlXPathCompExprPtr comp = ctxt->comp;
9665
  /*
9666
  * Process inner predicates first.
9667
  */
9668
0
  if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
9669
0
            XP_ERROR(XPATH_INVALID_OPERAND);
9670
0
  }
9671
0
        if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
9672
0
            XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
9673
0
        ctxt->context->depth += 1;
9674
0
  xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
9675
0
                                    1, set->nodeNr, hasNsNodes);
9676
0
        ctxt->context->depth -= 1;
9677
0
  CHECK_ERROR;
9678
0
    }
9679
9680
0
    if (op->ch2 != -1)
9681
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
9682
0
}
9683
9684
static int
9685
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
9686
          xmlXPathStepOpPtr op,
9687
          int *maxPos)
9688
0
{
9689
9690
0
    xmlXPathStepOpPtr exprOp;
9691
9692
    /*
9693
    * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
9694
    */
9695
9696
    /*
9697
    * If not -1, then ch1 will point to:
9698
    * 1) For predicates (XPATH_OP_PREDICATE):
9699
    *    - an inner predicate operator
9700
    * 2) For filters (XPATH_OP_FILTER):
9701
    *    - an inner filter operator OR
9702
    *    - an expression selecting the node set.
9703
    *      E.g. "key('a', 'b')" or "(//foo | //bar)".
9704
    */
9705
0
    if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
9706
0
  return(0);
9707
9708
0
    if (op->ch2 != -1) {
9709
0
  exprOp = &ctxt->comp->steps[op->ch2];
9710
0
    } else
9711
0
  return(0);
9712
9713
0
    if ((exprOp != NULL) &&
9714
0
  (exprOp->op == XPATH_OP_VALUE) &&
9715
0
  (exprOp->value4 != NULL) &&
9716
0
  (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
9717
0
    {
9718
0
        double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
9719
9720
  /*
9721
  * We have a "[n]" predicate here.
9722
  * TODO: Unfortunately this simplistic test here is not
9723
  * able to detect a position() predicate in compound
9724
  * expressions like "[@attr = 'a" and position() = 1],
9725
  * and even not the usage of position() in
9726
  * "[position() = 1]"; thus - obviously - a position-range,
9727
  * like it "[position() < 5]", is also not detected.
9728
  * Maybe we could rewrite the AST to ease the optimization.
9729
  */
9730
9731
0
        if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
9732
0
      *maxPos = (int) floatval;
9733
0
            if (floatval == (double) *maxPos)
9734
0
                return(1);
9735
0
        }
9736
0
    }
9737
0
    return(0);
9738
0
}
9739
9740
static int
9741
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
9742
                           xmlXPathStepOpPtr op,
9743
         xmlNodePtr * first, xmlNodePtr * last,
9744
         int toBool)
9745
0
{
9746
9747
0
#define XP_TEST_HIT \
9748
0
    if (hasAxisRange != 0) { \
9749
0
  if (++pos == maxPos) { \
9750
0
      if (addNode(seq, cur) < 0) \
9751
0
          xmlXPathPErrMemory(ctxt); \
9752
0
      goto axis_range_end; } \
9753
0
    } else { \
9754
0
  if (addNode(seq, cur) < 0) \
9755
0
      xmlXPathPErrMemory(ctxt); \
9756
0
  if (breakOnFirstHit) goto first_hit; }
9757
9758
0
#define XP_TEST_HIT_NS \
9759
0
    if (hasAxisRange != 0) { \
9760
0
  if (++pos == maxPos) { \
9761
0
      hasNsNodes = 1; \
9762
0
      if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9763
0
          xmlXPathPErrMemory(ctxt); \
9764
0
  goto axis_range_end; } \
9765
0
    } else { \
9766
0
  hasNsNodes = 1; \
9767
0
  if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
9768
0
      xmlXPathPErrMemory(ctxt); \
9769
0
  if (breakOnFirstHit) goto first_hit; }
9770
9771
0
    xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9772
0
    xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9773
0
    xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9774
0
    const xmlChar *prefix = op->value4;
9775
0
    const xmlChar *name = op->value5;
9776
0
    const xmlChar *URI = NULL;
9777
9778
0
    int total = 0, hasNsNodes = 0;
9779
    /* The popped object holding the context nodes */
9780
0
    xmlXPathObjectPtr obj;
9781
    /* The set of context nodes for the node tests */
9782
0
    xmlNodeSetPtr contextSeq;
9783
0
    int contextIdx;
9784
0
    xmlNodePtr contextNode;
9785
    /* The final resulting node set wrt to all context nodes */
9786
0
    xmlNodeSetPtr outSeq;
9787
    /*
9788
    * The temporary resulting node set wrt 1 context node.
9789
    * Used to feed predicate evaluation.
9790
    */
9791
0
    xmlNodeSetPtr seq;
9792
0
    xmlNodePtr cur;
9793
    /* First predicate operator */
9794
0
    xmlXPathStepOpPtr predOp;
9795
0
    int maxPos; /* The requested position() (when a "[n]" predicate) */
9796
0
    int hasPredicateRange, hasAxisRange, pos;
9797
0
    int breakOnFirstHit;
9798
9799
0
    xmlXPathTraversalFunction next = NULL;
9800
0
    int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9801
0
    xmlXPathNodeSetMergeFunction mergeAndClear;
9802
0
    xmlNodePtr oldContextNode;
9803
0
    xmlXPathContextPtr xpctxt = ctxt->context;
9804
9805
9806
0
    CHECK_TYPE0(XPATH_NODESET);
9807
0
    obj = xmlXPathValuePop(ctxt);
9808
    /*
9809
    * Setup namespaces.
9810
    */
9811
0
    if (prefix != NULL) {
9812
0
        URI = xmlXPathNsLookup(xpctxt, prefix);
9813
0
        if (URI == NULL) {
9814
0
      xmlXPathReleaseObject(xpctxt, obj);
9815
0
            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9816
0
  }
9817
0
    }
9818
    /*
9819
    * Setup axis.
9820
    *
9821
    * MAYBE FUTURE TODO: merging optimizations:
9822
    * - If the nodes to be traversed wrt to the initial nodes and
9823
    *   the current axis cannot overlap, then we could avoid searching
9824
    *   for duplicates during the merge.
9825
    *   But the question is how/when to evaluate if they cannot overlap.
9826
    *   Example: if we know that for two initial nodes, the one is
9827
    *   not in the ancestor-or-self axis of the other, then we could safely
9828
    *   avoid a duplicate-aware merge, if the axis to be traversed is e.g.
9829
    *   the descendant-or-self axis.
9830
    */
9831
0
    mergeAndClear = xmlXPathNodeSetMergeAndClear;
9832
0
    switch (axis) {
9833
0
        case AXIS_ANCESTOR:
9834
0
            first = NULL;
9835
0
            next = xmlXPathNextAncestor;
9836
0
            break;
9837
0
        case AXIS_ANCESTOR_OR_SELF:
9838
0
            first = NULL;
9839
0
            next = xmlXPathNextAncestorOrSelf;
9840
0
            break;
9841
0
        case AXIS_ATTRIBUTE:
9842
0
            first = NULL;
9843
0
      last = NULL;
9844
0
            next = xmlXPathNextAttribute;
9845
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9846
0
            break;
9847
0
        case AXIS_CHILD:
9848
0
      last = NULL;
9849
0
      if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
9850
0
    (type == NODE_TYPE_NODE))
9851
0
      {
9852
    /*
9853
    * Optimization if an element node type is 'element'.
9854
    */
9855
0
    next = xmlXPathNextChildElement;
9856
0
      } else
9857
0
    next = xmlXPathNextChild;
9858
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9859
0
            break;
9860
0
        case AXIS_DESCENDANT:
9861
0
      last = NULL;
9862
0
            next = xmlXPathNextDescendant;
9863
0
            break;
9864
0
        case AXIS_DESCENDANT_OR_SELF:
9865
0
      last = NULL;
9866
0
            next = xmlXPathNextDescendantOrSelf;
9867
0
            break;
9868
0
        case AXIS_FOLLOWING:
9869
0
      last = NULL;
9870
0
            next = xmlXPathNextFollowing;
9871
0
            break;
9872
0
        case AXIS_FOLLOWING_SIBLING:
9873
0
      last = NULL;
9874
0
            next = xmlXPathNextFollowingSibling;
9875
0
            break;
9876
0
        case AXIS_NAMESPACE:
9877
0
            first = NULL;
9878
0
      last = NULL;
9879
0
            next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9880
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9881
0
            break;
9882
0
        case AXIS_PARENT:
9883
0
            first = NULL;
9884
0
            next = xmlXPathNextParent;
9885
0
            break;
9886
0
        case AXIS_PRECEDING:
9887
0
            first = NULL;
9888
0
            next = xmlXPathNextPrecedingInternal;
9889
0
            break;
9890
0
        case AXIS_PRECEDING_SIBLING:
9891
0
            first = NULL;
9892
0
            next = xmlXPathNextPrecedingSibling;
9893
0
            break;
9894
0
        case AXIS_SELF:
9895
0
            first = NULL;
9896
0
      last = NULL;
9897
0
            next = xmlXPathNextSelf;
9898
0
      mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
9899
0
            break;
9900
0
    }
9901
9902
0
    if (next == NULL) {
9903
0
  xmlXPathReleaseObject(xpctxt, obj);
9904
0
        return(0);
9905
0
    }
9906
0
    contextSeq = obj->nodesetval;
9907
0
    if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
9908
0
        xmlXPathValuePush(ctxt, obj);
9909
0
        return(0);
9910
0
    }
9911
    /*
9912
    * Predicate optimization ---------------------------------------------
9913
    * If this step has a last predicate, which contains a position(),
9914
    * then we'll optimize (although not exactly "position()", but only
9915
    * the  short-hand form, i.e., "[n]".
9916
    *
9917
    * Example - expression "/foo[parent::bar][1]":
9918
    *
9919
    * COLLECT 'child' 'name' 'node' foo    -- op (we are here)
9920
    *   ROOT                               -- op->ch1
9921
    *   PREDICATE                          -- op->ch2 (predOp)
9922
    *     PREDICATE                          -- predOp->ch1 = [parent::bar]
9923
    *       SORT
9924
    *         COLLECT  'parent' 'name' 'node' bar
9925
    *           NODE
9926
    *     ELEM Object is a number : 1        -- predOp->ch2 = [1]
9927
    *
9928
    */
9929
0
    maxPos = 0;
9930
0
    predOp = NULL;
9931
0
    hasPredicateRange = 0;
9932
0
    hasAxisRange = 0;
9933
0
    if (op->ch2 != -1) {
9934
  /*
9935
  * There's at least one predicate. 16 == XPATH_OP_PREDICATE
9936
  */
9937
0
  predOp = &ctxt->comp->steps[op->ch2];
9938
0
  if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
9939
0
      if (predOp->ch1 != -1) {
9940
    /*
9941
    * Use the next inner predicate operator.
9942
    */
9943
0
    predOp = &ctxt->comp->steps[predOp->ch1];
9944
0
    hasPredicateRange = 1;
9945
0
      } else {
9946
    /*
9947
    * There's no other predicate than the [n] predicate.
9948
    */
9949
0
    predOp = NULL;
9950
0
    hasAxisRange = 1;
9951
0
      }
9952
0
  }
9953
0
    }
9954
0
    breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
9955
    /*
9956
    * Axis traversal -----------------------------------------------------
9957
    */
9958
    /*
9959
     * 2.3 Node Tests
9960
     *  - For the attribute axis, the principal node type is attribute.
9961
     *  - For the namespace axis, the principal node type is namespace.
9962
     *  - For other axes, the principal node type is element.
9963
     *
9964
     * A node test * is true for any node of the
9965
     * principal node type. For example, child::* will
9966
     * select all element children of the context node
9967
     */
9968
0
    oldContextNode = xpctxt->node;
9969
0
    addNode = xmlXPathNodeSetAddUnique;
9970
0
    outSeq = NULL;
9971
0
    seq = NULL;
9972
0
    contextNode = NULL;
9973
0
    contextIdx = 0;
9974
9975
9976
0
    while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
9977
0
           (ctxt->error == XPATH_EXPRESSION_OK)) {
9978
0
  xpctxt->node = contextSeq->nodeTab[contextIdx++];
9979
9980
0
  if (seq == NULL) {
9981
0
      seq = xmlXPathNodeSetCreate(NULL);
9982
0
      if (seq == NULL) {
9983
0
                xmlXPathPErrMemory(ctxt);
9984
0
    total = 0;
9985
0
    goto error;
9986
0
      }
9987
0
  }
9988
  /*
9989
  * Traverse the axis and test the nodes.
9990
  */
9991
0
  pos = 0;
9992
0
  cur = NULL;
9993
0
  hasNsNodes = 0;
9994
0
        do {
9995
0
            if (OP_LIMIT_EXCEEDED(ctxt, 1))
9996
0
                goto error;
9997
9998
0
            cur = next(ctxt, cur);
9999
0
            if (cur == NULL)
10000
0
                break;
10001
10002
      /*
10003
      * QUESTION TODO: What does the "first" and "last" stuff do?
10004
      */
10005
0
            if ((first != NULL) && (*first != NULL)) {
10006
0
    if (*first == cur)
10007
0
        break;
10008
0
    if (((total % 256) == 0) &&
10009
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10010
0
        (xmlXPathCmpNodesExt(*first, cur) >= 0))
10011
#else
10012
        (xmlXPathCmpNodes(*first, cur) >= 0))
10013
#endif
10014
0
    {
10015
0
        break;
10016
0
    }
10017
0
      }
10018
0
      if ((last != NULL) && (*last != NULL)) {
10019
0
    if (*last == cur)
10020
0
        break;
10021
0
    if (((total % 256) == 0) &&
10022
0
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
10023
0
        (xmlXPathCmpNodesExt(cur, *last) >= 0))
10024
#else
10025
        (xmlXPathCmpNodes(cur, *last) >= 0))
10026
#endif
10027
0
    {
10028
0
        break;
10029
0
    }
10030
0
      }
10031
10032
0
            total++;
10033
10034
0
      switch (test) {
10035
0
                case NODE_TEST_NONE:
10036
0
        total = 0;
10037
0
        goto error;
10038
0
                case NODE_TEST_TYPE:
10039
0
        if (type == NODE_TYPE_NODE) {
10040
0
      switch (cur->type) {
10041
0
          case XML_DOCUMENT_NODE:
10042
0
          case XML_HTML_DOCUMENT_NODE:
10043
0
          case XML_ELEMENT_NODE:
10044
0
          case XML_ATTRIBUTE_NODE:
10045
0
          case XML_PI_NODE:
10046
0
          case XML_COMMENT_NODE:
10047
0
          case XML_CDATA_SECTION_NODE:
10048
0
          case XML_TEXT_NODE:
10049
0
        XP_TEST_HIT
10050
0
        break;
10051
0
          case XML_NAMESPACE_DECL: {
10052
0
        if (axis == AXIS_NAMESPACE) {
10053
0
            XP_TEST_HIT_NS
10054
0
        } else {
10055
0
                              hasNsNodes = 1;
10056
0
            XP_TEST_HIT
10057
0
        }
10058
0
        break;
10059
0
                            }
10060
0
          default:
10061
0
        break;
10062
0
      }
10063
0
        } else if (cur->type == (xmlElementType) type) {
10064
0
      if (cur->type == XML_NAMESPACE_DECL)
10065
0
          XP_TEST_HIT_NS
10066
0
      else
10067
0
          XP_TEST_HIT
10068
0
        } else if ((type == NODE_TYPE_TEXT) &&
10069
0
       (cur->type == XML_CDATA_SECTION_NODE))
10070
0
        {
10071
0
      XP_TEST_HIT
10072
0
        }
10073
0
        break;
10074
0
                case NODE_TEST_PI:
10075
0
                    if ((cur->type == XML_PI_NODE) &&
10076
0
                        ((name == NULL) || xmlStrEqual(name, cur->name)))
10077
0
        {
10078
0
      XP_TEST_HIT
10079
0
                    }
10080
0
                    break;
10081
0
                case NODE_TEST_ALL:
10082
0
                    if (axis == AXIS_ATTRIBUTE) {
10083
0
                        if (cur->type == XML_ATTRIBUTE_NODE)
10084
0
      {
10085
0
                            if (prefix == NULL)
10086
0
          {
10087
0
        XP_TEST_HIT
10088
0
                            } else if ((cur->ns != NULL) &&
10089
0
        (xmlStrEqual(URI, cur->ns->href)))
10090
0
          {
10091
0
        XP_TEST_HIT
10092
0
                            }
10093
0
                        }
10094
0
                    } else if (axis == AXIS_NAMESPACE) {
10095
0
                        if (cur->type == XML_NAMESPACE_DECL)
10096
0
      {
10097
0
          XP_TEST_HIT_NS
10098
0
                        }
10099
0
                    } else {
10100
0
                        if (cur->type == XML_ELEMENT_NODE) {
10101
0
                            if (prefix == NULL)
10102
0
          {
10103
0
        XP_TEST_HIT
10104
10105
0
                            } else if ((cur->ns != NULL) &&
10106
0
        (xmlStrEqual(URI, cur->ns->href)))
10107
0
          {
10108
0
        XP_TEST_HIT
10109
0
                            }
10110
0
                        }
10111
0
                    }
10112
0
                    break;
10113
0
                case NODE_TEST_NS:{
10114
                        /* TODO */
10115
0
                        break;
10116
0
                    }
10117
0
                case NODE_TEST_NAME:
10118
0
                    if (axis == AXIS_ATTRIBUTE) {
10119
0
                        if (cur->type != XML_ATTRIBUTE_NODE)
10120
0
          break;
10121
0
        } else if (axis == AXIS_NAMESPACE) {
10122
0
                        if (cur->type != XML_NAMESPACE_DECL)
10123
0
          break;
10124
0
        } else {
10125
0
            if (cur->type != XML_ELEMENT_NODE)
10126
0
          break;
10127
0
        }
10128
0
                    switch (cur->type) {
10129
0
                        case XML_ELEMENT_NODE:
10130
0
                            if (xmlStrEqual(name, cur->name)) {
10131
0
                                if (prefix == NULL) {
10132
0
                                    if (cur->ns == NULL)
10133
0
            {
10134
0
          XP_TEST_HIT
10135
0
                                    }
10136
0
                                } else {
10137
0
                                    if ((cur->ns != NULL) &&
10138
0
                                        (xmlStrEqual(URI, cur->ns->href)))
10139
0
            {
10140
0
          XP_TEST_HIT
10141
0
                                    }
10142
0
                                }
10143
0
                            }
10144
0
                            break;
10145
0
                        case XML_ATTRIBUTE_NODE:{
10146
0
                                xmlAttrPtr attr = (xmlAttrPtr) cur;
10147
10148
0
                                if (xmlStrEqual(name, attr->name)) {
10149
0
                                    if (prefix == NULL) {
10150
0
                                        if ((attr->ns == NULL) ||
10151
0
                                            (attr->ns->prefix == NULL))
10152
0
          {
10153
0
              XP_TEST_HIT
10154
0
                                        }
10155
0
                                    } else {
10156
0
                                        if ((attr->ns != NULL) &&
10157
0
                                            (xmlStrEqual(URI,
10158
0
                attr->ns->href)))
10159
0
          {
10160
0
              XP_TEST_HIT
10161
0
                                        }
10162
0
                                    }
10163
0
                                }
10164
0
                                break;
10165
0
                            }
10166
0
                        case XML_NAMESPACE_DECL:
10167
0
                            if (cur->type == XML_NAMESPACE_DECL) {
10168
0
                                xmlNsPtr ns = (xmlNsPtr) cur;
10169
10170
0
                                if ((ns->prefix != NULL) && (name != NULL)
10171
0
                                    && (xmlStrEqual(ns->prefix, name)))
10172
0
        {
10173
0
            XP_TEST_HIT_NS
10174
0
                                }
10175
0
                            }
10176
0
                            break;
10177
0
                        default:
10178
0
                            break;
10179
0
                    }
10180
0
                    break;
10181
0
      } /* switch(test) */
10182
0
        } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
10183
10184
0
  goto apply_predicates;
10185
10186
0
axis_range_end: /* ----------------------------------------------------- */
10187
  /*
10188
  * We have a "/foo[n]", and position() = n was reached.
10189
  * Note that we can have as well "/foo/::parent::foo[1]", so
10190
  * a duplicate-aware merge is still needed.
10191
  * Merge with the result.
10192
  */
10193
0
  if (outSeq == NULL) {
10194
0
      outSeq = seq;
10195
0
      seq = NULL;
10196
0
  } else {
10197
0
      outSeq = mergeAndClear(outSeq, seq);
10198
0
            if (outSeq == NULL)
10199
0
                xmlXPathPErrMemory(ctxt);
10200
0
        }
10201
  /*
10202
  * Break if only a true/false result was requested.
10203
  */
10204
0
  if (toBool)
10205
0
      break;
10206
0
  continue;
10207
10208
0
first_hit: /* ---------------------------------------------------------- */
10209
  /*
10210
  * Break if only a true/false result was requested and
10211
  * no predicates existed and a node test succeeded.
10212
  */
10213
0
  if (outSeq == NULL) {
10214
0
      outSeq = seq;
10215
0
      seq = NULL;
10216
0
  } else {
10217
0
      outSeq = mergeAndClear(outSeq, seq);
10218
0
            if (outSeq == NULL)
10219
0
                xmlXPathPErrMemory(ctxt);
10220
0
        }
10221
0
  break;
10222
10223
0
apply_predicates: /* --------------------------------------------------- */
10224
0
        if (ctxt->error != XPATH_EXPRESSION_OK)
10225
0
      goto error;
10226
10227
        /*
10228
  * Apply predicates.
10229
  */
10230
0
        if ((predOp != NULL) && (seq->nodeNr > 0)) {
10231
      /*
10232
      * E.g. when we have a "/foo[some expression][n]".
10233
      */
10234
      /*
10235
      * QUESTION TODO: The old predicate evaluation took into
10236
      *  account location-sets.
10237
      *  (E.g. ctxt->value->type == XPATH_LOCATIONSET)
10238
      *  Do we expect such a set here?
10239
      *  All what I learned now from the evaluation semantics
10240
      *  does not indicate that a location-set will be processed
10241
      *  here, so this looks OK.
10242
      */
10243
      /*
10244
      * Iterate over all predicates, starting with the outermost
10245
      * predicate.
10246
      * TODO: Problem: we cannot execute the inner predicates first
10247
      *  since we cannot go back *up* the operator tree!
10248
      *  Options we have:
10249
      *  1) Use of recursive functions (like is it currently done
10250
      *     via xmlXPathCompOpEval())
10251
      *  2) Add a predicate evaluation information stack to the
10252
      *     context struct
10253
      *  3) Change the way the operators are linked; we need a
10254
      *     "parent" field on xmlXPathStepOp
10255
      *
10256
      * For the moment, I'll try to solve this with a recursive
10257
      * function: xmlXPathCompOpEvalPredicate().
10258
      */
10259
0
      if (hasPredicateRange != 0)
10260
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
10261
0
              hasNsNodes);
10262
0
      else
10263
0
    xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
10264
0
              hasNsNodes);
10265
10266
0
      if (ctxt->error != XPATH_EXPRESSION_OK) {
10267
0
    total = 0;
10268
0
    goto error;
10269
0
      }
10270
0
        }
10271
10272
0
        if (seq->nodeNr > 0) {
10273
      /*
10274
      * Add to result set.
10275
      */
10276
0
      if (outSeq == NULL) {
10277
0
    outSeq = seq;
10278
0
    seq = NULL;
10279
0
      } else {
10280
0
    outSeq = mergeAndClear(outSeq, seq);
10281
0
                if (outSeq == NULL)
10282
0
                    xmlXPathPErrMemory(ctxt);
10283
0
      }
10284
10285
0
            if (toBool)
10286
0
                break;
10287
0
  }
10288
0
    }
10289
10290
0
error:
10291
0
    if ((obj->boolval) && (obj->user != NULL)) {
10292
  /*
10293
  * QUESTION TODO: What does this do and why?
10294
  * TODO: Do we have to do this also for the "error"
10295
  * cleanup further down?
10296
  */
10297
0
  ctxt->value->boolval = 1;
10298
0
  ctxt->value->user = obj->user;
10299
0
  obj->user = NULL;
10300
0
  obj->boolval = 0;
10301
0
    }
10302
0
    xmlXPathReleaseObject(xpctxt, obj);
10303
10304
    /*
10305
    * Ensure we return at least an empty set.
10306
    */
10307
0
    if (outSeq == NULL) {
10308
0
  if ((seq != NULL) && (seq->nodeNr == 0)) {
10309
0
      outSeq = seq;
10310
0
        } else {
10311
0
      outSeq = xmlXPathNodeSetCreate(NULL);
10312
0
            if (outSeq == NULL)
10313
0
                xmlXPathPErrMemory(ctxt);
10314
0
        }
10315
0
    }
10316
0
    if ((seq != NULL) && (seq != outSeq)) {
10317
0
   xmlXPathFreeNodeSet(seq);
10318
0
    }
10319
    /*
10320
    * Hand over the result. Better to push the set also in
10321
    * case of errors.
10322
    */
10323
0
    xmlXPathValuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt, outSeq));
10324
    /*
10325
    * Reset the context node.
10326
    */
10327
0
    xpctxt->node = oldContextNode;
10328
    /*
10329
    * When traversing the namespace axis in "toBool" mode, it's
10330
    * possible that tmpNsList wasn't freed.
10331
    */
10332
0
    if (xpctxt->tmpNsList != NULL) {
10333
0
        xmlFree(xpctxt->tmpNsList);
10334
0
        xpctxt->tmpNsList = NULL;
10335
0
    }
10336
10337
0
    return(total);
10338
0
}
10339
10340
static int
10341
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10342
            xmlXPathStepOpPtr op, xmlNodePtr * first);
10343
10344
/**
10345
 * Evaluate the Precompiled XPath operation searching only the first
10346
 * element in document order
10347
 *
10348
 * @param ctxt  the XPath parser context with the compiled expression
10349
 * @param op  an XPath compiled operation
10350
 * @param first  the first elem found so far
10351
 * @returns the number of examined objects.
10352
 */
10353
static int
10354
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
10355
                        xmlXPathStepOpPtr op, xmlNodePtr * first)
10356
0
{
10357
0
    int total = 0, cur;
10358
0
    xmlXPathCompExprPtr comp;
10359
0
    xmlXPathObjectPtr arg1, arg2;
10360
10361
0
    CHECK_ERROR0;
10362
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10363
0
        return(0);
10364
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10365
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10366
0
    ctxt->context->depth += 1;
10367
0
    comp = ctxt->comp;
10368
0
    switch (op->op) {
10369
0
        case XPATH_OP_END:
10370
0
            break;
10371
0
        case XPATH_OP_UNION:
10372
0
            total =
10373
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10374
0
                                        first);
10375
0
      CHECK_ERROR0;
10376
0
            if ((ctxt->value != NULL)
10377
0
                && (ctxt->value->type == XPATH_NODESET)
10378
0
                && (ctxt->value->nodesetval != NULL)
10379
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10380
                /*
10381
                 * limit tree traversing to first node in the result
10382
                 */
10383
    /*
10384
    * OPTIMIZE TODO: This implicitly sorts
10385
    *  the result, even if not needed. E.g. if the argument
10386
    *  of the count() function, no sorting is needed.
10387
    * OPTIMIZE TODO: How do we know if the node-list wasn't
10388
    *  already sorted?
10389
    */
10390
0
    if (ctxt->value->nodesetval->nodeNr > 1)
10391
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10392
0
                *first = ctxt->value->nodesetval->nodeTab[0];
10393
0
            }
10394
0
            cur =
10395
0
                xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
10396
0
                                        first);
10397
0
      CHECK_ERROR0;
10398
10399
0
            arg2 = xmlXPathValuePop(ctxt);
10400
0
            arg1 = xmlXPathValuePop(ctxt);
10401
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10402
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10403
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10404
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10405
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10406
0
            }
10407
0
            if ((ctxt->context->opLimit != 0) &&
10408
0
                (((arg1->nodesetval != NULL) &&
10409
0
                  (xmlXPathCheckOpLimit(ctxt,
10410
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10411
0
                 ((arg2->nodesetval != NULL) &&
10412
0
                  (xmlXPathCheckOpLimit(ctxt,
10413
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10414
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10415
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10416
0
                break;
10417
0
            }
10418
10419
0
            if ((arg2->nodesetval != NULL) &&
10420
0
                (arg2->nodesetval->nodeNr != 0)) {
10421
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10422
0
                                                        arg2->nodesetval);
10423
0
                if (arg1->nodesetval == NULL)
10424
0
                    xmlXPathPErrMemory(ctxt);
10425
0
            }
10426
0
            xmlXPathValuePush(ctxt, arg1);
10427
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10428
0
            total += cur;
10429
0
            break;
10430
0
        case XPATH_OP_ROOT:
10431
0
            xmlXPathRoot(ctxt);
10432
0
            break;
10433
0
        case XPATH_OP_NODE:
10434
0
            if (op->ch1 != -1)
10435
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10436
0
      CHECK_ERROR0;
10437
0
            if (op->ch2 != -1)
10438
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10439
0
      CHECK_ERROR0;
10440
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10441
0
    ctxt->context->node));
10442
0
            break;
10443
0
        case XPATH_OP_COLLECT:{
10444
0
                if (op->ch1 == -1)
10445
0
                    break;
10446
10447
0
                total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10448
0
    CHECK_ERROR0;
10449
10450
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
10451
0
                break;
10452
0
            }
10453
0
        case XPATH_OP_VALUE:
10454
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10455
0
            break;
10456
0
        case XPATH_OP_SORT:
10457
0
            if (op->ch1 != -1)
10458
0
                total +=
10459
0
                    xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
10460
0
                                            first);
10461
0
      CHECK_ERROR0;
10462
0
            if ((ctxt->value != NULL)
10463
0
                && (ctxt->value->type == XPATH_NODESET)
10464
0
                && (ctxt->value->nodesetval != NULL)
10465
0
    && (ctxt->value->nodesetval->nodeNr > 1))
10466
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10467
0
            break;
10468
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10469
0
  case XPATH_OP_FILTER:
10470
0
                total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
10471
0
            break;
10472
0
#endif
10473
0
        default:
10474
0
            total += xmlXPathCompOpEval(ctxt, op);
10475
0
            break;
10476
0
    }
10477
10478
0
    ctxt->context->depth -= 1;
10479
0
    return(total);
10480
0
}
10481
10482
/**
10483
 * Evaluate the Precompiled XPath operation searching only the last
10484
 * element in document order
10485
 *
10486
 * @param ctxt  the XPath parser context with the compiled expression
10487
 * @param op  an XPath compiled operation
10488
 * @param last  the last elem found so far
10489
 * @returns the number of nodes traversed
10490
 */
10491
static int
10492
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
10493
                       xmlNodePtr * last)
10494
0
{
10495
0
    int total = 0, cur;
10496
0
    xmlXPathCompExprPtr comp;
10497
0
    xmlXPathObjectPtr arg1, arg2;
10498
10499
0
    CHECK_ERROR0;
10500
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10501
0
        return(0);
10502
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10503
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10504
0
    ctxt->context->depth += 1;
10505
0
    comp = ctxt->comp;
10506
0
    switch (op->op) {
10507
0
        case XPATH_OP_END:
10508
0
            break;
10509
0
        case XPATH_OP_UNION:
10510
0
            total =
10511
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
10512
0
      CHECK_ERROR0;
10513
0
            if ((ctxt->value != NULL)
10514
0
                && (ctxt->value->type == XPATH_NODESET)
10515
0
                && (ctxt->value->nodesetval != NULL)
10516
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) {
10517
                /*
10518
                 * limit tree traversing to first node in the result
10519
                 */
10520
0
    if (ctxt->value->nodesetval->nodeNr > 1)
10521
0
        xmlXPathNodeSetSort(ctxt->value->nodesetval);
10522
0
                *last =
10523
0
                    ctxt->value->nodesetval->nodeTab[ctxt->value->
10524
0
                                                     nodesetval->nodeNr -
10525
0
                                                     1];
10526
0
            }
10527
0
            cur =
10528
0
                xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
10529
0
      CHECK_ERROR0;
10530
0
            if ((ctxt->value != NULL)
10531
0
                && (ctxt->value->type == XPATH_NODESET)
10532
0
                && (ctxt->value->nodesetval != NULL)
10533
0
                && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
10534
0
            }
10535
10536
0
            arg2 = xmlXPathValuePop(ctxt);
10537
0
            arg1 = xmlXPathValuePop(ctxt);
10538
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10539
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10540
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10541
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10542
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10543
0
            }
10544
0
            if ((ctxt->context->opLimit != 0) &&
10545
0
                (((arg1->nodesetval != NULL) &&
10546
0
                  (xmlXPathCheckOpLimit(ctxt,
10547
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10548
0
                 ((arg2->nodesetval != NULL) &&
10549
0
                  (xmlXPathCheckOpLimit(ctxt,
10550
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10551
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10552
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10553
0
                break;
10554
0
            }
10555
10556
0
            if ((arg2->nodesetval != NULL) &&
10557
0
                (arg2->nodesetval->nodeNr != 0)) {
10558
0
                arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10559
0
                                                        arg2->nodesetval);
10560
0
                if (arg1->nodesetval == NULL)
10561
0
                    xmlXPathPErrMemory(ctxt);
10562
0
            }
10563
0
            xmlXPathValuePush(ctxt, arg1);
10564
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10565
0
            total += cur;
10566
0
            break;
10567
0
        case XPATH_OP_ROOT:
10568
0
            xmlXPathRoot(ctxt);
10569
0
            break;
10570
0
        case XPATH_OP_NODE:
10571
0
            if (op->ch1 != -1)
10572
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10573
0
      CHECK_ERROR0;
10574
0
            if (op->ch2 != -1)
10575
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10576
0
      CHECK_ERROR0;
10577
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10578
0
    ctxt->context->node));
10579
0
            break;
10580
0
        case XPATH_OP_COLLECT:{
10581
0
                if (op->ch1 == -1)
10582
0
                    break;
10583
10584
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10585
0
    CHECK_ERROR0;
10586
10587
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
10588
0
                break;
10589
0
            }
10590
0
        case XPATH_OP_VALUE:
10591
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10592
0
            break;
10593
0
        case XPATH_OP_SORT:
10594
0
            if (op->ch1 != -1)
10595
0
                total +=
10596
0
                    xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
10597
0
                                           last);
10598
0
      CHECK_ERROR0;
10599
0
            if ((ctxt->value != NULL)
10600
0
                && (ctxt->value->type == XPATH_NODESET)
10601
0
                && (ctxt->value->nodesetval != NULL)
10602
0
    && (ctxt->value->nodesetval->nodeNr > 1))
10603
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
10604
0
            break;
10605
0
        default:
10606
0
            total += xmlXPathCompOpEval(ctxt, op);
10607
0
            break;
10608
0
    }
10609
10610
0
    ctxt->context->depth -= 1;
10611
0
    return (total);
10612
0
}
10613
10614
#ifdef XP_OPTIMIZED_FILTER_FIRST
10615
static int
10616
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
10617
            xmlXPathStepOpPtr op, xmlNodePtr * first)
10618
0
{
10619
0
    int total = 0;
10620
0
    xmlXPathCompExprPtr comp;
10621
0
    xmlXPathObjectPtr obj;
10622
0
    xmlNodeSetPtr set;
10623
10624
0
    CHECK_ERROR0;
10625
0
    comp = ctxt->comp;
10626
    /*
10627
    * Optimization for ()[last()] selection i.e. the last elem
10628
    */
10629
0
    if ((op->ch1 != -1) && (op->ch2 != -1) &&
10630
0
  (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10631
0
  (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10632
0
  int f = comp->steps[op->ch2].ch1;
10633
10634
0
  if ((f != -1) &&
10635
0
      (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10636
0
      (comp->steps[f].value5 == NULL) &&
10637
0
      (comp->steps[f].value == 0) &&
10638
0
      (comp->steps[f].value4 != NULL) &&
10639
0
      (xmlStrEqual
10640
0
      (comp->steps[f].value4, BAD_CAST "last"))) {
10641
0
      xmlNodePtr last = NULL;
10642
10643
0
      total +=
10644
0
    xmlXPathCompOpEvalLast(ctxt,
10645
0
        &comp->steps[op->ch1],
10646
0
        &last);
10647
0
      CHECK_ERROR0;
10648
      /*
10649
      * The nodeset should be in document order,
10650
      * Keep only the last value
10651
      */
10652
0
      if ((ctxt->value != NULL) &&
10653
0
    (ctxt->value->type == XPATH_NODESET) &&
10654
0
    (ctxt->value->nodesetval != NULL) &&
10655
0
    (ctxt->value->nodesetval->nodeTab != NULL) &&
10656
0
    (ctxt->value->nodesetval->nodeNr > 1)) {
10657
0
                xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
10658
0
    *first = *(ctxt->value->nodesetval->nodeTab);
10659
0
      }
10660
0
      return (total);
10661
0
  }
10662
0
    }
10663
10664
0
    if (op->ch1 != -1)
10665
0
  total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10666
0
    CHECK_ERROR0;
10667
0
    if (op->ch2 == -1)
10668
0
  return (total);
10669
0
    if (ctxt->value == NULL)
10670
0
  return (total);
10671
10672
    /*
10673
     * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
10674
     * the stack. We have to temporarily remove the nodeset object from the
10675
     * stack to avoid freeing it prematurely.
10676
     */
10677
0
    CHECK_TYPE0(XPATH_NODESET);
10678
0
    obj = xmlXPathValuePop(ctxt);
10679
0
    set = obj->nodesetval;
10680
0
    if (set != NULL) {
10681
0
        xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
10682
0
        if (set->nodeNr > 0)
10683
0
            *first = set->nodeTab[0];
10684
0
    }
10685
0
    xmlXPathValuePush(ctxt, obj);
10686
10687
0
    return (total);
10688
0
}
10689
#endif /* XP_OPTIMIZED_FILTER_FIRST */
10690
10691
/**
10692
 * Evaluate the Precompiled XPath operation
10693
 *
10694
 * @param ctxt  the XPath parser context with the compiled expression
10695
 * @param op  an XPath compiled operation
10696
 * @returns the number of nodes traversed
10697
 */
10698
static int
10699
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
10700
0
{
10701
0
    int total = 0;
10702
0
    int equal, ret;
10703
0
    xmlXPathCompExprPtr comp;
10704
0
    xmlXPathObjectPtr arg1, arg2;
10705
10706
0
    CHECK_ERROR0;
10707
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
10708
0
        return(0);
10709
0
    if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
10710
0
        XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
10711
0
    ctxt->context->depth += 1;
10712
0
    comp = ctxt->comp;
10713
0
    switch (op->op) {
10714
0
        case XPATH_OP_END:
10715
0
            break;
10716
0
        case XPATH_OP_AND:
10717
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10718
0
      CHECK_ERROR0;
10719
0
            xmlXPathBooleanFunction(ctxt, 1);
10720
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
10721
0
                break;
10722
0
            arg2 = xmlXPathValuePop(ctxt);
10723
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10724
0
      if (ctxt->error) {
10725
0
    xmlXPathFreeObject(arg2);
10726
0
    break;
10727
0
      }
10728
0
            xmlXPathBooleanFunction(ctxt, 1);
10729
0
            if (ctxt->value != NULL)
10730
0
                ctxt->value->boolval &= arg2->boolval;
10731
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10732
0
            break;
10733
0
        case XPATH_OP_OR:
10734
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10735
0
      CHECK_ERROR0;
10736
0
            xmlXPathBooleanFunction(ctxt, 1);
10737
0
            if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
10738
0
                break;
10739
0
            arg2 = xmlXPathValuePop(ctxt);
10740
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10741
0
      if (ctxt->error) {
10742
0
    xmlXPathFreeObject(arg2);
10743
0
    break;
10744
0
      }
10745
0
            xmlXPathBooleanFunction(ctxt, 1);
10746
0
            if (ctxt->value != NULL)
10747
0
                ctxt->value->boolval |= arg2->boolval;
10748
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10749
0
            break;
10750
0
        case XPATH_OP_EQUAL:
10751
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10752
0
      CHECK_ERROR0;
10753
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10754
0
      CHECK_ERROR0;
10755
0
      if (op->value)
10756
0
    equal = xmlXPathEqualValues(ctxt);
10757
0
      else
10758
0
    equal = xmlXPathNotEqualValues(ctxt);
10759
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, equal));
10760
0
            break;
10761
0
        case XPATH_OP_CMP:
10762
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10763
0
      CHECK_ERROR0;
10764
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10765
0
      CHECK_ERROR0;
10766
0
            ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10767
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewBoolean(ctxt, ret));
10768
0
            break;
10769
0
        case XPATH_OP_PLUS:
10770
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10771
0
      CHECK_ERROR0;
10772
0
            if (op->ch2 != -1) {
10773
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10774
0
      }
10775
0
      CHECK_ERROR0;
10776
0
            if (op->value == 0)
10777
0
                xmlXPathSubValues(ctxt);
10778
0
            else if (op->value == 1)
10779
0
                xmlXPathAddValues(ctxt);
10780
0
            else if (op->value == 2)
10781
0
                xmlXPathValueFlipSign(ctxt);
10782
0
            else if (op->value == 3) {
10783
0
                CAST_TO_NUMBER;
10784
0
                CHECK_TYPE0(XPATH_NUMBER);
10785
0
            }
10786
0
            break;
10787
0
        case XPATH_OP_MULT:
10788
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10789
0
      CHECK_ERROR0;
10790
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10791
0
      CHECK_ERROR0;
10792
0
            if (op->value == 0)
10793
0
                xmlXPathMultValues(ctxt);
10794
0
            else if (op->value == 1)
10795
0
                xmlXPathDivValues(ctxt);
10796
0
            else if (op->value == 2)
10797
0
                xmlXPathModValues(ctxt);
10798
0
            break;
10799
0
        case XPATH_OP_UNION:
10800
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10801
0
      CHECK_ERROR0;
10802
0
            total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10803
0
      CHECK_ERROR0;
10804
10805
0
            arg2 = xmlXPathValuePop(ctxt);
10806
0
            arg1 = xmlXPathValuePop(ctxt);
10807
0
            if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
10808
0
                (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
10809
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10810
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10811
0
                XP_ERROR0(XPATH_INVALID_TYPE);
10812
0
            }
10813
0
            if ((ctxt->context->opLimit != 0) &&
10814
0
                (((arg1->nodesetval != NULL) &&
10815
0
                  (xmlXPathCheckOpLimit(ctxt,
10816
0
                                        arg1->nodesetval->nodeNr) < 0)) ||
10817
0
                 ((arg2->nodesetval != NULL) &&
10818
0
                  (xmlXPathCheckOpLimit(ctxt,
10819
0
                                        arg2->nodesetval->nodeNr) < 0)))) {
10820
0
          xmlXPathReleaseObject(ctxt->context, arg1);
10821
0
          xmlXPathReleaseObject(ctxt->context, arg2);
10822
0
                break;
10823
0
            }
10824
10825
0
      if (((arg2->nodesetval != NULL) &&
10826
0
     (arg2->nodesetval->nodeNr != 0)))
10827
0
      {
10828
0
    arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10829
0
              arg2->nodesetval);
10830
0
                if (arg1->nodesetval == NULL)
10831
0
                    xmlXPathPErrMemory(ctxt);
10832
0
      }
10833
10834
0
            xmlXPathValuePush(ctxt, arg1);
10835
0
      xmlXPathReleaseObject(ctxt->context, arg2);
10836
0
            break;
10837
0
        case XPATH_OP_ROOT:
10838
0
            xmlXPathRoot(ctxt);
10839
0
            break;
10840
0
        case XPATH_OP_NODE:
10841
0
            if (op->ch1 != -1)
10842
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10843
0
      CHECK_ERROR0;
10844
0
            if (op->ch2 != -1)
10845
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10846
0
      CHECK_ERROR0;
10847
0
      xmlXPathValuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt,
10848
0
                                                    ctxt->context->node));
10849
0
            break;
10850
0
        case XPATH_OP_COLLECT:{
10851
0
                if (op->ch1 == -1)
10852
0
                    break;
10853
10854
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10855
0
    CHECK_ERROR0;
10856
10857
0
                total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
10858
0
                break;
10859
0
            }
10860
0
        case XPATH_OP_VALUE:
10861
0
            xmlXPathValuePush(ctxt, xmlXPathCacheObjectCopy(ctxt, op->value4));
10862
0
            break;
10863
0
        case XPATH_OP_VARIABLE:{
10864
0
    xmlXPathObjectPtr val;
10865
10866
0
                if (op->ch1 != -1)
10867
0
                    total +=
10868
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10869
0
                if (op->value5 == NULL) {
10870
0
        val = xmlXPathVariableLookup(ctxt->context, op->value4);
10871
0
        if (val == NULL)
10872
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
10873
0
                    xmlXPathValuePush(ctxt, val);
10874
0
    } else {
10875
0
                    const xmlChar *URI;
10876
10877
0
                    URI = xmlXPathNsLookup(ctxt->context, op->value5);
10878
0
                    if (URI == NULL) {
10879
0
                        XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10880
0
                        break;
10881
0
                    }
10882
0
        val = xmlXPathVariableLookupNS(ctxt->context,
10883
0
                                                       op->value4, URI);
10884
0
        if (val == NULL)
10885
0
      XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
10886
0
                    xmlXPathValuePush(ctxt, val);
10887
0
                }
10888
0
                break;
10889
0
            }
10890
0
        case XPATH_OP_FUNCTION:{
10891
0
                xmlXPathFunction func;
10892
0
                const xmlChar *oldFunc, *oldFuncURI;
10893
0
    int i;
10894
0
                int frame;
10895
10896
0
                frame = ctxt->valueNr;
10897
0
                if (op->ch1 != -1) {
10898
0
                    total +=
10899
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10900
0
                    if (ctxt->error != XPATH_EXPRESSION_OK)
10901
0
                        break;
10902
0
                }
10903
0
    if (ctxt->valueNr < frame + op->value)
10904
0
        XP_ERROR0(XPATH_INVALID_OPERAND);
10905
0
    for (i = 0; i < op->value; i++) {
10906
0
        if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL)
10907
0
      XP_ERROR0(XPATH_INVALID_OPERAND);
10908
0
                }
10909
0
                if (op->cache != NULL)
10910
0
                    func = op->cache;
10911
0
                else {
10912
0
                    const xmlChar *URI = NULL;
10913
10914
0
                    if (op->value5 == NULL)
10915
0
                        func =
10916
0
                            xmlXPathFunctionLookup(ctxt->context,
10917
0
                                                   op->value4);
10918
0
                    else {
10919
0
                        URI = xmlXPathNsLookup(ctxt->context, op->value5);
10920
0
                        if (URI == NULL)
10921
0
                            XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10922
0
                        func = xmlXPathFunctionLookupNS(ctxt->context,
10923
0
                                                        op->value4, URI);
10924
0
                    }
10925
0
                    if (func == NULL)
10926
0
                        XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
10927
0
                    op->cache = func;
10928
0
                    op->cacheURI = (void *) URI;
10929
0
                }
10930
0
                oldFunc = ctxt->context->function;
10931
0
                oldFuncURI = ctxt->context->functionURI;
10932
0
                ctxt->context->function = op->value4;
10933
0
                ctxt->context->functionURI = op->cacheURI;
10934
0
                func(ctxt, op->value);
10935
0
                ctxt->context->function = oldFunc;
10936
0
                ctxt->context->functionURI = oldFuncURI;
10937
0
                if ((ctxt->error == XPATH_EXPRESSION_OK) &&
10938
0
                    (ctxt->valueNr != frame + 1))
10939
0
                    XP_ERROR0(XPATH_STACK_ERROR);
10940
0
                break;
10941
0
            }
10942
0
        case XPATH_OP_ARG:
10943
0
            if (op->ch1 != -1) {
10944
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10945
0
          CHECK_ERROR0;
10946
0
            }
10947
0
            if (op->ch2 != -1) {
10948
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10949
0
          CHECK_ERROR0;
10950
0
      }
10951
0
            break;
10952
0
        case XPATH_OP_PREDICATE:
10953
0
        case XPATH_OP_FILTER:{
10954
0
                xmlXPathObjectPtr obj;
10955
0
                xmlNodeSetPtr set;
10956
10957
                /*
10958
                 * Optimization for ()[1] selection i.e. the first elem
10959
                 */
10960
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
10961
0
#ifdef XP_OPTIMIZED_FILTER_FIRST
10962
        /*
10963
        * FILTER TODO: Can we assume that the inner processing
10964
        *  will result in an ordered list if we have an
10965
        *  XPATH_OP_FILTER?
10966
        *  What about an additional field or flag on
10967
        *  xmlXPathObject like @sorted ? This way we wouldn't need
10968
        *  to assume anything, so it would be more robust and
10969
        *  easier to optimize.
10970
        */
10971
0
                    ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
10972
0
         (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
10973
#else
10974
        (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10975
#endif
10976
0
                    (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
10977
0
                    xmlXPathObjectPtr val;
10978
10979
0
                    val = comp->steps[op->ch2].value4;
10980
0
                    if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10981
0
                        (val->floatval == 1.0)) {
10982
0
                        xmlNodePtr first = NULL;
10983
10984
0
                        total +=
10985
0
                            xmlXPathCompOpEvalFirst(ctxt,
10986
0
                                                    &comp->steps[op->ch1],
10987
0
                                                    &first);
10988
0
      CHECK_ERROR0;
10989
                        /*
10990
                         * The nodeset should be in document order,
10991
                         * Keep only the first value
10992
                         */
10993
0
                        if ((ctxt->value != NULL) &&
10994
0
                            (ctxt->value->type == XPATH_NODESET) &&
10995
0
                            (ctxt->value->nodesetval != NULL) &&
10996
0
                            (ctxt->value->nodesetval->nodeNr > 1))
10997
0
                            xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
10998
0
                                                        1, 1);
10999
0
                        break;
11000
0
                    }
11001
0
                }
11002
                /*
11003
                 * Optimization for ()[last()] selection i.e. the last elem
11004
                 */
11005
0
                if ((op->ch1 != -1) && (op->ch2 != -1) &&
11006
0
                    (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11007
0
                    (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11008
0
                    int f = comp->steps[op->ch2].ch1;
11009
11010
0
                    if ((f != -1) &&
11011
0
                        (comp->steps[f].op == XPATH_OP_FUNCTION) &&
11012
0
                        (comp->steps[f].value5 == NULL) &&
11013
0
                        (comp->steps[f].value == 0) &&
11014
0
                        (comp->steps[f].value4 != NULL) &&
11015
0
                        (xmlStrEqual
11016
0
                         (comp->steps[f].value4, BAD_CAST "last"))) {
11017
0
                        xmlNodePtr last = NULL;
11018
11019
0
                        total +=
11020
0
                            xmlXPathCompOpEvalLast(ctxt,
11021
0
                                                   &comp->steps[op->ch1],
11022
0
                                                   &last);
11023
0
      CHECK_ERROR0;
11024
                        /*
11025
                         * The nodeset should be in document order,
11026
                         * Keep only the last value
11027
                         */
11028
0
                        if ((ctxt->value != NULL) &&
11029
0
                            (ctxt->value->type == XPATH_NODESET) &&
11030
0
                            (ctxt->value->nodesetval != NULL) &&
11031
0
                            (ctxt->value->nodesetval->nodeTab != NULL) &&
11032
0
                            (ctxt->value->nodesetval->nodeNr > 1))
11033
0
                            xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
11034
0
                        break;
11035
0
                    }
11036
0
                }
11037
    /*
11038
    * Process inner predicates first.
11039
    * Example "index[parent::book][1]":
11040
    * ...
11041
    *   PREDICATE   <-- we are here "[1]"
11042
    *     PREDICATE <-- process "[parent::book]" first
11043
    *       SORT
11044
    *         COLLECT  'parent' 'name' 'node' book
11045
    *           NODE
11046
    *     ELEM Object is a number : 1
11047
    */
11048
0
                if (op->ch1 != -1)
11049
0
                    total +=
11050
0
                        xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11051
0
    CHECK_ERROR0;
11052
0
                if (op->ch2 == -1)
11053
0
                    break;
11054
0
                if (ctxt->value == NULL)
11055
0
                    break;
11056
11057
                /*
11058
                 * In case of errors, xmlXPathNodeSetFilter can pop additional
11059
                 * nodes from the stack. We have to temporarily remove the
11060
                 * nodeset object from the stack to avoid freeing it
11061
                 * prematurely.
11062
                 */
11063
0
                CHECK_TYPE0(XPATH_NODESET);
11064
0
                obj = xmlXPathValuePop(ctxt);
11065
0
                set = obj->nodesetval;
11066
0
                if (set != NULL)
11067
0
                    xmlXPathNodeSetFilter(ctxt, set, op->ch2,
11068
0
                                          1, set->nodeNr, 1);
11069
0
                xmlXPathValuePush(ctxt, obj);
11070
0
                break;
11071
0
            }
11072
0
        case XPATH_OP_SORT:
11073
0
            if (op->ch1 != -1)
11074
0
                total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11075
0
      CHECK_ERROR0;
11076
0
            if ((ctxt->value != NULL) &&
11077
0
                (ctxt->value->type == XPATH_NODESET) &&
11078
0
                (ctxt->value->nodesetval != NULL) &&
11079
0
    (ctxt->value->nodesetval->nodeNr > 1))
11080
0
      {
11081
0
                xmlXPathNodeSetSort(ctxt->value->nodesetval);
11082
0
      }
11083
0
            break;
11084
0
        default:
11085
0
            XP_ERROR0(XPATH_INVALID_OPERAND);
11086
0
            break;
11087
0
    }
11088
11089
0
    ctxt->context->depth -= 1;
11090
0
    return (total);
11091
0
}
11092
11093
/**
11094
 * Evaluates if the expression evaluates to true.
11095
 *
11096
 * @param ctxt  the XPath parser context
11097
 * @param op  the step operation
11098
 * @param isPredicate  whether a predicate is evaluated
11099
 * @returns 1 if true, 0 if false and -1 on API or internal errors.
11100
 */
11101
static int
11102
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
11103
          xmlXPathStepOpPtr op,
11104
          int isPredicate)
11105
0
{
11106
0
    xmlXPathObjectPtr resObj = NULL;
11107
11108
0
start:
11109
0
    if (OP_LIMIT_EXCEEDED(ctxt, 1))
11110
0
        return(0);
11111
    /* comp = ctxt->comp; */
11112
0
    switch (op->op) {
11113
0
        case XPATH_OP_END:
11114
0
            return (0);
11115
0
  case XPATH_OP_VALUE:
11116
0
      resObj = (xmlXPathObjectPtr) op->value4;
11117
0
      if (isPredicate)
11118
0
    return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
11119
0
      return(xmlXPathCastToBoolean(resObj));
11120
0
  case XPATH_OP_SORT:
11121
      /*
11122
      * We don't need sorting for boolean results. Skip this one.
11123
      */
11124
0
            if (op->ch1 != -1) {
11125
0
    op = &ctxt->comp->steps[op->ch1];
11126
0
    goto start;
11127
0
      }
11128
0
      return(0);
11129
0
  case XPATH_OP_COLLECT:
11130
0
      if (op->ch1 == -1)
11131
0
    return(0);
11132
11133
0
            xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
11134
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
11135
0
    return(-1);
11136
11137
0
            xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
11138
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
11139
0
    return(-1);
11140
11141
0
      resObj = xmlXPathValuePop(ctxt);
11142
0
      if (resObj == NULL)
11143
0
    return(-1);
11144
0
      break;
11145
0
  default:
11146
      /*
11147
      * Fallback to call xmlXPathCompOpEval().
11148
      */
11149
0
      xmlXPathCompOpEval(ctxt, op);
11150
0
      if (ctxt->error != XPATH_EXPRESSION_OK)
11151
0
    return(-1);
11152
11153
0
      resObj = xmlXPathValuePop(ctxt);
11154
0
      if (resObj == NULL)
11155
0
    return(-1);
11156
0
      break;
11157
0
    }
11158
11159
0
    if (resObj) {
11160
0
  int res;
11161
11162
0
  if (resObj->type == XPATH_BOOLEAN) {
11163
0
      res = resObj->boolval;
11164
0
  } else if (isPredicate) {
11165
      /*
11166
      * For predicates a result of type "number" is handled
11167
      * differently:
11168
      * SPEC XPath 1.0:
11169
      * "If the result is a number, the result will be converted
11170
      *  to true if the number is equal to the context position
11171
      *  and will be converted to false otherwise;"
11172
      */
11173
0
      res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
11174
0
  } else {
11175
0
      res = xmlXPathCastToBoolean(resObj);
11176
0
  }
11177
0
  xmlXPathReleaseObject(ctxt->context, resObj);
11178
0
  return(res);
11179
0
    }
11180
11181
0
    return(0);
11182
0
}
11183
11184
#ifdef XPATH_STREAMING
11185
/**
11186
 * Evaluate the Precompiled Streamable XPath expression in the given context.
11187
 *
11188
 * @param pctxt  the XPath parser context with the compiled expression
11189
 */
11190
static int
11191
xmlXPathRunStreamEval(xmlXPathParserContextPtr pctxt, xmlPatternPtr comp,
11192
          xmlXPathObjectPtr *resultSeq, int toBool)
11193
{
11194
    int max_depth, min_depth;
11195
    int from_root;
11196
    int ret, depth;
11197
    int eval_all_nodes;
11198
    xmlNodePtr cur = NULL, limit = NULL;
11199
    xmlStreamCtxtPtr patstream = NULL;
11200
    xmlXPathContextPtr ctxt = pctxt->context;
11201
11202
    if ((ctxt == NULL) || (comp == NULL))
11203
        return(-1);
11204
    max_depth = xmlPatternMaxDepth(comp);
11205
    if (max_depth == -1)
11206
        return(-1);
11207
    if (max_depth == -2)
11208
        max_depth = 10000;
11209
    min_depth = xmlPatternMinDepth(comp);
11210
    if (min_depth == -1)
11211
        return(-1);
11212
    from_root = xmlPatternFromRoot(comp);
11213
    if (from_root < 0)
11214
        return(-1);
11215
11216
    if (! toBool) {
11217
  if (resultSeq == NULL)
11218
      return(-1);
11219
  *resultSeq = xmlXPathCacheNewNodeSet(pctxt, NULL);
11220
  if (*resultSeq == NULL)
11221
      return(-1);
11222
    }
11223
11224
    /*
11225
     * handle the special cases of "/" amd "." being matched
11226
     */
11227
    if (min_depth == 0) {
11228
        int res;
11229
11230
  if (from_root) {
11231
      /* Select "/" */
11232
      if (toBool)
11233
    return(1);
11234
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11235
                                           (xmlNodePtr) ctxt->doc);
11236
  } else {
11237
      /* Select "self::node()" */
11238
      if (toBool)
11239
    return(1);
11240
            res = xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11241
                                           ctxt->node);
11242
  }
11243
11244
        if (res < 0)
11245
            xmlXPathPErrMemory(pctxt);
11246
    }
11247
    if (max_depth == 0) {
11248
  return(0);
11249
    }
11250
11251
    if (from_root) {
11252
        cur = (xmlNodePtr)ctxt->doc;
11253
    } else if (ctxt->node != NULL) {
11254
        switch (ctxt->node->type) {
11255
            case XML_ELEMENT_NODE:
11256
            case XML_DOCUMENT_NODE:
11257
            case XML_DOCUMENT_FRAG_NODE:
11258
            case XML_HTML_DOCUMENT_NODE:
11259
          cur = ctxt->node;
11260
    break;
11261
            case XML_ATTRIBUTE_NODE:
11262
            case XML_TEXT_NODE:
11263
            case XML_CDATA_SECTION_NODE:
11264
            case XML_ENTITY_REF_NODE:
11265
            case XML_ENTITY_NODE:
11266
            case XML_PI_NODE:
11267
            case XML_COMMENT_NODE:
11268
            case XML_NOTATION_NODE:
11269
            case XML_DTD_NODE:
11270
            case XML_DOCUMENT_TYPE_NODE:
11271
            case XML_ELEMENT_DECL:
11272
            case XML_ATTRIBUTE_DECL:
11273
            case XML_ENTITY_DECL:
11274
            case XML_NAMESPACE_DECL:
11275
            case XML_XINCLUDE_START:
11276
            case XML_XINCLUDE_END:
11277
    break;
11278
  }
11279
  limit = cur;
11280
    }
11281
    if (cur == NULL) {
11282
        return(0);
11283
    }
11284
11285
    patstream = xmlPatternGetStreamCtxt(comp);
11286
    if (patstream == NULL) {
11287
        xmlXPathPErrMemory(pctxt);
11288
  return(-1);
11289
    }
11290
11291
    eval_all_nodes = xmlStreamWantsAnyNode(patstream);
11292
11293
    if (from_root) {
11294
  ret = xmlStreamPush(patstream, NULL, NULL);
11295
  if (ret < 0) {
11296
  } else if (ret == 1) {
11297
      if (toBool)
11298
    goto return_1;
11299
      if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur) < 0)
11300
                xmlXPathPErrMemory(pctxt);
11301
  }
11302
    }
11303
    depth = 0;
11304
    goto scan_children;
11305
next_node:
11306
    do {
11307
        if (ctxt->opLimit != 0) {
11308
            if (ctxt->opCount >= ctxt->opLimit) {
11309
                xmlXPathErr(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
11310
                xmlFreeStreamCtxt(patstream);
11311
                return(-1);
11312
            }
11313
            ctxt->opCount++;
11314
        }
11315
11316
  switch (cur->type) {
11317
      case XML_ELEMENT_NODE:
11318
      case XML_TEXT_NODE:
11319
      case XML_CDATA_SECTION_NODE:
11320
      case XML_COMMENT_NODE:
11321
      case XML_PI_NODE:
11322
    if (cur->type == XML_ELEMENT_NODE) {
11323
        ret = xmlStreamPush(patstream, cur->name,
11324
        (cur->ns ? cur->ns->href : NULL));
11325
    } else if (eval_all_nodes)
11326
        ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
11327
    else
11328
        break;
11329
11330
    if (ret < 0) {
11331
        xmlXPathPErrMemory(pctxt);
11332
    } else if (ret == 1) {
11333
        if (toBool)
11334
      goto return_1;
11335
        if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
11336
                                                 cur) < 0)
11337
                        xmlXPathPErrMemory(pctxt);
11338
    }
11339
    if ((cur->children == NULL) || (depth >= max_depth)) {
11340
        ret = xmlStreamPop(patstream);
11341
        while (cur->next != NULL) {
11342
      cur = cur->next;
11343
      if ((cur->type != XML_ENTITY_DECL) &&
11344
          (cur->type != XML_DTD_NODE))
11345
          goto next_node;
11346
        }
11347
    }
11348
      default:
11349
    break;
11350
  }
11351
11352
scan_children:
11353
  if (cur->type == XML_NAMESPACE_DECL) break;
11354
  if ((cur->children != NULL) && (depth < max_depth)) {
11355
      /*
11356
       * Do not descend on entities declarations
11357
       */
11358
      if (cur->children->type != XML_ENTITY_DECL) {
11359
    cur = cur->children;
11360
    depth++;
11361
    /*
11362
     * Skip DTDs
11363
     */
11364
    if (cur->type != XML_DTD_NODE)
11365
        continue;
11366
      }
11367
  }
11368
11369
  if (cur == limit)
11370
      break;
11371
11372
  while (cur->next != NULL) {
11373
      cur = cur->next;
11374
      if ((cur->type != XML_ENTITY_DECL) &&
11375
    (cur->type != XML_DTD_NODE))
11376
    goto next_node;
11377
  }
11378
11379
  do {
11380
      cur = cur->parent;
11381
      depth--;
11382
      if ((cur == NULL) || (cur == limit) ||
11383
                (cur->type == XML_DOCUMENT_NODE))
11384
          goto done;
11385
      if (cur->type == XML_ELEMENT_NODE) {
11386
    ret = xmlStreamPop(patstream);
11387
      } else if ((eval_all_nodes) &&
11388
    ((cur->type == XML_TEXT_NODE) ||
11389
     (cur->type == XML_CDATA_SECTION_NODE) ||
11390
     (cur->type == XML_COMMENT_NODE) ||
11391
     (cur->type == XML_PI_NODE)))
11392
      {
11393
    ret = xmlStreamPop(patstream);
11394
      }
11395
      if (cur->next != NULL) {
11396
    cur = cur->next;
11397
    break;
11398
      }
11399
  } while (cur != NULL);
11400
11401
    } while ((cur != NULL) && (depth >= 0));
11402
11403
done:
11404
11405
    if (patstream)
11406
  xmlFreeStreamCtxt(patstream);
11407
    return(0);
11408
11409
return_1:
11410
    if (patstream)
11411
  xmlFreeStreamCtxt(patstream);
11412
    return(1);
11413
}
11414
#endif /* XPATH_STREAMING */
11415
11416
/**
11417
 * Evaluate the Precompiled XPath expression in the given context.
11418
 *
11419
 * @param ctxt  the XPath parser context with the compiled expression
11420
 * @param toBool  evaluate to a boolean result
11421
 */
11422
static int
11423
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
11424
0
{
11425
0
    xmlXPathCompExprPtr comp;
11426
0
    int oldDepth;
11427
11428
0
    if ((ctxt == NULL) || (ctxt->comp == NULL))
11429
0
  return(-1);
11430
11431
0
    if (ctxt->valueTab == NULL) {
11432
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
11433
0
        int valueMax = 1;
11434
#else
11435
        int valueMax = 10;
11436
#endif
11437
11438
  /* Allocate the value stack */
11439
0
  ctxt->valueTab = xmlMalloc(valueMax * sizeof(xmlXPathObjectPtr));
11440
0
  if (ctxt->valueTab == NULL) {
11441
0
      xmlXPathPErrMemory(ctxt);
11442
0
      return(-1);
11443
0
  }
11444
0
  ctxt->valueNr = 0;
11445
0
  ctxt->valueMax = valueMax;
11446
0
  ctxt->value = NULL;
11447
0
    }
11448
#ifdef XPATH_STREAMING
11449
    if (ctxt->comp->stream) {
11450
  int res;
11451
11452
  if (toBool) {
11453
      /*
11454
      * Evaluation to boolean result.
11455
      */
11456
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, NULL, 1);
11457
      if (res != -1)
11458
    return(res);
11459
  } else {
11460
      xmlXPathObjectPtr resObj = NULL;
11461
11462
      /*
11463
      * Evaluation to a sequence.
11464
      */
11465
      res = xmlXPathRunStreamEval(ctxt, ctxt->comp->stream, &resObj, 0);
11466
11467
      if ((res != -1) && (resObj != NULL)) {
11468
    xmlXPathValuePush(ctxt, resObj);
11469
    return(0);
11470
      }
11471
      if (resObj != NULL)
11472
    xmlXPathReleaseObject(ctxt->context, resObj);
11473
  }
11474
  /*
11475
  * QUESTION TODO: This falls back to normal XPath evaluation
11476
  * if res == -1. Is this intended?
11477
  */
11478
    }
11479
#endif
11480
0
    comp = ctxt->comp;
11481
0
    if (comp->last < 0) {
11482
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
11483
0
  return(-1);
11484
0
    }
11485
0
    oldDepth = ctxt->context->depth;
11486
0
    if (toBool)
11487
0
  return(xmlXPathCompOpEvalToBoolean(ctxt,
11488
0
      &comp->steps[comp->last], 0));
11489
0
    else
11490
0
  xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
11491
0
    ctxt->context->depth = oldDepth;
11492
11493
0
    return(0);
11494
0
}
11495
11496
/************************************************************************
11497
 *                  *
11498
 *      Public interfaces       *
11499
 *                  *
11500
 ************************************************************************/
11501
11502
/**
11503
 * Evaluate a predicate result for the current node.
11504
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11505
 * the result to a boolean. If the result is a number, the result will
11506
 * be converted to true if the number is equal to the position of the
11507
 * context node in the context node list (as returned by the position
11508
 * function) and will be converted to false otherwise; if the result
11509
 * is not a number, then the result will be converted as if by a call
11510
 * to the boolean function.
11511
 *
11512
 * @param ctxt  the XPath context
11513
 * @param res  the Predicate Expression evaluation result
11514
 * @returns 1 if predicate is true, 0 otherwise
11515
 */
11516
int
11517
0
xmlXPathEvalPredicate(xmlXPathContext *ctxt, xmlXPathObject *res) {
11518
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
11519
0
    switch (res->type) {
11520
0
        case XPATH_BOOLEAN:
11521
0
      return(res->boolval);
11522
0
        case XPATH_NUMBER:
11523
0
      return(res->floatval == ctxt->proximityPosition);
11524
0
        case XPATH_NODESET:
11525
0
        case XPATH_XSLT_TREE:
11526
0
      if (res->nodesetval == NULL)
11527
0
    return(0);
11528
0
      return(res->nodesetval->nodeNr != 0);
11529
0
        case XPATH_STRING:
11530
0
      return((res->stringval != NULL) &&
11531
0
             (xmlStrlen(res->stringval) != 0));
11532
0
        default:
11533
0
      break;
11534
0
    }
11535
0
    return(0);
11536
0
}
11537
11538
/**
11539
 * Evaluate a predicate result for the current node.
11540
 * A PredicateExpr is evaluated by evaluating the Expr and converting
11541
 * the result to a boolean. If the result is a number, the result will
11542
 * be converted to true if the number is equal to the position of the
11543
 * context node in the context node list (as returned by the position
11544
 * function) and will be converted to false otherwise; if the result
11545
 * is not a number, then the result will be converted as if by a call
11546
 * to the boolean function.
11547
 *
11548
 * @param ctxt  the XPath Parser context
11549
 * @param res  the Predicate Expression evaluation result
11550
 * @returns 1 if predicate is true, 0 otherwise
11551
 */
11552
int
11553
xmlXPathEvaluatePredicateResult(xmlXPathParserContext *ctxt,
11554
0
                                xmlXPathObject *res) {
11555
0
    if ((ctxt == NULL) || (res == NULL)) return(0);
11556
0
    switch (res->type) {
11557
0
        case XPATH_BOOLEAN:
11558
0
      return(res->boolval);
11559
0
        case XPATH_NUMBER:
11560
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
11561
      return((res->floatval == ctxt->context->proximityPosition) &&
11562
             (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
11563
#else
11564
0
      return(res->floatval == ctxt->context->proximityPosition);
11565
0
#endif
11566
0
        case XPATH_NODESET:
11567
0
        case XPATH_XSLT_TREE:
11568
0
      if (res->nodesetval == NULL)
11569
0
    return(0);
11570
0
      return(res->nodesetval->nodeNr != 0);
11571
0
        case XPATH_STRING:
11572
0
      return((res->stringval != NULL) && (res->stringval[0] != 0));
11573
0
        default:
11574
0
      break;
11575
0
    }
11576
0
    return(0);
11577
0
}
11578
11579
#ifdef XPATH_STREAMING
11580
/**
11581
 * Try to compile the XPath expression as a streamable subset.
11582
 *
11583
 * @param ctxt  an XPath context
11584
 * @param str  the XPath expression
11585
 * @returns the compiled expression or NULL if failed to compile.
11586
 */
11587
static xmlXPathCompExprPtr
11588
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
11589
    /*
11590
     * Optimization: use streaming patterns when the XPath expression can
11591
     * be compiled to a stream lookup
11592
     */
11593
    xmlPatternPtr stream;
11594
    xmlXPathCompExprPtr comp;
11595
    xmlDictPtr dict = NULL;
11596
    const xmlChar **namespaces = NULL;
11597
    xmlNsPtr ns;
11598
    int i, j;
11599
11600
    if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
11601
        (!xmlStrchr(str, '@'))) {
11602
  const xmlChar *tmp;
11603
        int res;
11604
11605
  /*
11606
   * We don't try to handle expressions using the verbose axis
11607
   * specifiers ("::"), just the simplified form at this point.
11608
   * Additionally, if there is no list of namespaces available and
11609
   *  there's a ":" in the expression, indicating a prefixed QName,
11610
   *  then we won't try to compile either. xmlPatterncompile() needs
11611
   *  to have a list of namespaces at compilation time in order to
11612
   *  compile prefixed name tests.
11613
   */
11614
  tmp = xmlStrchr(str, ':');
11615
  if ((tmp != NULL) &&
11616
      ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
11617
      return(NULL);
11618
11619
  if (ctxt != NULL) {
11620
      dict = ctxt->dict;
11621
      if (ctxt->nsNr > 0) {
11622
    namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
11623
    if (namespaces == NULL) {
11624
        xmlXPathErrMemory(ctxt);
11625
        return(NULL);
11626
    }
11627
    for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
11628
        ns = ctxt->namespaces[j];
11629
        namespaces[i++] = ns->href;
11630
        namespaces[i++] = ns->prefix;
11631
    }
11632
    namespaces[i++] = NULL;
11633
    namespaces[i] = NULL;
11634
      }
11635
  }
11636
11637
  res = xmlPatternCompileSafe(str, dict, XML_PATTERN_XPATH, namespaces,
11638
                                    &stream);
11639
  if (namespaces != NULL) {
11640
      xmlFree((xmlChar **)namespaces);
11641
  }
11642
        if (res < 0) {
11643
            xmlXPathErrMemory(ctxt);
11644
            return(NULL);
11645
        }
11646
  if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
11647
      comp = xmlXPathNewCompExpr();
11648
      if (comp == NULL) {
11649
    xmlXPathErrMemory(ctxt);
11650
          xmlFreePattern(stream);
11651
    return(NULL);
11652
      }
11653
      comp->stream = stream;
11654
      comp->dict = dict;
11655
      if (comp->dict)
11656
    xmlDictReference(comp->dict);
11657
      return(comp);
11658
  }
11659
  xmlFreePattern(stream);
11660
    }
11661
    return(NULL);
11662
}
11663
#endif /* XPATH_STREAMING */
11664
11665
static void
11666
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
11667
                           xmlXPathStepOpPtr op)
11668
0
{
11669
0
    xmlXPathCompExprPtr comp = pctxt->comp;
11670
0
    xmlXPathContextPtr ctxt;
11671
11672
    /*
11673
    * Try to rewrite "descendant-or-self::node()/foo" to an optimized
11674
    * internal representation.
11675
    */
11676
11677
0
    if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
11678
0
        (op->ch1 != -1) &&
11679
0
        (op->ch2 == -1 /* no predicate */))
11680
0
    {
11681
0
        xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
11682
11683
0
        if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
11684
0
            ((xmlXPathAxisVal) prevop->value ==
11685
0
                AXIS_DESCENDANT_OR_SELF) &&
11686
0
            (prevop->ch2 == -1) &&
11687
0
            ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
11688
0
            ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
11689
0
        {
11690
            /*
11691
            * This is a "descendant-or-self::node()" without predicates.
11692
            * Try to eliminate it.
11693
            */
11694
11695
0
            switch ((xmlXPathAxisVal) op->value) {
11696
0
                case AXIS_CHILD:
11697
0
                case AXIS_DESCENDANT:
11698
                    /*
11699
                    * Convert "descendant-or-self::node()/child::" or
11700
                    * "descendant-or-self::node()/descendant::" to
11701
                    * "descendant::"
11702
                    */
11703
0
                    op->ch1   = prevop->ch1;
11704
0
                    op->value = AXIS_DESCENDANT;
11705
0
                    break;
11706
0
                case AXIS_SELF:
11707
0
                case AXIS_DESCENDANT_OR_SELF:
11708
                    /*
11709
                    * Convert "descendant-or-self::node()/self::" or
11710
                    * "descendant-or-self::node()/descendant-or-self::" to
11711
                    * to "descendant-or-self::"
11712
                    */
11713
0
                    op->ch1   = prevop->ch1;
11714
0
                    op->value = AXIS_DESCENDANT_OR_SELF;
11715
0
                    break;
11716
0
                default:
11717
0
                    break;
11718
0
            }
11719
0
  }
11720
0
    }
11721
11722
    /* OP_VALUE has invalid ch1. */
11723
0
    if (op->op == XPATH_OP_VALUE)
11724
0
        return;
11725
11726
    /* Recurse */
11727
0
    ctxt = pctxt->context;
11728
0
    if (ctxt != NULL) {
11729
0
        if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
11730
0
            return;
11731
0
        ctxt->depth += 1;
11732
0
    }
11733
0
    if (op->ch1 != -1)
11734
0
        xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
11735
0
    if (op->ch2 != -1)
11736
0
  xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
11737
0
    if (ctxt != NULL)
11738
0
        ctxt->depth -= 1;
11739
0
}
11740
11741
/**
11742
 * Compile an XPath expression
11743
 *
11744
 * @param ctxt  an XPath context
11745
 * @param str  the XPath expression
11746
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11747
 *         the caller has to free the object.
11748
 */
11749
xmlXPathCompExpr *
11750
0
xmlXPathCtxtCompile(xmlXPathContext *ctxt, const xmlChar *str) {
11751
0
    xmlXPathParserContextPtr pctxt;
11752
0
    xmlXPathContextPtr tmpctxt = NULL;
11753
0
    xmlXPathCompExprPtr comp;
11754
0
    int oldDepth = 0;
11755
11756
0
    if (str == NULL)
11757
0
        return(NULL);
11758
11759
#ifdef XPATH_STREAMING
11760
    comp = xmlXPathTryStreamCompile(ctxt, str);
11761
    if (comp != NULL)
11762
        return(comp);
11763
#endif
11764
11765
0
    xmlInitParser();
11766
11767
    /*
11768
     * We need an xmlXPathContext for the depth check.
11769
     */
11770
0
    if (ctxt == NULL) {
11771
0
        tmpctxt = xmlXPathNewContext(NULL);
11772
0
        if (tmpctxt == NULL)
11773
0
            return(NULL);
11774
0
        ctxt = tmpctxt;
11775
0
    }
11776
11777
0
    pctxt = xmlXPathNewParserContext(str, ctxt);
11778
0
    if (pctxt == NULL) {
11779
0
        if (tmpctxt != NULL)
11780
0
            xmlXPathFreeContext(tmpctxt);
11781
0
        return NULL;
11782
0
    }
11783
11784
0
    oldDepth = ctxt->depth;
11785
0
    xmlXPathCompileExpr(pctxt, 1);
11786
0
    ctxt->depth = oldDepth;
11787
11788
0
    if( pctxt->error != XPATH_EXPRESSION_OK )
11789
0
    {
11790
0
        xmlXPathFreeParserContext(pctxt);
11791
0
        if (tmpctxt != NULL)
11792
0
            xmlXPathFreeContext(tmpctxt);
11793
0
        return(NULL);
11794
0
    }
11795
11796
0
    if (*pctxt->cur != 0) {
11797
  /*
11798
   * aleksey: in some cases this line prints *second* error message
11799
   * (see bug #78858) and probably this should be fixed.
11800
   * However, we are not sure that all error messages are printed
11801
   * out in other places. It's not critical so we leave it as-is for now
11802
   */
11803
0
  xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
11804
0
  comp = NULL;
11805
0
    } else {
11806
0
  comp = pctxt->comp;
11807
0
  if ((comp->nbStep > 1) && (comp->last >= 0)) {
11808
0
            if (ctxt != NULL)
11809
0
                oldDepth = ctxt->depth;
11810
0
      xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
11811
0
            if (ctxt != NULL)
11812
0
                ctxt->depth = oldDepth;
11813
0
  }
11814
0
  pctxt->comp = NULL;
11815
0
    }
11816
0
    xmlXPathFreeParserContext(pctxt);
11817
0
    if (tmpctxt != NULL)
11818
0
        xmlXPathFreeContext(tmpctxt);
11819
11820
0
    if (comp != NULL) {
11821
0
  comp->expr = xmlStrdup(str);
11822
0
    }
11823
0
    return(comp);
11824
0
}
11825
11826
/**
11827
 * Compile an XPath expression
11828
 *
11829
 * @param str  the XPath expression
11830
 * @returns the xmlXPathCompExpr resulting from the compilation or NULL.
11831
 *         the caller has to free the object.
11832
 */
11833
xmlXPathCompExpr *
11834
0
xmlXPathCompile(const xmlChar *str) {
11835
0
    return(xmlXPathCtxtCompile(NULL, str));
11836
0
}
11837
11838
/**
11839
 * Evaluate the Precompiled XPath expression in the given context.
11840
 * The caller has to free `resObj`.
11841
 *
11842
 * @param comp  the compiled XPath expression
11843
 * @param ctxt  the XPath context
11844
 * @param resObjPtr  the resulting XPath object or NULL
11845
 * @param toBool  1 if only a boolean result is requested
11846
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11847
 *         the caller has to free the object.
11848
 */
11849
static int
11850
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
11851
           xmlXPathContextPtr ctxt,
11852
           xmlXPathObjectPtr *resObjPtr,
11853
           int toBool)
11854
0
{
11855
0
    xmlXPathParserContextPtr pctxt;
11856
0
    xmlXPathObjectPtr resObj = NULL;
11857
0
    int res;
11858
11859
0
    if (comp == NULL)
11860
0
  return(-1);
11861
0
    xmlInitParser();
11862
11863
0
    xmlResetError(&ctxt->lastError);
11864
11865
0
    pctxt = xmlXPathCompParserContext(comp, ctxt);
11866
0
    if (pctxt == NULL)
11867
0
        return(-1);
11868
0
    res = xmlXPathRunEval(pctxt, toBool);
11869
11870
0
    if (pctxt->error == XPATH_EXPRESSION_OK) {
11871
0
        if (pctxt->valueNr != ((toBool) ? 0 : 1))
11872
0
            xmlXPathErr(pctxt, XPATH_STACK_ERROR);
11873
0
        else if (!toBool)
11874
0
            resObj = xmlXPathValuePop(pctxt);
11875
0
    }
11876
11877
0
    if (resObjPtr)
11878
0
        *resObjPtr = resObj;
11879
0
    else
11880
0
        xmlXPathReleaseObject(ctxt, resObj);
11881
11882
0
    pctxt->comp = NULL;
11883
0
    xmlXPathFreeParserContext(pctxt);
11884
11885
0
    return(res);
11886
0
}
11887
11888
/**
11889
 * Evaluate the Precompiled XPath expression in the given context.
11890
 *
11891
 * @param comp  the compiled XPath expression
11892
 * @param ctx  the XPath context
11893
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11894
 *         the caller has to free the object.
11895
 */
11896
xmlXPathObject *
11897
xmlXPathCompiledEval(xmlXPathCompExpr *comp, xmlXPathContext *ctx)
11898
0
{
11899
0
    xmlXPathObjectPtr res = NULL;
11900
11901
0
    xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
11902
0
    return(res);
11903
0
}
11904
11905
/**
11906
 * Applies the XPath boolean() function on the result of the given
11907
 * compiled expression.
11908
 *
11909
 * @param comp  the compiled XPath expression
11910
 * @param ctxt  the XPath context
11911
 * @returns 1 if the expression evaluated to true, 0 if to false and
11912
 *         -1 in API and internal errors.
11913
 */
11914
int
11915
xmlXPathCompiledEvalToBoolean(xmlXPathCompExpr *comp,
11916
            xmlXPathContext *ctxt)
11917
0
{
11918
0
    return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
11919
0
}
11920
11921
/**
11922
 * Parse and evaluate an XPath expression in the given context,
11923
 * then push the result on the context stack
11924
 *
11925
 * @deprecated Internal function, don't use.
11926
 *
11927
 * @param ctxt  the XPath Parser context
11928
 */
11929
void
11930
0
xmlXPathEvalExpr(xmlXPathParserContext *ctxt) {
11931
#ifdef XPATH_STREAMING
11932
    xmlXPathCompExprPtr comp;
11933
#endif
11934
0
    int oldDepth = 0;
11935
11936
0
    if ((ctxt == NULL) || (ctxt->context == NULL))
11937
0
        return;
11938
0
    if (ctxt->context->lastError.code != 0)
11939
0
        return;
11940
11941
#ifdef XPATH_STREAMING
11942
    comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
11943
    if ((comp == NULL) &&
11944
        (ctxt->context->lastError.code == XML_ERR_NO_MEMORY)) {
11945
        xmlXPathPErrMemory(ctxt);
11946
        return;
11947
    }
11948
    if (comp != NULL) {
11949
        if (ctxt->comp != NULL)
11950
      xmlXPathFreeCompExpr(ctxt->comp);
11951
        ctxt->comp = comp;
11952
    } else
11953
#endif
11954
0
    {
11955
0
        if (ctxt->context != NULL)
11956
0
            oldDepth = ctxt->context->depth;
11957
0
  xmlXPathCompileExpr(ctxt, 1);
11958
0
        if (ctxt->context != NULL)
11959
0
            ctxt->context->depth = oldDepth;
11960
0
        CHECK_ERROR;
11961
11962
        /* Check for trailing characters. */
11963
0
        if (*ctxt->cur != 0)
11964
0
            XP_ERROR(XPATH_EXPR_ERROR);
11965
11966
0
  if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
11967
0
            if (ctxt->context != NULL)
11968
0
                oldDepth = ctxt->context->depth;
11969
0
      xmlXPathOptimizeExpression(ctxt,
11970
0
    &ctxt->comp->steps[ctxt->comp->last]);
11971
0
            if (ctxt->context != NULL)
11972
0
                ctxt->context->depth = oldDepth;
11973
0
        }
11974
0
    }
11975
11976
0
    xmlXPathRunEval(ctxt, 0);
11977
0
}
11978
11979
/**
11980
 * Evaluate the XPath Location Path in the given context.
11981
 *
11982
 * @param str  the XPath expression
11983
 * @param ctx  the XPath context
11984
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
11985
 *         the caller has to free the object.
11986
 */
11987
xmlXPathObject *
11988
0
xmlXPathEval(const xmlChar *str, xmlXPathContext *ctx) {
11989
0
    xmlXPathParserContextPtr ctxt;
11990
0
    xmlXPathObjectPtr res;
11991
11992
0
    if (ctx == NULL)
11993
0
        return(NULL);
11994
11995
0
    xmlInitParser();
11996
11997
0
    xmlResetError(&ctx->lastError);
11998
11999
0
    ctxt = xmlXPathNewParserContext(str, ctx);
12000
0
    if (ctxt == NULL)
12001
0
        return NULL;
12002
0
    xmlXPathEvalExpr(ctxt);
12003
12004
0
    if (ctxt->error != XPATH_EXPRESSION_OK) {
12005
0
  res = NULL;
12006
0
    } else if (ctxt->valueNr != 1) {
12007
0
        xmlXPathErr(ctxt, XPATH_STACK_ERROR);
12008
0
  res = NULL;
12009
0
    } else {
12010
0
  res = xmlXPathValuePop(ctxt);
12011
0
    }
12012
12013
0
    xmlXPathFreeParserContext(ctxt);
12014
0
    return(res);
12015
0
}
12016
12017
/**
12018
 * Sets 'node' as the context node. The node must be in the same
12019
 * document as that associated with the context.
12020
 *
12021
 * @param node  the node to to use as the context node
12022
 * @param ctx  the XPath context
12023
 * @returns -1 in case of error or 0 if successful
12024
 */
12025
int
12026
0
xmlXPathSetContextNode(xmlNode *node, xmlXPathContext *ctx) {
12027
0
    if ((node == NULL) || (ctx == NULL))
12028
0
        return(-1);
12029
12030
0
    if (node->doc == ctx->doc) {
12031
0
        ctx->node = node;
12032
0
  return(0);
12033
0
    }
12034
0
    return(-1);
12035
0
}
12036
12037
/**
12038
 * Evaluate the XPath Location Path in the given context. The node 'node'
12039
 * is set as the context node. The context node is not restored.
12040
 *
12041
 * @param node  the node to to use as the context node
12042
 * @param str  the XPath expression
12043
 * @param ctx  the XPath context
12044
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12045
 *         the caller has to free the object.
12046
 */
12047
xmlXPathObject *
12048
0
xmlXPathNodeEval(xmlNode *node, const xmlChar *str, xmlXPathContext *ctx) {
12049
0
    if (str == NULL)
12050
0
        return(NULL);
12051
0
    if (xmlXPathSetContextNode(node, ctx) < 0)
12052
0
        return(NULL);
12053
0
    return(xmlXPathEval(str, ctx));
12054
0
}
12055
12056
/**
12057
 * Alias for #xmlXPathEval.
12058
 *
12059
 * @param str  the XPath expression
12060
 * @param ctxt  the XPath context
12061
 * @returns the xmlXPathObject resulting from the evaluation or NULL.
12062
 *         the caller has to free the object.
12063
 */
12064
xmlXPathObject *
12065
0
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContext *ctxt) {
12066
0
    return(xmlXPathEval(str, ctxt));
12067
0
}
12068
12069
/**
12070
 * Registers all default XPath functions in this context
12071
 *
12072
 * @deprecated No-op since 2.14.0.
12073
 *
12074
 * @param ctxt  the XPath context
12075
 */
12076
void
12077
xmlXPathRegisterAllFunctions(xmlXPathContext *ctxt ATTRIBUTE_UNUSED)
12078
0
{
12079
0
}
12080
12081
#endif /* LIBXML_XPATH_ENABLED */