1/*
2 * Copyright (C) 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(INDEXED_DATABASE)
29
30#include "IDBKey.h"
31#include <wtf/StdSet.h>
32#include <wtf/Variant.h>
33#include <wtf/text/StringHash.h>
34
35namespace WebCore {
36
37class KeyedDecoder;
38class KeyedEncoder;
39
40class IDBKeyData {
41 WTF_MAKE_FAST_ALLOCATED;
42public:
43 IDBKeyData()
44 : m_type(IndexedDB::KeyType::Invalid)
45 , m_isNull(true)
46 {
47 }
48
49 WEBCORE_EXPORT IDBKeyData(const IDBKey*);
50
51 enum IsolatedCopyTag { IsolatedCopy };
52 IDBKeyData(const IDBKeyData&, IsolatedCopyTag);
53
54 static IDBKeyData minimum()
55 {
56 IDBKeyData result;
57 result.m_type = IndexedDB::KeyType::Min;
58 result.m_isNull = false;
59 return result;
60 }
61
62 static IDBKeyData maximum()
63 {
64 IDBKeyData result;
65 result.m_type = IndexedDB::KeyType::Max;
66 result.m_isNull = false;
67 return result;
68 }
69
70 WEBCORE_EXPORT RefPtr<IDBKey> maybeCreateIDBKey() const;
71
72 IDBKeyData isolatedCopy() const;
73
74 WEBCORE_EXPORT void encode(KeyedEncoder&) const;
75 WEBCORE_EXPORT static bool decode(KeyedDecoder&, IDBKeyData&);
76
77 // compare() has the same semantics as strcmp().
78 // - Returns negative if this IDBKeyData is less than other.
79 // - Returns positive if this IDBKeyData is greater than other.
80 // - Returns zero if this IDBKeyData is equal to other.
81 WEBCORE_EXPORT int compare(const IDBKeyData& other) const;
82
83 void setArrayValue(const Vector<IDBKeyData>&);
84 void setBinaryValue(const ThreadSafeDataBuffer&);
85 void setStringValue(const String&);
86 void setDateValue(double);
87 WEBCORE_EXPORT void setNumberValue(double);
88
89 template<class Encoder> void encode(Encoder&) const;
90 template<class Decoder> static Optional<IDBKeyData> decode(Decoder&);
91
92#if !LOG_DISABLED
93 WEBCORE_EXPORT String loggingString() const;
94#endif
95
96 bool isNull() const { return m_isNull; }
97 bool isValid() const;
98 IndexedDB::KeyType type() const { return m_type; }
99
100 bool operator<(const IDBKeyData&) const;
101 bool operator>(const IDBKeyData& other) const
102 {
103 return !(*this < other) && !(*this == other);
104 }
105
106 bool operator<=(const IDBKeyData& other) const
107 {
108 return !(*this > other);
109 }
110
111 bool operator>=(const IDBKeyData& other) const
112 {
113 return !(*this < other);
114 }
115
116 bool operator==(const IDBKeyData& other) const;
117 bool operator!=(const IDBKeyData& other) const
118 {
119 return !(*this == other);
120 }
121
122 unsigned hash() const
123 {
124 Vector<unsigned> hashCodes;
125 hashCodes.append(static_cast<unsigned>(m_type));
126 hashCodes.append(m_isNull ? 1 : 0);
127 hashCodes.append(m_isDeletedValue ? 1 : 0);
128 switch (m_type) {
129 case IndexedDB::KeyType::Invalid:
130 case IndexedDB::KeyType::Max:
131 case IndexedDB::KeyType::Min:
132 break;
133 case IndexedDB::KeyType::Number:
134 case IndexedDB::KeyType::Date:
135 hashCodes.append(StringHasher::hashMemory<sizeof(double)>(&WTF::get<double>(m_value)));
136 break;
137 case IndexedDB::KeyType::String:
138 hashCodes.append(StringHash::hash(WTF::get<String>(m_value)));
139 break;
140 case IndexedDB::KeyType::Binary: {
141 auto* data = WTF::get<ThreadSafeDataBuffer>(m_value).data();
142 if (!data)
143 hashCodes.append(0);
144 else
145 hashCodes.append(StringHasher::hashMemory(data->data(), data->size()));
146 break;
147 }
148 case IndexedDB::KeyType::Array:
149 for (auto& key : WTF::get<Vector<IDBKeyData>>(m_value))
150 hashCodes.append(key.hash());
151 break;
152 }
153
154 return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned));
155 }
156
157 static IDBKeyData deletedValue();
158 bool isDeletedValue() const { return m_isDeletedValue; }
159
160 String string() const
161 {
162 ASSERT(m_type == IndexedDB::KeyType::String);
163 return WTF::get<String>(m_value);
164 }
165
166 double date() const
167 {
168 ASSERT(m_type == IndexedDB::KeyType::Date);
169 return WTF::get<double>(m_value);
170 }
171
172 double number() const
173 {
174 ASSERT(m_type == IndexedDB::KeyType::Number);
175 return WTF::get<double>(m_value);
176 }
177
178 const ThreadSafeDataBuffer& binary() const
179 {
180 ASSERT(m_type == IndexedDB::KeyType::Binary);
181 return WTF::get<ThreadSafeDataBuffer>(m_value);
182 }
183
184 const Vector<IDBKeyData>& array() const
185 {
186 ASSERT(m_type == IndexedDB::KeyType::Array);
187 return WTF::get<Vector<IDBKeyData>>(m_value);
188 }
189
190private:
191 static void isolatedCopy(const IDBKeyData& source, IDBKeyData& destination);
192
193 IndexedDB::KeyType m_type;
194 Variant<Vector<IDBKeyData>, String, double, ThreadSafeDataBuffer> m_value;
195
196 bool m_isNull { false };
197 bool m_isDeletedValue { false };
198};
199
200struct IDBKeyDataHash {
201 static unsigned hash(const IDBKeyData& a) { return a.hash(); }
202 static bool equal(const IDBKeyData& a, const IDBKeyData& b) { return a == b; }
203 static const bool safeToCompareToEmptyOrDeleted = false;
204};
205
206struct IDBKeyDataHashTraits : public WTF::CustomHashTraits<IDBKeyData> {
207 static const bool emptyValueIsZero = false;
208 static const bool hasIsEmptyValueFunction = true;
209
210 static void constructDeletedValue(IDBKeyData& key)
211 {
212 new (&key) IDBKeyData;
213 key = IDBKeyData::deletedValue();
214 }
215
216 static bool isDeletedValue(const IDBKeyData& key)
217 {
218 return key.isDeletedValue();
219 }
220
221 static IDBKeyData emptyValue()
222 {
223 return IDBKeyData();
224 }
225
226 static bool isEmptyValue(const IDBKeyData& key)
227 {
228 return key.isNull();
229 }
230};
231
232template<class Encoder>
233void IDBKeyData::encode(Encoder& encoder) const
234{
235 encoder << m_isNull;
236 if (m_isNull)
237 return;
238
239 encoder.encodeEnum(m_type);
240
241 switch (m_type) {
242 case IndexedDB::KeyType::Invalid:
243 case IndexedDB::KeyType::Max:
244 case IndexedDB::KeyType::Min:
245 break;
246 case IndexedDB::KeyType::Array:
247 encoder << WTF::get<Vector<IDBKeyData>>(m_value);
248 break;
249 case IndexedDB::KeyType::Binary:
250 encoder << WTF::get<ThreadSafeDataBuffer>(m_value);
251 break;
252 case IndexedDB::KeyType::String:
253 encoder << WTF::get<String>(m_value);
254 break;
255 case IndexedDB::KeyType::Date:
256 case IndexedDB::KeyType::Number:
257 encoder << WTF::get<double>(m_value);
258 break;
259 }
260}
261
262template<class Decoder>
263Optional<IDBKeyData> IDBKeyData::decode(Decoder& decoder)
264{
265 IDBKeyData keyData;
266 if (!decoder.decode(keyData.m_isNull))
267 return WTF::nullopt;
268
269 if (keyData.m_isNull)
270 return keyData;
271
272 if (!decoder.decodeEnum(keyData.m_type))
273 return WTF::nullopt;
274
275 switch (keyData.m_type) {
276 case IndexedDB::KeyType::Invalid:
277 case IndexedDB::KeyType::Max:
278 case IndexedDB::KeyType::Min:
279 break;
280 case IndexedDB::KeyType::Array:
281 keyData.m_value = Vector<IDBKeyData>();
282 if (!decoder.decode(WTF::get<Vector<IDBKeyData>>(keyData.m_value)))
283 return WTF::nullopt;
284 break;
285 case IndexedDB::KeyType::Binary:
286 keyData.m_value = ThreadSafeDataBuffer();
287 if (!decoder.decode(WTF::get<ThreadSafeDataBuffer>(keyData.m_value)))
288 return WTF::nullopt;
289 break;
290 case IndexedDB::KeyType::String:
291 keyData.m_value = String();
292 if (!decoder.decode(WTF::get<String>(keyData.m_value)))
293 return WTF::nullopt;
294 break;
295 case IndexedDB::KeyType::Date:
296 case IndexedDB::KeyType::Number:
297 keyData.m_value = 0.0;
298 if (!decoder.decode(WTF::get<double>(keyData.m_value)))
299 return WTF::nullopt;
300 break;
301 }
302
303 return keyData;
304}
305
306using IDBKeyDataSet = StdSet<IDBKeyData>;
307
308} // namespace WebCore
309
310#endif // ENABLE(INDEXED_DATABASE)
311