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#include "config.h"
27#include "IDBKeyData.h"
28
29#if ENABLE(INDEXED_DATABASE)
30
31#include "KeyedCoding.h"
32#include <wtf/text/StringBuilder.h>
33#include <wtf/text/StringConcatenateNumbers.h>
34
35namespace WebCore {
36
37IDBKeyData::IDBKeyData(const IDBKey* key)
38 : m_type(IndexedDB::KeyType::Invalid)
39{
40 if (!key) {
41 m_isNull = true;
42 return;
43 }
44
45 m_type = key->type();
46
47 switch (m_type) {
48 case IndexedDB::KeyType::Invalid:
49 break;
50 case IndexedDB::KeyType::Array: {
51 m_value = Vector<IDBKeyData>();
52 auto& array = WTF::get<Vector<IDBKeyData>>(m_value);
53 for (auto& key2 : key->array())
54 array.append(IDBKeyData(key2.get()));
55 break;
56 }
57 case IndexedDB::KeyType::Binary:
58 m_value = key->binary();
59 break;
60 case IndexedDB::KeyType::String:
61 m_value = key->string();
62 break;
63 case IndexedDB::KeyType::Date:
64 m_value = key->date();
65 break;
66 case IndexedDB::KeyType::Number:
67 m_value = key->number();
68 break;
69 case IndexedDB::KeyType::Max:
70 case IndexedDB::KeyType::Min:
71 break;
72 }
73}
74
75RefPtr<IDBKey> IDBKeyData::maybeCreateIDBKey() const
76{
77 if (m_isNull)
78 return nullptr;
79
80 switch (m_type) {
81 case IndexedDB::KeyType::Invalid:
82 return IDBKey::createInvalid();
83 case IndexedDB::KeyType::Array: {
84 Vector<RefPtr<IDBKey>> array;
85 for (auto& keyData : WTF::get<Vector<IDBKeyData>>(m_value)) {
86 array.append(keyData.maybeCreateIDBKey());
87 ASSERT(array.last());
88 }
89 return IDBKey::createArray(array);
90 }
91 case IndexedDB::KeyType::Binary:
92 return IDBKey::createBinary(WTF::get<ThreadSafeDataBuffer>(m_value));
93 case IndexedDB::KeyType::String:
94 return IDBKey::createString(WTF::get<String>(m_value));
95 case IndexedDB::KeyType::Date:
96 return IDBKey::createDate(WTF::get<double>(m_value));
97 case IndexedDB::KeyType::Number:
98 return IDBKey::createNumber(WTF::get<double>(m_value));
99 case IndexedDB::KeyType::Max:
100 case IndexedDB::KeyType::Min:
101 ASSERT_NOT_REACHED();
102 return nullptr;
103 }
104
105 ASSERT_NOT_REACHED();
106 return nullptr;
107}
108
109IDBKeyData::IDBKeyData(const IDBKeyData& that, IsolatedCopyTag)
110{
111 isolatedCopy(that, *this);
112}
113
114IDBKeyData IDBKeyData::isolatedCopy() const
115{
116 return { *this, IsolatedCopy };
117}
118
119void IDBKeyData::isolatedCopy(const IDBKeyData& source, IDBKeyData& destination)
120{
121 destination.m_type = source.m_type;
122 destination.m_isNull = source.m_isNull;
123
124 switch (source.m_type) {
125 case IndexedDB::KeyType::Invalid:
126 return;
127 case IndexedDB::KeyType::Array: {
128 destination.m_value = Vector<IDBKeyData>();
129 auto& destinationArray = WTF::get<Vector<IDBKeyData>>(destination.m_value);
130 for (auto& key : WTF::get<Vector<IDBKeyData>>(source.m_value))
131 destinationArray.append(key.isolatedCopy());
132 return;
133 }
134 case IndexedDB::KeyType::Binary:
135 destination.m_value = WTF::get<ThreadSafeDataBuffer>(source.m_value);
136 return;
137 case IndexedDB::KeyType::String:
138 destination.m_value = WTF::get<String>(source.m_value).isolatedCopy();
139 return;
140 case IndexedDB::KeyType::Date:
141 case IndexedDB::KeyType::Number:
142 destination.m_value = WTF::get<double>(source.m_value);
143 return;
144 case IndexedDB::KeyType::Max:
145 case IndexedDB::KeyType::Min:
146 return;
147 }
148
149 ASSERT_NOT_REACHED();
150}
151
152void IDBKeyData::encode(KeyedEncoder& encoder) const
153{
154 encoder.encodeBool("null", m_isNull);
155 if (m_isNull)
156 return;
157
158 encoder.encodeEnum("type", m_type);
159
160 switch (m_type) {
161 case IndexedDB::KeyType::Invalid:
162 return;
163 case IndexedDB::KeyType::Array: {
164 auto& array = WTF::get<Vector<IDBKeyData>>(m_value);
165 encoder.encodeObjects("array", array.begin(), array.end(), [](KeyedEncoder& encoder, const IDBKeyData& key) {
166 key.encode(encoder);
167 });
168 return;
169 }
170 case IndexedDB::KeyType::Binary: {
171 auto* data = WTF::get<ThreadSafeDataBuffer>(m_value).data();
172 encoder.encodeBool("hasBinary", !!data);
173 if (data)
174 encoder.encodeBytes("binary", data->data(), data->size());
175 return;
176 }
177 case IndexedDB::KeyType::String:
178 encoder.encodeString("string", WTF::get<String>(m_value));
179 return;
180 case IndexedDB::KeyType::Date:
181 case IndexedDB::KeyType::Number:
182 encoder.encodeDouble("number", WTF::get<double>(m_value));
183 return;
184 case IndexedDB::KeyType::Max:
185 case IndexedDB::KeyType::Min:
186 return;
187 }
188
189 ASSERT_NOT_REACHED();
190}
191
192bool IDBKeyData::decode(KeyedDecoder& decoder, IDBKeyData& result)
193{
194 if (!decoder.decodeBool("null", result.m_isNull))
195 return false;
196
197 if (result.m_isNull)
198 return true;
199
200 auto enumFunction = [](int64_t value) {
201 return value == IndexedDB::KeyType::Max
202 || value == IndexedDB::KeyType::Invalid
203 || value == IndexedDB::KeyType::Array
204 || value == IndexedDB::KeyType::Binary
205 || value == IndexedDB::KeyType::String
206 || value == IndexedDB::KeyType::Date
207 || value == IndexedDB::KeyType::Number
208 || value == IndexedDB::KeyType::Min;
209 };
210 if (!decoder.decodeEnum("type", result.m_type, enumFunction))
211 return false;
212
213 if (result.m_type == IndexedDB::KeyType::Invalid)
214 return true;
215
216 if (result.m_type == IndexedDB::KeyType::Max)
217 return true;
218
219 if (result.m_type == IndexedDB::KeyType::Min)
220 return true;
221
222 if (result.m_type == IndexedDB::KeyType::String) {
223 result.m_value = String();
224 return decoder.decodeString("string", WTF::get<String>(result.m_value));
225 }
226
227 if (result.m_type == IndexedDB::KeyType::Number || result.m_type == IndexedDB::KeyType::Date) {
228 result.m_value = 0.0;
229 return decoder.decodeDouble("number", WTF::get<double>(result.m_value));
230 }
231
232 if (result.m_type == IndexedDB::KeyType::Binary) {
233 result.m_value = ThreadSafeDataBuffer();
234
235 bool hasBinaryData;
236 if (!decoder.decodeBool("hasBinary", hasBinaryData))
237 return false;
238
239 if (!hasBinaryData)
240 return true;
241
242 Vector<uint8_t> bytes;
243 if (!decoder.decodeBytes("binary", bytes))
244 return false;
245
246 result.m_value = ThreadSafeDataBuffer::create(WTFMove(bytes));
247 return true;
248 }
249
250 ASSERT(result.m_type == IndexedDB::KeyType::Array);
251
252 auto arrayFunction = [](KeyedDecoder& decoder, IDBKeyData& result) {
253 return decode(decoder, result);
254 };
255
256 result.m_value = Vector<IDBKeyData>();
257 return decoder.decodeObjects("array", WTF::get<Vector<IDBKeyData>>(result.m_value), arrayFunction);
258}
259
260int IDBKeyData::compare(const IDBKeyData& other) const
261{
262 if (m_type == IndexedDB::KeyType::Invalid) {
263 if (other.m_type != IndexedDB::KeyType::Invalid)
264 return -1;
265 if (other.m_type == IndexedDB::KeyType::Invalid)
266 return 0;
267 } else if (other.m_type == IndexedDB::KeyType::Invalid)
268 return 1;
269
270 // The IDBKey::m_type enum is in reverse sort order.
271 if (m_type != other.m_type)
272 return m_type < other.m_type ? 1 : -1;
273
274 // The types are the same, so handle actual value comparison.
275 switch (m_type) {
276 case IndexedDB::KeyType::Invalid:
277 // Invalid type should have been fully handled above
278 ASSERT_NOT_REACHED();
279 return 0;
280 case IndexedDB::KeyType::Array: {
281 auto& array = WTF::get<Vector<IDBKeyData>>(m_value);
282 auto& otherArray = WTF::get<Vector<IDBKeyData>>(other.m_value);
283 for (size_t i = 0; i < array.size() && i < otherArray.size(); ++i) {
284 if (int result = array[i].compare(otherArray[i]))
285 return result;
286 }
287 if (array.size() < otherArray.size())
288 return -1;
289 if (array.size() > otherArray.size())
290 return 1;
291 return 0;
292 }
293 case IndexedDB::KeyType::Binary:
294 return compareBinaryKeyData(WTF::get<ThreadSafeDataBuffer>(m_value), WTF::get<ThreadSafeDataBuffer>(other.m_value));
295 case IndexedDB::KeyType::String:
296 return codePointCompare(WTF::get<String>(m_value), WTF::get<String>(other.m_value));
297 case IndexedDB::KeyType::Date:
298 case IndexedDB::KeyType::Number: {
299 auto number = WTF::get<double>(m_value);
300 auto otherNumber = WTF::get<double>(other.m_value);
301
302 if (number == otherNumber)
303 return 0;
304 return number > otherNumber ? 1 : -1;
305 }
306 case IndexedDB::KeyType::Max:
307 case IndexedDB::KeyType::Min:
308 return 0;
309 }
310
311 ASSERT_NOT_REACHED();
312 return 0;
313}
314
315#if !LOG_DISABLED
316String IDBKeyData::loggingString() const
317{
318 if (m_isNull)
319 return "<null>"_s;
320
321 String result;
322
323 switch (m_type) {
324 case IndexedDB::KeyType::Invalid:
325 return "<invalid>"_s;
326 case IndexedDB::KeyType::Array: {
327 StringBuilder builder;
328 builder.appendLiteral("<array> - { ");
329 auto& array = WTF::get<Vector<IDBKeyData>>(m_value);
330 for (size_t i = 0; i < array.size(); ++i) {
331 builder.append(array[i].loggingString());
332 if (i < array.size() - 1)
333 builder.appendLiteral(", ");
334 }
335 builder.appendLiteral(" }");
336 result = builder.toString();
337 break;
338 }
339 case IndexedDB::KeyType::Binary: {
340 StringBuilder builder;
341 builder.appendLiteral("<binary> - ");
342
343 auto* data = WTF::get<ThreadSafeDataBuffer>(m_value).data();
344 if (!data) {
345 builder.appendLiteral("(null)");
346 result = builder.toString();
347 break;
348 }
349
350 size_t i = 0;
351 for (; i < 8 && i < data->size(); ++i) {
352 uint8_t byte = data->at(i);
353 builder.append(upperNibbleToLowercaseASCIIHexDigit(byte));
354 builder.append(lowerNibbleToLowercaseASCIIHexDigit(byte));
355 }
356
357 if (data->size() > 8)
358 builder.appendLiteral("...");
359
360 result = builder.toString();
361 break;
362 }
363 case IndexedDB::KeyType::String:
364 result = "<string> - " + WTF::get<String>(m_value);
365 break;
366 case IndexedDB::KeyType::Date:
367 return makeString("<date> - ", WTF::get<double>(m_value));
368 case IndexedDB::KeyType::Number:
369 return makeString("<number> - ", WTF::get<double>(m_value));
370 case IndexedDB::KeyType::Max:
371 return "<maximum>"_s;
372 case IndexedDB::KeyType::Min:
373 return "<minimum>"_s;
374 }
375
376 if (result.length() > 150) {
377 result.truncate(147);
378 result.append("..."_s);
379 }
380
381 return result;
382}
383#endif
384
385void IDBKeyData::setArrayValue(const Vector<IDBKeyData>& value)
386{
387 *this = IDBKeyData();
388 m_value = value;
389 m_type = IndexedDB::KeyType::Array;
390 m_isNull = false;
391}
392
393void IDBKeyData::setBinaryValue(const ThreadSafeDataBuffer& value)
394{
395 *this = IDBKeyData();
396 m_value = value;
397 m_type = IndexedDB::KeyType::Binary;
398 m_isNull = false;
399}
400
401void IDBKeyData::setStringValue(const String& value)
402{
403 *this = IDBKeyData();
404 m_value = value;
405 m_type = IndexedDB::KeyType::String;
406 m_isNull = false;
407}
408
409void IDBKeyData::setDateValue(double value)
410{
411 *this = IDBKeyData();
412 m_value = value;
413 m_type = IndexedDB::KeyType::Date;
414 m_isNull = false;
415}
416
417void IDBKeyData::setNumberValue(double value)
418{
419 *this = IDBKeyData();
420 m_value = value;
421 m_type = IndexedDB::KeyType::Number;
422 m_isNull = false;
423}
424
425IDBKeyData IDBKeyData::deletedValue()
426{
427 IDBKeyData result;
428 result.m_isNull = false;
429 result.m_isDeletedValue = true;
430 return result;
431}
432
433bool IDBKeyData::isValid() const
434{
435 if (m_type == IndexedDB::KeyType::Invalid)
436 return false;
437
438 if (m_type == IndexedDB::KeyType::Array) {
439 for (auto& key : array()) {
440 if (!key.isValid())
441 return false;
442 }
443 }
444
445 return true;
446}
447
448bool IDBKeyData::operator<(const IDBKeyData& rhs) const
449{
450 return compare(rhs) < 0;
451}
452
453bool IDBKeyData::operator==(const IDBKeyData& other) const
454{
455 if (m_type != other.m_type || m_isNull != other.m_isNull || m_isDeletedValue != other.m_isDeletedValue)
456 return false;
457 switch (m_type) {
458 case IndexedDB::KeyType::Invalid:
459 case IndexedDB::KeyType::Max:
460 case IndexedDB::KeyType::Min:
461 return true;
462 case IndexedDB::KeyType::Number:
463 case IndexedDB::KeyType::Date:
464 return WTF::get<double>(m_value) == WTF::get<double>(other.m_value);
465 case IndexedDB::KeyType::String:
466 return WTF::get<String>(m_value) == WTF::get<String>(other.m_value);
467 case IndexedDB::KeyType::Binary:
468 return WTF::get<ThreadSafeDataBuffer>(m_value) == WTF::get<ThreadSafeDataBuffer>(other.m_value);
469 case IndexedDB::KeyType::Array:
470 return WTF::get<Vector<IDBKeyData>>(m_value) == WTF::get<Vector<IDBKeyData>>(other.m_value);
471 }
472 RELEASE_ASSERT_NOT_REACHED();
473}
474
475} // namespace WebCore
476
477#endif // ENABLE(INDEXED_DATABASE)
478