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