IDBLevelDBCoding.cpp [plain text]
#include "config.h"
#include "IDBLevelDBCoding.h"
#if ENABLE(INDEXED_DATABASE)
#if ENABLE(LEVELDB)
#include "IDBKey.h"
#include "LevelDBSlice.h"
namespace WebCore {
namespace IDBLevelDBCoding {
static const unsigned char kIDBKeyNullTypeByte = 0;
static const unsigned char kIDBKeyStringTypeByte = 1;
static const unsigned char kIDBKeyDateTypeByte = 2;
static const unsigned char kIDBKeyNumberTypeByte = 3;
static const unsigned char kIDBKeyMinKeyTypeByte = 4;
static const unsigned char kObjectStoreDataIndexId = 1;
static const unsigned char kExistsEntryIndexId = 2;
static const unsigned char kSchemaVersionTypeByte = 0;
static const unsigned char kMaxDatabaseIdTypeByte = 1;
static const unsigned char kDatabaseFreeListTypeByte = 100;
static const unsigned char kDatabaseNameTypeByte = 201;
static const unsigned char kObjectStoreMetaDataTypeByte = 50;
static const unsigned char kIndexMetaDataTypeByte = 100;
static const unsigned char kObjectStoreFreeListTypeByte = 150;
static const unsigned char kIndexFreeListTypeByte = 151;
static const unsigned char kObjectStoreNamesTypeByte = 200;
static const unsigned char kIndexNamesKeyTypeByte = 201;
#ifndef INT64_MAX
#define INT64_MAX 0x7fffffffffffffffLL
#endif
#ifndef INT32_MAX
#define INT32_MAX 0x7fffffffL
#endif
Vector<char> encodeByte(unsigned char c)
{
Vector<char> v;
v.append(c);
return v;
}
Vector<char> maxIDBKey()
{
return encodeByte(kIDBKeyNullTypeByte);
}
Vector<char> minIDBKey()
{
return encodeByte(kIDBKeyMinKeyTypeByte);
}
Vector<char> encodeInt(int64_t n)
{
ASSERT(n >= 0);
Vector<char> ret;
do {
unsigned char c = n;
ret.append(c);
n >>= 8;
} while (n);
return ret;
}
int64_t decodeInt(const char* begin, const char* end)
{
ASSERT(begin <= end);
int64_t ret = 0;
int shift = 0;
while (begin < end) {
unsigned char c = *begin++;
ret |= static_cast<int64_t>(c) << shift;
shift += 8;
}
return ret;
}
static int compareInts(int64_t a, int64_t b)
{
ASSERT(a >= 0);
ASSERT(b >= 0);
int64_t diff = a - b;
if (diff < 0)
return -1;
if (diff > 0)
return 1;
return 0;
}
Vector<char> encodeVarInt(int64_t n)
{
Vector<char> ret;
do {
unsigned char c = n & 0x7f;
n >>= 7;
if (n)
c |= 0x80;
ret.append(c);
} while (n);
return ret;
}
const char* decodeVarInt(const char *p, const char* limit, int64_t& foundInt)
{
ASSERT(limit >= p);
foundInt = 0;
int shift = 0;
do {
if (p >= limit)
return 0;
unsigned char c = *p;
foundInt |= static_cast<int64_t>(c & 0x7f) << shift;
shift += 7;
} while (*p++ & 0x80);
return p;
}
Vector<char> encodeString(const String& s)
{
Vector<char> ret;
for (unsigned i = 0; i < s.length(); ++i) {
UChar u = s[i];
unsigned char hi = u >> 8;
unsigned char lo = u;
ret.append(hi);
ret.append(lo);
}
return ret;
}
String decodeString(const char* p, const char* end)
{
ASSERT(end >= p);
ASSERT(!((end - p) % 2));
size_t len = (end - p) / 2;
Vector<UChar> vector(len);
for (size_t i = 0; i < len; ++i) {
unsigned char hi = *p++;
unsigned char lo = *p++;
vector[i] = (hi << 8) | lo;
}
return String::adopt(vector);
}
Vector<char> encodeStringWithLength(const String& s)
{
Vector<char> ret = encodeVarInt(s.length());
ret.append(encodeString(s));
return ret;
}
const char* decodeStringWithLength(const char* p, const char* limit, String& foundString)
{
ASSERT(limit >= p);
int64_t len;
p = decodeVarInt(p, limit, len);
if (!p)
return 0;
if (p + len * 2 > limit)
return 0;
foundString = decodeString(p, p + len * 2);
p += len * 2;
return p;
}
Vector<char> encodeDouble(double x)
{
const char* p = reinterpret_cast<char*>(&x);
Vector<char> v;
v.append(p, sizeof(x));
ASSERT(v.size() == sizeof(x));
return v;
}
const char* decodeDouble(const char* p, const char* limit, double* d)
{
if (p + sizeof(*d) > limit)
return 0;
char* x = reinterpret_cast<char*>(d);
for (size_t i = 0; i < sizeof(*d); ++i)
*x++ = *p++;
return p;
}
Vector<char> encodeIDBKey(const IDBKey& key)
{
Vector<char> ret;
switch (key.type()) {
case IDBKey::NullType:
return encodeByte(kIDBKeyNullTypeByte);
case IDBKey::StringType:
ret = encodeByte(kIDBKeyStringTypeByte);
ret.append(encodeStringWithLength(key.string()));
return ret;
case IDBKey::DateType:
ret = encodeByte(kIDBKeyDateTypeByte);
ret.append(encodeDouble(key.date()));
ASSERT(ret.size() == 9);
return ret;
case IDBKey::NumberType:
ret = encodeByte(kIDBKeyNumberTypeByte);
ret.append(encodeDouble(key.number()));
ASSERT(ret.size() == 9);
return ret;
}
ASSERT_NOT_REACHED();
return Vector<char>();
}
const char* decodeIDBKey(const char* p, const char* limit, RefPtr<IDBKey>& foundKey)
{
ASSERT(limit >= p);
if (p >= limit)
return 0;
unsigned char type = *p++;
String s;
double d;
switch (type) {
case kIDBKeyNullTypeByte:
foundKey = IDBKey::createNull();
return p;
case kIDBKeyStringTypeByte:
p = decodeStringWithLength(p, limit, s);
if (!p)
return 0;
foundKey = IDBKey::createString(s);
return p;
case kIDBKeyDateTypeByte:
p = decodeDouble(p, limit, &d);
if (!p)
return 0;
foundKey = IDBKey::createDate(d);
return p;
case kIDBKeyNumberTypeByte:
p = decodeDouble(p, limit, &d);
if (!p)
return 0;
foundKey = IDBKey::createNumber(d);
return p;
}
ASSERT_NOT_REACHED();
return 0;
}
const char* extractEncodedIDBKey(const char* start, const char* limit, Vector<char>* result)
{
const char* p = start;
if (p >= limit)
return 0;
unsigned char type = *p++;
int64_t stringLen;
switch (type) {
case kIDBKeyNullTypeByte:
case kIDBKeyMinKeyTypeByte:
*result = encodeByte(type);
return p;
case kIDBKeyStringTypeByte:
p = decodeVarInt(p, limit, stringLen);
if (!p)
return 0;
if (p + stringLen * 2 > limit)
return 0;
result->clear();
result->append(start, p - start + stringLen * 2);
return p + stringLen * 2;
case kIDBKeyDateTypeByte:
case kIDBKeyNumberTypeByte:
if (p + sizeof(double) > limit)
return 0;
result->clear();
result->append(start, 1 + sizeof(double));
return p + sizeof(double);
}
ASSERT_NOT_REACHED();
return 0;
}
int compareEncodedIDBKeys(const Vector<char>& keyA, const Vector<char>& keyB)
{
ASSERT(keyA.size() >= 1);
ASSERT(keyB.size() >= 1);
const char* p = keyA.data();
const char* limitA = p + keyA.size();
const char* q = keyB.data();
const char* limitB = q + keyB.size();
unsigned char typeA = *p++;
unsigned char typeB = *q++;
String s, t;
double d, e;
if (int x = typeB - typeA) return x;
switch (typeA) {
case kIDBKeyNullTypeByte:
case kIDBKeyMinKeyTypeByte:
return 0;
case kIDBKeyStringTypeByte:
p = decodeStringWithLength(p, limitA, s); ASSERT(p);
q = decodeStringWithLength(q, limitB, t);
ASSERT(q);
return codePointCompare(s, t);
case kIDBKeyDateTypeByte:
case kIDBKeyNumberTypeByte:
p = decodeDouble(p, limitA, &d);
ASSERT(p);
q = decodeDouble(q, limitB, &e);
ASSERT(q);
if (d < e)
return -1;
if (d > e)
return 1;
return 0;
}
ASSERT_NOT_REACHED();
return 0;
}
namespace {
template<typename KeyType>
int decodeAndCompare(const LevelDBSlice& a, const LevelDBSlice& b)
{
KeyType keyA;
KeyType keyB;
const char* ptrA = KeyType::decode(a.begin(), a.end(), &keyA);
ASSERT_UNUSED(ptrA, ptrA);
const char* ptrB = KeyType::decode(b.begin(), b.end(), &keyB);
ASSERT_UNUSED(ptrB, ptrB);
return keyA.compare(keyB);
}
}
int compare(const LevelDBSlice& a, const LevelDBSlice& b, bool indexKeys)
{
const char* ptrA = a.begin();
const char* ptrB = b.begin();
const char* endA = a.end();
const char* endB = b.end();
KeyPrefix prefixA;
KeyPrefix prefixB;
ptrA = KeyPrefix::decode(ptrA, endA, &prefixA);
ptrB = KeyPrefix::decode(ptrB, endB, &prefixB);
ASSERT(ptrA);
ASSERT(ptrB);
if (int x = prefixA.compare(prefixB))
return x;
if (prefixA.type() == KeyPrefix::kGlobalMetaData) {
ASSERT(ptrA != endA);
ASSERT(ptrB != endB);
unsigned char typeByteA = *ptrA++;
unsigned char typeByteB = *ptrB++;
if (int x = typeByteA - typeByteB)
return x;
if (typeByteA <= 1)
return 0;
if (typeByteA == kDatabaseFreeListTypeByte)
return decodeAndCompare<DatabaseFreeListKey>(a, b);
if (typeByteA == kDatabaseNameTypeByte)
return decodeAndCompare<DatabaseNameKey>(a, b);
}
if (prefixA.type() == KeyPrefix::kDatabaseMetaData) {
ASSERT(ptrA != endA);
ASSERT(ptrB != endB);
unsigned char typeByteA = *ptrA++;
unsigned char typeByteB = *ptrB++;
if (int x = typeByteA - typeByteB)
return x;
if (typeByteA <= 3)
return 0;
if (typeByteA == kObjectStoreMetaDataTypeByte)
return decodeAndCompare<ObjectStoreMetaDataKey>(a, b);
if (typeByteA == kIndexMetaDataTypeByte)
return decodeAndCompare<IndexMetaDataKey>(a, b);
if (typeByteA == kObjectStoreFreeListTypeByte)
return decodeAndCompare<ObjectStoreFreeListKey>(a, b);
if (typeByteA == kIndexFreeListTypeByte)
return decodeAndCompare<IndexFreeListKey>(a, b);
if (typeByteA == kObjectStoreNamesTypeByte)
return decodeAndCompare<ObjectStoreNamesKey>(a, b);
if (typeByteA == kIndexNamesKeyTypeByte)
return decodeAndCompare<IndexNamesKey>(a, b);
return 0;
ASSERT_NOT_REACHED();
}
if (prefixA.type() == KeyPrefix::kObjectStoreData) {
if (ptrA == endA && ptrB == endB)
return 0;
if (ptrA == endA)
return -1;
if (ptrB == endB)
return 1;
return decodeAndCompare<ObjectStoreDataKey>(a, b);
}
if (prefixA.type() == KeyPrefix::kExistsEntry) {
if (ptrA == endA && ptrB == endB)
return 0;
if (ptrA == endA)
return -1;
if (ptrB == endB)
return 1;
return decodeAndCompare<ExistsEntryKey>(a, b);
}
if (prefixA.type() == KeyPrefix::kIndexData) {
if (ptrA == endA && ptrB == endB)
return 0;
if (ptrA == endA)
return -1;
if (ptrB == endB)
return 1;
IndexDataKey indexDataKeyA;
IndexDataKey indexDataKeyB;
ptrA = IndexDataKey::decode(a.begin(), endA, &indexDataKeyA);
ptrB = IndexDataKey::decode(b.begin(), endB, &indexDataKeyB);
ASSERT(ptrA);
ASSERT(ptrB);
bool ignoreSequenceNumber = indexKeys;
return indexDataKeyA.compare(indexDataKeyB, ignoreSequenceNumber);
}
ASSERT_NOT_REACHED();
return 0;
}
KeyPrefix::KeyPrefix()
: m_databaseId(kInvalidType)
, m_objectStoreId(kInvalidType)
, m_indexId(kInvalidType)
{
}
KeyPrefix::KeyPrefix(int64_t databaseId, int64_t objectStoreId, int64_t indexId)
: m_databaseId(databaseId)
, m_objectStoreId(objectStoreId)
, m_indexId(indexId)
{
}
const char* KeyPrefix::decode(const char* start, const char* limit, KeyPrefix* result)
{
if (start == limit)
return 0;
unsigned char firstByte = *start++;
int databaseIdBytes = ((firstByte >> 5) & 0x7) + 1;
int objectStoreIdBytes = ((firstByte >> 2) & 0x7) + 1;
int indexIdBytes = (firstByte & 0x3) + 1;
if (start + databaseIdBytes + objectStoreIdBytes + indexIdBytes > limit)
return 0;
result->m_databaseId = decodeInt(start, start + databaseIdBytes);
start += databaseIdBytes;
result->m_objectStoreId = decodeInt(start, start + objectStoreIdBytes);
start += objectStoreIdBytes;
result->m_indexId = decodeInt(start, start + indexIdBytes);
start += indexIdBytes;
return start;
}
Vector<char> KeyPrefix::encode() const
{
ASSERT(m_databaseId != kInvalidId);
ASSERT(m_objectStoreId != kInvalidId);
ASSERT(m_indexId != kInvalidId);
Vector<char> databaseIdString = encodeInt(m_databaseId);
Vector<char> objectStoreIdString = encodeInt(m_objectStoreId);
Vector<char> indexIdString = encodeInt(m_indexId);
ASSERT(databaseIdString.size() <= 8);
ASSERT(objectStoreIdString.size() <= 8);
ASSERT(indexIdString.size() <= 4);
unsigned char firstByte = (databaseIdString.size() - 1) << 5 | (objectStoreIdString.size() - 1) << 2 | (indexIdString.size() - 1);
Vector<char> ret;
ret.append(firstByte);
ret.append(databaseIdString);
ret.append(objectStoreIdString);
ret.append(indexIdString);
return ret;
}
int KeyPrefix::compare(const KeyPrefix& other) const
{
ASSERT(m_databaseId != kInvalidId);
ASSERT(m_objectStoreId != kInvalidId);
ASSERT(m_indexId != kInvalidId);
if (m_databaseId != other.m_databaseId)
return compareInts(m_databaseId, other.m_databaseId);
if (m_objectStoreId != other.m_objectStoreId)
return compareInts(m_objectStoreId, other.m_objectStoreId);
if (m_indexId != other.m_indexId)
return compareInts(m_indexId, other.m_indexId);
return 0;
}
KeyPrefix::Type KeyPrefix::type() const
{
ASSERT(m_databaseId != kInvalidId);
ASSERT(m_objectStoreId != kInvalidId);
ASSERT(m_indexId != kInvalidId);
if (!m_databaseId)
return kGlobalMetaData;
if (!m_objectStoreId)
return kDatabaseMetaData;
if (m_indexId == kObjectStoreDataIndexId)
return kObjectStoreData;
if (m_indexId == kExistsEntryIndexId)
return kExistsEntry;
if (m_indexId >= kMinimumIndexId)
return kIndexData;
ASSERT_NOT_REACHED();
return kInvalidType;
}
Vector<char> SchemaVersionKey::encode()
{
KeyPrefix prefix(0, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kSchemaVersionTypeByte));
return ret;
}
Vector<char> MaxDatabaseIdKey::encode()
{
KeyPrefix prefix(0, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kMaxDatabaseIdTypeByte));
return ret;
}
DatabaseFreeListKey::DatabaseFreeListKey()
: m_databaseId(-1)
{
}
const char* DatabaseFreeListKey::decode(const char* start, const char* limit, DatabaseFreeListKey* result)
{
KeyPrefix prefix;
const char *p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return 0;
ASSERT(!prefix.m_databaseId);
ASSERT(!prefix.m_objectStoreId);
ASSERT(!prefix.m_indexId);
if (p == limit)
return 0;
unsigned char typeByte = *p++;
ASSERT_UNUSED(typeByte, typeByte == kDatabaseFreeListTypeByte);
if (p == limit)
return 0;
return decodeVarInt(p, limit, result->m_databaseId);
}
Vector<char> DatabaseFreeListKey::encode(int64_t databaseId)
{
KeyPrefix prefix(0, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kDatabaseFreeListTypeByte));
ret.append(encodeVarInt(databaseId));
return ret;
}
int64_t DatabaseFreeListKey::databaseId() const
{
ASSERT(m_databaseId >= 0);
return m_databaseId;
}
int DatabaseFreeListKey::compare(const DatabaseFreeListKey& other) const
{
ASSERT(m_databaseId >= 0);
return compareInts(m_databaseId, other.m_databaseId);
}
const char* DatabaseNameKey::decode(const char* start, const char* limit, DatabaseNameKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return p;
ASSERT(!prefix.m_databaseId);
ASSERT(!prefix.m_objectStoreId);
ASSERT(!prefix.m_indexId);
if (p == limit)
return 0;
unsigned char typeByte = *p++;
ASSERT_UNUSED(typeByte, typeByte == kDatabaseNameTypeByte);
if (p == limit)
return 0;
p = decodeStringWithLength(p, limit, result->m_origin);
if (!p)
return 0;
return decodeStringWithLength(p, limit, result->m_databaseName);
}
Vector<char> DatabaseNameKey::encode(const String& origin, const String& databaseName)
{
KeyPrefix prefix(0, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kDatabaseNameTypeByte));
ret.append(encodeStringWithLength(origin));
ret.append(encodeStringWithLength(databaseName));
return ret;
}
int DatabaseNameKey::compare(const DatabaseNameKey& other)
{
if (int x = codePointCompare(m_origin, other.m_origin))
return x;
return codePointCompare(m_databaseName, other.m_databaseName);
}
Vector<char> DatabaseMetaDataKey::encode(int64_t databaseId, MetaDataType metaDataType)
{
KeyPrefix prefix(databaseId, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(metaDataType));
return ret;
}
ObjectStoreMetaDataKey::ObjectStoreMetaDataKey()
: m_objectStoreId(-1)
, m_metaDataType(-1)
{
}
const char* ObjectStoreMetaDataKey::decode(const char* start, const char* limit, ObjectStoreMetaDataKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(!prefix.m_objectStoreId);
ASSERT(!prefix.m_indexId);
if (p == limit)
return 0;
unsigned char typeByte = *p++;
ASSERT_UNUSED(typeByte, typeByte == kObjectStoreMetaDataTypeByte);
if (p == limit)
return 0;
p = decodeVarInt(p, limit, result->m_objectStoreId);
if (!p)
return 0;
ASSERT(result->m_objectStoreId);
if (p == limit)
return 0;
return decodeVarInt(p, limit, result->m_metaDataType);
}
Vector<char> ObjectStoreMetaDataKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t metaDataType)
{
KeyPrefix prefix(databaseId, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kObjectStoreMetaDataTypeByte));
ret.append(encodeVarInt(objectStoreId));
ret.append(encodeVarInt(metaDataType));
return ret;
}
int64_t ObjectStoreMetaDataKey::objectStoreId() const
{
ASSERT(m_objectStoreId >= 0);
return m_objectStoreId;
}
int64_t ObjectStoreMetaDataKey::metaDataType() const
{
ASSERT(m_metaDataType >= 0);
return m_metaDataType;
}
int ObjectStoreMetaDataKey::compare(const ObjectStoreMetaDataKey& other)
{
ASSERT(m_objectStoreId >= 0);
ASSERT(m_metaDataType >= 0);
if (int x = compareInts(m_objectStoreId, other.m_objectStoreId))
return x;
return m_metaDataType - other.m_metaDataType;
}
IndexMetaDataKey::IndexMetaDataKey()
: m_objectStoreId(-1)
, m_indexId(-1)
, m_metaDataType(0)
{
}
const char* IndexMetaDataKey::decode(const char* start, const char* limit, IndexMetaDataKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(!prefix.m_objectStoreId);
ASSERT(!prefix.m_indexId);
if (p == limit)
return 0;
unsigned char typeByte = *p++;
ASSERT_UNUSED(typeByte, typeByte == kIndexMetaDataTypeByte);
if (p == limit)
return 0;
p = decodeVarInt(p, limit, result->m_objectStoreId);
if (!p)
return 0;
p = decodeVarInt(p, limit, result->m_indexId);
if (!p)
return 0;
if (p == limit)
return 0;
result->m_metaDataType = *p++;
return p;
}
Vector<char> IndexMetaDataKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, unsigned char metaDataType)
{
KeyPrefix prefix(databaseId, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kIndexMetaDataTypeByte));
ret.append(encodeVarInt(objectStoreId));
ret.append(encodeVarInt(indexId));
ret.append(encodeByte(metaDataType));
return ret;
}
int IndexMetaDataKey::compare(const IndexMetaDataKey& other)
{
ASSERT(m_objectStoreId >= 0);
ASSERT(m_indexId >= 0);
if (int x = compareInts(m_objectStoreId, other.m_objectStoreId))
return x;
if (int x = compareInts(m_indexId, other.m_indexId))
return x;
return m_metaDataType - other.m_metaDataType;
}
int64_t IndexMetaDataKey::indexId() const
{
ASSERT(m_indexId >= 0);
return m_indexId;
}
ObjectStoreFreeListKey::ObjectStoreFreeListKey()
: m_objectStoreId(-1)
{
}
const char* ObjectStoreFreeListKey::decode(const char* start, const char* limit, ObjectStoreFreeListKey* result)
{
KeyPrefix prefix;
const char *p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(!prefix.m_objectStoreId);
ASSERT(!prefix.m_indexId);
if (p == limit)
return 0;
unsigned char typeByte = *p++;
ASSERT_UNUSED(typeByte, typeByte == kObjectStoreFreeListTypeByte);
if (p == limit)
return 0;
return decodeVarInt(p, limit, result->m_objectStoreId);
}
Vector<char> ObjectStoreFreeListKey::encode(int64_t databaseId, int64_t objectStoreId)
{
KeyPrefix prefix(databaseId, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kObjectStoreFreeListTypeByte));
ret.append(encodeVarInt(objectStoreId));
return ret;
}
int64_t ObjectStoreFreeListKey::objectStoreId() const
{
ASSERT(m_objectStoreId >= 0);
return m_objectStoreId;
}
int ObjectStoreFreeListKey::compare(const ObjectStoreFreeListKey& other)
{
ASSERT(m_objectStoreId >= 0);
return compareInts(m_objectStoreId, other.m_objectStoreId);
}
IndexFreeListKey::IndexFreeListKey()
: m_objectStoreId(-1)
, m_indexId(-1)
{
}
const char* IndexFreeListKey::decode(const char* start, const char* limit, IndexFreeListKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(!prefix.m_objectStoreId);
ASSERT(!prefix.m_indexId);
if (p == limit)
return 0;
unsigned char typeByte = *p++;
ASSERT_UNUSED(typeByte, typeByte == kIndexFreeListTypeByte);
if (p == limit)
return 0;
p = decodeVarInt(p, limit, result->m_objectStoreId);
if (!p)
return 0;
return decodeVarInt(p, limit, result->m_indexId);
}
Vector<char> IndexFreeListKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId)
{
KeyPrefix prefix(databaseId, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kIndexFreeListTypeByte));
ret.append(encodeVarInt(objectStoreId));
ret.append(encodeVarInt(indexId));
return ret;
}
int IndexFreeListKey::compare(const IndexFreeListKey& other)
{
ASSERT(m_objectStoreId >= 0);
ASSERT(m_indexId >= 0);
if (int x = compareInts(m_objectStoreId, other.m_objectStoreId))
return x;
return compareInts(m_indexId, other.m_indexId);
}
int64_t IndexFreeListKey::objectStoreId() const
{
ASSERT(m_objectStoreId >= 0);
return m_objectStoreId;
}
int64_t IndexFreeListKey::indexId() const
{
ASSERT(m_indexId >= 0);
return m_indexId;
}
const char* ObjectStoreNamesKey::decode(const char* start, const char* limit, ObjectStoreNamesKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(!prefix.m_objectStoreId);
ASSERT(!prefix.m_indexId);
if (p == limit)
return 0;
unsigned char typeByte = *p++;
ASSERT_UNUSED(typeByte, typeByte == kObjectStoreNamesTypeByte);
return decodeStringWithLength(p, limit, result->m_objectStoreName);
}
Vector<char> ObjectStoreNamesKey::encode(int64_t databaseId, const String& objectStoreName)
{
KeyPrefix prefix(databaseId, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kObjectStoreNamesTypeByte));
ret.append(encodeStringWithLength(objectStoreName));
return ret;
}
int ObjectStoreNamesKey::compare(const ObjectStoreNamesKey& other)
{
return codePointCompare(m_objectStoreName, other.m_objectStoreName);
}
IndexNamesKey::IndexNamesKey()
: m_objectStoreId(-1)
{
}
const char* IndexNamesKey::decode(const char* start, const char* limit, IndexNamesKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(!prefix.m_objectStoreId);
ASSERT(!prefix.m_indexId);
if (p == limit)
return 0;
unsigned char typeByte = *p++;
ASSERT_UNUSED(typeByte, typeByte == kIndexNamesKeyTypeByte);
if (p == limit)
return 0;
p = decodeVarInt(p, limit, result->m_objectStoreId);
if (!p)
return 0;
return decodeStringWithLength(p, limit, result->m_indexName);
}
Vector<char> IndexNamesKey::encode(int64_t databaseId, int64_t objectStoreId, const String& indexName)
{
KeyPrefix prefix(databaseId, 0, 0);
Vector<char> ret = prefix.encode();
ret.append(encodeByte(kIndexNamesKeyTypeByte));
ret.append(encodeVarInt(objectStoreId));
ret.append(encodeStringWithLength(indexName));
return ret;
}
int IndexNamesKey::compare(const IndexNamesKey& other)
{
ASSERT(m_objectStoreId >= 0);
if (int x = compareInts(m_objectStoreId, other.m_objectStoreId))
return x;
return codePointCompare(m_indexName, other.m_indexName);
}
const char* ObjectStoreDataKey::decode(const char* start, const char* end, ObjectStoreDataKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, end, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(prefix.m_objectStoreId);
ASSERT(prefix.m_indexId == kSpecialIndexNumber);
if (p == end)
return 0;
return extractEncodedIDBKey(p, end, &result->m_encodedUserKey);
}
Vector<char> ObjectStoreDataKey::encode(int64_t databaseId, int64_t objectStoreId, const Vector<char> encodedUserKey)
{
KeyPrefix prefix(databaseId, objectStoreId, kSpecialIndexNumber);
Vector<char> ret = prefix.encode();
ret.append(encodedUserKey);
return ret;
}
Vector<char> ObjectStoreDataKey::encode(int64_t databaseId, int64_t objectStoreId, const IDBKey& userKey)
{
return encode(databaseId, objectStoreId, encodeIDBKey(userKey));
}
int ObjectStoreDataKey::compare(const ObjectStoreDataKey& other)
{
return compareEncodedIDBKeys(m_encodedUserKey, other.m_encodedUserKey);
}
PassRefPtr<IDBKey> ObjectStoreDataKey::userKey() const
{
RefPtr<IDBKey> key;
decodeIDBKey(m_encodedUserKey.begin(), m_encodedUserKey.end(), key);
return key;
}
const int64_t ObjectStoreDataKey::kSpecialIndexNumber = kObjectStoreDataIndexId;
const char* ExistsEntryKey::decode(const char* start, const char* end, ExistsEntryKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, end, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(prefix.m_objectStoreId);
ASSERT(prefix.m_indexId == kSpecialIndexNumber);
if (p == end)
return 0;
return extractEncodedIDBKey(p, end, &result->m_encodedUserKey);
}
Vector<char> ExistsEntryKey::encode(int64_t databaseId, int64_t objectStoreId, const Vector<char>& encodedKey)
{
KeyPrefix prefix(databaseId, objectStoreId, kSpecialIndexNumber);
Vector<char> ret = prefix.encode();
ret.append(encodedKey);
return ret;
}
Vector<char> ExistsEntryKey::encode(int64_t databaseId, int64_t objectStoreId, const IDBKey& userKey)
{
return encode(databaseId, objectStoreId, encodeIDBKey(userKey));
}
int ExistsEntryKey::compare(const ExistsEntryKey& other)
{
return compareEncodedIDBKeys(m_encodedUserKey, other.m_encodedUserKey);
}
PassRefPtr<IDBKey> ExistsEntryKey::userKey() const
{
RefPtr<IDBKey> key;
decodeIDBKey(m_encodedUserKey.begin(), m_encodedUserKey.end(), key);
return key;
}
const int64_t ExistsEntryKey::kSpecialIndexNumber = kExistsEntryIndexId;
IndexDataKey::IndexDataKey()
: m_databaseId(-1)
, m_objectStoreId(-1)
, m_indexId(-1)
, m_sequenceNumber(-1)
{
}
const char* IndexDataKey::decode(const char* start, const char* limit, IndexDataKey* result)
{
KeyPrefix prefix;
const char* p = KeyPrefix::decode(start, limit, &prefix);
if (!p)
return 0;
ASSERT(prefix.m_databaseId);
ASSERT(prefix.m_objectStoreId);
ASSERT(prefix.m_indexId >= kMinimumIndexId);
result->m_databaseId = prefix.m_databaseId;
result->m_objectStoreId = prefix.m_objectStoreId;
result->m_indexId = prefix.m_indexId;
p = extractEncodedIDBKey(p, limit, &result->m_encodedUserKey);
if (!p)
return 0;
if (p == limit) {
result->m_sequenceNumber = -1; return p;
}
return decodeVarInt(p, limit, result->m_sequenceNumber);
}
Vector<char> IndexDataKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const Vector<char>& encodedUserKey, int64_t sequenceNumber)
{
KeyPrefix prefix(databaseId, objectStoreId, indexId);
Vector<char> ret = prefix.encode();
ret.append(encodedUserKey);
ret.append(encodeVarInt(sequenceNumber));
return ret;
}
Vector<char> IndexDataKey::encode(int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey& userKey, int64_t sequenceNumber)
{
return encode(databaseId, objectStoreId, indexId, encodeIDBKey(userKey), sequenceNumber);
}
Vector<char> IndexDataKey::encodeMaxKey(int64_t databaseId, int64_t objectStoreId)
{
return encode(databaseId, objectStoreId, INT32_MAX, maxIDBKey(), INT64_MAX);
}
int IndexDataKey::compare(const IndexDataKey& other, bool ignoreSequenceNumber)
{
ASSERT(m_databaseId >= 0);
ASSERT(m_objectStoreId >= 0);
ASSERT(m_indexId >= 0);
if (int x = compareEncodedIDBKeys(m_encodedUserKey, other.m_encodedUserKey))
return x;
if (ignoreSequenceNumber)
return 0;
return compareInts(m_sequenceNumber, other.m_sequenceNumber);
}
int64_t IndexDataKey::databaseId() const
{
ASSERT(m_databaseId >= 0);
return m_databaseId;
}
int64_t IndexDataKey::objectStoreId() const
{
ASSERT(m_objectStoreId >= 0);
return m_objectStoreId;
}
int64_t IndexDataKey::indexId() const
{
ASSERT(m_indexId >= 0);
return m_indexId;
}
PassRefPtr<IDBKey> IndexDataKey::userKey() const
{
RefPtr<IDBKey> key;
decodeIDBKey(m_encodedUserKey.begin(), m_encodedUserKey.end(), key);
return key;
}
} }
#endif // ENABLE(LEVELDB)
#endif // ENABLE(INDEXED_DATABASE)