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