Home | History | Annotate | Download | only in xml
      1 /*
      2  * Copyright 2005 Frerich Raabe <raabe (at) kde.org>
      3  * Copyright (C) 2006 Apple Computer, Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "XPathValue.h"
     29 
     30 #if ENABLE(XPATH)
     31 
     32 #include "Node.h"
     33 #include "XPathExpressionNode.h"
     34 #include "XPathUtil.h"
     35 #include <limits>
     36 #include <wtf/MathExtras.h>
     37 #include <wtf/StdLibExtras.h>
     38 
     39 using std::numeric_limits;
     40 
     41 namespace WebCore {
     42 namespace XPath {
     43 
     44 const Value::AdoptTag Value::adopt = {};
     45 
     46 const NodeSet& Value::toNodeSet() const
     47 {
     48     if (!isNodeSet())
     49         Expression::evaluationContext().hadTypeConversionError = true;
     50 
     51     if (!m_data) {
     52         DEFINE_STATIC_LOCAL(NodeSet, emptyNodeSet, ());
     53         return emptyNodeSet;
     54     }
     55 
     56     return m_data->m_nodeSet;
     57 }
     58 
     59 NodeSet& Value::modifiableNodeSet()
     60 {
     61     if (!isNodeSet())
     62         Expression::evaluationContext().hadTypeConversionError = true;
     63 
     64     if (!m_data)
     65         m_data = ValueData::create();
     66 
     67     m_type = NodeSetValue;
     68     return m_data->m_nodeSet;
     69 }
     70 
     71 bool Value::toBoolean() const
     72 {
     73     switch (m_type) {
     74         case NodeSetValue:
     75             return !m_data->m_nodeSet.isEmpty();
     76         case BooleanValue:
     77             return m_bool;
     78         case NumberValue:
     79             return m_number != 0 && !isnan(m_number);
     80         case StringValue:
     81             return !m_data->m_string.isEmpty();
     82     }
     83     ASSERT_NOT_REACHED();
     84     return false;
     85 }
     86 
     87 double Value::toNumber() const
     88 {
     89     switch (m_type) {
     90         case NodeSetValue:
     91             return Value(toString()).toNumber();
     92         case NumberValue:
     93             return m_number;
     94         case StringValue: {
     95             const String& str = m_data->m_string.simplifyWhiteSpace();
     96 
     97             // String::toDouble() supports exponential notation, which is not allowed in XPath.
     98             unsigned len = str.length();
     99             for (unsigned i = 0; i < len; ++i) {
    100                 UChar c = str[i];
    101                 if (!isASCIIDigit(c) && c != '.'  && c != '-')
    102                     return numeric_limits<double>::quiet_NaN();
    103             }
    104 
    105             bool canConvert;
    106             double value = str.toDouble(&canConvert);
    107             if (canConvert)
    108                 return value;
    109             return numeric_limits<double>::quiet_NaN();
    110         }
    111         case BooleanValue:
    112             return m_bool;
    113     }
    114     ASSERT_NOT_REACHED();
    115     return 0.0;
    116 }
    117 
    118 String Value::toString() const
    119 {
    120     switch (m_type) {
    121         case NodeSetValue:
    122             if (m_data->m_nodeSet.isEmpty())
    123                 return "";
    124             return stringValue(m_data->m_nodeSet.firstNode());
    125         case StringValue:
    126             return m_data->m_string;
    127         case NumberValue:
    128             if (isnan(m_number))
    129                 return "NaN";
    130             if (m_number == 0)
    131                 return "0";
    132             if (isinf(m_number))
    133                 return signbit(m_number) ? "-Infinity" : "Infinity";
    134             return String::number(m_number);
    135         case BooleanValue:
    136             return m_bool ? "true" : "false";
    137     }
    138     ASSERT_NOT_REACHED();
    139     return String();
    140 }
    141 
    142 }
    143 }
    144 
    145 #endif // ENABLE(XPATH)
    146