dfindexeddb 20241031__py3-none-any.whl → 20251109__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dfindexeddb/indexeddb/chromium/blink.py +116 -74
- dfindexeddb/indexeddb/chromium/definitions.py +152 -124
- dfindexeddb/indexeddb/chromium/record.py +536 -348
- dfindexeddb/indexeddb/chromium/v8.py +112 -141
- dfindexeddb/indexeddb/cli.py +125 -114
- dfindexeddb/indexeddb/firefox/definitions.py +7 -4
- dfindexeddb/indexeddb/firefox/gecko.py +103 -79
- dfindexeddb/indexeddb/firefox/record.py +66 -24
- dfindexeddb/indexeddb/safari/definitions.py +12 -10
- dfindexeddb/indexeddb/safari/record.py +68 -51
- dfindexeddb/indexeddb/safari/webkit.py +112 -189
- dfindexeddb/indexeddb/types.py +5 -2
- dfindexeddb/leveldb/cli.py +146 -131
- dfindexeddb/leveldb/definitions.py +6 -2
- dfindexeddb/leveldb/descriptor.py +75 -45
- dfindexeddb/leveldb/ldb.py +39 -30
- dfindexeddb/leveldb/log.py +44 -27
- dfindexeddb/leveldb/plugins/chrome_notifications.py +30 -18
- dfindexeddb/leveldb/plugins/interface.py +5 -6
- dfindexeddb/leveldb/plugins/manager.py +11 -10
- dfindexeddb/leveldb/record.py +71 -62
- dfindexeddb/leveldb/utils.py +21 -13
- dfindexeddb/utils.py +35 -30
- dfindexeddb/version.py +2 -2
- dfindexeddb-20251109.dist-info/METADATA +222 -0
- dfindexeddb-20251109.dist-info/RECORD +40 -0
- {dfindexeddb-20241031.dist-info → dfindexeddb-20251109.dist-info}/WHEEL +1 -1
- dfindexeddb-20241031.dist-info/AUTHORS +0 -12
- dfindexeddb-20241031.dist-info/METADATA +0 -424
- dfindexeddb-20241031.dist-info/RECORD +0 -41
- {dfindexeddb-20241031.dist-info → dfindexeddb-20251109.dist-info}/entry_points.txt +0 -0
- {dfindexeddb-20241031.dist-info → dfindexeddb-20251109.dist-info/licenses}/LICENSE +0 -0
- {dfindexeddb-20241031.dist-info → dfindexeddb-20251109.dist-info}/top_level.txt +0 -0
|
@@ -14,26 +14,32 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
"""Parses Chromium IndexedDb structures."""
|
|
16
16
|
from __future__ import annotations
|
|
17
|
-
|
|
18
|
-
from datetime import datetime
|
|
17
|
+
|
|
19
18
|
import io
|
|
20
19
|
import pathlib
|
|
21
20
|
import sys
|
|
22
21
|
import traceback
|
|
23
|
-
from
|
|
24
|
-
|
|
22
|
+
from dataclasses import dataclass, field
|
|
23
|
+
from datetime import datetime
|
|
24
|
+
from typing import (
|
|
25
|
+
Any,
|
|
26
|
+
BinaryIO,
|
|
27
|
+
Generator,
|
|
28
|
+
Optional,
|
|
29
|
+
Tuple,
|
|
30
|
+
Type,
|
|
31
|
+
TypeVar,
|
|
32
|
+
Union,
|
|
33
|
+
)
|
|
25
34
|
|
|
26
35
|
from dfindexeddb import errors
|
|
27
|
-
from dfindexeddb.indexeddb.chromium import blink
|
|
28
|
-
from dfindexeddb.
|
|
29
|
-
from dfindexeddb.leveldb import record
|
|
30
|
-
from dfindexeddb.leveldb import utils
|
|
31
|
-
|
|
36
|
+
from dfindexeddb.indexeddb.chromium import blink, definitions
|
|
37
|
+
from dfindexeddb.leveldb import record, utils
|
|
32
38
|
|
|
33
|
-
T = TypeVar(
|
|
39
|
+
T = TypeVar("T")
|
|
34
40
|
|
|
35
41
|
|
|
36
|
-
@dataclass
|
|
42
|
+
@dataclass(frozen=True)
|
|
37
43
|
class KeyPrefix(utils.FromDecoderMixin):
|
|
38
44
|
"""The IndexedDB key prefix.
|
|
39
45
|
|
|
@@ -43,6 +49,7 @@ class KeyPrefix(utils.FromDecoderMixin):
|
|
|
43
49
|
object_store_id: the object store ID.
|
|
44
50
|
index_id: the index ID.
|
|
45
51
|
"""
|
|
52
|
+
|
|
46
53
|
offset: int = field(compare=False)
|
|
47
54
|
database_id: int
|
|
48
55
|
object_store_id: int
|
|
@@ -50,7 +57,8 @@ class KeyPrefix(utils.FromDecoderMixin):
|
|
|
50
57
|
|
|
51
58
|
@classmethod
|
|
52
59
|
def FromDecoder(
|
|
53
|
-
cls, decoder: utils.LevelDBDecoder, base_offset: int = 0
|
|
60
|
+
cls, decoder: utils.LevelDBDecoder, base_offset: int = 0
|
|
61
|
+
) -> KeyPrefix:
|
|
54
62
|
"""Decodes a KeyPrefix from the current position of a LevelDBDecoder.
|
|
55
63
|
|
|
56
64
|
Args:
|
|
@@ -71,23 +79,24 @@ class KeyPrefix(utils.FromDecoderMixin):
|
|
|
71
79
|
index_id_length = (raw_prefix[0] & 0x03) + 1
|
|
72
80
|
|
|
73
81
|
if database_id_length < 1 or database_id_length > 8:
|
|
74
|
-
raise errors.ParserError(
|
|
82
|
+
raise errors.ParserError("Invalid database ID length")
|
|
75
83
|
|
|
76
84
|
if object_store_id_length < 1 or object_store_id_length > 8:
|
|
77
|
-
raise errors.ParserError(
|
|
85
|
+
raise errors.ParserError("Invalid object store ID length")
|
|
78
86
|
|
|
79
87
|
if index_id_length < 1 or index_id_length > 4:
|
|
80
|
-
raise errors.ParserError(
|
|
88
|
+
raise errors.ParserError("Invalid index ID length")
|
|
81
89
|
|
|
82
|
-
_, database_id = decoder.DecodeInt(database_id_length)
|
|
83
|
-
_, object_store_id = decoder.DecodeInt(object_store_id_length)
|
|
84
|
-
_, index_id = decoder.DecodeInt(index_id_length)
|
|
90
|
+
_, database_id = decoder.DecodeInt(database_id_length, signed=False)
|
|
91
|
+
_, object_store_id = decoder.DecodeInt(object_store_id_length, signed=False)
|
|
92
|
+
_, index_id = decoder.DecodeInt(index_id_length, signed=False)
|
|
85
93
|
|
|
86
94
|
return cls(
|
|
87
95
|
offset=base_offset + offset,
|
|
88
96
|
database_id=database_id,
|
|
89
97
|
object_store_id=object_store_id,
|
|
90
|
-
index_id=index_id
|
|
98
|
+
index_id=index_id,
|
|
99
|
+
)
|
|
91
100
|
|
|
92
101
|
def GetKeyPrefixType(self) -> definitions.KeyPrefixType:
|
|
93
102
|
"""Returns the KeyPrefixType.
|
|
@@ -110,7 +119,8 @@ class KeyPrefix(utils.FromDecoderMixin):
|
|
|
110
119
|
if self.index_id >= 30:
|
|
111
120
|
return definitions.KeyPrefixType.INDEX_DATA
|
|
112
121
|
raise errors.ParserError(
|
|
113
|
-
f
|
|
122
|
+
f"Unknown KeyPrefixType (index_id={self.index_id})"
|
|
123
|
+
)
|
|
114
124
|
|
|
115
125
|
|
|
116
126
|
@dataclass
|
|
@@ -122,9 +132,10 @@ class IDBKey(utils.FromDecoderMixin):
|
|
|
122
132
|
type: the type of the IDBKey.
|
|
123
133
|
value: the value of the IDBKey.
|
|
124
134
|
"""
|
|
135
|
+
|
|
125
136
|
offset: int = field(compare=False)
|
|
126
137
|
type: definitions.IDBKeyType
|
|
127
|
-
value: Union[list, bytes, str, float, datetime, None]
|
|
138
|
+
value: Union[list[Any], bytes, str, float, datetime, None]
|
|
128
139
|
|
|
129
140
|
_MAXIMUM_DEPTH = 2000
|
|
130
141
|
|
|
@@ -132,7 +143,7 @@ class IDBKey(utils.FromDecoderMixin):
|
|
|
132
143
|
def FromDecoder(
|
|
133
144
|
cls,
|
|
134
145
|
decoder: utils.LevelDBDecoder,
|
|
135
|
-
base_offset: int = 0 #pylint: disable=unused-argument
|
|
146
|
+
base_offset: int = 0, # pylint: disable=unused-argument
|
|
136
147
|
) -> IDBKey:
|
|
137
148
|
"""Decodes an IDBKey from the current position of a LevelDBDecoder.
|
|
138
149
|
|
|
@@ -149,9 +160,13 @@ class IDBKey(utils.FromDecoderMixin):
|
|
|
149
160
|
RecursionError: if maximum depth encountered during parsing.
|
|
150
161
|
"""
|
|
151
162
|
|
|
152
|
-
def RecursiveParse(
|
|
153
|
-
int,
|
|
154
|
-
|
|
163
|
+
def RecursiveParse(
|
|
164
|
+
depth: int,
|
|
165
|
+
) -> Tuple[
|
|
166
|
+
int,
|
|
167
|
+
definitions.IDBKeyType,
|
|
168
|
+
Union[list[Any], bytes, str, float, datetime, None],
|
|
169
|
+
]:
|
|
155
170
|
"""Recursively parses IDBKeys.
|
|
156
171
|
|
|
157
172
|
Args:
|
|
@@ -167,16 +182,17 @@ class IDBKey(utils.FromDecoderMixin):
|
|
|
167
182
|
RecursionError: if maximum depth encountered during parsing.
|
|
168
183
|
"""
|
|
169
184
|
if depth == cls._MAXIMUM_DEPTH:
|
|
170
|
-
raise RecursionError(
|
|
185
|
+
raise RecursionError("Maximum recursion depth encountered during parse")
|
|
171
186
|
offset, key_type_value = decoder.DecodeInt(1)
|
|
172
187
|
key_type = definitions.IDBKeyType(key_type_value)
|
|
188
|
+
value: Any = None
|
|
173
189
|
|
|
174
190
|
if key_type == definitions.IDBKeyType.NULL:
|
|
175
191
|
value = None
|
|
176
192
|
elif key_type == definitions.IDBKeyType.ARRAY:
|
|
177
193
|
_, length = decoder.DecodeVarint()
|
|
178
194
|
if length < 0:
|
|
179
|
-
raise errors.ParserError(
|
|
195
|
+
raise errors.ParserError("Invalid length encountered")
|
|
180
196
|
value = []
|
|
181
197
|
while length:
|
|
182
198
|
entry = RecursiveParse(depth + 1)
|
|
@@ -188,13 +204,13 @@ class IDBKey(utils.FromDecoderMixin):
|
|
|
188
204
|
_, value = decoder.DecodeStringWithLength()
|
|
189
205
|
elif key_type == definitions.IDBKeyType.DATE:
|
|
190
206
|
_, raw_value = decoder.DecodeDouble()
|
|
191
|
-
value = datetime.utcfromtimestamp(raw_value/1000.0)
|
|
207
|
+
value = datetime.utcfromtimestamp(raw_value / 1000.0)
|
|
192
208
|
elif key_type == definitions.IDBKeyType.NUMBER:
|
|
193
209
|
_, value = decoder.DecodeDouble()
|
|
194
210
|
elif key_type == definitions.IDBKeyType.MIN_KEY:
|
|
195
211
|
value = None
|
|
196
212
|
else:
|
|
197
|
-
raise errors.ParserError(
|
|
213
|
+
raise errors.ParserError("Invalid IndexedDbKeyType")
|
|
198
214
|
return offset, key_type, value
|
|
199
215
|
|
|
200
216
|
offset, key_type, value = RecursiveParse(0)
|
|
@@ -210,13 +226,15 @@ class IDBKeyPath(utils.FromDecoderMixin):
|
|
|
210
226
|
type: the IDBKeyPath type.
|
|
211
227
|
value: the IDBKeyPath value.
|
|
212
228
|
"""
|
|
229
|
+
|
|
213
230
|
offset: int = field(compare=False)
|
|
214
231
|
type: definitions.IDBKeyPathType
|
|
215
232
|
value: Union[str, list[str], None]
|
|
216
233
|
|
|
217
234
|
@classmethod
|
|
218
|
-
def FromDecoder(
|
|
219
|
-
|
|
235
|
+
def FromDecoder(
|
|
236
|
+
cls, decoder: utils.LevelDBDecoder, base_offset: int = 0
|
|
237
|
+
) -> IDBKeyPath:
|
|
220
238
|
"""Decodes an IDBKeyPath from the current position of a LevelDBDecoder.
|
|
221
239
|
|
|
222
240
|
Args:
|
|
@@ -228,13 +246,15 @@ class IDBKeyPath(utils.FromDecoderMixin):
|
|
|
228
246
|
|
|
229
247
|
Raises:
|
|
230
248
|
ParserError: on insufficient bytes or invalid array length during
|
|
231
|
-
parsing.
|
|
249
|
+
parsing or unsupported key path type.
|
|
232
250
|
"""
|
|
233
|
-
buffer = decoder.stream.getvalue() #
|
|
251
|
+
buffer = decoder.stream.getvalue() # type: ignore[attr-defined]
|
|
234
252
|
if len(buffer) < 3:
|
|
235
|
-
raise errors.ParserError(
|
|
253
|
+
raise errors.ParserError("Insufficient bytes to parse.")
|
|
254
|
+
|
|
255
|
+
value: str | list[str] | None = None
|
|
236
256
|
|
|
237
|
-
if buffer[0:2] != b
|
|
257
|
+
if buffer[0:2] != b"\x00\x00":
|
|
238
258
|
offset, value = decoder.DecodeString()
|
|
239
259
|
return IDBKeyPath(offset, definitions.IDBKeyPathType.STRING, value)
|
|
240
260
|
|
|
@@ -251,10 +271,12 @@ class IDBKeyPath(utils.FromDecoderMixin):
|
|
|
251
271
|
value = []
|
|
252
272
|
offset, count = decoder.DecodeVarint()
|
|
253
273
|
if count < 0:
|
|
254
|
-
raise errors.ParserError(f
|
|
274
|
+
raise errors.ParserError(f"Invalid array length {count}")
|
|
255
275
|
for _ in range(count):
|
|
256
276
|
_, entry = decoder.DecodeStringWithLength()
|
|
257
277
|
value.append(entry)
|
|
278
|
+
else:
|
|
279
|
+
raise errors.ParserError(f"Unsupported key_path_type {key_path_type}.")
|
|
258
280
|
return IDBKeyPath(base_offset + offset, key_path_type, value)
|
|
259
281
|
|
|
260
282
|
|
|
@@ -267,13 +289,15 @@ class BlobJournalEntry(utils.FromDecoderMixin):
|
|
|
267
289
|
database_id (int): the database ID.
|
|
268
290
|
blob_number (int): the blob number.
|
|
269
291
|
"""
|
|
292
|
+
|
|
270
293
|
offset: int = field(compare=False)
|
|
271
294
|
database_id: int
|
|
272
295
|
blob_number: int
|
|
273
296
|
|
|
274
297
|
@classmethod
|
|
275
|
-
def FromDecoder(
|
|
276
|
-
|
|
298
|
+
def FromDecoder(
|
|
299
|
+
cls, decoder: utils.LevelDBDecoder, base_offset: int = 0
|
|
300
|
+
) -> BlobJournalEntry:
|
|
277
301
|
"""Decodes a BlobJournalEntry from the current position of a LevelDBDecoder.
|
|
278
302
|
|
|
279
303
|
Args:
|
|
@@ -285,8 +309,11 @@ class BlobJournalEntry(utils.FromDecoderMixin):
|
|
|
285
309
|
"""
|
|
286
310
|
offset, database_id = decoder.DecodeUint64Varint()
|
|
287
311
|
_, blob_number = decoder.DecodeUint64Varint()
|
|
288
|
-
return cls(
|
|
289
|
-
|
|
312
|
+
return cls(
|
|
313
|
+
offset=base_offset + offset,
|
|
314
|
+
database_id=database_id,
|
|
315
|
+
blob_number=blob_number,
|
|
316
|
+
)
|
|
290
317
|
|
|
291
318
|
|
|
292
319
|
@dataclass
|
|
@@ -297,12 +324,14 @@ class BlobJournal(utils.FromDecoderMixin):
|
|
|
297
324
|
offset (int): the offset.
|
|
298
325
|
entries (list[BlobJournalEntry]): the list of blob journal entries.
|
|
299
326
|
"""
|
|
327
|
+
|
|
300
328
|
offset: int = field(compare=False)
|
|
301
329
|
entries: list[BlobJournalEntry]
|
|
302
330
|
|
|
303
331
|
@classmethod
|
|
304
|
-
def FromDecoder(
|
|
305
|
-
|
|
332
|
+
def FromDecoder(
|
|
333
|
+
cls, decoder: utils.LevelDBDecoder, base_offset: int = 0
|
|
334
|
+
) -> BlobJournal:
|
|
306
335
|
"""Decodes a BlobJournal from the current position of a LevelDBDecoder.
|
|
307
336
|
|
|
308
337
|
Blob journals are zero-or-more instances of BlobJournalEntry. There is no
|
|
@@ -342,6 +371,7 @@ class BaseIndexedDBKey:
|
|
|
342
371
|
offset: the offset of the key (after the key_prefix).
|
|
343
372
|
key_prefix: the key prefix.
|
|
344
373
|
"""
|
|
374
|
+
|
|
345
375
|
offset: int
|
|
346
376
|
key_prefix: KeyPrefix
|
|
347
377
|
|
|
@@ -356,7 +386,7 @@ class BaseIndexedDBKey:
|
|
|
356
386
|
Raises:
|
|
357
387
|
NotImplementedError.
|
|
358
388
|
"""
|
|
359
|
-
raise NotImplementedError(f
|
|
389
|
+
raise NotImplementedError(f"{self.__class__.__name__}.decode_value")
|
|
360
390
|
|
|
361
391
|
def ParseValue(self, value_data: bytes) -> Any:
|
|
362
392
|
"""Parses the value from raw bytes.
|
|
@@ -374,11 +404,11 @@ class BaseIndexedDBKey:
|
|
|
374
404
|
|
|
375
405
|
@classmethod
|
|
376
406
|
def FromDecoder(
|
|
377
|
-
cls: T,
|
|
407
|
+
cls: Type[T],
|
|
378
408
|
decoder: utils.LevelDBDecoder,
|
|
379
409
|
key_prefix: KeyPrefix,
|
|
380
|
-
base_offset: int = 0
|
|
381
|
-
) -> T: #pylint: disable=unused-variable
|
|
410
|
+
base_offset: int = 0,
|
|
411
|
+
) -> T: # pylint: disable=unused-variable
|
|
382
412
|
"""Decodes the remaining key data from the current decoder position.
|
|
383
413
|
|
|
384
414
|
Args:
|
|
@@ -392,11 +422,10 @@ class BaseIndexedDBKey:
|
|
|
392
422
|
Raises:
|
|
393
423
|
NotImplementedError.
|
|
394
424
|
"""
|
|
395
|
-
raise NotImplementedError(f
|
|
425
|
+
raise NotImplementedError(f"{cls.__class__.__name__}.decode_key")
|
|
396
426
|
|
|
397
427
|
@classmethod
|
|
398
|
-
def FromStream(
|
|
399
|
-
cls: Type[T], stream: BinaryIO, base_offset: int = 0) -> T:
|
|
428
|
+
def FromStream(cls: Type[T], stream: BinaryIO, base_offset: int = 0) -> T:
|
|
400
429
|
"""Parses the key from the current position of the binary stream.
|
|
401
430
|
|
|
402
431
|
Args:
|
|
@@ -408,12 +437,12 @@ class BaseIndexedDBKey:
|
|
|
408
437
|
"""
|
|
409
438
|
decoder = utils.LevelDBDecoder(stream)
|
|
410
439
|
key_prefix = KeyPrefix.FromDecoder(decoder, base_offset=base_offset)
|
|
411
|
-
return cls.FromDecoder(
|
|
412
|
-
decoder=decoder, key_prefix=key_prefix, base_offset=base_offset
|
|
440
|
+
return cls.FromDecoder( # type: ignore[no-any-return,attr-defined]
|
|
441
|
+
decoder=decoder, key_prefix=key_prefix, base_offset=base_offset
|
|
442
|
+
)
|
|
413
443
|
|
|
414
444
|
@classmethod
|
|
415
|
-
def FromBytes(
|
|
416
|
-
cls: Type[T], raw_data: bytes, base_offset: int = 0) -> T:
|
|
445
|
+
def FromBytes(cls: Type[T], raw_data: bytes, base_offset: int = 0) -> T:
|
|
417
446
|
"""Parses the key from the raw key bytes.
|
|
418
447
|
|
|
419
448
|
Args:
|
|
@@ -424,7 +453,9 @@ class BaseIndexedDBKey:
|
|
|
424
453
|
The decoded key.
|
|
425
454
|
"""
|
|
426
455
|
stream = io.BytesIO(raw_data)
|
|
427
|
-
return cls.FromStream(
|
|
456
|
+
return cls.FromStream( # type: ignore[no-any-return,attr-defined]
|
|
457
|
+
stream=stream, base_offset=base_offset
|
|
458
|
+
)
|
|
428
459
|
|
|
429
460
|
|
|
430
461
|
@dataclass
|
|
@@ -433,17 +464,19 @@ class SchemaVersionKey(BaseIndexedDBKey):
|
|
|
433
464
|
|
|
434
465
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
435
466
|
"""Decodes the schema version value."""
|
|
436
|
-
return decoder.
|
|
467
|
+
return decoder.DecodeInt()[1]
|
|
437
468
|
|
|
438
469
|
@classmethod
|
|
439
470
|
def FromDecoder(
|
|
440
|
-
cls,
|
|
441
|
-
|
|
471
|
+
cls,
|
|
472
|
+
decoder: utils.LevelDBDecoder,
|
|
473
|
+
key_prefix: KeyPrefix,
|
|
474
|
+
base_offset: int = 0,
|
|
442
475
|
) -> SchemaVersionKey:
|
|
443
476
|
"""Decodes the schema version key."""
|
|
444
477
|
offset, key_type = decoder.DecodeUint8()
|
|
445
478
|
if key_type != definitions.GlobalMetadataKeyType.SCHEMA_VERSION:
|
|
446
|
-
raise errors.ParserError(
|
|
479
|
+
raise errors.ParserError("Not a SchemaVersionKey")
|
|
447
480
|
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
448
481
|
|
|
449
482
|
|
|
@@ -453,17 +486,19 @@ class MaxDatabaseIdKey(BaseIndexedDBKey):
|
|
|
453
486
|
|
|
454
487
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
455
488
|
"""Decodes the maximum database value."""
|
|
456
|
-
return decoder.
|
|
489
|
+
return decoder.DecodeInt()[1]
|
|
457
490
|
|
|
458
491
|
@classmethod
|
|
459
492
|
def FromDecoder(
|
|
460
|
-
cls,
|
|
461
|
-
|
|
493
|
+
cls,
|
|
494
|
+
decoder: utils.LevelDBDecoder,
|
|
495
|
+
key_prefix: KeyPrefix,
|
|
496
|
+
base_offset: int = 0,
|
|
462
497
|
) -> MaxDatabaseIdKey:
|
|
463
498
|
"""Decodes the maximum database key."""
|
|
464
499
|
offset, key_type = decoder.DecodeUint8()
|
|
465
500
|
if key_type != definitions.GlobalMetadataKeyType.MAX_DATABASE_ID:
|
|
466
|
-
raise errors.ParserError(
|
|
501
|
+
raise errors.ParserError("Not a MaxDatabaseIdKey")
|
|
467
502
|
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
468
503
|
|
|
469
504
|
|
|
@@ -473,17 +508,19 @@ class DataVersionKey(BaseIndexedDBKey):
|
|
|
473
508
|
|
|
474
509
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
475
510
|
"""Decodes the data version value."""
|
|
476
|
-
return decoder.
|
|
511
|
+
return decoder.DecodeInt()[1]
|
|
477
512
|
|
|
478
513
|
@classmethod
|
|
479
514
|
def FromDecoder(
|
|
480
|
-
cls,
|
|
481
|
-
|
|
515
|
+
cls,
|
|
516
|
+
decoder: utils.LevelDBDecoder,
|
|
517
|
+
key_prefix: KeyPrefix,
|
|
518
|
+
base_offset: int = 0,
|
|
482
519
|
) -> DataVersionKey:
|
|
483
520
|
"""Decodes the data version key."""
|
|
484
521
|
offset, key_type = decoder.DecodeUint8()
|
|
485
522
|
if key_type != definitions.GlobalMetadataKeyType.DATA_VERSION:
|
|
486
|
-
raise errors.ParserError(
|
|
523
|
+
raise errors.ParserError("Not a DataVersionKey")
|
|
487
524
|
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
488
525
|
|
|
489
526
|
|
|
@@ -497,13 +534,15 @@ class RecoveryBlobJournalKey(BaseIndexedDBKey):
|
|
|
497
534
|
|
|
498
535
|
@classmethod
|
|
499
536
|
def FromDecoder(
|
|
500
|
-
cls,
|
|
501
|
-
|
|
537
|
+
cls,
|
|
538
|
+
decoder: utils.LevelDBDecoder,
|
|
539
|
+
key_prefix: KeyPrefix,
|
|
540
|
+
base_offset: int = 0,
|
|
502
541
|
) -> RecoveryBlobJournalKey:
|
|
503
542
|
"""Decodes the recovery blob journal key."""
|
|
504
543
|
offset, key_type = decoder.DecodeUint8()
|
|
505
544
|
if key_type != definitions.GlobalMetadataKeyType.RECOVERY_BLOB_JOURNAL:
|
|
506
|
-
raise errors.ParserError(
|
|
545
|
+
raise errors.ParserError("Not a RecoveryBlobJournalKey")
|
|
507
546
|
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
508
547
|
|
|
509
548
|
|
|
@@ -517,13 +556,15 @@ class ActiveBlobJournalKey(BaseIndexedDBKey):
|
|
|
517
556
|
|
|
518
557
|
@classmethod
|
|
519
558
|
def FromDecoder(
|
|
520
|
-
cls,
|
|
521
|
-
|
|
559
|
+
cls,
|
|
560
|
+
decoder: utils.LevelDBDecoder,
|
|
561
|
+
key_prefix: KeyPrefix,
|
|
562
|
+
base_offset: int = 0,
|
|
522
563
|
) -> ActiveBlobJournalKey:
|
|
523
564
|
"""Decodes the active blob journal value."""
|
|
524
565
|
offset, key_type = decoder.DecodeUint8()
|
|
525
566
|
if key_type != definitions.GlobalMetadataKeyType.ACTIVE_BLOB_JOURNAL:
|
|
526
|
-
raise errors.ParserError(
|
|
567
|
+
raise errors.ParserError("Not a ActiveBlobJournalKey")
|
|
527
568
|
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
528
569
|
|
|
529
570
|
|
|
@@ -534,17 +575,19 @@ class EarliestSweepKey(BaseIndexedDBKey):
|
|
|
534
575
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
535
576
|
"""Decodes the earliest sweep value."""
|
|
536
577
|
_, data = decoder.ReadBytes()
|
|
537
|
-
return int.from_bytes(data, byteorder=
|
|
578
|
+
return int.from_bytes(data, byteorder="little", signed=False)
|
|
538
579
|
|
|
539
580
|
@classmethod
|
|
540
581
|
def FromDecoder(
|
|
541
|
-
cls,
|
|
542
|
-
|
|
582
|
+
cls,
|
|
583
|
+
decoder: utils.LevelDBDecoder,
|
|
584
|
+
key_prefix: KeyPrefix,
|
|
585
|
+
base_offset: int = 0,
|
|
543
586
|
) -> EarliestSweepKey:
|
|
544
587
|
"""Decodes the earliest sweep value."""
|
|
545
588
|
offset, key_type = decoder.DecodeUint8()
|
|
546
589
|
if key_type != definitions.GlobalMetadataKeyType.EARLIEST_SWEEP:
|
|
547
|
-
raise errors.ParserError(
|
|
590
|
+
raise errors.ParserError("Not a EarliestSweepKey")
|
|
548
591
|
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
549
592
|
|
|
550
593
|
|
|
@@ -555,17 +598,19 @@ class EarliestCompactionTimeKey(BaseIndexedDBKey):
|
|
|
555
598
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
556
599
|
"""Decodes the earliest compaction time value."""
|
|
557
600
|
_, data = decoder.ReadBytes()
|
|
558
|
-
return int.from_bytes(data, byteorder=
|
|
601
|
+
return int.from_bytes(data, byteorder="little", signed=False)
|
|
559
602
|
|
|
560
603
|
@classmethod
|
|
561
604
|
def FromDecoder(
|
|
562
|
-
cls,
|
|
563
|
-
|
|
605
|
+
cls,
|
|
606
|
+
decoder: utils.LevelDBDecoder,
|
|
607
|
+
key_prefix: KeyPrefix,
|
|
608
|
+
base_offset: int = 0,
|
|
564
609
|
) -> EarliestCompactionTimeKey:
|
|
565
610
|
"""Decodes the earliest compaction time key."""
|
|
566
611
|
offset, key_type = decoder.DecodeUint8()
|
|
567
612
|
if key_type != definitions.GlobalMetadataKeyType.EARLIEST_COMPACTION_TIME:
|
|
568
|
-
raise errors.ParserError(
|
|
613
|
+
raise errors.ParserError("Not a EarliestCompactionTimeKey")
|
|
569
614
|
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
570
615
|
|
|
571
616
|
|
|
@@ -575,19 +620,21 @@ class ScopesPrefixKey(BaseIndexedDBKey):
|
|
|
575
620
|
|
|
576
621
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Optional[bytes]:
|
|
577
622
|
"""Decodes the scopes prefix value."""
|
|
578
|
-
if decoder.NumRemainingBytes:
|
|
623
|
+
if decoder.NumRemainingBytes():
|
|
579
624
|
return decoder.ReadBytes()[1]
|
|
580
625
|
return None
|
|
581
626
|
|
|
582
627
|
@classmethod
|
|
583
628
|
def FromDecoder(
|
|
584
|
-
cls,
|
|
585
|
-
|
|
629
|
+
cls,
|
|
630
|
+
decoder: utils.LevelDBDecoder,
|
|
631
|
+
key_prefix: KeyPrefix,
|
|
632
|
+
base_offset: int = 0,
|
|
586
633
|
) -> ScopesPrefixKey:
|
|
587
634
|
"""Decodes the scopes prefix key."""
|
|
588
635
|
offset, key_type = decoder.DecodeUint8()
|
|
589
636
|
if key_type != definitions.GlobalMetadataKeyType.SCOPES_PREFIX:
|
|
590
|
-
raise errors.ParserError(
|
|
637
|
+
raise errors.ParserError("Not a ScopesPrefixKey")
|
|
591
638
|
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
592
639
|
|
|
593
640
|
|
|
@@ -598,25 +645,30 @@ class DatabaseFreeListKey(BaseIndexedDBKey):
|
|
|
598
645
|
Attributes:
|
|
599
646
|
database_id: the database ID.
|
|
600
647
|
"""
|
|
648
|
+
|
|
601
649
|
database_id: int
|
|
602
650
|
|
|
603
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder):
|
|
651
|
+
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> None:
|
|
604
652
|
"""Decodes the database free list value."""
|
|
605
|
-
raise NotImplementedError(
|
|
653
|
+
raise NotImplementedError("DatabaseFreeListKey.decode_value")
|
|
606
654
|
|
|
607
655
|
@classmethod
|
|
608
656
|
def FromDecoder(
|
|
609
|
-
cls,
|
|
610
|
-
|
|
657
|
+
cls,
|
|
658
|
+
decoder: utils.LevelDBDecoder,
|
|
659
|
+
key_prefix: KeyPrefix,
|
|
660
|
+
base_offset: int = 0,
|
|
611
661
|
) -> DatabaseFreeListKey:
|
|
612
662
|
"""Decodes the database free list key."""
|
|
613
663
|
offset, key_type = decoder.DecodeUint8()
|
|
614
664
|
if key_type != definitions.GlobalMetadataKeyType.DATABASE_FREE_LIST:
|
|
615
|
-
raise errors.ParserError(
|
|
665
|
+
raise errors.ParserError("Not a DatabaseFreeListKey")
|
|
616
666
|
_, database_id = decoder.DecodeVarint()
|
|
617
667
|
return cls(
|
|
618
|
-
offset=base_offset + offset,
|
|
619
|
-
|
|
668
|
+
offset=base_offset + offset,
|
|
669
|
+
key_prefix=key_prefix,
|
|
670
|
+
database_id=database_id,
|
|
671
|
+
)
|
|
620
672
|
|
|
621
673
|
|
|
622
674
|
@dataclass
|
|
@@ -627,6 +679,7 @@ class DatabaseNameKey(BaseIndexedDBKey):
|
|
|
627
679
|
origin: the origin of the database.
|
|
628
680
|
database_name: the database name.
|
|
629
681
|
"""
|
|
682
|
+
|
|
630
683
|
origin: str
|
|
631
684
|
database_name: str
|
|
632
685
|
|
|
@@ -635,49 +688,47 @@ class DatabaseNameKey(BaseIndexedDBKey):
|
|
|
635
688
|
|
|
636
689
|
The value is the corresponding database ID.
|
|
637
690
|
"""
|
|
638
|
-
return decoder.
|
|
691
|
+
return decoder.DecodeInt()[1]
|
|
639
692
|
|
|
640
693
|
@classmethod
|
|
641
694
|
def FromDecoder(
|
|
642
|
-
cls,
|
|
643
|
-
|
|
695
|
+
cls,
|
|
696
|
+
decoder: utils.LevelDBDecoder,
|
|
697
|
+
key_prefix: KeyPrefix,
|
|
698
|
+
base_offset: int = 0,
|
|
644
699
|
) -> DatabaseNameKey:
|
|
645
700
|
"""Decodes the database name key."""
|
|
646
701
|
offset, key_type = decoder.DecodeUint8()
|
|
647
702
|
if key_type != definitions.GlobalMetadataKeyType.DATABASE_NAME:
|
|
648
|
-
raise errors.ParserError(
|
|
703
|
+
raise errors.ParserError("Not a DatabaseNameKey")
|
|
649
704
|
_, origin = decoder.DecodeStringWithLength()
|
|
650
705
|
_, database_name = decoder.DecodeStringWithLength()
|
|
651
706
|
return cls(
|
|
652
|
-
offset=base_offset + offset,
|
|
653
|
-
|
|
707
|
+
offset=base_offset + offset,
|
|
708
|
+
key_prefix=key_prefix,
|
|
709
|
+
origin=origin,
|
|
710
|
+
database_name=database_name,
|
|
711
|
+
)
|
|
654
712
|
|
|
655
713
|
|
|
656
714
|
@dataclass
|
|
657
715
|
class GlobalMetaDataKey(BaseIndexedDBKey):
|
|
658
716
|
"""A GlobalMetaDataKey parser."""
|
|
659
717
|
|
|
718
|
+
# pylint: disable=line-too-long
|
|
660
719
|
METADATA_TYPE_TO_CLASS = {
|
|
661
|
-
definitions.GlobalMetadataKeyType
|
|
662
|
-
|
|
663
|
-
definitions.GlobalMetadataKeyType
|
|
664
|
-
|
|
665
|
-
definitions.GlobalMetadataKeyType
|
|
666
|
-
|
|
667
|
-
definitions.GlobalMetadataKeyType
|
|
668
|
-
|
|
669
|
-
definitions.GlobalMetadataKeyType
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
definitions.GlobalMetadataKeyType
|
|
674
|
-
.EARLIEST_COMPACTION_TIME: EarliestCompactionTimeKey,
|
|
675
|
-
definitions.GlobalMetadataKeyType
|
|
676
|
-
.SCOPES_PREFIX: ScopesPrefixKey,
|
|
677
|
-
definitions.GlobalMetadataKeyType
|
|
678
|
-
.DATABASE_FREE_LIST: DatabaseFreeListKey,
|
|
679
|
-
definitions.GlobalMetadataKeyType
|
|
680
|
-
.DATABASE_NAME: DatabaseNameKey}
|
|
720
|
+
definitions.GlobalMetadataKeyType.ACTIVE_BLOB_JOURNAL: ActiveBlobJournalKey,
|
|
721
|
+
definitions.GlobalMetadataKeyType.DATA_VERSION: DataVersionKey,
|
|
722
|
+
definitions.GlobalMetadataKeyType.DATABASE_FREE_LIST: DatabaseFreeListKey,
|
|
723
|
+
definitions.GlobalMetadataKeyType.DATABASE_NAME: DatabaseNameKey,
|
|
724
|
+
definitions.GlobalMetadataKeyType.EARLIEST_COMPACTION_TIME: EarliestCompactionTimeKey,
|
|
725
|
+
definitions.GlobalMetadataKeyType.EARLIEST_SWEEP: EarliestSweepKey,
|
|
726
|
+
definitions.GlobalMetadataKeyType.MAX_DATABASE_ID: MaxDatabaseIdKey,
|
|
727
|
+
definitions.GlobalMetadataKeyType.RECOVERY_BLOB_JOURNAL: RecoveryBlobJournalKey,
|
|
728
|
+
definitions.GlobalMetadataKeyType.SCHEMA_VERSION: SchemaVersionKey,
|
|
729
|
+
definitions.GlobalMetadataKeyType.SCOPES_PREFIX: ScopesPrefixKey,
|
|
730
|
+
}
|
|
731
|
+
# pylint: enable=line-too-long
|
|
681
732
|
|
|
682
733
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Any:
|
|
683
734
|
"""Decodes the value from the current position of the LevelDBDecoder.
|
|
@@ -688,18 +739,22 @@ class GlobalMetaDataKey(BaseIndexedDBKey):
|
|
|
688
739
|
|
|
689
740
|
@classmethod
|
|
690
741
|
def FromDecoder(
|
|
691
|
-
cls,
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
742
|
+
cls,
|
|
743
|
+
decoder: utils.LevelDBDecoder,
|
|
744
|
+
key_prefix: KeyPrefix,
|
|
745
|
+
base_offset: int = 0,
|
|
746
|
+
) -> Union[
|
|
747
|
+
ActiveBlobJournalKey,
|
|
748
|
+
DataVersionKey,
|
|
749
|
+
DatabaseFreeListKey,
|
|
750
|
+
DatabaseNameKey,
|
|
751
|
+
EarliestSweepKey,
|
|
752
|
+
EarliestCompactionTimeKey,
|
|
753
|
+
MaxDatabaseIdKey,
|
|
754
|
+
RecoveryBlobJournalKey,
|
|
755
|
+
SchemaVersionKey,
|
|
756
|
+
ScopesPrefixKey,
|
|
757
|
+
]:
|
|
703
758
|
"""Decodes the global metadata key.
|
|
704
759
|
|
|
705
760
|
Raises:
|
|
@@ -710,9 +765,10 @@ class GlobalMetaDataKey(BaseIndexedDBKey):
|
|
|
710
765
|
|
|
711
766
|
key_class = cls.METADATA_TYPE_TO_CLASS.get(metadata_type)
|
|
712
767
|
if not key_class:
|
|
713
|
-
raise errors.ParserError(
|
|
714
|
-
return key_class.FromDecoder(
|
|
715
|
-
decoder, key_prefix, base_offset
|
|
768
|
+
raise errors.ParserError("Unknown metadata key type")
|
|
769
|
+
return key_class.FromDecoder( # type: ignore[attr-defined,no-any-return]
|
|
770
|
+
decoder, key_prefix, base_offset
|
|
771
|
+
)
|
|
716
772
|
|
|
717
773
|
|
|
718
774
|
@dataclass
|
|
@@ -722,25 +778,30 @@ class ObjectStoreFreeListKey(BaseIndexedDBKey):
|
|
|
722
778
|
Attributes:
|
|
723
779
|
object_store_id: the ID of the object store containing the free list.
|
|
724
780
|
"""
|
|
781
|
+
|
|
725
782
|
object_store_id: int
|
|
726
783
|
|
|
727
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder):
|
|
784
|
+
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> None:
|
|
728
785
|
"""Decodes the object store free list value."""
|
|
729
|
-
raise NotImplementedError(
|
|
786
|
+
raise NotImplementedError("ObjectStoreFreeListKey.decode_value")
|
|
730
787
|
|
|
731
788
|
@classmethod
|
|
732
789
|
def FromDecoder(
|
|
733
|
-
cls,
|
|
734
|
-
|
|
790
|
+
cls,
|
|
791
|
+
decoder: utils.LevelDBDecoder,
|
|
792
|
+
key_prefix: KeyPrefix,
|
|
793
|
+
base_offset: int = 0,
|
|
735
794
|
) -> ObjectStoreFreeListKey:
|
|
736
795
|
"""Decodes the object store free list key."""
|
|
737
796
|
offset, key_type = decoder.DecodeUint8()
|
|
738
797
|
if key_type != definitions.DatabaseMetaDataKeyType.OBJECT_STORE_FREE_LIST:
|
|
739
|
-
raise errors.ParserError(
|
|
798
|
+
raise errors.ParserError("Not am ObjectStoreFreeListKey")
|
|
740
799
|
_, object_store_id = decoder.DecodeVarint()
|
|
741
800
|
return cls(
|
|
742
|
-
offset=base_offset + offset,
|
|
743
|
-
|
|
801
|
+
offset=base_offset + offset,
|
|
802
|
+
key_prefix=key_prefix,
|
|
803
|
+
object_store_id=object_store_id,
|
|
804
|
+
)
|
|
744
805
|
|
|
745
806
|
|
|
746
807
|
@dataclass
|
|
@@ -750,25 +811,30 @@ class IndexFreeListKey(BaseIndexedDBKey):
|
|
|
750
811
|
Attributes:
|
|
751
812
|
object_store_id: the ID of the object store containing the free list.
|
|
752
813
|
"""
|
|
814
|
+
|
|
753
815
|
object_store_id: int
|
|
754
816
|
|
|
755
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder):
|
|
817
|
+
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> None:
|
|
756
818
|
"""Decodes the index free list value."""
|
|
757
|
-
raise NotImplementedError(
|
|
819
|
+
raise NotImplementedError("IndexFreeListKey.decode_value")
|
|
758
820
|
|
|
759
821
|
@classmethod
|
|
760
822
|
def FromDecoder(
|
|
761
|
-
cls,
|
|
762
|
-
|
|
763
|
-
|
|
823
|
+
cls,
|
|
824
|
+
decoder: utils.LevelDBDecoder,
|
|
825
|
+
key_prefix: KeyPrefix,
|
|
826
|
+
base_offset: int = 0,
|
|
827
|
+
) -> IndexFreeListKey:
|
|
764
828
|
"""Decodes the index free list key."""
|
|
765
829
|
offset, key_type = decoder.DecodeUint8()
|
|
766
830
|
if key_type != definitions.DatabaseMetaDataKeyType.INDEX_FREE_LIST:
|
|
767
|
-
raise errors.ParserError(
|
|
831
|
+
raise errors.ParserError("Not am IndexFreeListKey")
|
|
768
832
|
_, object_store_id = decoder.DecodeVarint()
|
|
769
833
|
return cls(
|
|
770
|
-
offset=base_offset + offset,
|
|
771
|
-
|
|
834
|
+
offset=base_offset + offset,
|
|
835
|
+
key_prefix=key_prefix,
|
|
836
|
+
object_store_id=object_store_id,
|
|
837
|
+
)
|
|
772
838
|
|
|
773
839
|
|
|
774
840
|
@dataclass
|
|
@@ -778,22 +844,30 @@ class ObjectStoreNamesKey(BaseIndexedDBKey):
|
|
|
778
844
|
Attributes:
|
|
779
845
|
object_store_name: the name of the object store.
|
|
780
846
|
"""
|
|
847
|
+
|
|
781
848
|
object_store_name: str
|
|
782
849
|
|
|
783
850
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
784
851
|
"""Decodes the object store names value."""
|
|
785
|
-
return decoder.
|
|
852
|
+
return decoder.DecodeInt()[1]
|
|
786
853
|
|
|
787
854
|
@classmethod
|
|
788
|
-
def FromDecoder(
|
|
789
|
-
|
|
855
|
+
def FromDecoder(
|
|
856
|
+
cls,
|
|
857
|
+
decoder: utils.LevelDBDecoder,
|
|
858
|
+
key_prefix: KeyPrefix,
|
|
859
|
+
base_offset: int = 0,
|
|
860
|
+
) -> ObjectStoreNamesKey:
|
|
790
861
|
"""Decodes the object store names key."""
|
|
791
862
|
offset, key_type = decoder.DecodeUint8()
|
|
792
863
|
if key_type != definitions.DatabaseMetaDataKeyType.OBJECT_STORE_NAMES:
|
|
793
|
-
raise errors.ParserError(
|
|
864
|
+
raise errors.ParserError("Not am ObjectStoreNamesKey")
|
|
794
865
|
_, object_store_name = decoder.DecodeStringWithLength()
|
|
795
|
-
return cls(
|
|
796
|
-
|
|
866
|
+
return cls(
|
|
867
|
+
key_prefix=key_prefix,
|
|
868
|
+
offset=base_offset + offset,
|
|
869
|
+
object_store_name=object_store_name,
|
|
870
|
+
)
|
|
797
871
|
|
|
798
872
|
|
|
799
873
|
@dataclass
|
|
@@ -803,22 +877,30 @@ class IndexNamesKey(BaseIndexedDBKey):
|
|
|
803
877
|
Attributes:
|
|
804
878
|
index_name: the name of the index.
|
|
805
879
|
"""
|
|
880
|
+
|
|
806
881
|
index_name: str
|
|
807
882
|
|
|
808
883
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
809
884
|
"""Decodes the index names value."""
|
|
810
|
-
return decoder.
|
|
885
|
+
return decoder.DecodeInt()[1]
|
|
811
886
|
|
|
812
887
|
@classmethod
|
|
813
|
-
def FromDecoder(
|
|
814
|
-
|
|
888
|
+
def FromDecoder(
|
|
889
|
+
cls,
|
|
890
|
+
decoder: utils.LevelDBDecoder,
|
|
891
|
+
key_prefix: KeyPrefix,
|
|
892
|
+
base_offset: int = 0,
|
|
893
|
+
) -> IndexNamesKey:
|
|
815
894
|
"""Decodes the index names key."""
|
|
816
895
|
offset, key_type = decoder.DecodeUint8()
|
|
817
896
|
if key_type != definitions.DatabaseMetaDataKeyType.INDEX_NAMES:
|
|
818
|
-
raise errors.ParserError(
|
|
897
|
+
raise errors.ParserError("Not am IndexNamesKey")
|
|
819
898
|
_, index_name = decoder.DecodeStringWithLength()
|
|
820
|
-
return cls(
|
|
821
|
-
|
|
899
|
+
return cls(
|
|
900
|
+
key_prefix=key_prefix,
|
|
901
|
+
offset=base_offset + offset,
|
|
902
|
+
index_name=index_name,
|
|
903
|
+
)
|
|
822
904
|
|
|
823
905
|
|
|
824
906
|
@dataclass
|
|
@@ -828,39 +910,45 @@ class DatabaseMetaDataKey(BaseIndexedDBKey):
|
|
|
828
910
|
Attributes:
|
|
829
911
|
metadata_type: the type of metadata that the key value contains.
|
|
830
912
|
"""
|
|
913
|
+
|
|
831
914
|
metadata_type: definitions.DatabaseMetaDataKeyType
|
|
832
915
|
|
|
833
|
-
def DecodeValue(
|
|
834
|
-
self, decoder: utils.LevelDBDecoder) -> Union[str, int]:
|
|
916
|
+
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Union[str, int]:
|
|
835
917
|
"""Decodes the database metadata value."""
|
|
836
|
-
if
|
|
837
|
-
definitions.DatabaseMetaDataKeyType.ORIGIN_NAME):
|
|
918
|
+
if self.metadata_type == definitions.DatabaseMetaDataKeyType.ORIGIN_NAME:
|
|
838
919
|
return decoder.DecodeString()[1]
|
|
839
|
-
if
|
|
840
|
-
definitions.DatabaseMetaDataKeyType.DATABASE_NAME):
|
|
920
|
+
if self.metadata_type == definitions.DatabaseMetaDataKeyType.DATABASE_NAME:
|
|
841
921
|
return decoder.DecodeString()[1]
|
|
842
|
-
if (
|
|
843
|
-
|
|
922
|
+
if (
|
|
923
|
+
self.metadata_type
|
|
924
|
+
== definitions.DatabaseMetaDataKeyType.IDB_STRING_VERSION_DATA
|
|
925
|
+
):
|
|
844
926
|
return decoder.DecodeString()[1]
|
|
845
|
-
if (
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
927
|
+
if (
|
|
928
|
+
self.metadata_type
|
|
929
|
+
== definitions.DatabaseMetaDataKeyType.MAX_ALLOCATED_OBJECT_STORE_ID
|
|
930
|
+
):
|
|
931
|
+
return decoder.DecodeInt()[1]
|
|
932
|
+
if (
|
|
933
|
+
self.metadata_type
|
|
934
|
+
== definitions.DatabaseMetaDataKeyType.IDB_INTEGER_VERSION
|
|
935
|
+
):
|
|
850
936
|
return decoder.DecodeVarint()[1]
|
|
851
|
-
if (
|
|
852
|
-
|
|
853
|
-
|
|
937
|
+
if (
|
|
938
|
+
self.metadata_type
|
|
939
|
+
== definitions.DatabaseMetaDataKeyType.BLOB_NUMBER_GENERATOR_CURRENT_NUMBER # pylint: disable=line-too-long
|
|
940
|
+
):
|
|
854
941
|
return decoder.DecodeVarint()[1]
|
|
855
942
|
raise errors.ParserError(
|
|
856
|
-
f
|
|
943
|
+
f"Unknown database metadata type {self.metadata_type}"
|
|
944
|
+
)
|
|
857
945
|
|
|
858
946
|
@classmethod
|
|
859
947
|
def FromDecoder(
|
|
860
948
|
cls,
|
|
861
949
|
decoder: utils.LevelDBDecoder,
|
|
862
950
|
key_prefix: KeyPrefix,
|
|
863
|
-
base_offset: int = 0
|
|
951
|
+
base_offset: int = 0,
|
|
864
952
|
) -> Union[
|
|
865
953
|
DatabaseMetaDataKey,
|
|
866
954
|
IndexFreeListKey,
|
|
@@ -868,7 +956,8 @@ class DatabaseMetaDataKey(BaseIndexedDBKey):
|
|
|
868
956
|
IndexNamesKey,
|
|
869
957
|
ObjectStoreFreeListKey,
|
|
870
958
|
ObjectStoreMetaDataKey,
|
|
871
|
-
ObjectStoreNamesKey
|
|
959
|
+
ObjectStoreNamesKey,
|
|
960
|
+
]:
|
|
872
961
|
"""Decodes the database metadata key."""
|
|
873
962
|
offset, metadata_value = decoder.PeekBytes(1)
|
|
874
963
|
metadata_type = definitions.DatabaseMetaDataKeyType(metadata_value[0])
|
|
@@ -879,32 +968,36 @@ class DatabaseMetaDataKey(BaseIndexedDBKey):
|
|
|
879
968
|
definitions.DatabaseMetaDataKeyType.IDB_STRING_VERSION_DATA,
|
|
880
969
|
definitions.DatabaseMetaDataKeyType.MAX_ALLOCATED_OBJECT_STORE_ID,
|
|
881
970
|
definitions.DatabaseMetaDataKeyType.IDB_INTEGER_VERSION,
|
|
882
|
-
definitions.DatabaseMetaDataKeyType
|
|
883
|
-
|
|
884
|
-
return cls(
|
|
885
|
-
|
|
971
|
+
definitions.DatabaseMetaDataKeyType.BLOB_NUMBER_GENERATOR_CURRENT_NUMBER, # pylint: disable=line-too-long
|
|
972
|
+
):
|
|
973
|
+
return cls(
|
|
974
|
+
key_prefix=key_prefix,
|
|
975
|
+
offset=base_offset + offset,
|
|
976
|
+
metadata_type=metadata_type,
|
|
977
|
+
)
|
|
886
978
|
if metadata_type == definitions.DatabaseMetaDataKeyType.INDEX_META_DATA:
|
|
887
|
-
return IndexMetaDataKey.FromDecoder(
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
definitions.DatabaseMetaDataKeyType.OBJECT_STORE_META_DATA
|
|
979
|
+
return IndexMetaDataKey.FromDecoder(decoder, key_prefix, base_offset)
|
|
980
|
+
if (
|
|
981
|
+
metadata_type
|
|
982
|
+
== definitions.DatabaseMetaDataKeyType.OBJECT_STORE_META_DATA
|
|
983
|
+
):
|
|
891
984
|
return ObjectStoreMetaDataKey.FromDecoder(
|
|
892
|
-
decoder, key_prefix, base_offset
|
|
893
|
-
|
|
894
|
-
|
|
985
|
+
decoder, key_prefix, base_offset
|
|
986
|
+
)
|
|
987
|
+
if (
|
|
988
|
+
metadata_type
|
|
989
|
+
== definitions.DatabaseMetaDataKeyType.OBJECT_STORE_FREE_LIST
|
|
990
|
+
):
|
|
895
991
|
return ObjectStoreFreeListKey.FromDecoder(
|
|
896
|
-
decoder, key_prefix, base_offset
|
|
992
|
+
decoder, key_prefix, base_offset
|
|
993
|
+
)
|
|
897
994
|
if metadata_type == definitions.DatabaseMetaDataKeyType.INDEX_FREE_LIST:
|
|
898
|
-
return IndexFreeListKey.FromDecoder(
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
definitions.DatabaseMetaDataKeyType.OBJECT_STORE_NAMES):
|
|
902
|
-
return ObjectStoreNamesKey.FromDecoder(
|
|
903
|
-
decoder, key_prefix, base_offset)
|
|
995
|
+
return IndexFreeListKey.FromDecoder(decoder, key_prefix, base_offset)
|
|
996
|
+
if metadata_type == definitions.DatabaseMetaDataKeyType.OBJECT_STORE_NAMES:
|
|
997
|
+
return ObjectStoreNamesKey.FromDecoder(decoder, key_prefix, base_offset)
|
|
904
998
|
if metadata_type == definitions.DatabaseMetaDataKeyType.INDEX_NAMES:
|
|
905
|
-
return IndexNamesKey.FromDecoder(
|
|
906
|
-
|
|
907
|
-
raise errors.ParserError(f'unknown database metadata type {metadata_type}.')
|
|
999
|
+
return IndexNamesKey.FromDecoder(decoder, key_prefix, base_offset)
|
|
1000
|
+
raise errors.ParserError(f"unknown database metadata type {metadata_type}.")
|
|
908
1001
|
|
|
909
1002
|
|
|
910
1003
|
@dataclass
|
|
@@ -915,68 +1008,91 @@ class ObjectStoreMetaDataKey(BaseIndexedDBKey):
|
|
|
915
1008
|
object_store_id: the ID of the object store.
|
|
916
1009
|
metadata_type: the object store metadata type.
|
|
917
1010
|
"""
|
|
1011
|
+
|
|
918
1012
|
object_store_id: int
|
|
919
1013
|
metadata_type: definitions.ObjectStoreMetaDataKeyType
|
|
920
1014
|
|
|
921
1015
|
def DecodeValue(
|
|
922
|
-
self, decoder: utils.LevelDBDecoder
|
|
1016
|
+
self, decoder: utils.LevelDBDecoder
|
|
1017
|
+
) -> Union[IDBKeyPath, str, bool, int]:
|
|
923
1018
|
"""Decodes the object store metadata value."""
|
|
924
|
-
if (
|
|
925
|
-
|
|
1019
|
+
if (
|
|
1020
|
+
self.metadata_type
|
|
1021
|
+
== definitions.ObjectStoreMetaDataKeyType.OBJECT_STORE_NAME
|
|
1022
|
+
):
|
|
926
1023
|
return decoder.DecodeString()[1]
|
|
927
1024
|
if self.metadata_type == definitions.ObjectStoreMetaDataKeyType.KEY_PATH:
|
|
928
1025
|
return IDBKeyPath.FromDecoder(decoder)
|
|
929
|
-
if (
|
|
930
|
-
|
|
1026
|
+
if (
|
|
1027
|
+
self.metadata_type
|
|
1028
|
+
== definitions.ObjectStoreMetaDataKeyType.AUTO_INCREMENT_FLAG
|
|
1029
|
+
):
|
|
931
1030
|
return decoder.DecodeBool()[1]
|
|
932
|
-
if (
|
|
933
|
-
|
|
1031
|
+
if (
|
|
1032
|
+
self.metadata_type
|
|
1033
|
+
== definitions.ObjectStoreMetaDataKeyType.IS_EVICTABLE
|
|
1034
|
+
):
|
|
934
1035
|
return decoder.DecodeBool()[1]
|
|
935
|
-
if (
|
|
936
|
-
|
|
1036
|
+
if (
|
|
1037
|
+
self.metadata_type
|
|
1038
|
+
== definitions.ObjectStoreMetaDataKeyType.LAST_VERSION_NUMBER
|
|
1039
|
+
):
|
|
937
1040
|
return decoder.DecodeInt(signed=False)[1]
|
|
938
|
-
if (
|
|
939
|
-
|
|
1041
|
+
if (
|
|
1042
|
+
self.metadata_type
|
|
1043
|
+
== definitions.ObjectStoreMetaDataKeyType.MAXIMUM_ALLOCATED_INDEX_ID
|
|
1044
|
+
):
|
|
940
1045
|
return decoder.DecodeInt()[1]
|
|
941
|
-
if (
|
|
942
|
-
|
|
1046
|
+
if (
|
|
1047
|
+
self.metadata_type
|
|
1048
|
+
== definitions.ObjectStoreMetaDataKeyType.HAS_KEY_PATH
|
|
1049
|
+
):
|
|
943
1050
|
return decoder.DecodeBool()[1]
|
|
944
|
-
if (
|
|
945
|
-
|
|
1051
|
+
if (
|
|
1052
|
+
self.metadata_type
|
|
1053
|
+
== definitions.ObjectStoreMetaDataKeyType.KEY_GENERATOR_CURRENT_NUMBER
|
|
1054
|
+
):
|
|
946
1055
|
return decoder.DecodeInt()[1]
|
|
947
|
-
raise errors.ParserError(f
|
|
1056
|
+
raise errors.ParserError(f"Unknown metadata type {self.metadata_type}")
|
|
948
1057
|
|
|
949
1058
|
@classmethod
|
|
950
1059
|
def FromDecoder(
|
|
951
|
-
cls,
|
|
952
|
-
|
|
1060
|
+
cls,
|
|
1061
|
+
decoder: utils.LevelDBDecoder,
|
|
1062
|
+
key_prefix: KeyPrefix,
|
|
1063
|
+
base_offset: int = 0,
|
|
953
1064
|
) -> ObjectStoreMetaDataKey:
|
|
954
1065
|
"""Decodes the object store metadata key."""
|
|
955
1066
|
offset, metadata_value = decoder.DecodeUint8()
|
|
956
|
-
if (
|
|
957
|
-
|
|
958
|
-
|
|
1067
|
+
if (
|
|
1068
|
+
metadata_value
|
|
1069
|
+
!= definitions.DatabaseMetaDataKeyType.OBJECT_STORE_META_DATA
|
|
1070
|
+
):
|
|
1071
|
+
raise errors.ParserError("Not a ObjectStoreMetaDataKey")
|
|
959
1072
|
|
|
960
1073
|
_, object_store_id = decoder.DecodeVarint()
|
|
961
1074
|
_, metadata_value = decoder.DecodeUint8()
|
|
962
1075
|
metadata_type = definitions.ObjectStoreMetaDataKeyType(metadata_value)
|
|
963
1076
|
return cls(
|
|
964
|
-
offset=base_offset + offset,
|
|
965
|
-
|
|
1077
|
+
offset=base_offset + offset,
|
|
1078
|
+
key_prefix=key_prefix,
|
|
1079
|
+
object_store_id=object_store_id,
|
|
1080
|
+
metadata_type=metadata_type,
|
|
1081
|
+
)
|
|
1082
|
+
|
|
966
1083
|
|
|
967
1084
|
@dataclass
|
|
968
1085
|
class ObjectStoreDataValue:
|
|
969
1086
|
"""The parsed values from an ObjectStoreDataKey.
|
|
970
1087
|
|
|
971
1088
|
Attributes:
|
|
972
|
-
|
|
973
|
-
is_wrapped: True if the value was wrapped.
|
|
1089
|
+
version: the version prefix.
|
|
974
1090
|
blob_size: the blob size, only valid if wrapped.
|
|
975
1091
|
blob_offset: the blob offset, only valid if wrapped.
|
|
976
1092
|
value: the blink serialized value, only valid if not wrapped.
|
|
977
1093
|
"""
|
|
978
|
-
|
|
979
|
-
|
|
1094
|
+
|
|
1095
|
+
version: int
|
|
980
1096
|
blob_size: Optional[int]
|
|
981
1097
|
blob_offset: Optional[int]
|
|
982
1098
|
value: Any
|
|
@@ -989,51 +1105,59 @@ class ObjectStoreDataKey(BaseIndexedDBKey):
|
|
|
989
1105
|
Attributes:
|
|
990
1106
|
encoded_user_key: the encoded user key.
|
|
991
1107
|
"""
|
|
1108
|
+
|
|
992
1109
|
encoded_user_key: IDBKey
|
|
993
1110
|
|
|
994
|
-
def DecodeValue(
|
|
995
|
-
self, decoder: utils.LevelDBDecoder) -> ObjectStoreDataValue:
|
|
1111
|
+
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> ObjectStoreDataValue:
|
|
996
1112
|
"""Decodes the object store data value."""
|
|
997
|
-
_,
|
|
1113
|
+
_, version = decoder.DecodeVarint()
|
|
998
1114
|
|
|
999
1115
|
_, wrapped_header_bytes = decoder.PeekBytes(3)
|
|
1000
1116
|
if len(wrapped_header_bytes) != 3:
|
|
1001
|
-
raise errors.DecoderError(
|
|
1002
|
-
|
|
1003
|
-
if (
|
|
1004
|
-
wrapped_header_bytes[
|
|
1005
|
-
wrapped_header_bytes[
|
|
1117
|
+
raise errors.DecoderError("Insufficient bytes")
|
|
1118
|
+
|
|
1119
|
+
if (
|
|
1120
|
+
wrapped_header_bytes[0] == definitions.BlinkSerializationTag.VERSION
|
|
1121
|
+
and wrapped_header_bytes[1]
|
|
1122
|
+
== definitions.REQUIRES_PROCESSING_SSV_PSEUDO_VERSION
|
|
1123
|
+
and wrapped_header_bytes[2] == definitions.REPLACE_WITH_BLOB
|
|
1124
|
+
):
|
|
1125
|
+
_ = decoder.ReadBytes(3)
|
|
1006
1126
|
_, blob_size = decoder.DecodeVarint()
|
|
1007
1127
|
_, blob_offset = decoder.DecodeVarint()
|
|
1008
1128
|
return ObjectStoreDataValue(
|
|
1009
|
-
|
|
1010
|
-
is_wrapped=True,
|
|
1129
|
+
version=version,
|
|
1011
1130
|
blob_size=blob_size,
|
|
1012
1131
|
blob_offset=blob_offset,
|
|
1013
|
-
value=None
|
|
1132
|
+
value=None,
|
|
1133
|
+
)
|
|
1134
|
+
|
|
1014
1135
|
_, blink_bytes = decoder.ReadBytes()
|
|
1015
1136
|
blink_value = blink.V8ScriptValueDecoder.FromBytes(blink_bytes)
|
|
1016
1137
|
return ObjectStoreDataValue(
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
blob_size=None,
|
|
1020
|
-
blob_offset=None,
|
|
1021
|
-
value=blink_value)
|
|
1138
|
+
version=version, blob_size=None, blob_offset=None, value=blink_value
|
|
1139
|
+
)
|
|
1022
1140
|
|
|
1023
1141
|
@classmethod
|
|
1024
1142
|
def FromDecoder(
|
|
1025
|
-
cls,
|
|
1026
|
-
|
|
1143
|
+
cls,
|
|
1144
|
+
decoder: utils.LevelDBDecoder,
|
|
1145
|
+
key_prefix: KeyPrefix,
|
|
1146
|
+
base_offset: int = 0,
|
|
1027
1147
|
) -> ObjectStoreDataKey:
|
|
1028
1148
|
"""Decodes the object store data key."""
|
|
1029
|
-
if (
|
|
1030
|
-
|
|
1031
|
-
|
|
1149
|
+
if (
|
|
1150
|
+
key_prefix.GetKeyPrefixType()
|
|
1151
|
+
!= definitions.KeyPrefixType.OBJECT_STORE_DATA
|
|
1152
|
+
):
|
|
1153
|
+
raise errors.ParserError("Invalid KeyPrefix for ObjectStoreDataKey")
|
|
1032
1154
|
offset = decoder.stream.tell()
|
|
1033
1155
|
encoded_user_key = IDBKey.FromDecoder(decoder, offset)
|
|
1034
1156
|
return cls(
|
|
1035
1157
|
offset=base_offset + offset,
|
|
1036
|
-
key_prefix=key_prefix,
|
|
1158
|
+
key_prefix=key_prefix,
|
|
1159
|
+
encoded_user_key=encoded_user_key,
|
|
1160
|
+
)
|
|
1037
1161
|
|
|
1038
1162
|
|
|
1039
1163
|
@dataclass
|
|
@@ -1043,25 +1167,29 @@ class ExistsEntryKey(BaseIndexedDBKey):
|
|
|
1043
1167
|
Attributes:
|
|
1044
1168
|
encoded_user_key: the encoded user key.
|
|
1045
1169
|
"""
|
|
1170
|
+
|
|
1046
1171
|
encoded_user_key: IDBKey
|
|
1047
1172
|
|
|
1048
1173
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
1049
1174
|
"""Decodes the exists entry value."""
|
|
1050
1175
|
_, data = decoder.ReadBytes()
|
|
1051
|
-
return int.from_bytes(data, byteorder=
|
|
1176
|
+
return int.from_bytes(data, byteorder="little", signed=False)
|
|
1052
1177
|
|
|
1053
1178
|
@classmethod
|
|
1054
1179
|
def FromDecoder(
|
|
1055
|
-
cls,
|
|
1056
|
-
|
|
1180
|
+
cls,
|
|
1181
|
+
decoder: utils.LevelDBDecoder,
|
|
1182
|
+
key_prefix: KeyPrefix,
|
|
1183
|
+
base_offset: int = 0,
|
|
1057
1184
|
) -> ExistsEntryKey:
|
|
1058
1185
|
"""Decodes the exists entry key."""
|
|
1059
1186
|
offset = decoder.stream.tell()
|
|
1060
1187
|
encoded_user_key = IDBKey.FromDecoder(decoder, offset)
|
|
1061
|
-
|
|
1062
1188
|
return cls(
|
|
1063
1189
|
offset=base_offset + offset,
|
|
1064
|
-
key_prefix=key_prefix,
|
|
1190
|
+
key_prefix=key_prefix,
|
|
1191
|
+
encoded_user_key=encoded_user_key,
|
|
1192
|
+
)
|
|
1065
1193
|
|
|
1066
1194
|
|
|
1067
1195
|
@dataclass
|
|
@@ -1073,6 +1201,7 @@ class IndexDataKey(BaseIndexedDBKey):
|
|
|
1073
1201
|
sequence_number: the sequence number of the data key.
|
|
1074
1202
|
encoded_primary_key: the encoded primary key.
|
|
1075
1203
|
"""
|
|
1204
|
+
|
|
1076
1205
|
encoded_user_key: IDBKey
|
|
1077
1206
|
sequence_number: Optional[int]
|
|
1078
1207
|
encoded_primary_key: Optional[IDBKey]
|
|
@@ -1084,8 +1213,12 @@ class IndexDataKey(BaseIndexedDBKey):
|
|
|
1084
1213
|
return version, idb_key
|
|
1085
1214
|
|
|
1086
1215
|
@classmethod
|
|
1087
|
-
def FromDecoder(
|
|
1088
|
-
|
|
1216
|
+
def FromDecoder(
|
|
1217
|
+
cls,
|
|
1218
|
+
decoder: utils.LevelDBDecoder,
|
|
1219
|
+
key_prefix: KeyPrefix,
|
|
1220
|
+
base_offset: int = 0,
|
|
1221
|
+
) -> IndexDataKey:
|
|
1089
1222
|
"""Decodes the index data key."""
|
|
1090
1223
|
offset = decoder.stream.tell()
|
|
1091
1224
|
encoded_user_key = IDBKey.FromDecoder(decoder, offset)
|
|
@@ -1098,7 +1231,8 @@ class IndexDataKey(BaseIndexedDBKey):
|
|
|
1098
1231
|
if decoder.NumRemainingBytes() > 0:
|
|
1099
1232
|
encoded_primary_key_offset = decoder.stream.tell()
|
|
1100
1233
|
encoded_primary_key = IDBKey.FromDecoder(
|
|
1101
|
-
decoder, encoded_primary_key_offset
|
|
1234
|
+
decoder, encoded_primary_key_offset
|
|
1235
|
+
)
|
|
1102
1236
|
else:
|
|
1103
1237
|
encoded_primary_key = None
|
|
1104
1238
|
|
|
@@ -1107,7 +1241,8 @@ class IndexDataKey(BaseIndexedDBKey):
|
|
|
1107
1241
|
encoded_user_key=encoded_user_key,
|
|
1108
1242
|
sequence_number=sequence_number,
|
|
1109
1243
|
encoded_primary_key=encoded_primary_key,
|
|
1110
|
-
offset=base_offset + offset
|
|
1244
|
+
offset=base_offset + offset,
|
|
1245
|
+
)
|
|
1111
1246
|
|
|
1112
1247
|
|
|
1113
1248
|
@dataclass
|
|
@@ -1117,24 +1252,29 @@ class BlobEntryKey(BaseIndexedDBKey):
|
|
|
1117
1252
|
Attributes:
|
|
1118
1253
|
user_key: the user/primary key.
|
|
1119
1254
|
"""
|
|
1255
|
+
|
|
1120
1256
|
user_key: IDBKey
|
|
1121
1257
|
|
|
1122
1258
|
def DecodeValue(
|
|
1123
|
-
self, decoder: utils.LevelDBDecoder
|
|
1259
|
+
self, decoder: utils.LevelDBDecoder
|
|
1260
|
+
) -> IndexedDBExternalObject:
|
|
1124
1261
|
"""Decodes the blob entry value."""
|
|
1125
1262
|
return IndexedDBExternalObject.FromDecoder(decoder)
|
|
1126
1263
|
|
|
1127
1264
|
@classmethod
|
|
1128
1265
|
def FromDecoder(
|
|
1129
|
-
cls,
|
|
1130
|
-
|
|
1266
|
+
cls,
|
|
1267
|
+
decoder: utils.LevelDBDecoder,
|
|
1268
|
+
key_prefix: KeyPrefix,
|
|
1269
|
+
base_offset: int = 0,
|
|
1131
1270
|
) -> BlobEntryKey:
|
|
1132
1271
|
"""Decodes the blob entry key."""
|
|
1133
1272
|
offset = decoder.stream.tell()
|
|
1134
1273
|
user_key = IDBKey.FromDecoder(decoder, offset)
|
|
1135
1274
|
|
|
1136
|
-
return cls(
|
|
1137
|
-
|
|
1275
|
+
return cls(
|
|
1276
|
+
key_prefix=key_prefix, user_key=user_key, offset=base_offset + offset
|
|
1277
|
+
)
|
|
1138
1278
|
|
|
1139
1279
|
|
|
1140
1280
|
@dataclass
|
|
@@ -1145,13 +1285,13 @@ class IndexedDbKey(BaseIndexedDBKey):
|
|
|
1145
1285
|
"""
|
|
1146
1286
|
|
|
1147
1287
|
METADATA_TYPE_TO_CLASS = {
|
|
1148
|
-
definitions.KeyPrefixType.
|
|
1288
|
+
definitions.KeyPrefixType.BLOB_ENTRY: BlobEntryKey,
|
|
1149
1289
|
definitions.KeyPrefixType.DATABASE_METADATA: DatabaseMetaDataKey,
|
|
1150
|
-
definitions.KeyPrefixType.OBJECT_STORE_DATA: ObjectStoreDataKey,
|
|
1151
1290
|
definitions.KeyPrefixType.EXISTS_ENTRY: ExistsEntryKey,
|
|
1291
|
+
definitions.KeyPrefixType.GLOBAL_METADATA: GlobalMetaDataKey,
|
|
1292
|
+
definitions.KeyPrefixType.INVALID_TYPE: None,
|
|
1152
1293
|
definitions.KeyPrefixType.INDEX_DATA: IndexDataKey,
|
|
1153
|
-
definitions.KeyPrefixType.
|
|
1154
|
-
definitions.KeyPrefixType.INVALID_TYPE: None
|
|
1294
|
+
definitions.KeyPrefixType.OBJECT_STORE_DATA: ObjectStoreDataKey,
|
|
1155
1295
|
}
|
|
1156
1296
|
|
|
1157
1297
|
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Any:
|
|
@@ -1166,19 +1306,25 @@ class IndexedDbKey(BaseIndexedDBKey):
|
|
|
1166
1306
|
cls,
|
|
1167
1307
|
decoder: utils.LevelDBDecoder,
|
|
1168
1308
|
key_prefix: KeyPrefix,
|
|
1169
|
-
base_offset: int = 0
|
|
1170
|
-
) -> Union[
|
|
1171
|
-
|
|
1172
|
-
|
|
1309
|
+
base_offset: int = 0,
|
|
1310
|
+
) -> Union[
|
|
1311
|
+
BlobEntryKey,
|
|
1312
|
+
DatabaseMetaDataKey,
|
|
1313
|
+
ExistsEntryKey,
|
|
1314
|
+
GlobalMetaDataKey,
|
|
1315
|
+
IndexDataKey,
|
|
1316
|
+
ObjectStoreDataKey,
|
|
1317
|
+
]:
|
|
1173
1318
|
"""Decodes the IndexedDB key."""
|
|
1174
1319
|
key_type = key_prefix.GetKeyPrefixType()
|
|
1175
1320
|
key_class = cls.METADATA_TYPE_TO_CLASS.get(key_type)
|
|
1176
1321
|
if not key_class:
|
|
1177
|
-
raise errors.ParserError(
|
|
1322
|
+
raise errors.ParserError("Unknown KeyPrefixType")
|
|
1178
1323
|
return key_class.FromDecoder(
|
|
1179
1324
|
decoder=decoder,
|
|
1180
|
-
key_prefix=key_prefix, #
|
|
1181
|
-
base_offset=base_offset
|
|
1325
|
+
key_prefix=key_prefix, # type: ignore[return-value]
|
|
1326
|
+
base_offset=base_offset,
|
|
1327
|
+
)
|
|
1182
1328
|
|
|
1183
1329
|
|
|
1184
1330
|
@dataclass
|
|
@@ -1190,42 +1336,49 @@ class IndexMetaDataKey(BaseIndexedDBKey):
|
|
|
1190
1336
|
index_id: the index ID.
|
|
1191
1337
|
metadata_type: the metadata key type.
|
|
1192
1338
|
"""
|
|
1339
|
+
|
|
1193
1340
|
object_store_id: int
|
|
1194
1341
|
index_id: int
|
|
1195
1342
|
metadata_type: definitions.IndexMetaDataKeyType
|
|
1196
1343
|
|
|
1197
1344
|
def DecodeValue(
|
|
1198
|
-
self, decoder: utils.LevelDBDecoder
|
|
1345
|
+
self, decoder: utils.LevelDBDecoder
|
|
1346
|
+
) -> Union[bool, IDBKeyPath, str]:
|
|
1199
1347
|
"""Decodes the index metadata value."""
|
|
1200
1348
|
if self.metadata_type == definitions.IndexMetaDataKeyType.INDEX_NAME:
|
|
1201
1349
|
return decoder.DecodeString()[1]
|
|
1202
1350
|
if self.metadata_type == definitions.IndexMetaDataKeyType.KEY_PATH:
|
|
1203
1351
|
return IDBKeyPath.FromDecoder(decoder)
|
|
1204
|
-
if
|
|
1205
|
-
definitions.IndexMetaDataKeyType.MULTI_ENTRY_FLAG):
|
|
1352
|
+
if self.metadata_type == definitions.IndexMetaDataKeyType.MULTI_ENTRY_FLAG:
|
|
1206
1353
|
return decoder.DecodeBool()[1]
|
|
1207
1354
|
if self.metadata_type == definitions.IndexMetaDataKeyType.UNIQUE_FLAG:
|
|
1208
1355
|
return decoder.DecodeBool()[1]
|
|
1209
1356
|
raise errors.ParserError(
|
|
1210
|
-
f
|
|
1357
|
+
f"Unknown index metadata type {self.metadata_type}"
|
|
1358
|
+
)
|
|
1211
1359
|
|
|
1212
1360
|
@classmethod
|
|
1213
1361
|
def FromDecoder(
|
|
1214
1362
|
cls,
|
|
1215
1363
|
decoder: utils.LevelDBDecoder,
|
|
1216
|
-
key_prefix: KeyPrefix,
|
|
1364
|
+
key_prefix: KeyPrefix,
|
|
1365
|
+
base_offset: int = 0,
|
|
1217
1366
|
) -> IndexMetaDataKey:
|
|
1218
1367
|
"""Decodes the index metadata key."""
|
|
1219
1368
|
offset, key_type = decoder.DecodeUint8()
|
|
1220
1369
|
if key_type != definitions.DatabaseMetaDataKeyType.INDEX_META_DATA:
|
|
1221
|
-
raise errors.ParserError(
|
|
1370
|
+
raise errors.ParserError("Not an IndexMetaDataKey.")
|
|
1222
1371
|
_, object_store_id = decoder.DecodeVarint()
|
|
1223
1372
|
_, index_id = decoder.DecodeVarint()
|
|
1224
1373
|
_, metadata_bytes = decoder.ReadBytes(1)
|
|
1225
1374
|
metadata_type = definitions.IndexMetaDataKeyType(metadata_bytes[0])
|
|
1226
|
-
return cls(
|
|
1227
|
-
|
|
1228
|
-
|
|
1375
|
+
return cls(
|
|
1376
|
+
offset=base_offset + offset,
|
|
1377
|
+
key_prefix=key_prefix,
|
|
1378
|
+
object_store_id=object_store_id,
|
|
1379
|
+
index_id=index_id,
|
|
1380
|
+
metadata_type=metadata_type,
|
|
1381
|
+
)
|
|
1229
1382
|
|
|
1230
1383
|
|
|
1231
1384
|
@dataclass
|
|
@@ -1244,6 +1397,7 @@ class ExternalObjectEntry(utils.FromDecoderMixin):
|
|
|
1244
1397
|
last_modified: the last modified time if a blob or file, None otherwise.
|
|
1245
1398
|
token: the token if a filesystem access handle, None otherwise.
|
|
1246
1399
|
"""
|
|
1400
|
+
|
|
1247
1401
|
offset: int = field(compare=False)
|
|
1248
1402
|
object_type: definitions.ExternalObjectType
|
|
1249
1403
|
blob_number: Optional[int]
|
|
@@ -1255,16 +1409,15 @@ class ExternalObjectEntry(utils.FromDecoderMixin):
|
|
|
1255
1409
|
|
|
1256
1410
|
@classmethod
|
|
1257
1411
|
def FromDecoder(
|
|
1258
|
-
cls,
|
|
1259
|
-
decoder: utils.LevelDBDecoder,
|
|
1260
|
-
base_offset: int = 0
|
|
1412
|
+
cls, decoder: utils.LevelDBDecoder, base_offset: int = 0
|
|
1261
1413
|
) -> ExternalObjectEntry:
|
|
1262
1414
|
"""Decodes the external object entry."""
|
|
1263
1415
|
offset, object_type_value = decoder.DecodeUint8()
|
|
1264
1416
|
object_type = definitions.ExternalObjectType(object_type_value)
|
|
1265
|
-
if
|
|
1266
|
-
|
|
1267
|
-
|
|
1417
|
+
if object_type in (
|
|
1418
|
+
definitions.ExternalObjectType.BLOB,
|
|
1419
|
+
definitions.ExternalObjectType.FILE,
|
|
1420
|
+
):
|
|
1268
1421
|
_, blob_number = decoder.DecodeVarint()
|
|
1269
1422
|
_, mime_type = decoder.DecodeStringWithLength()
|
|
1270
1423
|
_, size = decoder.DecodeVarint()
|
|
@@ -1276,8 +1429,10 @@ class ExternalObjectEntry(utils.FromDecoderMixin):
|
|
|
1276
1429
|
last_modified = None
|
|
1277
1430
|
token = None
|
|
1278
1431
|
else:
|
|
1279
|
-
if (
|
|
1280
|
-
|
|
1432
|
+
if (
|
|
1433
|
+
object_type
|
|
1434
|
+
== definitions.ExternalObjectType.FILE_SYSTEM_ACCESS_HANDLE
|
|
1435
|
+
):
|
|
1281
1436
|
_, token = decoder.DecodeBlobWithLength()
|
|
1282
1437
|
else:
|
|
1283
1438
|
token = None
|
|
@@ -1287,9 +1442,16 @@ class ExternalObjectEntry(utils.FromDecoderMixin):
|
|
|
1287
1442
|
filename = None
|
|
1288
1443
|
last_modified = None
|
|
1289
1444
|
|
|
1290
|
-
return cls(
|
|
1291
|
-
|
|
1292
|
-
|
|
1445
|
+
return cls(
|
|
1446
|
+
offset=base_offset + offset,
|
|
1447
|
+
object_type=object_type,
|
|
1448
|
+
blob_number=blob_number,
|
|
1449
|
+
mime_type=mime_type,
|
|
1450
|
+
size=size,
|
|
1451
|
+
filename=filename,
|
|
1452
|
+
last_modified=last_modified,
|
|
1453
|
+
token=token,
|
|
1454
|
+
)
|
|
1293
1455
|
|
|
1294
1456
|
|
|
1295
1457
|
@dataclass
|
|
@@ -1300,14 +1462,13 @@ class IndexedDBExternalObject(utils.FromDecoderMixin):
|
|
|
1300
1462
|
offset: the offset of the IndexedDBExternalObject.
|
|
1301
1463
|
entries: a list of external objects.
|
|
1302
1464
|
"""
|
|
1465
|
+
|
|
1303
1466
|
offset: int = field(compare=False)
|
|
1304
1467
|
entries: list[ExternalObjectEntry]
|
|
1305
1468
|
|
|
1306
1469
|
@classmethod
|
|
1307
1470
|
def FromDecoder(
|
|
1308
|
-
cls,
|
|
1309
|
-
decoder: utils.LevelDBDecoder,
|
|
1310
|
-
base_offset: int = 0
|
|
1471
|
+
cls, decoder: utils.LevelDBDecoder, base_offset: int = 0
|
|
1311
1472
|
) -> IndexedDBExternalObject:
|
|
1312
1473
|
"""Decodes the external object."""
|
|
1313
1474
|
entries = []
|
|
@@ -1319,20 +1480,6 @@ class IndexedDBExternalObject(utils.FromDecoderMixin):
|
|
|
1319
1480
|
return cls(offset=base_offset + offset, entries=entries)
|
|
1320
1481
|
|
|
1321
1482
|
|
|
1322
|
-
@dataclass
|
|
1323
|
-
class ObjectStore:
|
|
1324
|
-
"""An IndexedDB Object Store.
|
|
1325
|
-
|
|
1326
|
-
Attributes:
|
|
1327
|
-
id: the object store ID.
|
|
1328
|
-
name: the object store name.
|
|
1329
|
-
records: the records in the object store.
|
|
1330
|
-
"""
|
|
1331
|
-
id: int
|
|
1332
|
-
name: str
|
|
1333
|
-
records: list = field(default_factory=list, repr=False)
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
1483
|
@dataclass
|
|
1337
1484
|
class IndexedDBRecord:
|
|
1338
1485
|
"""An IndexedDB Record.
|
|
@@ -1347,7 +1494,15 @@ class IndexedDBRecord:
|
|
|
1347
1494
|
level: the leveldb level, if applicable, None can indicate the record
|
|
1348
1495
|
originated from a log file or the level could not be determined.
|
|
1349
1496
|
recovered: True if the record is a recovered record.
|
|
1497
|
+
database_id: the database ID.
|
|
1498
|
+
object_store_id: the object store ID.
|
|
1499
|
+
database_name: the name of the database, if available.
|
|
1500
|
+
object_store_name: the name of the object store, if available.
|
|
1501
|
+
blob: the blob contents, if available.
|
|
1502
|
+
raw_key: the raw key, if available.
|
|
1503
|
+
raw_value: the raw value, if available.
|
|
1350
1504
|
"""
|
|
1505
|
+
|
|
1351
1506
|
path: str
|
|
1352
1507
|
offset: int
|
|
1353
1508
|
key: Any
|
|
@@ -1356,72 +1511,97 @@ class IndexedDBRecord:
|
|
|
1356
1511
|
type: int
|
|
1357
1512
|
level: Optional[int]
|
|
1358
1513
|
recovered: Optional[bool]
|
|
1514
|
+
database_id: int
|
|
1515
|
+
object_store_id: int
|
|
1516
|
+
database_name: Optional[str] = None
|
|
1517
|
+
object_store_name: Optional[str] = None
|
|
1518
|
+
blob: Optional[bytes] = None
|
|
1519
|
+
raw_key: Optional[bytes] = None
|
|
1520
|
+
raw_value: Optional[bytes] = None
|
|
1359
1521
|
|
|
1360
1522
|
@classmethod
|
|
1361
1523
|
def FromLevelDBRecord(
|
|
1362
|
-
cls,
|
|
1363
|
-
db_record: record.LevelDBRecord
|
|
1524
|
+
cls, db_record: record.LevelDBRecord, parse_value: bool = True
|
|
1364
1525
|
) -> IndexedDBRecord:
|
|
1365
1526
|
"""Returns an IndexedDBRecord from a ParsedInternalKey."""
|
|
1366
1527
|
idb_key = IndexedDbKey.FromBytes(
|
|
1367
|
-
db_record.record.key, base_offset=db_record.record.offset
|
|
1368
|
-
|
|
1528
|
+
db_record.record.key, base_offset=db_record.record.offset
|
|
1529
|
+
)
|
|
1530
|
+
|
|
1531
|
+
if parse_value:
|
|
1532
|
+
idb_value = idb_key.ParseValue(db_record.record.value)
|
|
1533
|
+
else:
|
|
1534
|
+
idb_value = None
|
|
1535
|
+
|
|
1369
1536
|
return cls(
|
|
1370
1537
|
path=db_record.path,
|
|
1371
1538
|
offset=db_record.record.offset,
|
|
1372
1539
|
key=idb_key,
|
|
1373
1540
|
value=idb_value,
|
|
1374
|
-
sequence_number=db_record.record.sequence_number
|
|
1375
|
-
|
|
1541
|
+
sequence_number=db_record.record.sequence_number
|
|
1542
|
+
if hasattr(db_record.record, "sequence_number")
|
|
1543
|
+
else None,
|
|
1376
1544
|
type=db_record.record.record_type,
|
|
1377
1545
|
level=db_record.level,
|
|
1378
|
-
recovered=db_record.recovered
|
|
1546
|
+
recovered=db_record.recovered,
|
|
1547
|
+
database_id=idb_key.key_prefix.database_id,
|
|
1548
|
+
object_store_id=idb_key.key_prefix.object_store_id,
|
|
1549
|
+
database_name=None,
|
|
1550
|
+
object_store_name=None,
|
|
1551
|
+
blob=None,
|
|
1552
|
+
raw_key=db_record.record.key,
|
|
1553
|
+
raw_value=db_record.record.value,
|
|
1554
|
+
)
|
|
1379
1555
|
|
|
1380
1556
|
@classmethod
|
|
1381
1557
|
def FromFile(
|
|
1382
|
-
cls,
|
|
1383
|
-
file_path: pathlib.Path
|
|
1558
|
+
cls, file_path: pathlib.Path, parse_value: bool = True
|
|
1384
1559
|
) -> Generator[IndexedDBRecord, None, None]:
|
|
1385
1560
|
"""Yields IndexedDBRecords from a file."""
|
|
1386
1561
|
for db_record in record.LevelDBRecord.FromFile(file_path):
|
|
1387
1562
|
try:
|
|
1388
|
-
yield cls.FromLevelDBRecord(db_record)
|
|
1389
|
-
except(
|
|
1563
|
+
yield cls.FromLevelDBRecord(db_record, parse_value=parse_value)
|
|
1564
|
+
except (
|
|
1390
1565
|
errors.ParserError,
|
|
1391
1566
|
errors.DecoderError,
|
|
1392
|
-
NotImplementedError
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1567
|
+
NotImplementedError,
|
|
1568
|
+
) as err:
|
|
1569
|
+
print(
|
|
1570
|
+
(
|
|
1571
|
+
"Error parsing Indexeddb record: "
|
|
1572
|
+
f"{err} at offset {db_record.record.offset} in "
|
|
1573
|
+
f"{db_record.path}"
|
|
1574
|
+
),
|
|
1575
|
+
file=sys.stderr,
|
|
1576
|
+
)
|
|
1577
|
+
print(f"Traceback: {traceback.format_exc()}", file=sys.stderr)
|
|
1399
1578
|
|
|
1400
1579
|
|
|
1401
1580
|
class FolderReader:
|
|
1402
1581
|
"""A IndexedDB folder reader for Chrome/Chromium.
|
|
1403
1582
|
|
|
1404
1583
|
Attributes:
|
|
1405
|
-
|
|
1584
|
+
folder_name (str): the source LevelDB folder.
|
|
1406
1585
|
"""
|
|
1407
1586
|
|
|
1408
|
-
def __init__(self,
|
|
1587
|
+
def __init__(self, folder_name: pathlib.Path):
|
|
1409
1588
|
"""Initializes the FileReader.
|
|
1410
1589
|
|
|
1411
1590
|
Args:
|
|
1412
|
-
|
|
1591
|
+
folder_name: the source IndexedDB folder.
|
|
1413
1592
|
|
|
1414
1593
|
Raises:
|
|
1415
|
-
ValueError: if
|
|
1594
|
+
ValueError: if folder_name is None or not a directory.
|
|
1416
1595
|
"""
|
|
1417
|
-
if not
|
|
1418
|
-
raise ValueError(f
|
|
1419
|
-
self.
|
|
1596
|
+
if not folder_name or not folder_name.is_dir():
|
|
1597
|
+
raise ValueError(f"{folder_name} is None or not a directory")
|
|
1598
|
+
self.folder_name = folder_name
|
|
1420
1599
|
|
|
1421
1600
|
def GetRecords(
|
|
1422
1601
|
self,
|
|
1423
1602
|
use_manifest: bool = False,
|
|
1424
|
-
use_sequence_number: bool = False
|
|
1603
|
+
use_sequence_number: bool = False,
|
|
1604
|
+
parse_value: bool = True,
|
|
1425
1605
|
) -> Generator[IndexedDBRecord, None, None]:
|
|
1426
1606
|
"""Yield LevelDBRecords.
|
|
1427
1607
|
|
|
@@ -1429,23 +1609,31 @@ class FolderReader:
|
|
|
1429
1609
|
use_manifest: True to use the current manifest in the folder as a means to
|
|
1430
1610
|
find the active file set.
|
|
1431
1611
|
use_sequence_number: True to use the sequence number to determine the
|
|
1612
|
+
recovered field.
|
|
1613
|
+
parse_value: True to parse values.
|
|
1614
|
+
|
|
1432
1615
|
Yields:
|
|
1433
1616
|
IndexedDBRecord.
|
|
1434
1617
|
"""
|
|
1435
|
-
leveldb_folder_reader = record.FolderReader(self.
|
|
1618
|
+
leveldb_folder_reader = record.FolderReader(self.folder_name)
|
|
1436
1619
|
for leveldb_record in leveldb_folder_reader.GetRecords(
|
|
1437
|
-
use_manifest=use_manifest,
|
|
1438
|
-
|
|
1620
|
+
use_manifest=use_manifest, use_sequence_number=use_sequence_number
|
|
1621
|
+
):
|
|
1439
1622
|
try:
|
|
1440
1623
|
yield IndexedDBRecord.FromLevelDBRecord(
|
|
1441
|
-
leveldb_record
|
|
1442
|
-
|
|
1624
|
+
leveldb_record, parse_value=parse_value
|
|
1625
|
+
)
|
|
1626
|
+
except (
|
|
1443
1627
|
errors.ParserError,
|
|
1444
1628
|
errors.DecoderError,
|
|
1445
|
-
NotImplementedError
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1629
|
+
NotImplementedError,
|
|
1630
|
+
) as err:
|
|
1631
|
+
print(
|
|
1632
|
+
(
|
|
1633
|
+
"Error parsing Indexeddb record: "
|
|
1634
|
+
f"{err} at offset {leveldb_record.record.offset} in "
|
|
1635
|
+
f"{leveldb_record.path}"
|
|
1636
|
+
),
|
|
1637
|
+
file=sys.stderr,
|
|
1638
|
+
)
|
|
1639
|
+
print(f"Traceback: {traceback.format_exc()}", file=sys.stderr)
|