WebCore/xml/XPathFunctions.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
       
     3  * Copyright (C) 2006, 2009 Apple Inc.
       
     4  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
       
     5  *
       
     6  * Redistribution and use in source and binary forms, with or without
       
     7  * modification, are permitted provided that the following conditions
       
     8  * are met:
       
     9  * 
       
    10  * 1. Redistributions of source code must retain the above copyright
       
    11  *    notice, this list of conditions and the following disclaimer.
       
    12  * 2. Redistributions in binary form must reproduce the above copyright
       
    13  *    notice, this list of conditions and the following disclaimer in the
       
    14  *    documentation and/or other materials provided with the distribution.
       
    15  * 
       
    16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
       
    17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
       
    18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
       
    19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
       
    20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
       
    21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    26  */
       
    27 
       
    28 #include "config.h"
       
    29 #include "XPathFunctions.h"
       
    30 
       
    31 #if ENABLE(XPATH)
       
    32 
       
    33 #include "Document.h"
       
    34 #include "Element.h"
       
    35 #include "NamedNodeMap.h"
       
    36 #include "ProcessingInstruction.h"
       
    37 #include "XMLNames.h"
       
    38 #include "XPathUtil.h"
       
    39 #include "XPathValue.h"
       
    40 #include <wtf/MathExtras.h>
       
    41 
       
    42 namespace WebCore {
       
    43 namespace XPath {
       
    44 
       
    45 static inline bool isWhitespace(UChar c)
       
    46 {
       
    47     return c == ' ' || c == '\n' || c == '\r' || c == '\t';
       
    48 }
       
    49 
       
    50 
       
    51 #define DEFINE_FUNCTION_CREATOR(Class) static Function* create##Class() { return new Class; }
       
    52 
       
    53 class Interval {
       
    54 public:
       
    55     static const int Inf = -1;
       
    56 
       
    57     Interval();
       
    58     Interval(int value);
       
    59     Interval(int min, int max);
       
    60 
       
    61     bool contains(int value) const;
       
    62 
       
    63 private:
       
    64     int m_min;
       
    65     int m_max;
       
    66 };
       
    67 
       
    68 struct FunctionRec {
       
    69     typedef Function *(*FactoryFn)();
       
    70     FactoryFn factoryFn;
       
    71     Interval args;
       
    72 };
       
    73 
       
    74 static HashMap<String, FunctionRec>* functionMap;
       
    75 
       
    76 class FunLast : public Function {
       
    77     virtual Value evaluate() const;
       
    78     virtual Value::Type resultType() const { return Value::NumberValue; }
       
    79 public:
       
    80     FunLast() { setIsContextSizeSensitive(true); }
       
    81 };
       
    82 
       
    83 class FunPosition : public Function {
       
    84     virtual Value evaluate() const;
       
    85     virtual Value::Type resultType() const { return Value::NumberValue; }
       
    86 public:
       
    87     FunPosition() { setIsContextPositionSensitive(true); }
       
    88 };
       
    89 
       
    90 class FunCount : public Function {
       
    91     virtual Value evaluate() const;
       
    92     virtual Value::Type resultType() const { return Value::NumberValue; }
       
    93 };
       
    94 
       
    95 class FunId : public Function {
       
    96     virtual Value evaluate() const;
       
    97     virtual Value::Type resultType() const { return Value::NodeSetValue; }
       
    98 };
       
    99 
       
   100 class FunLocalName : public Function {
       
   101     virtual Value evaluate() const;
       
   102     virtual Value::Type resultType() const { return Value::StringValue; }
       
   103 public:
       
   104     FunLocalName() { setIsContextNodeSensitive(true); } // local-name() with no arguments uses context node. 
       
   105 };
       
   106 
       
   107 class FunNamespaceURI : public Function {
       
   108     virtual Value evaluate() const;
       
   109     virtual Value::Type resultType() const { return Value::StringValue; }
       
   110 public:
       
   111     FunNamespaceURI() { setIsContextNodeSensitive(true); } // namespace-uri() with no arguments uses context node. 
       
   112 };
       
   113 
       
   114 class FunName : public Function {
       
   115     virtual Value evaluate() const;
       
   116     virtual Value::Type resultType() const { return Value::StringValue; }
       
   117 public:
       
   118     FunName() { setIsContextNodeSensitive(true); } // name() with no arguments uses context node. 
       
   119 };
       
   120 
       
   121 class FunString : public Function {
       
   122     virtual Value evaluate() const;
       
   123     virtual Value::Type resultType() const { return Value::StringValue; }
       
   124 public:
       
   125     FunString() { setIsContextNodeSensitive(true); } // string() with no arguments uses context node. 
       
   126 };
       
   127 
       
   128 class FunConcat : public Function {
       
   129     virtual Value evaluate() const;
       
   130     virtual Value::Type resultType() const { return Value::StringValue; }
       
   131 };
       
   132 
       
   133 class FunStartsWith : public Function {
       
   134     virtual Value evaluate() const;
       
   135     virtual Value::Type resultType() const { return Value::BooleanValue; }
       
   136 };
       
   137 
       
   138 class FunContains : public Function {
       
   139     virtual Value evaluate() const;
       
   140     virtual Value::Type resultType() const { return Value::BooleanValue; }
       
   141 };
       
   142 
       
   143 class FunSubstringBefore : public Function {
       
   144     virtual Value evaluate() const;
       
   145     virtual Value::Type resultType() const { return Value::StringValue; }
       
   146 };
       
   147 
       
   148 class FunSubstringAfter : public Function {
       
   149     virtual Value evaluate() const;
       
   150     virtual Value::Type resultType() const { return Value::StringValue; }
       
   151 };
       
   152 
       
   153 class FunSubstring : public Function {
       
   154     virtual Value evaluate() const;
       
   155     virtual Value::Type resultType() const { return Value::StringValue; }
       
   156 };
       
   157 
       
   158 class FunStringLength : public Function {
       
   159     virtual Value evaluate() const;
       
   160     virtual Value::Type resultType() const { return Value::NumberValue; }
       
   161 public:
       
   162     FunStringLength() { setIsContextNodeSensitive(true); } // string-length() with no arguments uses context node. 
       
   163 };
       
   164 
       
   165 class FunNormalizeSpace : public Function {
       
   166     virtual Value evaluate() const;
       
   167     virtual Value::Type resultType() const { return Value::StringValue; }
       
   168 public:
       
   169     FunNormalizeSpace() { setIsContextNodeSensitive(true); } // normalize-space() with no arguments uses context node. 
       
   170 };
       
   171 
       
   172 class FunTranslate : public Function {
       
   173     virtual Value evaluate() const;
       
   174     virtual Value::Type resultType() const { return Value::StringValue; }
       
   175 };
       
   176 
       
   177 class FunBoolean : public Function {
       
   178     virtual Value evaluate() const;
       
   179     virtual Value::Type resultType() const { return Value::BooleanValue; }
       
   180 };
       
   181 
       
   182 class FunNot : public Function {
       
   183     virtual Value evaluate() const;
       
   184     virtual Value::Type resultType() const { return Value::BooleanValue; }
       
   185 };
       
   186 
       
   187 class FunTrue : public Function {
       
   188     virtual Value evaluate() const;
       
   189     virtual Value::Type resultType() const { return Value::BooleanValue; }
       
   190 };
       
   191 
       
   192 class FunFalse : public Function {
       
   193     virtual Value evaluate() const;
       
   194     virtual Value::Type resultType() const { return Value::BooleanValue; }
       
   195 };
       
   196 
       
   197 class FunLang : public Function {
       
   198     virtual Value evaluate() const;
       
   199     virtual Value::Type resultType() const { return Value::BooleanValue; }
       
   200 public:
       
   201     FunLang() { setIsContextNodeSensitive(true); } // lang() always works on context node. 
       
   202 };
       
   203 
       
   204 class FunNumber : public Function {
       
   205     virtual Value evaluate() const;
       
   206     virtual Value::Type resultType() const { return Value::NumberValue; }
       
   207 public:
       
   208     FunNumber() { setIsContextNodeSensitive(true); } // number() with no arguments uses context node. 
       
   209 };
       
   210 
       
   211 class FunSum : public Function {
       
   212     virtual Value evaluate() const;
       
   213     virtual Value::Type resultType() const { return Value::NumberValue; }
       
   214 };
       
   215 
       
   216 class FunFloor : public Function {
       
   217     virtual Value evaluate() const;
       
   218     virtual Value::Type resultType() const { return Value::NumberValue; }
       
   219 };
       
   220 
       
   221 class FunCeiling : public Function {
       
   222     virtual Value evaluate() const;
       
   223     virtual Value::Type resultType() const { return Value::NumberValue; }
       
   224 };
       
   225 
       
   226 class FunRound : public Function {
       
   227     virtual Value evaluate() const;
       
   228     virtual Value::Type resultType() const { return Value::NumberValue; }
       
   229 public:
       
   230     static double round(double);
       
   231 };
       
   232 
       
   233 DEFINE_FUNCTION_CREATOR(FunLast)
       
   234 DEFINE_FUNCTION_CREATOR(FunPosition)
       
   235 DEFINE_FUNCTION_CREATOR(FunCount)
       
   236 DEFINE_FUNCTION_CREATOR(FunId)
       
   237 DEFINE_FUNCTION_CREATOR(FunLocalName)
       
   238 DEFINE_FUNCTION_CREATOR(FunNamespaceURI)
       
   239 DEFINE_FUNCTION_CREATOR(FunName)
       
   240 
       
   241 DEFINE_FUNCTION_CREATOR(FunString)
       
   242 DEFINE_FUNCTION_CREATOR(FunConcat)
       
   243 DEFINE_FUNCTION_CREATOR(FunStartsWith)
       
   244 DEFINE_FUNCTION_CREATOR(FunContains)
       
   245 DEFINE_FUNCTION_CREATOR(FunSubstringBefore)
       
   246 DEFINE_FUNCTION_CREATOR(FunSubstringAfter)
       
   247 DEFINE_FUNCTION_CREATOR(FunSubstring)
       
   248 DEFINE_FUNCTION_CREATOR(FunStringLength)
       
   249 DEFINE_FUNCTION_CREATOR(FunNormalizeSpace)
       
   250 DEFINE_FUNCTION_CREATOR(FunTranslate)
       
   251 
       
   252 DEFINE_FUNCTION_CREATOR(FunBoolean)
       
   253 DEFINE_FUNCTION_CREATOR(FunNot)
       
   254 DEFINE_FUNCTION_CREATOR(FunTrue)
       
   255 DEFINE_FUNCTION_CREATOR(FunFalse)
       
   256 DEFINE_FUNCTION_CREATOR(FunLang)
       
   257 
       
   258 DEFINE_FUNCTION_CREATOR(FunNumber)
       
   259 DEFINE_FUNCTION_CREATOR(FunSum)
       
   260 DEFINE_FUNCTION_CREATOR(FunFloor)
       
   261 DEFINE_FUNCTION_CREATOR(FunCeiling)
       
   262 DEFINE_FUNCTION_CREATOR(FunRound)
       
   263 
       
   264 #undef DEFINE_FUNCTION_CREATOR
       
   265 
       
   266 inline Interval::Interval()
       
   267     : m_min(Inf), m_max(Inf)
       
   268 {
       
   269 }
       
   270 
       
   271 inline Interval::Interval(int value)
       
   272     : m_min(value), m_max(value)
       
   273 {
       
   274 }
       
   275 
       
   276 inline Interval::Interval(int min, int max)
       
   277     : m_min(min), m_max(max)
       
   278 {
       
   279 }
       
   280 
       
   281 inline bool Interval::contains(int value) const
       
   282 {
       
   283     if (m_min == Inf && m_max == Inf)
       
   284         return true;
       
   285 
       
   286     if (m_min == Inf)
       
   287         return value <= m_max;
       
   288 
       
   289     if (m_max == Inf)
       
   290         return value >= m_min;
       
   291 
       
   292     return value >= m_min && value <= m_max;
       
   293 }
       
   294 
       
   295 void Function::setArguments(const Vector<Expression*>& args)
       
   296 {
       
   297     ASSERT(!subExprCount());
       
   298 
       
   299     // Some functions use context node as implicit argument, so when explicit arguments are added, they may no longer be context node sensitive.
       
   300     if (m_name != "lang" && !args.isEmpty())
       
   301         setIsContextNodeSensitive(false);
       
   302 
       
   303     Vector<Expression*>::const_iterator end = args.end();
       
   304     for (Vector<Expression*>::const_iterator it = args.begin(); it != end; it++)
       
   305         addSubExpression(*it);
       
   306 }
       
   307 
       
   308 Value FunLast::evaluate() const
       
   309 {
       
   310     return Expression::evaluationContext().size;
       
   311 }
       
   312 
       
   313 Value FunPosition::evaluate() const
       
   314 {
       
   315     return Expression::evaluationContext().position;
       
   316 }
       
   317 
       
   318 Value FunId::evaluate() const
       
   319 {
       
   320     Value a = arg(0)->evaluate();
       
   321     Vector<UChar> idList; // A whitespace-separated list of IDs
       
   322 
       
   323     if (a.isNodeSet()) {
       
   324         const NodeSet& nodes = a.toNodeSet();
       
   325         for (size_t i = 0; i < nodes.size(); ++i) {
       
   326             String str = stringValue(nodes[i]);
       
   327             idList.append(str.characters(), str.length());
       
   328             idList.append(' ');
       
   329         }
       
   330     } else {
       
   331         String str = a.toString();
       
   332         idList.append(str.characters(), str.length());
       
   333     }
       
   334     
       
   335     Document* contextDocument = evaluationContext().node->document();
       
   336     NodeSet result;
       
   337     HashSet<Node*> resultSet;
       
   338 
       
   339     size_t startPos = 0;
       
   340     size_t length = idList.size();
       
   341     while (true) {
       
   342         while (startPos < length && isWhitespace(idList[startPos]))
       
   343             ++startPos;
       
   344         
       
   345         if (startPos == length)
       
   346             break;
       
   347 
       
   348         size_t endPos = startPos;
       
   349         while (endPos < length && !isWhitespace(idList[endPos]))
       
   350             ++endPos;
       
   351 
       
   352         // If there are several nodes with the same id, id() should return the first one.
       
   353         // In WebKit, getElementById behaves so, too, although its behavior in this case is formally undefined.
       
   354         Node* node = contextDocument->getElementById(String(&idList[startPos], endPos - startPos));
       
   355         if (node && resultSet.add(node).second)
       
   356             result.append(node);
       
   357         
       
   358         startPos = endPos;
       
   359     }
       
   360     
       
   361     result.markSorted(false);
       
   362     
       
   363     return Value(result, Value::adopt);
       
   364 }
       
   365 
       
   366 static inline String expandedNameLocalPart(Node* node)
       
   367 {
       
   368     // The local part of an XPath expanded-name matches DOM local name for most node types, except for namespace nodes and processing instruction nodes.
       
   369     ASSERT(node->nodeType() != Node::XPATH_NAMESPACE_NODE); // Not supported yet.
       
   370     if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
       
   371         return static_cast<ProcessingInstruction*>(node)->target();
       
   372     return node->localName().string();
       
   373 }
       
   374 
       
   375 static inline String expandedName(Node* node)
       
   376 {
       
   377     const AtomicString& prefix = node->prefix();
       
   378     return prefix.isEmpty() ? expandedNameLocalPart(node) : prefix + ":" + expandedNameLocalPart(node);
       
   379 }
       
   380 
       
   381 Value FunLocalName::evaluate() const
       
   382 {
       
   383     if (argCount() > 0) {
       
   384         Value a = arg(0)->evaluate();
       
   385         if (!a.isNodeSet())
       
   386             return "";
       
   387 
       
   388         Node* node = a.toNodeSet().firstNode();
       
   389         return node ? expandedNameLocalPart(node) : "";
       
   390     }
       
   391 
       
   392     return expandedNameLocalPart(evaluationContext().node.get());
       
   393 }
       
   394 
       
   395 Value FunNamespaceURI::evaluate() const
       
   396 {
       
   397     if (argCount() > 0) {
       
   398         Value a = arg(0)->evaluate();
       
   399         if (!a.isNodeSet())
       
   400             return "";
       
   401 
       
   402         Node* node = a.toNodeSet().firstNode();
       
   403         return node ? node->namespaceURI().string() : "";
       
   404     }
       
   405 
       
   406     return evaluationContext().node->namespaceURI().string();
       
   407 }
       
   408 
       
   409 Value FunName::evaluate() const
       
   410 {
       
   411     if (argCount() > 0) {
       
   412         Value a = arg(0)->evaluate();
       
   413         if (!a.isNodeSet())
       
   414             return "";
       
   415 
       
   416         Node* node = a.toNodeSet().firstNode();
       
   417         return node ? expandedName(node) : "";
       
   418     }
       
   419 
       
   420     return expandedName(evaluationContext().node.get());
       
   421 }
       
   422 
       
   423 Value FunCount::evaluate() const
       
   424 {
       
   425     Value a = arg(0)->evaluate();
       
   426     
       
   427     return double(a.toNodeSet().size());
       
   428 }
       
   429 
       
   430 Value FunString::evaluate() const
       
   431 {
       
   432     if (!argCount())
       
   433         return Value(Expression::evaluationContext().node.get()).toString();
       
   434     return arg(0)->evaluate().toString();
       
   435 }
       
   436 
       
   437 Value FunConcat::evaluate() const
       
   438 {
       
   439     Vector<UChar, 1024> result;
       
   440 
       
   441     unsigned count = argCount();
       
   442     for (unsigned i = 0; i < count; ++i) {
       
   443         String str(arg(i)->evaluate().toString());
       
   444         result.append(str.characters(), str.length());
       
   445     }
       
   446 
       
   447     return String(result.data(), result.size());
       
   448 }
       
   449 
       
   450 Value FunStartsWith::evaluate() const
       
   451 {
       
   452     String s1 = arg(0)->evaluate().toString();
       
   453     String s2 = arg(1)->evaluate().toString();
       
   454 
       
   455     if (s2.isEmpty())
       
   456         return (unsigned long)true;
       
   457 
       
   458     return (unsigned long)(s1.startsWith(s2));
       
   459 }
       
   460 
       
   461 Value FunContains::evaluate() const
       
   462 {
       
   463     String s1 = arg(0)->evaluate().toString();
       
   464     String s2 = arg(1)->evaluate().toString();
       
   465 
       
   466     if (s2.isEmpty()) 
       
   467         return (unsigned long)true;
       
   468 
       
   469     return (unsigned long)(s1.contains(s2) != 0);
       
   470 }
       
   471 
       
   472 Value FunSubstringBefore::evaluate() const
       
   473 {
       
   474     String s1 = arg(0)->evaluate().toString();
       
   475     String s2 = arg(1)->evaluate().toString();
       
   476 
       
   477     if (s2.isEmpty())
       
   478         return "";
       
   479 
       
   480     int i = s1.find(s2);
       
   481 
       
   482     if (i == -1)
       
   483         return "";
       
   484 
       
   485     return s1.left(i);
       
   486 }
       
   487 
       
   488 Value FunSubstringAfter::evaluate() const
       
   489 {
       
   490     String s1 = arg(0)->evaluate().toString();
       
   491     String s2 = arg(1)->evaluate().toString();
       
   492 
       
   493     int i = s1.find(s2);
       
   494     if (i == -1)
       
   495         return "";
       
   496 
       
   497     return s1.substring(i + s2.length());
       
   498 }
       
   499 
       
   500 Value FunSubstring::evaluate() const
       
   501 {
       
   502     String s = arg(0)->evaluate().toString();
       
   503     double doublePos = arg(1)->evaluate().toNumber();
       
   504     if (isnan(doublePos))
       
   505         return "";
       
   506     long pos = static_cast<long>(FunRound::round(doublePos));
       
   507     bool haveLength = argCount() == 3;
       
   508     long len = -1;
       
   509     if (haveLength) {
       
   510         double doubleLen = arg(2)->evaluate().toNumber();
       
   511         if (isnan(doubleLen))
       
   512             return "";
       
   513         len = static_cast<long>(FunRound::round(doubleLen));
       
   514     }
       
   515 
       
   516     if (pos > long(s.length())) 
       
   517         return "";
       
   518 
       
   519     if (pos < 1) {
       
   520         if (haveLength) {
       
   521             len -= 1 - pos;
       
   522             if (len < 1)
       
   523                 return "";
       
   524         }
       
   525         pos = 1;
       
   526     }
       
   527 
       
   528     return s.substring(pos - 1, len);
       
   529 }
       
   530 
       
   531 Value FunStringLength::evaluate() const
       
   532 {
       
   533     if (!argCount())
       
   534         return Value(Expression::evaluationContext().node.get()).toString().length();
       
   535     return arg(0)->evaluate().toString().length();
       
   536 }
       
   537 
       
   538 Value FunNormalizeSpace::evaluate() const
       
   539 {
       
   540     if (!argCount()) {
       
   541         String s = Value(Expression::evaluationContext().node.get()).toString();
       
   542         return s.simplifyWhiteSpace();
       
   543     }
       
   544 
       
   545     String s = arg(0)->evaluate().toString();
       
   546     return s.simplifyWhiteSpace();
       
   547 }
       
   548 
       
   549 Value FunTranslate::evaluate() const
       
   550 {
       
   551     String s1 = arg(0)->evaluate().toString();
       
   552     String s2 = arg(1)->evaluate().toString();
       
   553     String s3 = arg(2)->evaluate().toString();
       
   554     String newString;
       
   555 
       
   556     // FIXME: Building a String a character at a time is quite slow.
       
   557     for (unsigned i1 = 0; i1 < s1.length(); ++i1) {
       
   558         UChar ch = s1[i1];
       
   559         int i2 = s2.find(ch);
       
   560         
       
   561         if (i2 == -1)
       
   562             newString += String(&ch, 1);
       
   563         else if ((unsigned)i2 < s3.length()) {
       
   564             UChar c2 = s3[i2];
       
   565             newString += String(&c2, 1);
       
   566         }
       
   567     }
       
   568 
       
   569     return newString;
       
   570 }
       
   571 
       
   572 Value FunBoolean::evaluate() const
       
   573 {
       
   574     return (unsigned long)(arg(0)->evaluate().toBoolean());
       
   575 }
       
   576 
       
   577 Value FunNot::evaluate() const
       
   578 {
       
   579     return (unsigned long)(!arg(0)->evaluate().toBoolean());
       
   580 }
       
   581 
       
   582 Value FunTrue::evaluate() const
       
   583 {
       
   584     return (unsigned long)true;
       
   585 }
       
   586 
       
   587 Value FunLang::evaluate() const
       
   588 {
       
   589     String lang = arg(0)->evaluate().toString();
       
   590 
       
   591     Attribute* languageAttribute = 0;
       
   592     Node* node = evaluationContext().node.get();
       
   593     while (node) {
       
   594         NamedNodeMap* attrs = node->attributes();
       
   595         if (attrs)
       
   596             languageAttribute = attrs->getAttributeItem(XMLNames::langAttr);
       
   597         if (languageAttribute)
       
   598             break;
       
   599         node = node->parentNode();
       
   600     }
       
   601 
       
   602     if (!languageAttribute)
       
   603         return (unsigned long)false;
       
   604 
       
   605     String langValue = languageAttribute->value();
       
   606     while (true) {
       
   607         if (equalIgnoringCase(langValue, lang))
       
   608             return (unsigned long)true;
       
   609 
       
   610         // Remove suffixes one by one.
       
   611         int index = langValue.reverseFind('-');
       
   612         if (index == -1)
       
   613             break;
       
   614         langValue = langValue.left(index);
       
   615     }
       
   616 
       
   617     return (unsigned long)false;
       
   618 }
       
   619 
       
   620 Value FunFalse::evaluate() const
       
   621 {
       
   622     return (unsigned long)false;
       
   623 }
       
   624 
       
   625 Value FunNumber::evaluate() const
       
   626 {
       
   627     if (!argCount())
       
   628         return Value(Expression::evaluationContext().node.get()).toNumber();
       
   629     return arg(0)->evaluate().toNumber();
       
   630 }
       
   631 
       
   632 Value FunSum::evaluate() const
       
   633 {
       
   634     Value a = arg(0)->evaluate();
       
   635     if (!a.isNodeSet())
       
   636         return 0.0;
       
   637 
       
   638     double sum = 0.0;
       
   639     const NodeSet& nodes = a.toNodeSet();
       
   640     // To be really compliant, we should sort the node-set, as floating point addition is not associative.
       
   641     // However, this is unlikely to ever become a practical issue, and sorting is slow.
       
   642 
       
   643     for (unsigned i = 0; i < nodes.size(); i++)
       
   644         sum += Value(stringValue(nodes[i])).toNumber();
       
   645     
       
   646     return sum;
       
   647 }
       
   648 
       
   649 Value FunFloor::evaluate() const
       
   650 {
       
   651     return floor(arg(0)->evaluate().toNumber());
       
   652 }
       
   653 
       
   654 Value FunCeiling::evaluate() const
       
   655 {
       
   656     return ceil(arg(0)->evaluate().toNumber());
       
   657 }
       
   658 
       
   659 double FunRound::round(double val)
       
   660 {
       
   661     if (!isnan(val) && !isinf(val)) {
       
   662         if (signbit(val) && val >= -0.5)
       
   663             val *= 0; // negative zero
       
   664         else
       
   665             val = floor(val + 0.5);
       
   666     }
       
   667     return val;
       
   668 }
       
   669 
       
   670 Value FunRound::evaluate() const
       
   671 {
       
   672     return round(arg(0)->evaluate().toNumber());
       
   673 }
       
   674 
       
   675 struct FunctionMapping {
       
   676     const char* name;
       
   677     FunctionRec function;
       
   678 };
       
   679 
       
   680 static void createFunctionMap()
       
   681 {
       
   682     static const FunctionMapping functions[] = {
       
   683         { "boolean", { &createFunBoolean, 1 } },
       
   684         { "ceiling", { &createFunCeiling, 1 } },
       
   685         { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
       
   686         { "contains", { &createFunContains, 2 } },
       
   687         { "count", { &createFunCount, 1 } },
       
   688         { "false", { &createFunFalse, 0 } },
       
   689         { "floor", { &createFunFloor, 1 } },
       
   690         { "id", { &createFunId, 1 } },
       
   691         { "lang", { &createFunLang, 1 } },
       
   692         { "last", { &createFunLast, 0 } },
       
   693         { "local-name", { &createFunLocalName, Interval(0, 1) } },
       
   694         { "name", { &createFunName, Interval(0, 1) } },
       
   695         { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
       
   696         { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } },
       
   697         { "not", { &createFunNot, 1 } },
       
   698         { "number", { &createFunNumber, Interval(0, 1) } },
       
   699         { "position", { &createFunPosition, 0 } },
       
   700         { "round", { &createFunRound, 1 } },
       
   701         { "starts-with", { &createFunStartsWith, 2 } },
       
   702         { "string", { &createFunString, Interval(0, 1) } },
       
   703         { "string-length", { &createFunStringLength, Interval(0, 1) } },
       
   704         { "substring", { &createFunSubstring, Interval(2, 3) } },
       
   705         { "substring-after", { &createFunSubstringAfter, 2 } },
       
   706         { "substring-before", { &createFunSubstringBefore, 2 } },
       
   707         { "sum", { &createFunSum, 1 } },
       
   708         { "translate", { &createFunTranslate, 3 } },
       
   709         { "true", { &createFunTrue, 0 } },
       
   710     };
       
   711     const unsigned int numFunctions = sizeof(functions) / sizeof(functions[0]);
       
   712 
       
   713     functionMap = new HashMap<String, FunctionRec>;
       
   714     for (unsigned i = 0; i < numFunctions; ++i)
       
   715         functionMap->set(functions[i].name, functions[i].function);
       
   716 }
       
   717 
       
   718 Function* createFunction(const String& name, const Vector<Expression*>& args)
       
   719 {
       
   720     if (!functionMap)
       
   721         createFunctionMap();
       
   722 
       
   723     HashMap<String, FunctionRec>::iterator functionMapIter = functionMap->find(name);
       
   724     FunctionRec* functionRec = 0;
       
   725 
       
   726     if (functionMapIter == functionMap->end() || !(functionRec = &functionMapIter->second)->args.contains(args.size()))
       
   727         return 0;
       
   728 
       
   729     Function* function = functionRec->factoryFn();
       
   730     function->setArguments(args);
       
   731     function->setName(name);
       
   732     return function;
       
   733 }
       
   734 
       
   735 }
       
   736 }
       
   737 
       
   738 #endif // ENABLE(XPATH)