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