diff options
Diffstat (limited to 'Source/WebCore/Modules/indexeddb/IDBKeyData.cpp')
-rw-r--r-- | Source/WebCore/Modules/indexeddb/IDBKeyData.cpp | 446 |
1 files changed, 366 insertions, 80 deletions
diff --git a/Source/WebCore/Modules/indexeddb/IDBKeyData.cpp b/Source/WebCore/Modules/indexeddb/IDBKeyData.cpp index 46ca3fc0c..3d5abf383 100644 --- a/Source/WebCore/Modules/indexeddb/IDBKeyData.cpp +++ b/Source/WebCore/Modules/indexeddb/IDBKeyData.cpp @@ -29,68 +29,74 @@ #if ENABLE(INDEXED_DATABASE) #include "KeyedCoding.h" +#include <wtf/text/StringBuilder.h> namespace WebCore { IDBKeyData::IDBKeyData(const IDBKey* key) - : type(IDBKey::InvalidType) - , numberValue(0) - , isNull(false) + : m_type(KeyType::Invalid) { if (!key) { - isNull = true; + m_isNull = true; return; } - type = key->type(); - numberValue = 0; + m_type = key->type(); - switch (type) { - case IDBKey::InvalidType: + switch (m_type) { + case KeyType::Invalid: break; - case IDBKey::ArrayType: - for (auto key2 : key->array()) - arrayValue.append(IDBKeyData(key2.get())); + case KeyType::Array: { + m_value = Vector<IDBKeyData>(); + auto& array = WTF::get<Vector<IDBKeyData>>(m_value); + for (auto& key2 : key->array()) + array.append(IDBKeyData(key2.get())); break; - case IDBKey::StringType: - stringValue = key->string(); + } + case KeyType::Binary: + m_value = key->binary(); break; - case IDBKey::DateType: - numberValue = key->date(); + case KeyType::String: + m_value = key->string(); break; - case IDBKey::NumberType: - numberValue = key->number(); + case KeyType::Date: + m_value = key->date(); break; - case IDBKey::MinType: - ASSERT_NOT_REACHED(); + case KeyType::Number: + m_value = key->number(); + break; + case KeyType::Max: + case KeyType::Min: break; } } -PassRefPtr<IDBKey> IDBKeyData::maybeCreateIDBKey() const +RefPtr<IDBKey> IDBKeyData::maybeCreateIDBKey() const { - if (isNull) + if (m_isNull) return nullptr; - switch (type) { - case IDBKey::InvalidType: + switch (m_type) { + case KeyType::Invalid: return IDBKey::createInvalid(); - case IDBKey::ArrayType: - { - IDBKey::KeyArray array; - for (auto keyData : arrayValue) { - array.append(keyData.maybeCreateIDBKey()); - ASSERT(array.last()); - } - return IDBKey::createArray(array); + case KeyType::Array: { + Vector<RefPtr<IDBKey>> array; + for (auto& keyData : WTF::get<Vector<IDBKeyData>>(m_value)) { + array.append(keyData.maybeCreateIDBKey()); + ASSERT(array.last()); } - case IDBKey::StringType: - return IDBKey::createString(stringValue); - case IDBKey::DateType: - return IDBKey::createDate(numberValue); - case IDBKey::NumberType: - return IDBKey::createNumber(numberValue); - case IDBKey::MinType: + return IDBKey::createArray(array); + } + case KeyType::Binary: + return IDBKey::createBinary(WTF::get<ThreadSafeDataBuffer>(m_value)); + case KeyType::String: + return IDBKey::createString(WTF::get<String>(m_value)); + case KeyType::Date: + return IDBKey::createDate(WTF::get<double>(m_value)); + case KeyType::Number: + return IDBKey::createNumber(WTF::get<double>(m_value)); + case KeyType::Max: + case KeyType::Min: ASSERT_NOT_REACHED(); return nullptr; } @@ -99,74 +105,354 @@ PassRefPtr<IDBKey> IDBKeyData::maybeCreateIDBKey() const return nullptr; } +IDBKeyData::IDBKeyData(const IDBKeyData& that, IsolatedCopyTag) +{ + isolatedCopy(that, *this); +} + IDBKeyData IDBKeyData::isolatedCopy() const { - IDBKeyData result; - result.type = type; - result.isNull = isNull; - - switch (type) { - case IDBKey::InvalidType: - return result; - case IDBKey::ArrayType: - for (auto key : arrayValue) - result.arrayValue.append(key.isolatedCopy()); - return result; - case IDBKey::StringType: - result.stringValue = stringValue.isolatedCopy(); - return result; - case IDBKey::DateType: - case IDBKey::NumberType: - result.numberValue = numberValue; - return result; - case IDBKey::MinType: - ASSERT_NOT_REACHED(); - return result; + return { *this, IsolatedCopy }; +} + +void IDBKeyData::isolatedCopy(const IDBKeyData& source, IDBKeyData& destination) +{ + destination.m_type = source.m_type; + destination.m_isNull = source.m_isNull; + + switch (source.m_type) { + case KeyType::Invalid: + return; + case KeyType::Array: { + destination.m_value = Vector<IDBKeyData>(); + auto& destinationArray = WTF::get<Vector<IDBKeyData>>(destination.m_value); + for (auto& key : WTF::get<Vector<IDBKeyData>>(source.m_value)) + destinationArray.append(key.isolatedCopy()); + return; + } + case KeyType::Binary: + destination.m_value = WTF::get<ThreadSafeDataBuffer>(source.m_value); + return; + case KeyType::String: + destination.m_value = WTF::get<String>(source.m_value).isolatedCopy(); + return; + case KeyType::Date: + case KeyType::Number: + destination.m_value = WTF::get<double>(source.m_value); + return; + case KeyType::Max: + case KeyType::Min: + return; } ASSERT_NOT_REACHED(); - return result; } void IDBKeyData::encode(KeyedEncoder& encoder) const { - encoder.encodeBool("null", isNull); - if (isNull) + encoder.encodeBool("null", m_isNull); + if (m_isNull) return; - encoder.encodeEnum("type", type); + encoder.encodeEnum("type", m_type); - switch (type) { - case IDBKey::InvalidType: + switch (m_type) { + case KeyType::Invalid: return; - case IDBKey::ArrayType: - encoder.encodeObjects("array", arrayValue.begin(), arrayValue.end(), [](KeyedEncoder& encoder, const IDBKeyData& key) { - encoder.encodeObject("idbKeyData", key, [](KeyedEncoder& encoder, const IDBKeyData& key) { - key.encode(encoder); - }); + case KeyType::Array: { + auto& array = WTF::get<Vector<IDBKeyData>>(m_value); + encoder.encodeObjects("array", array.begin(), array.end(), [](KeyedEncoder& encoder, const IDBKeyData& key) { + key.encode(encoder); }); return; - case IDBKey::StringType: - encoder.encodeString("string", stringValue); + } + case KeyType::Binary: { + auto* data = WTF::get<ThreadSafeDataBuffer>(m_value).data(); + encoder.encodeBool("hasBinary", !!data); + if (data) + encoder.encodeBytes("binary", data->data(), data->size()); + return; + } + case KeyType::String: + encoder.encodeString("string", WTF::get<String>(m_value)); return; - case IDBKey::DateType: - case IDBKey::NumberType: - encoder.encodeDouble("number", numberValue); + case KeyType::Date: + case KeyType::Number: + encoder.encodeDouble("number", WTF::get<double>(m_value)); return; - case IDBKey::MinType: - ASSERT_NOT_REACHED(); + case KeyType::Max: + case KeyType::Min: return; } ASSERT_NOT_REACHED(); } -bool IDBKeyData::decode(KeyedDecoder&, IDBKeyData&) +bool IDBKeyData::decode(KeyedDecoder& decoder, IDBKeyData& result) +{ + if (!decoder.decodeBool("null", result.m_isNull)) + return false; + + if (result.m_isNull) + return true; + + auto enumFunction = [](int64_t value) { + return value == KeyType::Max + || value == KeyType::Invalid + || value == KeyType::Array + || value == KeyType::Binary + || value == KeyType::String + || value == KeyType::Date + || value == KeyType::Number + || value == KeyType::Min; + }; + if (!decoder.decodeEnum("type", result.m_type, enumFunction)) + return false; + + if (result.m_type == KeyType::Invalid) + return true; + + if (result.m_type == KeyType::Max) + return true; + + if (result.m_type == KeyType::Min) + return true; + + if (result.m_type == KeyType::String) { + result.m_value = String(); + return decoder.decodeString("string", WTF::get<String>(result.m_value)); + } + + if (result.m_type == KeyType::Number || result.m_type == KeyType::Date) { + result.m_value = 0.0; + return decoder.decodeDouble("number", WTF::get<double>(result.m_value)); + } + + if (result.m_type == KeyType::Binary) { + result.m_value = ThreadSafeDataBuffer(); + + bool hasBinaryData; + if (!decoder.decodeBool("hasBinary", hasBinaryData)) + return false; + + if (!hasBinaryData) + return true; + + Vector<uint8_t> bytes; + if (!decoder.decodeBytes("binary", bytes)) + return false; + + result.m_value = ThreadSafeDataBuffer::adoptVector(bytes); + return true; + } + + ASSERT(result.m_type == KeyType::Array); + + auto arrayFunction = [](KeyedDecoder& decoder, IDBKeyData& result) { + return decode(decoder, result); + }; + + result.m_value = Vector<IDBKeyData>(); + return decoder.decodeObjects("array", WTF::get<Vector<IDBKeyData>>(result.m_value), arrayFunction); +} + +int IDBKeyData::compare(const IDBKeyData& other) const +{ + if (m_type == KeyType::Invalid) { + if (other.m_type != KeyType::Invalid) + return -1; + if (other.m_type == KeyType::Invalid) + return 0; + } else if (other.m_type == KeyType::Invalid) + return 1; + + // The IDBKey::m_type enum is in reverse sort order. + if (m_type != other.m_type) + return m_type < other.m_type ? 1 : -1; + + // The types are the same, so handle actual value comparison. + switch (m_type) { + case KeyType::Invalid: + // Invalid type should have been fully handled above + ASSERT_NOT_REACHED(); + return 0; + case KeyType::Array: { + auto& array = WTF::get<Vector<IDBKeyData>>(m_value); + auto& otherArray = WTF::get<Vector<IDBKeyData>>(other.m_value); + for (size_t i = 0; i < array.size() && i < otherArray.size(); ++i) { + if (int result = array[i].compare(otherArray[i])) + return result; + } + if (array.size() < otherArray.size()) + return -1; + if (array.size() > otherArray.size()) + return 1; + return 0; + } + case KeyType::Binary: + return compareBinaryKeyData(WTF::get<ThreadSafeDataBuffer>(m_value), WTF::get<ThreadSafeDataBuffer>(other.m_value)); + case KeyType::String: + return codePointCompare(WTF::get<String>(m_value), WTF::get<String>(other.m_value)); + case KeyType::Date: + case KeyType::Number: { + auto number = WTF::get<double>(m_value); + auto otherNumber = WTF::get<double>(other.m_value); + + if (number == otherNumber) + return 0; + return number > otherNumber ? 1 : -1; + } + case KeyType::Max: + case KeyType::Min: + return 0; + } + + ASSERT_NOT_REACHED(); + return 0; +} + +#if !LOG_DISABLED +String IDBKeyData::loggingString() const { - // FIXME: Implement when IDB Get support is implemented (<rdar://problem/15779644>) - return false; + if (m_isNull) + return "<null>"; + + String result; + + switch (m_type) { + case KeyType::Invalid: + return "<invalid>"; + case KeyType::Array: { + StringBuilder builder; + builder.appendLiteral("<array> - { "); + auto& array = WTF::get<Vector<IDBKeyData>>(m_value); + for (size_t i = 0; i < array.size(); ++i) { + builder.append(array[i].loggingString()); + if (i < array.size() - 1) + builder.appendLiteral(", "); + } + builder.appendLiteral(" }"); + result = builder.toString(); + break; + } + case KeyType::Binary: { + StringBuilder builder; + builder.append("<binary> - "); + + auto* data = WTF::get<ThreadSafeDataBuffer>(m_value).data(); + if (!data) { + builder.append("(null)"); + result = builder.toString(); + break; + } + + size_t i = 0; + for (; i < 8 && i < data->size(); ++i) + builder.append(String::format("%02x", data->at(i))); + + if (data->size() > 8) + builder.append("..."); + + result = builder.toString(); + break; + } + case KeyType::String: + result = "<string> - " + WTF::get<String>(m_value); + break; + case KeyType::Date: + return String::format("<date> - %f", WTF::get<double>(m_value)); + case KeyType::Number: + return String::format("<number> - %f", WTF::get<double>(m_value)); + case KeyType::Max: + return "<maximum>"; + case KeyType::Min: + return "<minimum>"; + } + + if (result.length() > 150) { + result.truncate(147); + result.append(WTF::ASCIILiteral("...")); + } + + return result; } +#endif +void IDBKeyData::setArrayValue(const Vector<IDBKeyData>& value) +{ + *this = IDBKeyData(); + m_value = value; + m_type = KeyType::Array; + m_isNull = false; } +void IDBKeyData::setBinaryValue(const ThreadSafeDataBuffer& value) +{ + *this = IDBKeyData(); + m_value = value; + m_type = KeyType::Binary; + m_isNull = false; +} + +void IDBKeyData::setStringValue(const String& value) +{ + *this = IDBKeyData(); + m_value = value; + m_type = KeyType::String; + m_isNull = false; +} + +void IDBKeyData::setDateValue(double value) +{ + *this = IDBKeyData(); + m_value = value; + m_type = KeyType::Date; + m_isNull = false; +} + +void IDBKeyData::setNumberValue(double value) +{ + *this = IDBKeyData(); + m_value = value; + m_type = KeyType::Number; + m_isNull = false; +} + +IDBKeyData IDBKeyData::deletedValue() +{ + IDBKeyData result; + result.m_isNull = false; + result.m_isDeletedValue = true; + return result; +} + +bool IDBKeyData::operator<(const IDBKeyData& rhs) const +{ + return compare(rhs) < 0; +} + +bool IDBKeyData::operator==(const IDBKeyData& other) const +{ + if (m_type != other.m_type || m_isNull != other.m_isNull || m_isDeletedValue != other.m_isDeletedValue) + return false; + switch (m_type) { + case KeyType::Invalid: + case KeyType::Max: + case KeyType::Min: + return true; + case KeyType::Number: + case KeyType::Date: + return WTF::get<double>(m_value) == WTF::get<double>(other.m_value); + case KeyType::String: + return WTF::get<String>(m_value) == WTF::get<String>(other.m_value); + case KeyType::Binary: + return WTF::get<ThreadSafeDataBuffer>(m_value) == WTF::get<ThreadSafeDataBuffer>(other.m_value); + case KeyType::Array: + return WTF::get<Vector<IDBKeyData>>(m_value) == WTF::get<Vector<IDBKeyData>>(other.m_value); + } + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WebCore + #endif // ENABLE(INDEXED_DATABASE) |