Index: content/browser/indexed_db/indexed_db_leveldb_coding.cc |
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/content/browser/indexed_db/indexed_db_leveldb_coding.cc |
deleted file mode 100644 |
index d3b25b2f3dd9fcb6981b156c5ae98e7ba996f7a9..0000000000000000000000000000000000000000 |
--- a/content/browser/indexed_db/indexed_db_leveldb_coding.cc |
+++ /dev/null |
@@ -1,1880 +0,0 @@ |
-// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
- |
-#include <iterator> |
-#include <limits> |
-#include <string> |
- |
-#include "base/logging.h" |
-#include "base/string16.h" |
-#include "base/sys_byteorder.h" |
-#include "content/browser/indexed_db/leveldb/leveldb_slice.h" |
-#include "content/common/indexed_db/indexed_db_key.h" |
-#include "content/common/indexed_db/indexed_db_key_path.h" |
-#include "third_party/WebKit/Source/Platform/chromium/public/WebIDBKeyPath.h" |
- |
-// LevelDB stores key/value pairs. Keys and values are strings of bytes, |
-// normally of type std::vector<char>. |
-// |
-// The keys in the backing store are variable-length tuples with different types |
-// of fields. Each key in the backing store starts with a ternary prefix: |
-// (database id, object store id, index id). For each, 0 is reserved for |
-// meta-data. |
-// The prefix makes sure that data for a specific database, object store, and |
-// index are grouped together. The locality is important for performance: common |
-// operations should only need a minimal number of seek operations. For example, |
-// all the meta-data for a database is grouped together so that reading that |
-// meta-data only requires one seek. |
-// |
-// Each key type has a class (in square brackets below) which knows how to |
-// encode, decode, and compare that key type. |
-// |
-// Global meta-data have keys with prefix (0,0,0), followed by a type byte: |
-// |
-// <0, 0, 0, 0> => |
-// IndexedDB/LevelDB schema version [SchemaVersionKey] |
-// <0, 0, 0, 1> => The maximum |
-// database id ever allocated [MaxDatabaseIdKey] |
-// <0, 0, 0, 2> => |
-// SerializedScriptValue version [DataVersionKey] |
-// <0, 0, 0, 100, database id> => Existence |
-// implies the database id is in the free list [DatabaseFreeListKey] |
-// <0, 0, 0, 201, utf16 origin name, utf16 database name> => Database id |
-// [DatabaseNameKey] |
-// |
-// |
-// Database meta-data: |
-// |
-// Again, the prefix is followed by a type byte. |
-// |
-// <database id, 0, 0, 0> => utf16 origin name [DatabaseMetaDataKey] |
-// <database id, 0, 0, 1> => utf16 database name [DatabaseMetaDataKey] |
-// <database id, 0, 0, 2> => utf16 user version data [DatabaseMetaDataKey] |
-// <database id, 0, 0, 3> => maximum object store id ever allocated |
-// [DatabaseMetaDataKey] |
-// <database id, 0, 0, 4> => user integer version (var int) |
-// [DatabaseMetaDataKey] |
-// |
-// |
-// Object store meta-data: |
-// |
-// The prefix is followed by a type byte, then a variable-length integer, |
-// and then another type byte. |
-// |
-// <database id, 0, 0, 50, object store id, 0> => utf16 object store name |
-// [ObjectStoreMetaDataKey] |
-// <database id, 0, 0, 50, object store id, 1> => utf16 key path |
-// [ObjectStoreMetaDataKey] |
-// <database id, 0, 0, 50, object store id, 2> => has auto increment |
-// [ObjectStoreMetaDataKey] |
-// <database id, 0, 0, 50, object store id, 3> => is evictable |
-// [ObjectStoreMetaDataKey] |
-// <database id, 0, 0, 50, object store id, 4> => last "version" number |
-// [ObjectStoreMetaDataKey] |
-// <database id, 0, 0, 50, object store id, 5> => maximum index id ever |
-// allocated [ObjectStoreMetaDataKey] |
-// <database id, 0, 0, 50, object store id, 6> => has key path (vs. null) |
-// [ObjectStoreMetaDataKey] |
-// <database id, 0, 0, 50, object store id, 7> => key generator current |
-// number [ObjectStoreMetaDataKey] |
-// |
-// |
-// Index meta-data: |
-// |
-// The prefix is followed by a type byte, then two variable-length integers, |
-// and then another type byte. |
-// |
-// <database id, 0, 0, 100, object store id, index id, 0> => utf16 index |
-// name [IndexMetaDataKey] |
-// <database id, 0, 0, 100, object store id, index id, 1> => are index keys |
-// unique [IndexMetaDataKey] |
-// <database id, 0, 0, 100, object store id, index id, 2> => utf16 key path |
-// [IndexMetaDataKey] |
-// <database id, 0, 0, 100, object store id, index id, 3> => is index |
-// multi-entry [IndexMetaDataKey] |
-// |
-// |
-// Other object store and index meta-data: |
-// |
-// The prefix is followed by a type byte. The object store and index id are |
-// variable length integers, the utf16 strings are variable length strings. |
-// |
-// <database id, 0, 0, 150, object store id> => existence |
-// implies the object store id is in the free list [ObjectStoreFreeListKey] |
-// <database id, 0, 0, 151, object store id, index id> => existence |
-// implies the index id is in the free list [IndexFreeListKey] |
-// <database id, 0, 0, 200, utf16 object store name> => object |
-// store id [ObjectStoreNamesKey] |
-// <database id, 0, 0, 201, object store id, utf16 index name> => index id |
-// [IndexNamesKey] |
-// |
-// |
-// Object store data: |
-// |
-// The prefix is followed by a type byte. The user key is an encoded |
-// IndexedDBKey. |
-// |
-// <database id, object store id, 1, user key> => "version", serialized |
-// script value [ObjectStoreDataKey] |
-// |
-// |
-// "Exists" entry: |
-// |
-// The prefix is followed by a type byte. The user key is an encoded |
-// IndexedDBKey. |
-// |
-// <database id, object store id, 2, user key> => "version" [ExistsEntryKey] |
-// |
-// |
-// Index data: |
-// |
-// The prefix is followed by a type byte. The index key is an encoded |
-// IndexedDBKey. The sequence number is a variable length integer. |
-// The primary key is an encoded IndexedDBKey. |
-// |
-// <database id, object store id, index id, index key, sequence number, |
-// primary key> => "version", primary key [IndexDataKey] |
-// |
-// (The sequence number is obsolete; it was used to allow two entries with |
-// the same user (index) key in non-unique indexes prior to the inclusion of |
-// the primary key in the data. The "version" field is used to weed out |
-// stale |
-// index data. Whenever new object store data is inserted, it gets a new |
-// "version" number, and new index data is written with this number. When |
-// the index is used for look-ups, entries are validated against the |
-// "exists" entries, and records with old "version" numbers are deleted |
-// when they are encountered in get_primary_key_via_index, |
-// IndexCursorImpl::load_current_row, and |
-// IndexKeyCursorImpl::load_current_row). |
- |
-using WebKit::WebIDBKey; |
-using WebKit::WebIDBKeyPath; |
- |
-namespace content { |
- |
-// As most of the IndexedDBKeys and encoded values are short, we |
-// initialize some Vectors with a default inline buffer size to reduce |
-// the memory re-allocations when the Vectors are appended. |
-static const size_t kDefaultInlineBufferSize = 32; |
- |
-static const unsigned char kIndexedDBKeyNullTypeByte = 0; |
-static const unsigned char kIndexedDBKeyStringTypeByte = 1; |
-static const unsigned char kIndexedDBKeyDateTypeByte = 2; |
-static const unsigned char kIndexedDBKeyNumberTypeByte = 3; |
-static const unsigned char kIndexedDBKeyArrayTypeByte = 4; |
-static const unsigned char kIndexedDBKeyMinKeyTypeByte = 5; |
- |
-static const unsigned char kIndexedDBKeyPathTypeCodedByte1 = 0; |
-static const unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0; |
- |
-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 kDataVersionTypeByte = 2; |
-static const unsigned char kMaxSimpleGlobalMetaDataTypeByte = |
- 3; // Insert before this and increment. |
-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; |
- |
-static const unsigned char kObjectMetaDataTypeMaximum = 255; |
-static const unsigned char kIndexMetaDataTypeMaximum = 255; |
- |
-const unsigned char kMinimumIndexId = 30; |
- |
-std::vector<char> EncodeByte(unsigned char c) { |
- std::vector<char> v; |
- v.reserve(kDefaultInlineBufferSize); |
- v.push_back(c); |
- |
- DCHECK_LE(v.size(), kDefaultInlineBufferSize); |
- return v; |
-} |
- |
-const char* DecodeByte(const char* p, |
- const char* limit, |
- unsigned char& found_char) { |
- if (p >= limit) |
- return 0; |
- |
- found_char = *p++; |
- return p; |
-} |
- |
-std::vector<char> MaxIDBKey() { return EncodeByte(kIndexedDBKeyNullTypeByte); } |
- |
-std::vector<char> MinIDBKey() { |
- return EncodeByte(kIndexedDBKeyMinKeyTypeByte); |
-} |
- |
-std::vector<char> EncodeBool(bool b) { |
- std::vector<char> ret; |
- ret.reserve(kDefaultInlineBufferSize); |
- ret.push_back(b ? 1 : 0); |
- |
- DCHECK_LE(ret.size(), kDefaultInlineBufferSize); |
- return ret; |
-} |
- |
-bool DecodeBool(const char* begin, const char* end) { |
- DCHECK_LT(begin, end); |
- return !!*begin; |
-} |
- |
-std::vector<char> EncodeInt(int64 nParam) { |
-#ifndef NDEBUG |
- // Exercised by unit tests in debug only. |
- DCHECK_GE(nParam, 0); |
-#endif |
- uint64 n = static_cast<uint64>(nParam); |
- std::vector<char> ret; |
- ret.reserve(kDefaultInlineBufferSize); |
- |
- do { |
- unsigned char c = n; |
- ret.push_back(c); |
- n >>= 8; |
- } while (n); |
- |
- DCHECK_LE(ret.size(), kDefaultInlineBufferSize); |
- return ret; |
-} |
- |
-static int CompareInts(int64 a, int64 b) { |
-#ifndef NDEBUG |
- // Exercised by unit tests in debug only. |
- DCHECK_GE(a, 0); |
- DCHECK_GE(b, 0); |
-#endif |
- int64 diff = a - b; |
- if (diff < 0) |
- return -1; |
- if (diff > 0) |
- return 1; |
- return 0; |
-} |
- |
-std::vector<char> EncodeVarInt(int64 nParam) { |
-#ifndef NDEBUG |
- // Exercised by unit tests in debug only. |
- DCHECK_GE(nParam, 0); |
-#endif |
- uint64 n = static_cast<uint64>(nParam); |
- std::vector<char> ret; |
- ret.reserve(kDefaultInlineBufferSize); |
- |
- do { |
- unsigned char c = n & 0x7f; |
- n >>= 7; |
- if (n) |
- c |= 0x80; |
- ret.push_back(c); |
- } while (n); |
- |
- DCHECK_LE(ret.size(), kDefaultInlineBufferSize); |
- return ret; |
-} |
- |
-const char* DecodeVarInt(const char* p, const char* limit, int64& found_int) { |
- DCHECK_GE(limit, p); |
- found_int = 0; |
- int shift = 0; |
- |
- do { |
- if (p >= limit) |
- return 0; |
- |
- unsigned char c = *p; |
- found_int |= static_cast<int64>(c & 0x7f) << shift; |
- shift += 7; |
- } while (*p++ & 0x80); |
- return p; |
-} |
- |
-std::vector<char> EncodeString(const string16& s) { |
- // Backing store is UTF-16BE, convert from host endianness. |
- size_t length = s.length(); |
- std::vector<char> ret(length * sizeof(char16)); |
- |
- const char16* src = s.c_str(); |
- char16* dst = reinterpret_cast<char16*>(&*ret.begin()); |
- for (unsigned i = 0; i < length; ++i) |
- *dst++ = htons(*src++); |
- |
- return ret; |
-} |
- |
-string16 DecodeString(const char* start, const char* end) { |
- // Backing store is UTF-16BE, convert to host endianness. |
- DCHECK_GE(end, start); |
- DCHECK(!((end - start) % sizeof(char16))); |
- |
- size_t length = (end - start) / sizeof(char16); |
- string16 decoded; |
- decoded.reserve(length); |
- const char16* encoded = reinterpret_cast<const char16*>(start); |
- for (unsigned i = 0; i < length; ++i) |
- decoded.push_back(ntohs(*encoded++)); |
- return decoded; |
-} |
- |
-std::vector<char> EncodeStringWithLength(const string16& s) { |
- std::vector<char> result = EncodeVarInt(s.length()); |
- std::vector<char> encoded_value = EncodeString(s); |
- result.insert(result.end(), encoded_value.begin(), encoded_value.end()); |
- return result; |
-} |
- |
-const char* DecodeStringWithLength(const char* p, |
- const char* limit, |
- string16& found_string) { |
- DCHECK_GE(limit, p); |
- int64 len; |
- p = DecodeVarInt(p, limit, len); |
- if (!p || len < 0 || p + len * 2 > limit) |
- return 0; |
- |
- found_string = DecodeString(p, p + len * 2); |
- p += len * 2; |
- return p; |
-} |
- |
-int CompareEncodedStringsWithLength(const char*& p, |
- const char* limit_p, |
- const char*& q, |
- const char* limit_q, |
- bool& ok) { |
- DCHECK_NE(&p, &q); |
- DCHECK_GE(limit_p, p); |
- DCHECK_GE(limit_q, q); |
- int64 len_p, len_q; |
- p = DecodeVarInt(p, limit_p, len_p); |
- q = DecodeVarInt(q, limit_q, len_q); |
- if (!p || !q || len_p < 0 || len_q < 0) { |
- ok = false; |
- return 0; |
- } |
- DCHECK(p && q); |
- DCHECK_GE(len_p, 0); |
- DCHECK_GE(len_q, 0); |
- DCHECK_LE(p + len_p * 2, limit_p); |
- DCHECK_LE(q + len_q * 2, limit_q); |
- |
- const char* start_p = p; |
- const char* start_q = q; |
- p += len_p * 2; |
- q += len_q * 2; |
- |
- if (p > limit_p || q > limit_q) { |
- ok = false; |
- return 0; |
- } |
- |
- ok = true; |
- const size_t lmin = static_cast<size_t>(len_p < len_q ? len_p : len_q); |
- if (int x = memcmp(start_p, start_q, lmin * 2)) |
- return x; |
- |
- if (len_p == len_q) |
- return 0; |
- |
- return (len_p > len_q) ? 1 : -1; |
-} |
- |
-std::vector<char> EncodeDouble(double x) { |
- // TODO(jsbell): It would be nice if we could be byte order independent. |
- const char* p = reinterpret_cast<char*>(&x); |
- std::vector<char> v; |
- v.reserve(kDefaultInlineBufferSize); |
- v.insert(v.end(), p, p + sizeof(x)); |
- |
- DCHECK_LE(v.size(), kDefaultInlineBufferSize); |
- 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; |
-} |
- |
-std::vector<char> EncodeIDBKey(const IndexedDBKey& key) { |
- std::vector<char> ret; |
- ret.reserve(kDefaultInlineBufferSize); |
- EncodeIDBKey(key, ret); |
- return ret; |
-} |
- |
-void EncodeIDBKey(const IndexedDBKey& key, std::vector<char>& into) { |
- size_t previous_size = into.size(); |
- DCHECK(key.IsValid()); |
- switch (key.type()) { |
- case WebIDBKey::NullType: |
- case WebIDBKey::InvalidType: |
- case WebIDBKey::MinType: { |
- NOTREACHED(); |
- into.push_back(kIndexedDBKeyNullTypeByte); |
- return; |
- } |
- case WebIDBKey::ArrayType: { |
- into.push_back(kIndexedDBKeyArrayTypeByte); |
- size_t length = key.array().size(); |
- std::vector<char> encoded_length = EncodeVarInt(length); |
- into.insert(into.end(), encoded_length.begin(), encoded_length.end()); |
- for (size_t i = 0; i < length; ++i) |
- EncodeIDBKey(key.array()[i], into); |
- DCHECK_GT(into.size(), previous_size); |
- return; |
- } |
- case WebIDBKey::StringType: { |
- into.push_back(kIndexedDBKeyStringTypeByte); |
- std::vector<char> tmp = EncodeStringWithLength(key.string()); |
- into.insert(into.end(), tmp.begin(), tmp.end()); |
- DCHECK_GT(into.size(), previous_size); |
- return; |
- } |
- case WebIDBKey::DateType: { |
- into.push_back(kIndexedDBKeyDateTypeByte); |
- std::vector<char> tmp = EncodeDouble(key.date()); |
- into.insert(into.end(), tmp.begin(), tmp.end()); |
- DCHECK_EQ(static_cast<size_t>(9), |
- static_cast<size_t>(into.size() - previous_size)); |
- return; |
- } |
- case WebIDBKey::NumberType: { |
- into.push_back(kIndexedDBKeyNumberTypeByte); |
- std::vector<char> tmp = EncodeDouble(key.number()); |
- into.insert(into.end(), tmp.begin(), tmp.end()); |
- DCHECK_EQ(static_cast<size_t>(9), |
- static_cast<size_t>(into.size() - previous_size)); |
- return; |
- } |
- } |
- |
- NOTREACHED(); |
-} |
- |
-const char* DecodeIDBKey(const char* p, |
- const char* limit, |
- scoped_ptr<IndexedDBKey>* found_key) { |
- DCHECK_GE(limit, p); |
- if (p >= limit) |
- return 0; |
- |
- unsigned char type = *p++; |
- |
- switch (type) { |
- case kIndexedDBKeyNullTypeByte: |
- *found_key = make_scoped_ptr(new IndexedDBKey()); |
- return p; |
- |
- case kIndexedDBKeyArrayTypeByte: { |
- int64 length; |
- p = DecodeVarInt(p, limit, length); |
- if (!p || length < 0) |
- return 0; |
- IndexedDBKey::KeyArray array; |
- while (length--) { |
- scoped_ptr<IndexedDBKey> key; |
- p = DecodeIDBKey(p, limit, &key); |
- if (!p) |
- return 0; |
- array.push_back(*key); |
- } |
- *found_key = make_scoped_ptr(new IndexedDBKey(array)); |
- return p; |
- } |
- case kIndexedDBKeyStringTypeByte: { |
- string16 s; |
- p = DecodeStringWithLength(p, limit, s); |
- if (!p) |
- return 0; |
- *found_key = make_scoped_ptr(new IndexedDBKey(s)); |
- return p; |
- } |
- case kIndexedDBKeyDateTypeByte: { |
- double d; |
- p = DecodeDouble(p, limit, &d); |
- if (!p) |
- return 0; |
- *found_key = make_scoped_ptr(new IndexedDBKey(d, WebIDBKey::DateType)); |
- return p; |
- } |
- case kIndexedDBKeyNumberTypeByte: { |
- double d; |
- p = DecodeDouble(p, limit, &d); |
- if (!p) |
- return 0; |
- *found_key = make_scoped_ptr(new IndexedDBKey(d, WebIDBKey::NumberType)); |
- return p; |
- } |
- } |
- |
- NOTREACHED(); |
- return 0; |
-} |
- |
-const char* ExtractEncodedIDBKey(const char* start, |
- const char* limit, |
- std::vector<char>* result = 0) { |
- const char* p = start; |
- if (p >= limit) |
- return 0; |
- |
- unsigned char type = *p++; |
- |
- switch (type) { |
- case kIndexedDBKeyNullTypeByte: |
- case kIndexedDBKeyMinKeyTypeByte: |
- break; |
- case kIndexedDBKeyArrayTypeByte: { |
- int64 length; |
- p = DecodeVarInt(p, limit, length); |
- if (!p || length < 0) |
- return 0; |
- while (length--) { |
- p = ExtractEncodedIDBKey(p, limit); |
- if (!p) |
- return 0; |
- } |
- break; |
- } |
- case kIndexedDBKeyStringTypeByte: { |
- int64 length; |
- p = DecodeVarInt(p, limit, length); |
- if (!p || length < 0 || p + length * 2 > limit) |
- return 0; |
- p += length * 2; |
- break; |
- } |
- case kIndexedDBKeyDateTypeByte: |
- case kIndexedDBKeyNumberTypeByte: |
- if (p + sizeof(double) > limit) |
- return 0; |
- p += sizeof(double); |
- break; |
- } |
- |
- if (result) { |
- DCHECK(p); |
- DCHECK_LE(p, limit); |
- result->assign(start, p); |
- } |
- |
- return p; |
-} |
- |
-static WebIDBKey::Type KeyTypeByteToKeyType(unsigned char type) { |
- switch (type) { |
- case kIndexedDBKeyNullTypeByte: |
- return WebIDBKey::InvalidType; |
- case kIndexedDBKeyArrayTypeByte: |
- return WebIDBKey::ArrayType; |
- case kIndexedDBKeyStringTypeByte: |
- return WebIDBKey::StringType; |
- case kIndexedDBKeyDateTypeByte: |
- return WebIDBKey::DateType; |
- case kIndexedDBKeyNumberTypeByte: |
- return WebIDBKey::NumberType; |
- case kIndexedDBKeyMinKeyTypeByte: |
- return WebIDBKey::MinType; |
- } |
- |
- NOTREACHED(); |
- return WebIDBKey::InvalidType; |
-} |
- |
-static int CompareTypes(WebIDBKey::Type a, WebIDBKey::Type b) { return b - a; } |
- |
-int CompareEncodedIDBKeys(const char*& ptr_a, |
- const char* limit_a, |
- const char*& ptr_b, |
- const char* limit_b, |
- bool& ok) { |
- ok = true; |
- DCHECK_NE(&ptr_a, &ptr_b); |
- DCHECK_LT(ptr_a, limit_a); |
- DCHECK_LT(ptr_b, limit_b); |
- unsigned char type_a = *ptr_a++; |
- unsigned char type_b = *ptr_b++; |
- |
- if (int x = CompareTypes(KeyTypeByteToKeyType(type_a), |
- KeyTypeByteToKeyType(type_b))) |
- return x; |
- |
- switch (type_a) { |
- case kIndexedDBKeyNullTypeByte: |
- case kIndexedDBKeyMinKeyTypeByte: |
- // Null type or max type; no payload to compare. |
- return 0; |
- case kIndexedDBKeyArrayTypeByte: { |
- int64 length_a, length_b; |
- ptr_a = DecodeVarInt(ptr_a, limit_a, length_a); |
- ptr_b = DecodeVarInt(ptr_b, limit_b, length_b); |
- if (!ptr_a || !ptr_b || length_a < 0 || length_b < 0) { |
- ok = false; |
- return 0; |
- } |
- for (int64 i = 0; i < length_a && i < length_b; ++i) { |
- int result = CompareEncodedIDBKeys(ptr_a, limit_a, ptr_b, limit_b, ok); |
- if (!ok || result) |
- return result; |
- } |
- if (length_a < length_b) |
- return -1; |
- if (length_a > length_b) |
- return 1; |
- return 0; |
- } |
- case kIndexedDBKeyStringTypeByte: |
- return CompareEncodedStringsWithLength( |
- ptr_a, limit_a, ptr_b, limit_b, ok); |
- case kIndexedDBKeyDateTypeByte: |
- case kIndexedDBKeyNumberTypeByte: { |
- double d, e; |
- ptr_a = DecodeDouble(ptr_a, limit_a, &d); |
- ptr_b = DecodeDouble(ptr_b, limit_b, &e); |
- DCHECK(ptr_a); |
- DCHECK(ptr_b); |
- if (!ptr_a || !ptr_b) { |
- ok = false; |
- return 0; |
- } |
- if (d < e) |
- return -1; |
- if (d > e) |
- return 1; |
- return 0; |
- } |
- } |
- |
- NOTREACHED(); |
- return 0; |
-} |
- |
-int CompareEncodedIDBKeys(const std::vector<char>& key_a, |
- const std::vector<char>& key_b, |
- bool& ok) { |
- DCHECK_GE(key_a.size(), static_cast<size_t>(1)); |
- DCHECK_GE(key_b.size(), static_cast<size_t>(1)); |
- |
- const char* ptr_a = &*key_a.begin(); |
- const char* limit_a = &*key_a.rbegin() + 1; |
- const char* ptr_b = &*key_b.begin(); |
- const char* limit_b = &*key_b.rbegin() + 1; |
- |
- return CompareEncodedIDBKeys(ptr_a, limit_a, ptr_b, limit_b, ok); |
-} |
- |
-std::vector<char> EncodeIDBKeyPath(const IndexedDBKeyPath& key_path) { |
- // May be typed, or may be a raw string. An invalid leading |
- // byte is used to identify typed coding. New records are |
- // always written as typed. |
- std::vector<char> ret; |
- ret.reserve(kDefaultInlineBufferSize); |
- ret.push_back(kIndexedDBKeyPathTypeCodedByte1); |
- ret.push_back(kIndexedDBKeyPathTypeCodedByte2); |
- ret.push_back(static_cast<char>(key_path.type())); |
- switch (key_path.type()) { |
- case WebIDBKeyPath::NullType: |
- break; |
- case WebIDBKeyPath::StringType: { |
- std::vector<char> encoded_string = |
- EncodeStringWithLength(key_path.string()); |
- ret.insert(ret.end(), encoded_string.begin(), encoded_string.end()); |
- break; |
- } |
- case WebIDBKeyPath::ArrayType: { |
- const std::vector<string16>& array = key_path.array(); |
- size_t count = array.size(); |
- std::vector<char> encoded_count = EncodeVarInt(count); |
- ret.insert(ret.end(), encoded_count.begin(), encoded_count.end()); |
- for (size_t i = 0; i < count; ++i) { |
- std::vector<char> encoded_string = EncodeStringWithLength(array[i]); |
- ret.insert(ret.end(), encoded_string.begin(), encoded_string.end()); |
- } |
- break; |
- } |
- } |
- return ret; |
-} |
- |
-IndexedDBKeyPath DecodeIDBKeyPath(const char* p, const char* limit) { |
- // May be typed, or may be a raw string. An invalid leading |
- // byte sequence is used to identify typed coding. New records are |
- // always written as typed. |
- if (p == limit || |
- (limit - p >= 2 && (*p != kIndexedDBKeyPathTypeCodedByte1 || |
- *(p + 1) != kIndexedDBKeyPathTypeCodedByte2))) |
- return IndexedDBKeyPath(DecodeString(p, limit)); |
- p += 2; |
- |
- DCHECK_NE(p, limit); |
- WebIDBKeyPath::Type type = static_cast<WebIDBKeyPath::Type>(*p++); |
- switch (type) { |
- case WebIDBKeyPath::NullType: |
- DCHECK_EQ(p, limit); |
- return IndexedDBKeyPath(); |
- case WebIDBKeyPath::StringType: { |
- string16 string; |
- p = DecodeStringWithLength(p, limit, string); |
- DCHECK_EQ(p, limit); |
- return IndexedDBKeyPath(string); |
- } |
- case WebIDBKeyPath::ArrayType: { |
- std::vector<string16> array; |
- int64 count; |
- p = DecodeVarInt(p, limit, count); |
- DCHECK(p); |
- DCHECK_GE(count, 0); |
- while (count--) { |
- string16 string; |
- p = DecodeStringWithLength(p, limit, string); |
- DCHECK(p); |
- array.push_back(string); |
- } |
- DCHECK_EQ(p, limit); |
- return IndexedDBKeyPath(array); |
- } |
- } |
- NOTREACHED(); |
- return IndexedDBKeyPath(); |
-} |
- |
-namespace { |
- |
-template <typename KeyType> |
-int Compare(const LevelDBSlice& a, const LevelDBSlice& b, bool, bool& ok) { |
- KeyType key_a; |
- KeyType key_b; |
- |
- const char* ptr_a = KeyType::Decode(a.begin(), a.end(), &key_a); |
- DCHECK(ptr_a); |
- if (!ptr_a) { |
- ok = false; |
- return 0; |
- } |
- const char* ptr_b = KeyType::Decode(b.begin(), b.end(), &key_b); |
- DCHECK(ptr_b); |
- if (!ptr_b) { |
- ok = false; |
- return 0; |
- } |
- |
- ok = true; |
- return key_a.Compare(key_b); |
-} |
- |
-template <> |
-int Compare<ExistsEntryKey>(const LevelDBSlice& a, |
- const LevelDBSlice& b, |
- bool, |
- bool& ok) { |
- KeyPrefix prefix_a; |
- KeyPrefix prefix_b; |
- const char* ptr_a = KeyPrefix::Decode(a.begin(), a.end(), &prefix_a); |
- const char* ptr_b = KeyPrefix::Decode(b.begin(), b.end(), &prefix_b); |
- DCHECK(ptr_a); |
- DCHECK(ptr_b); |
- DCHECK(prefix_a.database_id_); |
- DCHECK(prefix_a.object_store_id_); |
- DCHECK_EQ(prefix_a.index_id_, ExistsEntryKey::kSpecialIndexNumber); |
- DCHECK(prefix_b.database_id_); |
- DCHECK(prefix_b.object_store_id_); |
- DCHECK_EQ(prefix_b.index_id_, ExistsEntryKey::kSpecialIndexNumber); |
- DCHECK_NE(ptr_a, a.end()); |
- DCHECK_NE(ptr_b, b.end()); |
- // Prefixes are not compared - it is assumed this was already done. |
- DCHECK(!prefix_a.Compare(prefix_b)); |
- |
- return CompareEncodedIDBKeys(ptr_a, a.end(), ptr_b, b.end(), ok); |
-} |
- |
-template <> |
-int Compare<ObjectStoreDataKey>(const LevelDBSlice& a, |
- const LevelDBSlice& b, |
- bool, |
- bool& ok) { |
- KeyPrefix prefix_a; |
- KeyPrefix prefix_b; |
- const char* ptr_a = KeyPrefix::Decode(a.begin(), a.end(), &prefix_a); |
- const char* ptr_b = KeyPrefix::Decode(b.begin(), b.end(), &prefix_b); |
- DCHECK(ptr_a); |
- DCHECK(ptr_b); |
- DCHECK(prefix_a.database_id_); |
- DCHECK(prefix_a.object_store_id_); |
- DCHECK_EQ(prefix_a.index_id_, ObjectStoreDataKey::kSpecialIndexNumber); |
- DCHECK(prefix_b.database_id_); |
- DCHECK(prefix_b.object_store_id_); |
- DCHECK_EQ(prefix_b.index_id_, ObjectStoreDataKey::kSpecialIndexNumber); |
- DCHECK_NE(ptr_a, a.end()); |
- DCHECK_NE(ptr_b, b.end()); |
- // Prefixes are not compared - it is assumed this was already done. |
- DCHECK(!prefix_a.Compare(prefix_b)); |
- |
- return CompareEncodedIDBKeys(ptr_a, a.end(), ptr_b, b.end(), ok); |
-} |
- |
-template <> |
-int Compare<IndexDataKey>(const LevelDBSlice& a, |
- const LevelDBSlice& b, |
- bool ignore_duplicates, |
- bool& ok) { |
- KeyPrefix prefix_a; |
- KeyPrefix prefix_b; |
- const char* ptr_a = KeyPrefix::Decode(a.begin(), a.end(), &prefix_a); |
- const char* ptr_b = KeyPrefix::Decode(b.begin(), b.end(), &prefix_b); |
- DCHECK(ptr_a); |
- DCHECK(ptr_b); |
- DCHECK(prefix_a.database_id_); |
- DCHECK(prefix_a.object_store_id_); |
- DCHECK_GE(prefix_a.index_id_, kMinimumIndexId); |
- DCHECK(prefix_b.database_id_); |
- DCHECK(prefix_b.object_store_id_); |
- DCHECK_GE(prefix_b.index_id_, kMinimumIndexId); |
- DCHECK_NE(ptr_a, a.end()); |
- DCHECK_NE(ptr_b, b.end()); |
- // Prefixes are not compared - it is assumed this was already done. |
- DCHECK(!prefix_a.Compare(prefix_b)); |
- |
- // index key |
- int result = CompareEncodedIDBKeys(ptr_a, a.end(), ptr_b, b.end(), ok); |
- if (!ok || result) |
- return result; |
- if (ignore_duplicates) |
- return 0; |
- |
- // sequence number [optional] |
- int64 sequence_number_a = -1; |
- int64 sequence_number_b = -1; |
- if (ptr_a != a.end()) |
- ptr_a = DecodeVarInt(ptr_a, a.end(), sequence_number_a); |
- if (ptr_b != b.end()) |
- ptr_b = DecodeVarInt(ptr_b, b.end(), sequence_number_b); |
- |
- // primary key [optional] |
- if (!ptr_a || !ptr_b) |
- return 0; |
- if (ptr_a == a.end() && ptr_b == b.end()) |
- return 0; |
- if (ptr_a == a.end()) |
- return -1; |
- if (ptr_b == b.end()) |
- return 1; |
- |
- result = CompareEncodedIDBKeys(ptr_a, a.end(), ptr_b, b.end(), ok); |
- if (!ok || result) |
- return result; |
- |
- return CompareInts(sequence_number_a, sequence_number_b); |
-} |
- |
-int Compare(const LevelDBSlice& a, |
- const LevelDBSlice& b, |
- bool index_keys, |
- bool& ok) { |
- const char* ptr_a = a.begin(); |
- const char* ptr_b = b.begin(); |
- const char* end_a = a.end(); |
- const char* end_b = b.end(); |
- |
- KeyPrefix prefix_a; |
- KeyPrefix prefix_b; |
- |
- ptr_a = KeyPrefix::Decode(ptr_a, end_a, &prefix_a); |
- ptr_b = KeyPrefix::Decode(ptr_b, end_b, &prefix_b); |
- DCHECK(ptr_a); |
- DCHECK(ptr_b); |
- if (!ptr_a || !ptr_b) { |
- ok = false; |
- return 0; |
- } |
- |
- ok = true; |
- if (int x = prefix_a.Compare(prefix_b)) |
- return x; |
- |
- if (prefix_a.type() == KeyPrefix::GLOBAL_METADATA) { |
- DCHECK_NE(ptr_a, end_a); |
- DCHECK_NE(ptr_b, end_b); |
- |
- unsigned char type_byte_a = *ptr_a++; |
- unsigned char type_byte_b = *ptr_b++; |
- |
- if (int x = type_byte_a - type_byte_b) |
- return x; |
- if (type_byte_a < kMaxSimpleGlobalMetaDataTypeByte) |
- return 0; |
- |
- const bool ignore_duplicates = false; |
- if (type_byte_a == kDatabaseFreeListTypeByte) |
- return Compare<DatabaseFreeListKey>(a, b, ignore_duplicates, ok); |
- if (type_byte_a == kDatabaseNameTypeByte) |
- return Compare<DatabaseNameKey>(a, b, ignore_duplicates, ok); |
- } |
- |
- if (prefix_a.type() == KeyPrefix::DATABASE_METADATA) { |
- DCHECK_NE(ptr_a, end_a); |
- DCHECK_NE(ptr_b, end_b); |
- |
- unsigned char type_byte_a = *ptr_a++; |
- unsigned char type_byte_b = *ptr_b++; |
- |
- if (int x = type_byte_a - type_byte_b) |
- return x; |
- if (type_byte_a < DatabaseMetaDataKey::MAX_SIMPLE_METADATA_TYPE) |
- return 0; |
- |
- const bool ignore_duplicates = false; |
- if (type_byte_a == kObjectStoreMetaDataTypeByte) |
- return Compare<ObjectStoreMetaDataKey>(a, b, ignore_duplicates, ok); |
- if (type_byte_a == kIndexMetaDataTypeByte) |
- return Compare<IndexMetaDataKey>(a, b, ignore_duplicates, ok); |
- if (type_byte_a == kObjectStoreFreeListTypeByte) |
- return Compare<ObjectStoreFreeListKey>(a, b, ignore_duplicates, ok); |
- if (type_byte_a == kIndexFreeListTypeByte) |
- return Compare<IndexFreeListKey>(a, b, ignore_duplicates, ok); |
- if (type_byte_a == kObjectStoreNamesTypeByte) |
- return Compare<ObjectStoreNamesKey>(a, b, ignore_duplicates, ok); |
- if (type_byte_a == kIndexNamesKeyTypeByte) |
- return Compare<IndexNamesKey>(a, b, ignore_duplicates, ok); |
- } |
- |
- if (prefix_a.type() == KeyPrefix::OBJECT_STORE_DATA) { |
- if (ptr_a == end_a && ptr_b == end_b) |
- return 0; |
- if (ptr_a == end_a) |
- return -1; |
- if (ptr_b == end_b) |
- return 1; // TODO(jsbell): This case of non-existing user keys should not |
- // have to be handled this way. |
- |
- const bool ignore_duplicates = false; |
- return Compare<ObjectStoreDataKey>(a, b, ignore_duplicates, ok); |
- } |
- if (prefix_a.type() == KeyPrefix::EXISTS_ENTRY) { |
- if (ptr_a == end_a && ptr_b == end_b) |
- return 0; |
- if (ptr_a == end_a) |
- return -1; |
- if (ptr_b == end_b) |
- return 1; // TODO(jsbell): This case of non-existing user keys should not |
- // have to be handled this way. |
- |
- const bool ignore_duplicates = false; |
- return Compare<ExistsEntryKey>(a, b, ignore_duplicates, ok); |
- } |
- if (prefix_a.type() == KeyPrefix::INDEX_DATA) { |
- if (ptr_a == end_a && ptr_b == end_b) |
- return 0; |
- if (ptr_a == end_a) |
- return -1; |
- if (ptr_b == end_b) |
- return 1; // TODO(jsbell): This case of non-existing user keys should not |
- // have to be handled this way. |
- |
- bool ignore_duplicates = index_keys; |
- return Compare<IndexDataKey>(a, b, ignore_duplicates, ok); |
- } |
- |
- NOTREACHED(); |
- ok = false; |
- return 0; |
-} |
- |
-} // namespace |
- |
-int Compare(const LevelDBSlice& a, const LevelDBSlice& b, bool index_keys) { |
- bool ok; |
- int result = Compare(a, b, index_keys, ok); |
- DCHECK(ok); |
- if (!ok) |
- return 0; |
- return result; |
-} |
- |
-KeyPrefix::KeyPrefix() |
- : database_id_(INVALID_TYPE), |
- object_store_id_(INVALID_TYPE), |
- index_id_(INVALID_TYPE) {} |
- |
-KeyPrefix::KeyPrefix(int64 database_id) |
- : database_id_(database_id), object_store_id_(0), index_id_(0) { |
- DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
-} |
- |
-KeyPrefix::KeyPrefix(int64 database_id, int64 object_store_id) |
- : database_id_(database_id), |
- object_store_id_(object_store_id), |
- index_id_(0) { |
- DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
- DCHECK(KeyPrefix::IsValidObjectStoreId(object_store_id)); |
-} |
- |
-KeyPrefix::KeyPrefix(int64 database_id, int64 object_store_id, int64 index_id) |
- : database_id_(database_id), |
- object_store_id_(object_store_id), |
- index_id_(index_id) { |
- DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
- DCHECK(KeyPrefix::IsValidObjectStoreId(object_store_id)); |
- DCHECK(KeyPrefix::IsValidIndexId(index_id)); |
-} |
- |
-KeyPrefix::KeyPrefix(enum Type type, |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id) |
- : database_id_(database_id), |
- object_store_id_(object_store_id), |
- index_id_(index_id) { |
- DCHECK_EQ(type, INVALID_TYPE); |
- DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
- DCHECK(KeyPrefix::IsValidObjectStoreId(object_store_id)); |
-} |
- |
-KeyPrefix KeyPrefix::CreateWithSpecialIndex(int64 database_id, |
- int64 object_store_id, |
- int64 index_id) { |
- DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); |
- DCHECK(KeyPrefix::IsValidObjectStoreId(object_store_id)); |
- DCHECK(index_id); |
- return KeyPrefix(INVALID_TYPE, database_id, object_store_id, index_id); |
-} |
- |
-bool KeyPrefix::IsValidDatabaseId(int64 database_id) { |
- return (database_id > 0) && (database_id < KeyPrefix::kMaxDatabaseId); |
-} |
- |
-bool KeyPrefix::IsValidObjectStoreId(int64 object_store_id) { |
- return (object_store_id > 0) && |
- (object_store_id < KeyPrefix::kMaxObjectStoreId); |
-} |
- |
-bool KeyPrefix::IsValidIndexId(int64 index_id) { |
- return (index_id >= kMinimumIndexId) && (index_id < KeyPrefix::kMaxIndexId); |
-} |
- |
-const char* KeyPrefix::Decode(const char* start, |
- const char* limit, |
- KeyPrefix* result) { |
- if (start == limit) |
- return 0; |
- |
- unsigned char first_byte = *start++; |
- |
- int database_id_bytes = ((first_byte >> 5) & 0x7) + 1; |
- int object_store_id_bytes = ((first_byte >> 2) & 0x7) + 1; |
- int index_id_bytes = (first_byte & 0x3) + 1; |
- |
- if (start + database_id_bytes + object_store_id_bytes + index_id_bytes > |
- limit) |
- return 0; |
- |
- result->database_id_ = DecodeInt(start, start + database_id_bytes); |
- start += database_id_bytes; |
- result->object_store_id_ = DecodeInt(start, start + object_store_id_bytes); |
- start += object_store_id_bytes; |
- result->index_id_ = DecodeInt(start, start + index_id_bytes); |
- start += index_id_bytes; |
- |
- return start; |
-} |
- |
-std::vector<char> KeyPrefix::EncodeEmpty() { |
- const std::vector<char> result(4, 0); |
- DCHECK(EncodeInternal(0, 0, 0) == std::vector<char>(4, 0)); |
- return result; |
-} |
- |
-std::vector<char> KeyPrefix::Encode() const { |
- DCHECK(database_id_ != kInvalidId); |
- DCHECK(object_store_id_ != kInvalidId); |
- DCHECK(index_id_ != kInvalidId); |
- return EncodeInternal(database_id_, object_store_id_, index_id_); |
-} |
- |
-std::vector<char> KeyPrefix::EncodeInternal(int64 database_id, |
- int64 object_store_id, |
- int64 index_id) { |
- std::vector<char> database_id_string = |
- EncodeIntSafely(database_id, kMaxDatabaseId); |
- std::vector<char> object_store_id_string = |
- EncodeIntSafely(object_store_id, kMaxObjectStoreId); |
- std::vector<char> index_id_string = EncodeIntSafely(index_id, kMaxIndexId); |
- |
- DCHECK(database_id_string.size() <= kMaxDatabaseIdSizeBytes); |
- DCHECK(object_store_id_string.size() <= kMaxObjectStoreIdSizeBytes); |
- DCHECK(index_id_string.size() <= kMaxIndexIdSizeBytes); |
- |
- unsigned char first_byte = |
- (database_id_string.size() - 1) |
- << (kMaxObjectStoreIdSizeBits + kMaxIndexIdSizeBits) | |
- (object_store_id_string.size() - 1) << kMaxIndexIdSizeBits | |
- (index_id_string.size() - 1); |
- COMPILE_ASSERT(kMaxDatabaseIdSizeBits + kMaxObjectStoreIdSizeBits + |
- kMaxIndexIdSizeBits == |
- sizeof(first_byte) * 8, |
- CANT_ENCODE_IDS); |
- std::vector<char> ret; |
- ret.reserve(kDefaultInlineBufferSize); |
- ret.push_back(first_byte); |
- ret.insert(ret.end(), database_id_string.begin(), database_id_string.end()); |
- ret.insert( |
- ret.end(), object_store_id_string.begin(), object_store_id_string.end()); |
- ret.insert(ret.end(), index_id_string.begin(), index_id_string.end()); |
- |
- DCHECK_LE(ret.size(), kDefaultInlineBufferSize); |
- return ret; |
-} |
- |
-int KeyPrefix::Compare(const KeyPrefix& other) const { |
- DCHECK(database_id_ != kInvalidId); |
- DCHECK(object_store_id_ != kInvalidId); |
- DCHECK(index_id_ != kInvalidId); |
- |
- if (database_id_ != other.database_id_) |
- return CompareInts(database_id_, other.database_id_); |
- if (object_store_id_ != other.object_store_id_) |
- return CompareInts(object_store_id_, other.object_store_id_); |
- if (index_id_ != other.index_id_) |
- return CompareInts(index_id_, other.index_id_); |
- return 0; |
-} |
- |
-KeyPrefix::Type KeyPrefix::type() const { |
- DCHECK(database_id_ != kInvalidId); |
- DCHECK(object_store_id_ != kInvalidId); |
- DCHECK(index_id_ != kInvalidId); |
- |
- if (!database_id_) |
- return GLOBAL_METADATA; |
- if (!object_store_id_) |
- return DATABASE_METADATA; |
- if (index_id_ == kObjectStoreDataIndexId) |
- return OBJECT_STORE_DATA; |
- if (index_id_ == kExistsEntryIndexId) |
- return EXISTS_ENTRY; |
- if (index_id_ >= kMinimumIndexId) |
- return INDEX_DATA; |
- |
- NOTREACHED(); |
- return INVALID_TYPE; |
-} |
- |
-std::vector<char> SchemaVersionKey::Encode() { |
- std::vector<char> ret = KeyPrefix::EncodeEmpty(); |
- ret.push_back(kSchemaVersionTypeByte); |
- return ret; |
-} |
- |
-std::vector<char> MaxDatabaseIdKey::Encode() { |
- std::vector<char> ret = KeyPrefix::EncodeEmpty(); |
- ret.push_back(kMaxDatabaseIdTypeByte); |
- return ret; |
-} |
- |
-std::vector<char> DataVersionKey::Encode() { |
- std::vector<char> ret = KeyPrefix::EncodeEmpty(); |
- ret.push_back(kDataVersionTypeByte); |
- return ret; |
-} |
- |
-DatabaseFreeListKey::DatabaseFreeListKey() : database_id_(-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; |
- DCHECK(!prefix.database_id_); |
- DCHECK(!prefix.object_store_id_); |
- DCHECK(!prefix.index_id_); |
- if (p == limit) |
- return 0; |
- unsigned char type_byte = 0; |
- p = DecodeByte(p, limit, type_byte); |
- DCHECK_EQ(type_byte, kDatabaseFreeListTypeByte); |
- if (p == limit) |
- return 0; |
- return DecodeVarInt(p, limit, result->database_id_); |
-} |
- |
-std::vector<char> DatabaseFreeListKey::Encode(int64 database_id) { |
- std::vector<char> ret = KeyPrefix::EncodeEmpty(); |
- ret.push_back(kDatabaseFreeListTypeByte); |
- std::vector<char> tmp = EncodeVarInt(database_id); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- return ret; |
-} |
- |
-std::vector<char> DatabaseFreeListKey::EncodeMaxKey() { |
- return Encode(std::numeric_limits<int64>::max()); |
-} |
- |
-int64 DatabaseFreeListKey::DatabaseId() const { |
- DCHECK_GE(database_id_, 0); |
- return database_id_; |
-} |
- |
-int DatabaseFreeListKey::Compare(const DatabaseFreeListKey& other) const { |
- DCHECK_GE(database_id_, 0); |
- return CompareInts(database_id_, other.database_id_); |
-} |
- |
-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; |
- DCHECK(!prefix.database_id_); |
- DCHECK(!prefix.object_store_id_); |
- DCHECK(!prefix.index_id_); |
- if (p == limit) |
- return 0; |
- unsigned char type_byte = 0; |
- p = DecodeByte(p, limit, type_byte); |
- DCHECK_EQ(type_byte, kDatabaseNameTypeByte); |
- if (p == limit) |
- return 0; |
- p = DecodeStringWithLength(p, limit, result->origin_); |
- if (!p) |
- return 0; |
- return DecodeStringWithLength(p, limit, result->database_name_); |
-} |
- |
-std::vector<char> DatabaseNameKey::Encode(const string16& origin, |
- const string16& database_name) { |
- std::vector<char> ret = KeyPrefix::EncodeEmpty(); |
- ret.push_back(kDatabaseNameTypeByte); |
- std::vector<char> tmp = EncodeStringWithLength(origin); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- tmp = EncodeStringWithLength(database_name); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- return ret; |
-} |
- |
-std::vector<char> DatabaseNameKey::EncodeMinKeyForOrigin( |
- const string16& origin) { |
- return Encode(origin, string16()); |
-} |
- |
-std::vector<char> DatabaseNameKey::EncodeStopKeyForOrigin( |
- const string16& origin) { |
- // just after origin in collation order |
- return EncodeMinKeyForOrigin(origin + base::char16('\x01')); |
-} |
- |
-int DatabaseNameKey::Compare(const DatabaseNameKey& other) { |
- if (int x = origin_.compare(other.origin_)) |
- return x; |
- return database_name_.compare(other.database_name_); |
-} |
- |
-std::vector<char> DatabaseMetaDataKey::Encode(int64 database_id, |
- MetaDataType meta_data_type) { |
- KeyPrefix prefix(database_id); |
- std::vector<char> ret = prefix.Encode(); |
- ret.push_back(meta_data_type); |
- return ret; |
-} |
- |
-ObjectStoreMetaDataKey::ObjectStoreMetaDataKey() |
- : object_store_id_(-1), meta_data_type_(-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; |
- DCHECK(prefix.database_id_); |
- DCHECK(!prefix.object_store_id_); |
- DCHECK(!prefix.index_id_); |
- if (p == limit) |
- return 0; |
- unsigned char type_byte = 0; |
- p = DecodeByte(p, limit, type_byte); |
- DCHECK_EQ(type_byte, kObjectStoreMetaDataTypeByte); |
- if (p == limit) |
- return 0; |
- p = DecodeVarInt(p, limit, result->object_store_id_); |
- if (!p) |
- return 0; |
- DCHECK(result->object_store_id_); |
- if (p == limit) |
- return 0; |
- return DecodeByte(p, limit, result->meta_data_type_); |
-} |
- |
-std::vector<char> ObjectStoreMetaDataKey::Encode(int64 database_id, |
- int64 object_store_id, |
- unsigned char meta_data_type) { |
- KeyPrefix prefix(database_id); |
- std::vector<char> ret = prefix.Encode(); |
- ret.push_back(kObjectStoreMetaDataTypeByte); |
- std::vector<char> tmp = EncodeVarInt(object_store_id); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- ret.push_back(meta_data_type); |
- return ret; |
-} |
- |
-std::vector<char> ObjectStoreMetaDataKey::EncodeMaxKey(int64 database_id) { |
- return Encode(database_id, |
- std::numeric_limits<int64>::max(), |
- kObjectMetaDataTypeMaximum); |
-} |
- |
-std::vector<char> ObjectStoreMetaDataKey::EncodeMaxKey(int64 database_id, |
- int64 object_store_id) { |
- return Encode(database_id, object_store_id, kObjectMetaDataTypeMaximum); |
-} |
- |
-int64 ObjectStoreMetaDataKey::ObjectStoreId() const { |
- DCHECK_GE(object_store_id_, 0); |
- return object_store_id_; |
-} |
-unsigned char ObjectStoreMetaDataKey::MetaDataType() const { |
- return meta_data_type_; |
-} |
- |
-int ObjectStoreMetaDataKey::Compare(const ObjectStoreMetaDataKey& other) { |
- DCHECK_GE(object_store_id_, 0); |
- if (int x = CompareInts(object_store_id_, other.object_store_id_)) |
- return x; |
- int64 result = meta_data_type_ - other.meta_data_type_; |
- if (result < 0) |
- return -1; |
- return (result > 0) ? 1 : result; |
-} |
- |
-IndexMetaDataKey::IndexMetaDataKey() |
- : object_store_id_(-1), index_id_(-1), meta_data_type_(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; |
- DCHECK(prefix.database_id_); |
- DCHECK(!prefix.object_store_id_); |
- DCHECK(!prefix.index_id_); |
- if (p == limit) |
- return 0; |
- unsigned char type_byte = 0; |
- p = DecodeByte(p, limit, type_byte); |
- DCHECK_EQ(type_byte, kIndexMetaDataTypeByte); |
- if (p == limit) |
- return 0; |
- p = DecodeVarInt(p, limit, result->object_store_id_); |
- if (!p) |
- return 0; |
- p = DecodeVarInt(p, limit, result->index_id_); |
- if (!p) |
- return 0; |
- if (p == limit) |
- return 0; |
- return DecodeByte(p, limit, result->meta_data_type_); |
-} |
- |
-std::vector<char> IndexMetaDataKey::Encode(int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- unsigned char meta_data_type) { |
- KeyPrefix prefix(database_id); |
- std::vector<char> ret = prefix.Encode(); |
- ret.push_back(kIndexMetaDataTypeByte); |
- std::vector<char> tmp = EncodeVarInt(object_store_id); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- tmp = EncodeVarInt(index_id); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- tmp = EncodeByte(meta_data_type); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- return ret; |
-} |
- |
-std::vector<char> IndexMetaDataKey::EncodeMaxKey(int64 database_id, |
- int64 object_store_id) { |
- return Encode(database_id, |
- object_store_id, |
- std::numeric_limits<int64>::max(), |
- kIndexMetaDataTypeMaximum); |
-} |
- |
-std::vector<char> IndexMetaDataKey::EncodeMaxKey(int64 database_id, |
- int64 object_store_id, |
- int64 index_id) { |
- return Encode( |
- database_id, object_store_id, index_id, kIndexMetaDataTypeMaximum); |
-} |
- |
-int IndexMetaDataKey::Compare(const IndexMetaDataKey& other) { |
- DCHECK_GE(object_store_id_, 0); |
- DCHECK_GE(index_id_, 0); |
- |
- if (int x = CompareInts(object_store_id_, other.object_store_id_)) |
- return x; |
- if (int x = CompareInts(index_id_, other.index_id_)) |
- return x; |
- return meta_data_type_ - other.meta_data_type_; |
-} |
- |
-int64 IndexMetaDataKey::IndexId() const { |
- DCHECK_GE(index_id_, 0); |
- return index_id_; |
-} |
- |
-ObjectStoreFreeListKey::ObjectStoreFreeListKey() : object_store_id_(-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; |
- DCHECK(prefix.database_id_); |
- DCHECK(!prefix.object_store_id_); |
- DCHECK(!prefix.index_id_); |
- if (p == limit) |
- return 0; |
- unsigned char type_byte = 0; |
- p = DecodeByte(p, limit, type_byte); |
- DCHECK_EQ(type_byte, kObjectStoreFreeListTypeByte); |
- if (p == limit) |
- return 0; |
- return DecodeVarInt(p, limit, result->object_store_id_); |
-} |
- |
-std::vector<char> ObjectStoreFreeListKey::Encode(int64 database_id, |
- int64 object_store_id) { |
- KeyPrefix prefix(database_id); |
- std::vector<char> ret = prefix.Encode(); |
- ret.push_back(kObjectStoreFreeListTypeByte); |
- std::vector<char> tmp = EncodeVarInt(object_store_id); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- return ret; |
-} |
- |
-std::vector<char> ObjectStoreFreeListKey::EncodeMaxKey(int64 database_id) { |
- return Encode(database_id, std::numeric_limits<int64>::max()); |
-} |
- |
-int64 ObjectStoreFreeListKey::ObjectStoreId() const { |
- DCHECK_GE(object_store_id_, 0); |
- return object_store_id_; |
-} |
- |
-int ObjectStoreFreeListKey::Compare(const ObjectStoreFreeListKey& other) { |
- // TODO(jsbell): It may seem strange that we're not comparing database id's, |
- // but that comparison will have been made earlier. |
- // We should probably make this more clear, though... |
- DCHECK_GE(object_store_id_, 0); |
- return CompareInts(object_store_id_, other.object_store_id_); |
-} |
- |
-IndexFreeListKey::IndexFreeListKey() : object_store_id_(-1), index_id_(-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; |
- DCHECK(prefix.database_id_); |
- DCHECK(!prefix.object_store_id_); |
- DCHECK(!prefix.index_id_); |
- if (p == limit) |
- return 0; |
- unsigned char type_byte = 0; |
- p = DecodeByte(p, limit, type_byte); |
- DCHECK_EQ(type_byte, kIndexFreeListTypeByte); |
- if (p == limit) |
- return 0; |
- p = DecodeVarInt(p, limit, result->object_store_id_); |
- if (!p) |
- return 0; |
- return DecodeVarInt(p, limit, result->index_id_); |
-} |
- |
-std::vector<char> IndexFreeListKey::Encode(int64 database_id, |
- int64 object_store_id, |
- int64 index_id) { |
- KeyPrefix prefix(database_id); |
- std::vector<char> ret = prefix.Encode(); |
- ret.push_back(kIndexFreeListTypeByte); |
- std::vector<char> tmp = EncodeVarInt(object_store_id); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- tmp = EncodeVarInt(index_id); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- return ret; |
-} |
- |
-std::vector<char> IndexFreeListKey::EncodeMaxKey(int64 database_id, |
- int64 object_store_id) { |
- return Encode( |
- database_id, object_store_id, std::numeric_limits<int64>::max()); |
-} |
- |
-int IndexFreeListKey::Compare(const IndexFreeListKey& other) { |
- DCHECK_GE(object_store_id_, 0); |
- DCHECK_GE(index_id_, 0); |
- if (int x = CompareInts(object_store_id_, other.object_store_id_)) |
- return x; |
- return CompareInts(index_id_, other.index_id_); |
-} |
- |
-int64 IndexFreeListKey::ObjectStoreId() const { |
- DCHECK_GE(object_store_id_, 0); |
- return object_store_id_; |
-} |
- |
-int64 IndexFreeListKey::IndexId() const { |
- DCHECK_GE(index_id_, 0); |
- return index_id_; |
-} |
- |
-// TODO(jsbell): We never use this to look up object store ids, |
-// because a mapping is kept in the IndexedDBDatabaseImpl. Can the |
-// mapping become unreliable? Can we remove this? |
-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; |
- DCHECK(prefix.database_id_); |
- DCHECK(!prefix.object_store_id_); |
- DCHECK(!prefix.index_id_); |
- if (p == limit) |
- return 0; |
- unsigned char type_byte = 0; |
- p = DecodeByte(p, limit, type_byte); |
- DCHECK_EQ(type_byte, kObjectStoreNamesTypeByte); |
- return DecodeStringWithLength(p, limit, result->object_store_name_); |
-} |
- |
-std::vector<char> ObjectStoreNamesKey::Encode( |
- int64 database_id, |
- const string16& object_store_name) { |
- KeyPrefix prefix(database_id); |
- std::vector<char> ret = prefix.Encode(); |
- ret.push_back(kObjectStoreNamesTypeByte); |
- std::vector<char> tmp = EncodeStringWithLength(object_store_name); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- return ret; |
-} |
- |
-int ObjectStoreNamesKey::Compare(const ObjectStoreNamesKey& other) { |
- return object_store_name_.compare(other.object_store_name_); |
-} |
- |
-IndexNamesKey::IndexNamesKey() : object_store_id_(-1) {} |
- |
-// TODO(jsbell): We never use this to look up index ids, because a mapping |
-// is kept at a higher level. |
-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; |
- DCHECK(prefix.database_id_); |
- DCHECK(!prefix.object_store_id_); |
- DCHECK(!prefix.index_id_); |
- if (p == limit) |
- return 0; |
- unsigned char type_byte = 0; |
- p = DecodeByte(p, limit, type_byte); |
- DCHECK_EQ(type_byte, kIndexNamesKeyTypeByte); |
- if (p == limit) |
- return 0; |
- p = DecodeVarInt(p, limit, result->object_store_id_); |
- if (!p) |
- return 0; |
- return DecodeStringWithLength(p, limit, result->index_name_); |
-} |
- |
-std::vector<char> IndexNamesKey::Encode(int64 database_id, |
- int64 object_store_id, |
- const string16& index_name) { |
- KeyPrefix prefix(database_id); |
- std::vector<char> ret = prefix.Encode(); |
- ret.push_back(kIndexNamesKeyTypeByte); |
- std::vector<char> tmp = EncodeVarInt(object_store_id); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- tmp = EncodeStringWithLength(index_name); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- return ret; |
-} |
- |
-int IndexNamesKey::Compare(const IndexNamesKey& other) { |
- DCHECK_GE(object_store_id_, 0); |
- if (int x = CompareInts(object_store_id_, other.object_store_id_)) |
- return x; |
- return index_name_.compare(other.index_name_); |
-} |
- |
-ObjectStoreDataKey::ObjectStoreDataKey() {} |
-ObjectStoreDataKey::~ObjectStoreDataKey() {} |
- |
-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; |
- DCHECK(prefix.database_id_); |
- DCHECK(prefix.object_store_id_); |
- DCHECK_EQ(prefix.index_id_, kSpecialIndexNumber); |
- if (p == end) |
- return 0; |
- return ExtractEncodedIDBKey(p, end, &result->encoded_user_key_); |
-} |
- |
-std::vector<char> ObjectStoreDataKey::Encode( |
- int64 database_id, |
- int64 object_store_id, |
- const std::vector<char> encoded_user_key) { |
- KeyPrefix prefix(KeyPrefix::CreateWithSpecialIndex( |
- database_id, object_store_id, kSpecialIndexNumber)); |
- std::vector<char> ret = prefix.Encode(); |
- ret.insert(ret.end(), encoded_user_key.begin(), encoded_user_key.end()); |
- |
- return ret; |
-} |
- |
-std::vector<char> ObjectStoreDataKey::Encode(int64 database_id, |
- int64 object_store_id, |
- const IndexedDBKey& user_key) { |
- return Encode(database_id, object_store_id, EncodeIDBKey(user_key)); |
-} |
- |
-int ObjectStoreDataKey::Compare(const ObjectStoreDataKey& other, bool& ok) { |
- return CompareEncodedIDBKeys(encoded_user_key_, other.encoded_user_key_, ok); |
-} |
- |
-scoped_ptr<IndexedDBKey> ObjectStoreDataKey::user_key() const { |
- scoped_ptr<IndexedDBKey> key; |
- DecodeIDBKey(&encoded_user_key_[0], |
- &encoded_user_key_[0] + encoded_user_key_.size(), |
- &key); |
- return key.Pass(); |
-} |
- |
-const int64 ObjectStoreDataKey::kSpecialIndexNumber = kObjectStoreDataIndexId; |
- |
-ExistsEntryKey::ExistsEntryKey() {} |
-ExistsEntryKey::~ExistsEntryKey() {} |
- |
-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; |
- DCHECK(prefix.database_id_); |
- DCHECK(prefix.object_store_id_); |
- DCHECK_EQ(prefix.index_id_, kSpecialIndexNumber); |
- if (p == end) |
- return 0; |
- return ExtractEncodedIDBKey(p, end, &result->encoded_user_key_); |
-} |
- |
-std::vector<char> ExistsEntryKey::Encode(int64 database_id, |
- int64 object_store_id, |
- const std::vector<char>& encoded_key) { |
- KeyPrefix prefix(KeyPrefix::CreateWithSpecialIndex( |
- database_id, object_store_id, kSpecialIndexNumber)); |
- std::vector<char> ret = prefix.Encode(); |
- ret.insert(ret.end(), encoded_key.begin(), encoded_key.end()); |
- return ret; |
-} |
- |
-std::vector<char> ExistsEntryKey::Encode(int64 database_id, |
- int64 object_store_id, |
- const IndexedDBKey& user_key) { |
- return Encode(database_id, object_store_id, EncodeIDBKey(user_key)); |
-} |
- |
-int ExistsEntryKey::Compare(const ExistsEntryKey& other, bool& ok) { |
- return CompareEncodedIDBKeys(encoded_user_key_, other.encoded_user_key_, ok); |
-} |
- |
-scoped_ptr<IndexedDBKey> ExistsEntryKey::user_key() const { |
- scoped_ptr<IndexedDBKey> key; |
- DecodeIDBKey(&encoded_user_key_[0], |
- &encoded_user_key_[0] + encoded_user_key_.size(), |
- &key); |
- return key.Pass(); |
-} |
- |
-const int64 ExistsEntryKey::kSpecialIndexNumber = kExistsEntryIndexId; |
- |
-IndexDataKey::IndexDataKey() |
- : database_id_(-1), |
- object_store_id_(-1), |
- index_id_(-1), |
- sequence_number_(-1) {} |
- |
-IndexDataKey::~IndexDataKey() {} |
- |
-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; |
- DCHECK(prefix.database_id_); |
- DCHECK(prefix.object_store_id_); |
- DCHECK_GE(prefix.index_id_, kMinimumIndexId); |
- result->database_id_ = prefix.database_id_; |
- result->object_store_id_ = prefix.object_store_id_; |
- result->index_id_ = prefix.index_id_; |
- result->sequence_number_ = -1; |
- result->encoded_primary_key_ = MinIDBKey(); |
- |
- p = ExtractEncodedIDBKey(p, limit, &result->encoded_user_key_); |
- if (!p) |
- return 0; |
- |
- // [optional] sequence number |
- if (p == limit) |
- return p; |
- p = DecodeVarInt(p, limit, result->sequence_number_); |
- if (!p) |
- return 0; |
- |
- // [optional] primary key |
- if (p == limit) |
- return p; |
- p = ExtractEncodedIDBKey(p, limit, &result->encoded_primary_key_); |
- if (!p) |
- return 0; |
- |
- return p; |
-} |
- |
-std::vector<char> IndexDataKey::Encode( |
- int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const std::vector<char>& encoded_user_key, |
- const std::vector<char>& encoded_primary_key, |
- int64 sequence_number) { |
- KeyPrefix prefix(database_id, object_store_id, index_id); |
- std::vector<char> ret = prefix.Encode(); |
- ret.insert(ret.end(), encoded_user_key.begin(), encoded_user_key.end()); |
- std::vector<char> tmp = EncodeVarInt(sequence_number); |
- ret.insert(ret.end(), tmp.begin(), tmp.end()); |
- ret.insert(ret.end(), encoded_primary_key.begin(), encoded_primary_key.end()); |
- return ret; |
-} |
- |
-std::vector<char> IndexDataKey::Encode(int64 database_id, |
- int64 object_store_id, |
- int64 index_id, |
- const IndexedDBKey& user_key) { |
- return Encode(database_id, |
- object_store_id, |
- index_id, |
- EncodeIDBKey(user_key), |
- MinIDBKey()); |
-} |
- |
-std::vector<char> IndexDataKey::EncodeMinKey(int64 database_id, |
- int64 object_store_id, |
- int64 index_id) { |
- return Encode( |
- database_id, object_store_id, index_id, MinIDBKey(), MinIDBKey()); |
-} |
- |
-std::vector<char> IndexDataKey::EncodeMaxKey(int64 database_id, |
- int64 object_store_id, |
- int64 index_id) { |
- return Encode(database_id, |
- object_store_id, |
- index_id, |
- MaxIDBKey(), |
- MaxIDBKey(), |
- std::numeric_limits<int64>::max()); |
-} |
- |
-int IndexDataKey::Compare(const IndexDataKey& other, |
- bool ignore_duplicates, |
- bool& ok) { |
- DCHECK_GE(database_id_, 0); |
- DCHECK_GE(object_store_id_, 0); |
- DCHECK_GE(index_id_, 0); |
- int result = |
- CompareEncodedIDBKeys(encoded_user_key_, other.encoded_user_key_, ok); |
- if (!ok || result) |
- return result; |
- if (ignore_duplicates) |
- return 0; |
- result = CompareEncodedIDBKeys( |
- encoded_primary_key_, other.encoded_primary_key_, ok); |
- if (!ok || result) |
- return result; |
- return CompareInts(sequence_number_, other.sequence_number_); |
-} |
- |
-int64 IndexDataKey::DatabaseId() const { |
- DCHECK_GE(database_id_, 0); |
- return database_id_; |
-} |
- |
-int64 IndexDataKey::ObjectStoreId() const { |
- DCHECK_GE(object_store_id_, 0); |
- return object_store_id_; |
-} |
- |
-int64 IndexDataKey::IndexId() const { |
- DCHECK_GE(index_id_, 0); |
- return index_id_; |
-} |
- |
-scoped_ptr<IndexedDBKey> IndexDataKey::user_key() const { |
- scoped_ptr<IndexedDBKey> key; |
- DecodeIDBKey(&encoded_user_key_[0], |
- &encoded_user_key_[0] + encoded_user_key_.size(), |
- &key); |
- return key.Pass(); |
-} |
- |
-scoped_ptr<IndexedDBKey> IndexDataKey::primary_key() const { |
- scoped_ptr<IndexedDBKey> key; |
- DecodeIDBKey(&encoded_primary_key_[0], |
- &encoded_primary_key_[0] + encoded_primary_key_.size(), |
- &key); |
- return key.Pass(); |
-} |
- |
-} // namespace content |