1 | /* |
2 | * Copyright 2005 Frerich Raabe <raabe@kde.org> |
3 | * Copyright (C) 2006, 2013 Apple Inc. All rights reserved. |
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 | #include "XPathExpressionNode.h" |
31 | #include "XPathUtil.h" |
32 | #include <limits> |
33 | #include <wtf/MathExtras.h> |
34 | #include <wtf/NeverDestroyed.h> |
35 | #include <wtf/StdLibExtras.h> |
36 | |
37 | namespace WebCore { |
38 | namespace XPath { |
39 | |
40 | const NodeSet& Value::toNodeSet() const |
41 | { |
42 | if (!isNodeSet()) |
43 | Expression::evaluationContext().hadTypeConversionError = true; |
44 | |
45 | if (!m_data) { |
46 | static NeverDestroyed<NodeSet> emptyNodeSet; |
47 | return emptyNodeSet; |
48 | } |
49 | |
50 | return m_data->nodeSet; |
51 | } |
52 | |
53 | NodeSet& Value::modifiableNodeSet() |
54 | { |
55 | if (!isNodeSet()) |
56 | Expression::evaluationContext().hadTypeConversionError = true; |
57 | |
58 | if (!m_data) |
59 | m_data = Data::create(); |
60 | |
61 | m_type = NodeSetValue; |
62 | return m_data->nodeSet; |
63 | } |
64 | |
65 | bool Value::toBoolean() const |
66 | { |
67 | switch (m_type) { |
68 | case NodeSetValue: |
69 | return !m_data->nodeSet.isEmpty(); |
70 | case BooleanValue: |
71 | return m_bool; |
72 | case NumberValue: |
73 | return m_number && !std::isnan(m_number); |
74 | case StringValue: |
75 | return !m_data->string.isEmpty(); |
76 | } |
77 | ASSERT_NOT_REACHED(); |
78 | return false; |
79 | } |
80 | |
81 | double Value::toNumber() const |
82 | { |
83 | switch (m_type) { |
84 | case NodeSetValue: |
85 | return Value(toString()).toNumber(); |
86 | case NumberValue: |
87 | return m_number; |
88 | case StringValue: { |
89 | const String& str = m_data->string.simplifyWhiteSpace(); |
90 | |
91 | // String::toDouble() supports exponential notation, which is not allowed in XPath. |
92 | unsigned len = str.length(); |
93 | for (unsigned i = 0; i < len; ++i) { |
94 | UChar c = str[i]; |
95 | if (!isASCIIDigit(c) && c != '.' && c != '-') |
96 | return std::numeric_limits<double>::quiet_NaN(); |
97 | } |
98 | |
99 | bool canConvert; |
100 | double value = str.toDouble(&canConvert); |
101 | if (canConvert) |
102 | return value; |
103 | return std::numeric_limits<double>::quiet_NaN(); |
104 | } |
105 | case BooleanValue: |
106 | return m_bool; |
107 | } |
108 | |
109 | ASSERT_NOT_REACHED(); |
110 | return 0.0; |
111 | } |
112 | |
113 | String Value::toString() const |
114 | { |
115 | switch (m_type) { |
116 | case NodeSetValue: |
117 | if (m_data->nodeSet.isEmpty()) |
118 | return emptyString(); |
119 | return stringValue(m_data->nodeSet.firstNode()); |
120 | case StringValue: |
121 | return m_data->string; |
122 | case NumberValue: |
123 | if (std::isnan(m_number)) |
124 | return "NaN"_s ; |
125 | if (m_number == 0) |
126 | return "0"_s ; |
127 | if (std::isinf(m_number)) |
128 | return std::signbit(m_number) ? "-Infinity"_s : "Infinity"_s ; |
129 | return String::numberToStringFixedPrecision(m_number); |
130 | case BooleanValue: |
131 | return m_bool ? "true"_s : "false"_s ; |
132 | } |
133 | |
134 | ASSERT_NOT_REACHED(); |
135 | return String(); |
136 | } |
137 | |
138 | } |
139 | } |
140 | |