dfindexeddb 20240324__py3-none-any.whl → 20240331__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/cli.py +19 -8
- dfindexeddb/leveldb/cli.py +66 -23
- dfindexeddb/leveldb/descriptor.py +51 -3
- dfindexeddb/version.py +1 -1
- {dfindexeddb-20240324.dist-info → dfindexeddb-20240331.dist-info}/METADATA +36 -6
- dfindexeddb-20240331.dist-info/RECORD +22 -0
- dfindexeddb/indexeddb/blink.py +0 -116
- dfindexeddb/indexeddb/chromium.py +0 -1360
- dfindexeddb/indexeddb/definitions.py +0 -306
- dfindexeddb/indexeddb/v8.py +0 -642
- dfindexeddb-20240324.dist-info/RECORD +0 -26
- {dfindexeddb-20240324.dist-info → dfindexeddb-20240331.dist-info}/AUTHORS +0 -0
- {dfindexeddb-20240324.dist-info → dfindexeddb-20240331.dist-info}/LICENSE +0 -0
- {dfindexeddb-20240324.dist-info → dfindexeddb-20240331.dist-info}/WHEEL +0 -0
- {dfindexeddb-20240324.dist-info → dfindexeddb-20240331.dist-info}/entry_points.txt +0 -0
- {dfindexeddb-20240324.dist-info → dfindexeddb-20240331.dist-info}/top_level.txt +0 -0
|
@@ -1,1360 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# Copyright 2024 Google LLC
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
"""Parses Chromium IndexedDb structures."""
|
|
16
|
-
from __future__ import annotations
|
|
17
|
-
from dataclasses import dataclass, field
|
|
18
|
-
from datetime import datetime
|
|
19
|
-
import io
|
|
20
|
-
from typing import Any, BinaryIO, Optional, Tuple, Type, TypeVar, Union
|
|
21
|
-
|
|
22
|
-
from dfindexeddb import errors
|
|
23
|
-
from dfindexeddb.indexeddb import blink
|
|
24
|
-
from dfindexeddb.indexeddb import definitions
|
|
25
|
-
from dfindexeddb.leveldb import ldb
|
|
26
|
-
from dfindexeddb.leveldb import log
|
|
27
|
-
from dfindexeddb.leveldb import utils
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
T = TypeVar('T')
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@dataclass
|
|
34
|
-
class KeyPrefix(utils.FromDecoderMixin):
|
|
35
|
-
"""The IndexedDB key prefix.
|
|
36
|
-
|
|
37
|
-
Attributes:
|
|
38
|
-
offset: the offset of the key prefix.
|
|
39
|
-
database_id: the database ID.
|
|
40
|
-
object_store_id: the object store ID.
|
|
41
|
-
index_id: the index ID.
|
|
42
|
-
"""
|
|
43
|
-
offset: int = field(compare=False)
|
|
44
|
-
database_id: int
|
|
45
|
-
object_store_id: int
|
|
46
|
-
index_id: int
|
|
47
|
-
|
|
48
|
-
@classmethod
|
|
49
|
-
def FromDecoder(
|
|
50
|
-
cls, decoder: utils.LevelDBDecoder, base_offset: int = 0) -> KeyPrefix:
|
|
51
|
-
"""Decodes a KeyPrefix from the current position of a LevelDBDecoder.
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
decoder: the LevelDBDecoder.
|
|
55
|
-
base_offset: the base offset.
|
|
56
|
-
|
|
57
|
-
Returns:
|
|
58
|
-
the decoded KeyPrefix.
|
|
59
|
-
|
|
60
|
-
Raises:
|
|
61
|
-
ParserError: when there is an invalid database/object store/index ID
|
|
62
|
-
length.
|
|
63
|
-
"""
|
|
64
|
-
offset, raw_prefix = decoder.ReadBytes(1)
|
|
65
|
-
|
|
66
|
-
database_id_length = (raw_prefix[0] & 0xE0 >> 5) + 1
|
|
67
|
-
object_store_id_length = (raw_prefix[0] & 0x1C >> 2) + 1
|
|
68
|
-
index_id_length = (raw_prefix[0] & 0x03) + 1
|
|
69
|
-
|
|
70
|
-
if database_id_length < 1 or database_id_length > 8:
|
|
71
|
-
raise errors.ParserError('Invalid database ID length')
|
|
72
|
-
|
|
73
|
-
if object_store_id_length < 1 or object_store_id_length > 8:
|
|
74
|
-
raise errors.ParserError('Invalid object store ID length')
|
|
75
|
-
|
|
76
|
-
if index_id_length < 1 or index_id_length > 4:
|
|
77
|
-
raise errors.ParserError('Invalid index ID length')
|
|
78
|
-
|
|
79
|
-
_, database_id = decoder.DecodeInt(database_id_length)
|
|
80
|
-
_, object_store_id = decoder.DecodeInt(object_store_id_length)
|
|
81
|
-
_, index_id = decoder.DecodeInt(index_id_length)
|
|
82
|
-
|
|
83
|
-
return cls(
|
|
84
|
-
offset=base_offset + offset,
|
|
85
|
-
database_id=database_id,
|
|
86
|
-
object_store_id=object_store_id,
|
|
87
|
-
index_id=index_id)
|
|
88
|
-
|
|
89
|
-
def GetKeyPrefixType(self) -> definitions.KeyPrefixType:
|
|
90
|
-
"""Returns the KeyPrefixType.
|
|
91
|
-
|
|
92
|
-
The KeyPrefixType is based on the database/object store/index ID values.
|
|
93
|
-
|
|
94
|
-
Raises:
|
|
95
|
-
ParserError: if the key prefix is unknown.
|
|
96
|
-
"""
|
|
97
|
-
if not self.database_id:
|
|
98
|
-
return definitions.KeyPrefixType.GLOBAL_METADATA
|
|
99
|
-
if not self.object_store_id:
|
|
100
|
-
return definitions.KeyPrefixType.DATABASE_METADATA
|
|
101
|
-
if self.index_id == 1:
|
|
102
|
-
return definitions.KeyPrefixType.OBJECT_STORE_DATA
|
|
103
|
-
if self.index_id == 2:
|
|
104
|
-
return definitions.KeyPrefixType.EXISTS_ENTRY
|
|
105
|
-
if self.index_id == 3:
|
|
106
|
-
return definitions.KeyPrefixType.BLOB_ENTRY
|
|
107
|
-
if self.index_id >= 30:
|
|
108
|
-
return definitions.KeyPrefixType.INDEX_DATA
|
|
109
|
-
raise errors.ParserError(
|
|
110
|
-
f'Unknown KeyPrefixType (index_id={self.index_id})')
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
@dataclass
|
|
114
|
-
class IDBKey(utils.FromDecoderMixin):
|
|
115
|
-
"""An IDBKey.
|
|
116
|
-
|
|
117
|
-
Attributes:
|
|
118
|
-
offset: the offset of the IDBKey.
|
|
119
|
-
type: the type of the IDBKey.
|
|
120
|
-
value: the value of the IDBKey.
|
|
121
|
-
"""
|
|
122
|
-
offset: int = field(compare=False)
|
|
123
|
-
type: definitions.IDBKeyType
|
|
124
|
-
value: Union[list, bytes, str, float, datetime, None]
|
|
125
|
-
|
|
126
|
-
_MAXIMUM_DEPTH = 2000
|
|
127
|
-
|
|
128
|
-
@classmethod
|
|
129
|
-
def FromDecoder(
|
|
130
|
-
cls,
|
|
131
|
-
decoder: utils.LevelDBDecoder,
|
|
132
|
-
base_offset: int = 0 #pylint: disable=unused-argument
|
|
133
|
-
) -> IDBKey:
|
|
134
|
-
"""Decodes an IDBKey from the current position of a LevelDBDecoder.
|
|
135
|
-
|
|
136
|
-
Args:
|
|
137
|
-
decoder: the LevelDBDecoder
|
|
138
|
-
base_offset: the base offset.
|
|
139
|
-
|
|
140
|
-
Returns:
|
|
141
|
-
An IDBKey
|
|
142
|
-
|
|
143
|
-
Raises:
|
|
144
|
-
ParserError: on invalid IDBKeyType or invalid array length during
|
|
145
|
-
parsing.
|
|
146
|
-
RecursionError: if maximum depth encountered during parsing.
|
|
147
|
-
"""
|
|
148
|
-
|
|
149
|
-
def RecursiveParse(depth: int) -> Tuple[
|
|
150
|
-
int, definitions.IDBKeyType, Union[
|
|
151
|
-
list, bytes, str, float, datetime, None]]:
|
|
152
|
-
"""Recursively parses IDBKeys.
|
|
153
|
-
|
|
154
|
-
Args:
|
|
155
|
-
depth: the current recursion depth.
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
A tuple of the offset, the key type and the key value (where the value
|
|
159
|
-
can be bytes, str, float, datetime or a list of these types).
|
|
160
|
-
|
|
161
|
-
Raises:
|
|
162
|
-
ParserError: on invalid IDBKeyType or invalid array length during
|
|
163
|
-
parsing.
|
|
164
|
-
RecursionError: if maximum depth encountered during parsing.
|
|
165
|
-
"""
|
|
166
|
-
if depth == cls._MAXIMUM_DEPTH:
|
|
167
|
-
raise RecursionError('Maximum recursion depth encountered during parse')
|
|
168
|
-
offset, key_type_value = decoder.DecodeInt(1)
|
|
169
|
-
key_type = definitions.IDBKeyType(key_type_value)
|
|
170
|
-
|
|
171
|
-
if key_type == definitions.IDBKeyType.NULL:
|
|
172
|
-
value = None
|
|
173
|
-
elif key_type == definitions.IDBKeyType.ARRAY:
|
|
174
|
-
_, length = decoder.DecodeVarint()
|
|
175
|
-
if length < 0:
|
|
176
|
-
raise errors.ParserError('Invalid length encountered')
|
|
177
|
-
value = []
|
|
178
|
-
while length:
|
|
179
|
-
entry = RecursiveParse(depth + 1)
|
|
180
|
-
value.append(entry[2])
|
|
181
|
-
length -= 1
|
|
182
|
-
elif key_type == definitions.IDBKeyType.BINARY:
|
|
183
|
-
_, value = decoder.DecodeBlobWithLength()
|
|
184
|
-
elif key_type == definitions.IDBKeyType.STRING:
|
|
185
|
-
_, value = decoder.DecodeStringWithLength()
|
|
186
|
-
elif key_type == definitions.IDBKeyType.DATE:
|
|
187
|
-
_, raw_value = decoder.DecodeDouble()
|
|
188
|
-
value = datetime.utcfromtimestamp(raw_value/1000.0)
|
|
189
|
-
elif key_type == definitions.IDBKeyType.NUMBER:
|
|
190
|
-
_, value = decoder.DecodeDouble()
|
|
191
|
-
elif key_type == definitions.IDBKeyType.MIN_KEY:
|
|
192
|
-
value = None
|
|
193
|
-
else:
|
|
194
|
-
raise errors.ParserError('Invalid IndexedDbKeyType')
|
|
195
|
-
return offset, key_type, value
|
|
196
|
-
|
|
197
|
-
offset, key_type, value = RecursiveParse(0)
|
|
198
|
-
return cls(base_offset + offset, key_type, value)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
@dataclass
|
|
202
|
-
class IDBKeyPath(utils.FromDecoderMixin):
|
|
203
|
-
"""An IDBKeyPath.
|
|
204
|
-
|
|
205
|
-
Arguments:
|
|
206
|
-
offset: the offset of the IDBKeyPath.
|
|
207
|
-
type: the IDBKeyPath type.
|
|
208
|
-
value: the IDBKeyPath value.
|
|
209
|
-
"""
|
|
210
|
-
offset: int = field(compare=False)
|
|
211
|
-
type: definitions.IDBKeyPathType
|
|
212
|
-
value: Union[str, list[str], None]
|
|
213
|
-
|
|
214
|
-
@classmethod
|
|
215
|
-
def FromDecoder(cls, decoder: utils.LevelDBDecoder,
|
|
216
|
-
base_offset: int = 0) -> IDBKeyPath:
|
|
217
|
-
"""Decodes an IDBKeyPath from the current position of a LevelDBDecoder.
|
|
218
|
-
|
|
219
|
-
Args:
|
|
220
|
-
decoder: the LevelDBDecoder.
|
|
221
|
-
base_offset: the base offset.
|
|
222
|
-
|
|
223
|
-
Returns:
|
|
224
|
-
An IDBKeyPath
|
|
225
|
-
|
|
226
|
-
Raises:
|
|
227
|
-
ParserError: on insufficient bytes or invalid array length during
|
|
228
|
-
parsing.
|
|
229
|
-
"""
|
|
230
|
-
buffer = decoder.stream.getvalue() #pytype: disable=attribute-error
|
|
231
|
-
if len(buffer) < 3:
|
|
232
|
-
raise errors.ParserError('Insufficient bytes to parse.')
|
|
233
|
-
|
|
234
|
-
if buffer[0:2] != b'\x00\x00':
|
|
235
|
-
offset, value = decoder.DecodeString()
|
|
236
|
-
return IDBKeyPath(offset, definitions.IDBKeyPathType.STRING, value)
|
|
237
|
-
|
|
238
|
-
_, type_bytes = decoder.ReadBytes(3)
|
|
239
|
-
key_path_type_byte = type_bytes[2]
|
|
240
|
-
key_path_type = definitions.IDBKeyPathType(key_path_type_byte)
|
|
241
|
-
|
|
242
|
-
if key_path_type == definitions.IDBKeyPathType.NULL:
|
|
243
|
-
value = None
|
|
244
|
-
offset = decoder.stream.tell()
|
|
245
|
-
elif key_path_type == definitions.IDBKeyPathType.STRING:
|
|
246
|
-
offset, value = decoder.DecodeStringWithLength()
|
|
247
|
-
elif key_path_type == definitions.IDBKeyPathType.ARRAY:
|
|
248
|
-
value = []
|
|
249
|
-
offset, count = decoder.DecodeVarint()
|
|
250
|
-
if count < 0:
|
|
251
|
-
raise errors.ParserError(f'Invalid array length {count}')
|
|
252
|
-
for _ in range(count):
|
|
253
|
-
_, entry = decoder.DecodeStringWithLength()
|
|
254
|
-
value.append(entry)
|
|
255
|
-
return IDBKeyPath(base_offset + offset, key_path_type, value)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
@dataclass
|
|
259
|
-
class BlobJournalEntry(utils.FromDecoderMixin):
|
|
260
|
-
"""A blob journal entry.
|
|
261
|
-
|
|
262
|
-
Attributes:
|
|
263
|
-
offset (int): the offset.
|
|
264
|
-
database_id (int): the database ID.
|
|
265
|
-
blob_number (int): the blob number.
|
|
266
|
-
"""
|
|
267
|
-
offset: int = field(compare=False)
|
|
268
|
-
database_id: int
|
|
269
|
-
blob_number: int
|
|
270
|
-
|
|
271
|
-
@classmethod
|
|
272
|
-
def FromDecoder(cls, decoder: utils.LevelDBDecoder,
|
|
273
|
-
base_offset: int = 0) -> BlobJournalEntry:
|
|
274
|
-
"""Decodes a BlobJournalEntry from the current position of a LevelDBDecoder.
|
|
275
|
-
|
|
276
|
-
Args:
|
|
277
|
-
decoder: the LevelDBDecoder.
|
|
278
|
-
base_offset: the base offset.
|
|
279
|
-
|
|
280
|
-
Returns:
|
|
281
|
-
A BlobJournalEntry.
|
|
282
|
-
"""
|
|
283
|
-
offset, database_id = decoder.DecodeUint64Varint()
|
|
284
|
-
_, blob_number = decoder.DecodeUint64Varint()
|
|
285
|
-
return cls(offset=base_offset + offset, database_id=database_id,
|
|
286
|
-
blob_number=blob_number)
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
@dataclass
|
|
290
|
-
class BlobJournal(utils.FromDecoderMixin):
|
|
291
|
-
"""A BlobJournal.
|
|
292
|
-
|
|
293
|
-
Attributes:
|
|
294
|
-
offset (int): the offset.
|
|
295
|
-
entries (list[BlobJournalEntry]): the list of blob journal entries.
|
|
296
|
-
"""
|
|
297
|
-
offset: int = field(compare=False)
|
|
298
|
-
entries: list[BlobJournalEntry]
|
|
299
|
-
|
|
300
|
-
@classmethod
|
|
301
|
-
def FromDecoder(cls, decoder: utils.LevelDBDecoder,
|
|
302
|
-
base_offset: int = 0) -> BlobJournal:
|
|
303
|
-
"""Decodes a BlobJournal from the current position of a LevelDBDecoder.
|
|
304
|
-
|
|
305
|
-
Blob journals are zero-or-more instances of BlobJournalEntry. There is no
|
|
306
|
-
length prefix; just read until you run out of data.
|
|
307
|
-
|
|
308
|
-
Ref: indexeddb_db_leveldb_coding.cc#DecodeBlobJournal
|
|
309
|
-
|
|
310
|
-
Args:
|
|
311
|
-
decoder: the LevelDBDecoder
|
|
312
|
-
base_offset: the base offset.
|
|
313
|
-
|
|
314
|
-
Returns:
|
|
315
|
-
A BlobJournal
|
|
316
|
-
"""
|
|
317
|
-
offset = decoder.stream.tell()
|
|
318
|
-
entries = []
|
|
319
|
-
|
|
320
|
-
# since there is no length prefix, consume the remaining buffer
|
|
321
|
-
while True:
|
|
322
|
-
try:
|
|
323
|
-
journal_entry = BlobJournalEntry.FromDecoder(decoder, base_offset)
|
|
324
|
-
except errors.DecoderError:
|
|
325
|
-
break
|
|
326
|
-
entries.append(journal_entry)
|
|
327
|
-
|
|
328
|
-
return cls(offset=base_offset + offset, entries=entries)
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
@dataclass
|
|
332
|
-
class BaseIndexedDBKey:
|
|
333
|
-
"""A base class for IndexedDB coded leveldb keys and values.
|
|
334
|
-
|
|
335
|
-
This class provides an interface to parse the key (using from_bytes/
|
|
336
|
-
from_stream/from_decoder) and the value (using parse_value/decode_value).
|
|
337
|
-
|
|
338
|
-
Attributes:
|
|
339
|
-
offset: the offset of the key (after the key_prefix).
|
|
340
|
-
key_prefix: the key prefix.
|
|
341
|
-
"""
|
|
342
|
-
offset: int
|
|
343
|
-
key_prefix: KeyPrefix
|
|
344
|
-
|
|
345
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Any:
|
|
346
|
-
"""Decodes the value from the current position of the LevelDBDecoder.
|
|
347
|
-
|
|
348
|
-
To be implemented by subclasses.
|
|
349
|
-
|
|
350
|
-
Args:
|
|
351
|
-
decoder: the stream decoder
|
|
352
|
-
|
|
353
|
-
Raises:
|
|
354
|
-
NotImplementedError.
|
|
355
|
-
"""
|
|
356
|
-
raise NotImplementedError(f'{self.__class__.__name__}.decode_value')
|
|
357
|
-
|
|
358
|
-
def ParseValue(self, value_data: bytes) -> Any:
|
|
359
|
-
"""Parses the value from raw bytes.
|
|
360
|
-
|
|
361
|
-
Args:
|
|
362
|
-
value_data: the raw value bytes.
|
|
363
|
-
|
|
364
|
-
Returns:
|
|
365
|
-
The parsed value.
|
|
366
|
-
"""
|
|
367
|
-
if not value_data:
|
|
368
|
-
return None
|
|
369
|
-
decoder = utils.LevelDBDecoder(io.BytesIO(value_data))
|
|
370
|
-
return self.DecodeValue(decoder)
|
|
371
|
-
|
|
372
|
-
@classmethod
|
|
373
|
-
def FromDecoder(
|
|
374
|
-
cls: T,
|
|
375
|
-
decoder: utils.LevelDBDecoder,
|
|
376
|
-
key_prefix: KeyPrefix,
|
|
377
|
-
base_offset: int = 0
|
|
378
|
-
) -> T: #pylint: disable=unused-variable
|
|
379
|
-
"""Decodes the remaining key data from the current decoder position.
|
|
380
|
-
|
|
381
|
-
Args:
|
|
382
|
-
decoder: the stream decoder.
|
|
383
|
-
key_prefix: the decoded key_prefix.
|
|
384
|
-
base_offset: the base offset.
|
|
385
|
-
|
|
386
|
-
Returns:
|
|
387
|
-
The decoded key.
|
|
388
|
-
|
|
389
|
-
Raises:
|
|
390
|
-
NotImplementedError.
|
|
391
|
-
"""
|
|
392
|
-
raise NotImplementedError(f'{cls.__class__.__name__}.decode_key')
|
|
393
|
-
|
|
394
|
-
@classmethod
|
|
395
|
-
def FromStream(
|
|
396
|
-
cls: Type[T], stream: BinaryIO, base_offset: int = 0) -> T:
|
|
397
|
-
"""Parses the key from the current position of the binary stream.
|
|
398
|
-
|
|
399
|
-
Args:
|
|
400
|
-
stream: the binary stream.
|
|
401
|
-
base_offset: the base offset of the stream.
|
|
402
|
-
|
|
403
|
-
Returns:
|
|
404
|
-
The decoded key.
|
|
405
|
-
"""
|
|
406
|
-
decoder = utils.LevelDBDecoder(stream)
|
|
407
|
-
key_prefix = KeyPrefix.FromDecoder(decoder, base_offset=base_offset)
|
|
408
|
-
return cls.FromDecoder(
|
|
409
|
-
decoder=decoder, key_prefix=key_prefix, base_offset=base_offset)
|
|
410
|
-
|
|
411
|
-
@classmethod
|
|
412
|
-
def FromBytes(
|
|
413
|
-
cls: Type[T], raw_data: bytes, base_offset: int = 0) -> T:
|
|
414
|
-
"""Parses the key from the raw key bytes.
|
|
415
|
-
|
|
416
|
-
Args:
|
|
417
|
-
raw_data: the raw key data.
|
|
418
|
-
base_offset: the base offset of the key data.
|
|
419
|
-
|
|
420
|
-
Returns:
|
|
421
|
-
The decoded key.
|
|
422
|
-
"""
|
|
423
|
-
stream = io.BytesIO(raw_data)
|
|
424
|
-
return cls.FromStream(stream=stream, base_offset=base_offset)
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
@dataclass
|
|
428
|
-
class SchemaVersionKey(BaseIndexedDBKey):
|
|
429
|
-
"""A schema version IndexedDb key."""
|
|
430
|
-
|
|
431
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
432
|
-
"""Decodes the schema version value."""
|
|
433
|
-
return decoder.DecodeVarint()[1]
|
|
434
|
-
|
|
435
|
-
@classmethod
|
|
436
|
-
def FromDecoder(
|
|
437
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
438
|
-
base_offset: int = 0
|
|
439
|
-
) -> SchemaVersionKey:
|
|
440
|
-
"""Decodes the schema version key."""
|
|
441
|
-
offset, key_type = decoder.DecodeUint8()
|
|
442
|
-
if key_type != definitions.GlobalMetadataKeyType.SCHEMA_VERSION:
|
|
443
|
-
raise errors.ParserError('Not a SchemaVersionKey')
|
|
444
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
@dataclass
|
|
448
|
-
class MaxDatabaseIdKey(BaseIndexedDBKey):
|
|
449
|
-
"""A max database ID IndexedDB key."""
|
|
450
|
-
|
|
451
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
452
|
-
"""Decodes the maximum database value."""
|
|
453
|
-
return decoder.DecodeVarint()[1]
|
|
454
|
-
|
|
455
|
-
@classmethod
|
|
456
|
-
def FromDecoder(
|
|
457
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
458
|
-
base_offset: int = 0
|
|
459
|
-
) -> MaxDatabaseIdKey:
|
|
460
|
-
"""Decodes the maximum databse key."""
|
|
461
|
-
offset, key_type = decoder.DecodeUint8()
|
|
462
|
-
if key_type != definitions.GlobalMetadataKeyType.MAX_DATABASE_ID:
|
|
463
|
-
raise errors.ParserError('Not a MaxDatabaseIdKey')
|
|
464
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
@dataclass
|
|
468
|
-
class DataVersionKey(BaseIndexedDBKey):
|
|
469
|
-
"""A data version IndexedDB key."""
|
|
470
|
-
|
|
471
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
472
|
-
"""Decodes the data version value."""
|
|
473
|
-
return decoder.DecodeUint64Varint()[1]
|
|
474
|
-
|
|
475
|
-
@classmethod
|
|
476
|
-
def FromDecoder(
|
|
477
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
478
|
-
base_offset: int = 0
|
|
479
|
-
) -> DataVersionKey:
|
|
480
|
-
"""Decodes the data version key."""
|
|
481
|
-
offset, key_type = decoder.DecodeUint8()
|
|
482
|
-
if key_type != definitions.GlobalMetadataKeyType.DATA_VERSION:
|
|
483
|
-
raise errors.ParserError('Not a DataVersionKey')
|
|
484
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
@dataclass
|
|
488
|
-
class RecoveryBlobJournalKey(BaseIndexedDBKey):
|
|
489
|
-
"""A recovery blob journal IndexedDB key."""
|
|
490
|
-
|
|
491
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> BlobJournal:
|
|
492
|
-
"""Decodes the recovery blob journal value."""
|
|
493
|
-
return BlobJournal.FromDecoder(decoder)
|
|
494
|
-
|
|
495
|
-
@classmethod
|
|
496
|
-
def FromDecoder(
|
|
497
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
498
|
-
base_offset: int = 0
|
|
499
|
-
) -> RecoveryBlobJournalKey:
|
|
500
|
-
"""Decodes the recovery blob journal key."""
|
|
501
|
-
offset, key_type = decoder.DecodeUint8()
|
|
502
|
-
if key_type != definitions.GlobalMetadataKeyType.RECOVERY_BLOB_JOURNAL:
|
|
503
|
-
raise errors.ParserError('Not a RecoveryBlobJournalKey')
|
|
504
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
@dataclass
|
|
508
|
-
class ActiveBlobJournalKey(BaseIndexedDBKey):
|
|
509
|
-
"""An active blob journal IndexedDB key."""
|
|
510
|
-
|
|
511
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> BlobJournal:
|
|
512
|
-
"""Decodes the active blob journal value."""
|
|
513
|
-
return BlobJournal.FromDecoder(decoder)
|
|
514
|
-
|
|
515
|
-
@classmethod
|
|
516
|
-
def FromDecoder(
|
|
517
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
518
|
-
base_offset: int = 0
|
|
519
|
-
) -> ActiveBlobJournalKey:
|
|
520
|
-
"""Decodes the active blob journal value."""
|
|
521
|
-
offset, key_type = decoder.DecodeUint8()
|
|
522
|
-
if key_type != definitions.GlobalMetadataKeyType.ACTIVE_BLOB_JOURNAL:
|
|
523
|
-
raise errors.ParserError('Not a ActiveBlobJournalKey')
|
|
524
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
@dataclass
|
|
528
|
-
class EarliestSweepKey(BaseIndexedDBKey):
|
|
529
|
-
"""An earliest sweep IndexedDB key."""
|
|
530
|
-
|
|
531
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
532
|
-
"""Decodes the earliest sweep value."""
|
|
533
|
-
_, data = decoder.ReadBytes()
|
|
534
|
-
return int.from_bytes(data, byteorder='little', signed=False)
|
|
535
|
-
|
|
536
|
-
@classmethod
|
|
537
|
-
def FromDecoder(
|
|
538
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
539
|
-
base_offset: int = 0
|
|
540
|
-
) -> EarliestSweepKey:
|
|
541
|
-
"""Decodes the earliest sweep value."""
|
|
542
|
-
offset, key_type = decoder.DecodeUint8()
|
|
543
|
-
if key_type != definitions.GlobalMetadataKeyType.EARLIEST_SWEEP:
|
|
544
|
-
raise errors.ParserError('Not a EarliestSweepKey')
|
|
545
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
@dataclass
|
|
549
|
-
class EarlistCompactionTimeKey(BaseIndexedDBKey):
|
|
550
|
-
"""An earliest compaction time IndexedDB key."""
|
|
551
|
-
|
|
552
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
553
|
-
"""Decodes the earliest compaction time value."""
|
|
554
|
-
_, data = decoder.ReadBytes()
|
|
555
|
-
return int.from_bytes(data, byteorder='little', signed=False)
|
|
556
|
-
|
|
557
|
-
@classmethod
|
|
558
|
-
def FromDecoder(
|
|
559
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
560
|
-
base_offset: int = 0
|
|
561
|
-
) -> EarlistCompactionTimeKey:
|
|
562
|
-
"""Decodes the earliest compaction time key."""
|
|
563
|
-
offset, key_type = decoder.DecodeUint8()
|
|
564
|
-
if key_type != definitions.GlobalMetadataKeyType.EARLIEST_COMPACTION_TIME:
|
|
565
|
-
raise errors.ParserError('Not a EarlistCompactionTimeKey')
|
|
566
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
@dataclass
|
|
570
|
-
class ScopesPrefixKey(BaseIndexedDBKey):
|
|
571
|
-
"""A scopes prefix IndexedDB key."""
|
|
572
|
-
|
|
573
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Optional[bytes]:
|
|
574
|
-
"""Decodes the scopes prefix value."""
|
|
575
|
-
if decoder.NumRemainingBytes:
|
|
576
|
-
return decoder.ReadBytes()[1]
|
|
577
|
-
return None
|
|
578
|
-
|
|
579
|
-
@classmethod
|
|
580
|
-
def FromDecoder(
|
|
581
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
582
|
-
base_offset: int = 0
|
|
583
|
-
) -> ScopesPrefixKey:
|
|
584
|
-
"""Decodes the scopes prefix key."""
|
|
585
|
-
offset, key_type = decoder.DecodeUint8()
|
|
586
|
-
if key_type != definitions.GlobalMetadataKeyType.SCOPES_PREFIX:
|
|
587
|
-
raise errors.ParserError('Not a ScopesPrefixKey')
|
|
588
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix)
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
@dataclass
|
|
592
|
-
class DatabaseFreeListKey(BaseIndexedDBKey):
|
|
593
|
-
"""A database free list IndexedDB key.
|
|
594
|
-
|
|
595
|
-
Attributes:
|
|
596
|
-
database_id: the database ID.
|
|
597
|
-
"""
|
|
598
|
-
database_id: int
|
|
599
|
-
|
|
600
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder):
|
|
601
|
-
"""Decodes the database free list value."""
|
|
602
|
-
raise NotImplementedError('DatabaseFreeListKey.decode_value')
|
|
603
|
-
|
|
604
|
-
@classmethod
|
|
605
|
-
def FromDecoder(
|
|
606
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
607
|
-
base_offset: int = 0
|
|
608
|
-
) -> DatabaseFreeListKey:
|
|
609
|
-
"""Decodes the database free list key."""
|
|
610
|
-
offset, key_type = decoder.DecodeUint8()
|
|
611
|
-
if key_type != definitions.GlobalMetadataKeyType.DATABASE_FREE_LIST:
|
|
612
|
-
raise errors.ParserError('Not a DatabaseFreeListKey')
|
|
613
|
-
_, database_id = decoder.DecodeVarint()
|
|
614
|
-
return cls(
|
|
615
|
-
offset=base_offset + offset, key_prefix=key_prefix,
|
|
616
|
-
database_id=database_id)
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
@dataclass
|
|
620
|
-
class DatabaseNameKey(BaseIndexedDBKey):
|
|
621
|
-
"""A database name key.
|
|
622
|
-
|
|
623
|
-
Attributes:
|
|
624
|
-
origin: the origin of the database.
|
|
625
|
-
database_name: the database name.
|
|
626
|
-
"""
|
|
627
|
-
origin: str
|
|
628
|
-
database_name: str
|
|
629
|
-
|
|
630
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
631
|
-
"""Decodes the database name value.
|
|
632
|
-
|
|
633
|
-
The value is the corresponding database ID.
|
|
634
|
-
"""
|
|
635
|
-
return decoder.DecodeVarint()[1]
|
|
636
|
-
|
|
637
|
-
@classmethod
|
|
638
|
-
def FromDecoder(
|
|
639
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
640
|
-
base_offset: int = 0
|
|
641
|
-
) -> DatabaseNameKey:
|
|
642
|
-
"""Decodes the database name key."""
|
|
643
|
-
offset, key_type = decoder.DecodeUint8()
|
|
644
|
-
if key_type != definitions.GlobalMetadataKeyType.DATABASE_NAME:
|
|
645
|
-
raise errors.ParserError('Not a DatabaseNameKey')
|
|
646
|
-
_, origin = decoder.DecodeStringWithLength()
|
|
647
|
-
_, database_name = decoder.DecodeStringWithLength()
|
|
648
|
-
return cls(
|
|
649
|
-
offset=base_offset + offset, key_prefix=key_prefix, origin=origin,
|
|
650
|
-
database_name=database_name)
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
@dataclass
|
|
654
|
-
class GlobalMetaDataKey(BaseIndexedDBKey):
|
|
655
|
-
"""A GlobalMetaDataKey parser."""
|
|
656
|
-
|
|
657
|
-
METADATA_TYPE_TO_CLASS = {
|
|
658
|
-
definitions.GlobalMetadataKeyType
|
|
659
|
-
.SCHEMA_VERSION: SchemaVersionKey,
|
|
660
|
-
definitions.GlobalMetadataKeyType
|
|
661
|
-
.MAX_DATABASE_ID: MaxDatabaseIdKey,
|
|
662
|
-
definitions.GlobalMetadataKeyType
|
|
663
|
-
.DATA_VERSION: DataVersionKey,
|
|
664
|
-
definitions.GlobalMetadataKeyType
|
|
665
|
-
.RECOVERY_BLOB_JOURNAL: RecoveryBlobJournalKey,
|
|
666
|
-
definitions.GlobalMetadataKeyType
|
|
667
|
-
.ACTIVE_BLOB_JOURNAL: ActiveBlobJournalKey,
|
|
668
|
-
definitions.GlobalMetadataKeyType
|
|
669
|
-
.EARLIEST_SWEEP: EarliestSweepKey,
|
|
670
|
-
definitions.GlobalMetadataKeyType
|
|
671
|
-
.EARLIEST_COMPACTION_TIME: EarlistCompactionTimeKey,
|
|
672
|
-
definitions.GlobalMetadataKeyType
|
|
673
|
-
.SCOPES_PREFIX: ScopesPrefixKey,
|
|
674
|
-
definitions.GlobalMetadataKeyType
|
|
675
|
-
.DATABASE_FREE_LIST: DatabaseFreeListKey,
|
|
676
|
-
definitions.GlobalMetadataKeyType
|
|
677
|
-
.DATABASE_NAME: DatabaseNameKey}
|
|
678
|
-
|
|
679
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Any:
|
|
680
|
-
"""Decodes the value from the current position of the LevelDBDecoder.
|
|
681
|
-
|
|
682
|
-
Args:
|
|
683
|
-
decoder: the stream decoder
|
|
684
|
-
"""
|
|
685
|
-
|
|
686
|
-
@classmethod
|
|
687
|
-
def FromDecoder(
|
|
688
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
689
|
-
base_offset: int = 0
|
|
690
|
-
) -> Union[Type[ActiveBlobJournalKey],
|
|
691
|
-
Type[DataVersionKey],
|
|
692
|
-
Type[DatabaseFreeListKey],
|
|
693
|
-
Type[DatabaseNameKey],
|
|
694
|
-
Type[EarliestSweepKey],
|
|
695
|
-
Type[EarlistCompactionTimeKey],
|
|
696
|
-
Type[MaxDatabaseIdKey],
|
|
697
|
-
Type[RecoveryBlobJournalKey],
|
|
698
|
-
Type[SchemaVersionKey],
|
|
699
|
-
Type[ScopesPrefixKey]]:
|
|
700
|
-
"""Decodes the global metadata key.
|
|
701
|
-
|
|
702
|
-
Raises:
|
|
703
|
-
ParserError: if the key contains an unknown metadata key type.
|
|
704
|
-
"""
|
|
705
|
-
_, metadata_value = decoder.PeekBytes(1)
|
|
706
|
-
metadata_type = definitions.GlobalMetadataKeyType(metadata_value[0])
|
|
707
|
-
|
|
708
|
-
key_class = cls.METADATA_TYPE_TO_CLASS.get(metadata_type)
|
|
709
|
-
if not key_class:
|
|
710
|
-
raise errors.ParserError('Unknown metadata key type')
|
|
711
|
-
return key_class.FromDecoder(
|
|
712
|
-
decoder, key_prefix, base_offset) #pytype: disable=bad-return-type
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
@dataclass
|
|
716
|
-
class ObjectStoreFreeListKey(BaseIndexedDBKey):
|
|
717
|
-
"""An IndexedDB object store free list key.
|
|
718
|
-
|
|
719
|
-
Attributes:
|
|
720
|
-
object_store_id: the ID of the object store containing the free list.
|
|
721
|
-
"""
|
|
722
|
-
object_store_id: int
|
|
723
|
-
|
|
724
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder):
|
|
725
|
-
"""Decodes the object store free list value."""
|
|
726
|
-
raise NotImplementedError('ObjectStoreFreeListKey.decode_value')
|
|
727
|
-
|
|
728
|
-
@classmethod
|
|
729
|
-
def FromDecoder(
|
|
730
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
731
|
-
base_offset: int = 0
|
|
732
|
-
) -> ObjectStoreFreeListKey:
|
|
733
|
-
"""Decodes the object store free list key."""
|
|
734
|
-
offset, key_type = decoder.DecodeUint8()
|
|
735
|
-
if key_type != definitions.DatabaseMetaDataKeyType.OBJECT_STORE_FREE_LIST:
|
|
736
|
-
raise errors.ParserError('Not am ObjectStoreFreeListKey')
|
|
737
|
-
_, object_store_id = decoder.DecodeVarint()
|
|
738
|
-
return cls(
|
|
739
|
-
offset=base_offset + offset, key_prefix=key_prefix,
|
|
740
|
-
object_store_id=object_store_id)
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
@dataclass
|
|
744
|
-
class IndexFreeListKey(BaseIndexedDBKey):
|
|
745
|
-
"""An IndexedDB index free list key.
|
|
746
|
-
|
|
747
|
-
Attributes:
|
|
748
|
-
object_store_id: the ID of the object store containing the free list.
|
|
749
|
-
"""
|
|
750
|
-
object_store_id: int
|
|
751
|
-
|
|
752
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder):
|
|
753
|
-
"""Decodes the index free list value."""
|
|
754
|
-
raise NotImplementedError('IndexFreeListKey.decode_value')
|
|
755
|
-
|
|
756
|
-
@classmethod
|
|
757
|
-
def FromDecoder(
|
|
758
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
759
|
-
base_offset: int = 0
|
|
760
|
-
) -> IndexFreeListKey:
|
|
761
|
-
"""Decodes the index free list key."""
|
|
762
|
-
offset, key_type = decoder.DecodeUint8()
|
|
763
|
-
if key_type != definitions.DatabaseMetaDataKeyType.INDEX_FREE_LIST:
|
|
764
|
-
raise errors.ParserError('Not am IndexFreeListKey')
|
|
765
|
-
_, object_store_id = decoder.DecodeVarint()
|
|
766
|
-
return cls(
|
|
767
|
-
offset=base_offset + offset, key_prefix=key_prefix,
|
|
768
|
-
object_store_id=object_store_id)
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
@dataclass
|
|
772
|
-
class ObjectStoreNamesKey(BaseIndexedDBKey):
|
|
773
|
-
"""An IndexedDB object store name key.
|
|
774
|
-
|
|
775
|
-
Attributes:
|
|
776
|
-
object_store_name: the name of the object store.
|
|
777
|
-
"""
|
|
778
|
-
object_store_name: str
|
|
779
|
-
|
|
780
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
781
|
-
"""Decodes the object store names value."""
|
|
782
|
-
return decoder.DecodeVarint()[1]
|
|
783
|
-
|
|
784
|
-
@classmethod
|
|
785
|
-
def FromDecoder(cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
786
|
-
base_offset: int = 0) -> ObjectStoreNamesKey:
|
|
787
|
-
"""Decodes the object store names key."""
|
|
788
|
-
offset, key_type = decoder.DecodeUint8()
|
|
789
|
-
if key_type != definitions.DatabaseMetaDataKeyType.OBJECT_STORE_NAMES:
|
|
790
|
-
raise errors.ParserError('Not am ObjectStoreNamesKey')
|
|
791
|
-
_, object_store_name = decoder.DecodeStringWithLength()
|
|
792
|
-
return cls(key_prefix=key_prefix, offset=base_offset + offset,
|
|
793
|
-
object_store_name=object_store_name)
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
@dataclass
|
|
797
|
-
class IndexNamesKey(BaseIndexedDBKey):
|
|
798
|
-
"""An IndexedDB index name key.
|
|
799
|
-
|
|
800
|
-
Attributes:
|
|
801
|
-
index_name: the name of the index.
|
|
802
|
-
"""
|
|
803
|
-
index_name: str
|
|
804
|
-
|
|
805
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
806
|
-
"""Decodes the index names value."""
|
|
807
|
-
return decoder.DecodeVarint()[1]
|
|
808
|
-
|
|
809
|
-
@classmethod
|
|
810
|
-
def FromDecoder(cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
811
|
-
base_offset: int = 0) -> IndexNamesKey:
|
|
812
|
-
"""Decodes the index names key."""
|
|
813
|
-
offset, key_type = decoder.DecodeUint8()
|
|
814
|
-
if key_type != definitions.DatabaseMetaDataKeyType.INDEX_NAMES:
|
|
815
|
-
raise errors.ParserError('Not am IndexNamesKey')
|
|
816
|
-
_, index_name = decoder.DecodeStringWithLength()
|
|
817
|
-
return cls(key_prefix=key_prefix, offset=base_offset + offset,
|
|
818
|
-
index_name=index_name)
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
@dataclass
|
|
822
|
-
class DatabaseMetaDataKey(BaseIndexedDBKey):
|
|
823
|
-
"""An IndexedDB database metadata key.
|
|
824
|
-
|
|
825
|
-
Attributes:
|
|
826
|
-
metadata_type: the type of metadata that the key value contains.
|
|
827
|
-
"""
|
|
828
|
-
metadata_type: definitions.DatabaseMetaDataKeyType
|
|
829
|
-
|
|
830
|
-
def DecodeValue(
|
|
831
|
-
self, decoder: utils.LevelDBDecoder) -> Union[str, int]:
|
|
832
|
-
"""Decodes the database metadata value."""
|
|
833
|
-
if (self.metadata_type ==
|
|
834
|
-
definitions.DatabaseMetaDataKeyType.ORIGIN_NAME):
|
|
835
|
-
return decoder.DecodeString()[1]
|
|
836
|
-
if (self.metadata_type ==
|
|
837
|
-
definitions.DatabaseMetaDataKeyType.DATABASE_NAME):
|
|
838
|
-
return decoder.DecodeString()[1]
|
|
839
|
-
if (self.metadata_type ==
|
|
840
|
-
definitions.DatabaseMetaDataKeyType.IDB_STRING_VERSION_DATA):
|
|
841
|
-
return decoder.DecodeString()[1]
|
|
842
|
-
if (self.metadata_type ==
|
|
843
|
-
definitions.DatabaseMetaDataKeyType.MAX_ALLOCATED_OBJECT_STORE_ID):
|
|
844
|
-
return decoder.DecodeVarint()[1]
|
|
845
|
-
if (self.metadata_type ==
|
|
846
|
-
definitions.DatabaseMetaDataKeyType.IDB_INTEGER_VERSION):
|
|
847
|
-
return decoder.DecodeVarint()[1]
|
|
848
|
-
if (self.metadata_type ==
|
|
849
|
-
definitions.DatabaseMetaDataKeyType
|
|
850
|
-
.BLOB_NUMBER_GENERATOR_CURRENT_NUMBER):
|
|
851
|
-
return decoder.DecodeVarint()[1]
|
|
852
|
-
raise errors.ParserError(
|
|
853
|
-
f'Unknown database metadata type {self.metadata_type}')
|
|
854
|
-
|
|
855
|
-
@classmethod
|
|
856
|
-
def FromDecoder(
|
|
857
|
-
cls,
|
|
858
|
-
decoder: utils.LevelDBDecoder,
|
|
859
|
-
key_prefix: KeyPrefix,
|
|
860
|
-
base_offset: int = 0
|
|
861
|
-
) -> Union[
|
|
862
|
-
DatabaseMetaDataKey,
|
|
863
|
-
IndexFreeListKey,
|
|
864
|
-
IndexMetaDataKey,
|
|
865
|
-
IndexNamesKey,
|
|
866
|
-
ObjectStoreFreeListKey,
|
|
867
|
-
ObjectStoreMetaDataKey,
|
|
868
|
-
ObjectStoreNamesKey]:
|
|
869
|
-
"""Decodes the database metadata key."""
|
|
870
|
-
offset, metadata_value = decoder.PeekBytes(1)
|
|
871
|
-
metadata_type = definitions.DatabaseMetaDataKeyType(metadata_value[0])
|
|
872
|
-
|
|
873
|
-
if metadata_type in (
|
|
874
|
-
definitions.DatabaseMetaDataKeyType.ORIGIN_NAME,
|
|
875
|
-
definitions.DatabaseMetaDataKeyType.DATABASE_NAME,
|
|
876
|
-
definitions.DatabaseMetaDataKeyType.IDB_STRING_VERSION_DATA,
|
|
877
|
-
definitions.DatabaseMetaDataKeyType.MAX_ALLOCATED_OBJECT_STORE_ID,
|
|
878
|
-
definitions.DatabaseMetaDataKeyType.IDB_INTEGER_VERSION,
|
|
879
|
-
definitions.DatabaseMetaDataKeyType
|
|
880
|
-
.BLOB_NUMBER_GENERATOR_CURRENT_NUMBER):
|
|
881
|
-
return cls(key_prefix=key_prefix, offset=base_offset + offset,
|
|
882
|
-
metadata_type=metadata_type)
|
|
883
|
-
if metadata_type == definitions.DatabaseMetaDataKeyType.INDEX_META_DATA:
|
|
884
|
-
return IndexMetaDataKey.FromDecoder(
|
|
885
|
-
decoder, key_prefix, base_offset)
|
|
886
|
-
if (metadata_type ==
|
|
887
|
-
definitions.DatabaseMetaDataKeyType.OBJECT_STORE_META_DATA):
|
|
888
|
-
return ObjectStoreMetaDataKey.FromDecoder(
|
|
889
|
-
decoder, key_prefix, base_offset)
|
|
890
|
-
if (metadata_type ==
|
|
891
|
-
definitions.DatabaseMetaDataKeyType.OBJECT_STORE_FREE_LIST):
|
|
892
|
-
return ObjectStoreFreeListKey.FromDecoder(
|
|
893
|
-
decoder, key_prefix, base_offset)
|
|
894
|
-
if metadata_type == definitions.DatabaseMetaDataKeyType.INDEX_FREE_LIST:
|
|
895
|
-
return IndexFreeListKey.FromDecoder(
|
|
896
|
-
decoder, key_prefix, base_offset)
|
|
897
|
-
if (metadata_type ==
|
|
898
|
-
definitions.DatabaseMetaDataKeyType.OBJECT_STORE_NAMES):
|
|
899
|
-
return ObjectStoreNamesKey.FromDecoder(
|
|
900
|
-
decoder, key_prefix, base_offset)
|
|
901
|
-
if metadata_type == definitions.DatabaseMetaDataKeyType.INDEX_NAMES:
|
|
902
|
-
return IndexNamesKey.FromDecoder(
|
|
903
|
-
decoder, key_prefix, base_offset)
|
|
904
|
-
raise errors.ParserError(f'unknown database metadata type {metadata_type}.')
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
@dataclass
|
|
908
|
-
class ObjectStoreMetaDataKey(BaseIndexedDBKey):
|
|
909
|
-
"""An IndexedDB object store meta data key.
|
|
910
|
-
|
|
911
|
-
Attributes:
|
|
912
|
-
object_store_id: the ID of the object store.
|
|
913
|
-
metadata_type: the object store metadata type.
|
|
914
|
-
"""
|
|
915
|
-
object_store_id: int
|
|
916
|
-
metadata_type: definitions.ObjectStoreMetaDataKeyType
|
|
917
|
-
|
|
918
|
-
def DecodeValue(
|
|
919
|
-
self, decoder: utils.LevelDBDecoder) -> Union[IDBKeyPath, str, bool, int]:
|
|
920
|
-
"""Decodes the object store metadata value."""
|
|
921
|
-
if (self.metadata_type ==
|
|
922
|
-
definitions.ObjectStoreMetaDataKeyType.OBJECT_STORE_NAME):
|
|
923
|
-
return decoder.DecodeString()[1]
|
|
924
|
-
if self.metadata_type == definitions.ObjectStoreMetaDataKeyType.KEY_PATH:
|
|
925
|
-
return IDBKeyPath.FromDecoder(decoder)
|
|
926
|
-
if (self.metadata_type ==
|
|
927
|
-
definitions.ObjectStoreMetaDataKeyType.AUTO_INCREMENT_FLAG):
|
|
928
|
-
return decoder.DecodeBool()[1]
|
|
929
|
-
if (self.metadata_type ==
|
|
930
|
-
definitions.ObjectStoreMetaDataKeyType.IS_EVICTABLE):
|
|
931
|
-
return decoder.DecodeBool()[1]
|
|
932
|
-
if (self.metadata_type ==
|
|
933
|
-
definitions.ObjectStoreMetaDataKeyType.LAST_VERSION_NUMBER):
|
|
934
|
-
return decoder.DecodeInt(signed=False)[1]
|
|
935
|
-
if (self.metadata_type ==
|
|
936
|
-
definitions.ObjectStoreMetaDataKeyType.MAXIMUM_ALLOCATED_INDEX_ID):
|
|
937
|
-
return decoder.DecodeInt()[1]
|
|
938
|
-
if (self.metadata_type ==
|
|
939
|
-
definitions.ObjectStoreMetaDataKeyType.HAS_KEY_PATH):
|
|
940
|
-
return decoder.DecodeBool()[1]
|
|
941
|
-
if (self.metadata_type ==
|
|
942
|
-
definitions.ObjectStoreMetaDataKeyType.KEY_GENERATOR_CURRENT_NUMBER):
|
|
943
|
-
return decoder.DecodeInt()[1]
|
|
944
|
-
raise errors.ParserError(f'Unknown metadata type {self.metadata_type}')
|
|
945
|
-
|
|
946
|
-
@classmethod
|
|
947
|
-
def FromDecoder(
|
|
948
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
949
|
-
base_offset: int = 0
|
|
950
|
-
) -> ObjectStoreMetaDataKey:
|
|
951
|
-
"""Decodes the object store metadata key."""
|
|
952
|
-
offset, metadata_value = decoder.DecodeUint8()
|
|
953
|
-
if (metadata_value !=
|
|
954
|
-
definitions.DatabaseMetaDataKeyType.OBJECT_STORE_META_DATA):
|
|
955
|
-
raise errors.ParserError('Not a ObjectStoreMetaDataKey')
|
|
956
|
-
|
|
957
|
-
_, object_store_id = decoder.DecodeVarint()
|
|
958
|
-
_, metadata_value = decoder.DecodeUint8()
|
|
959
|
-
metadata_type = definitions.ObjectStoreMetaDataKeyType(metadata_value)
|
|
960
|
-
return cls(
|
|
961
|
-
offset=base_offset + offset, key_prefix=key_prefix,
|
|
962
|
-
object_store_id=object_store_id, metadata_type=metadata_type)
|
|
963
|
-
|
|
964
|
-
@dataclass
|
|
965
|
-
class ObjectStoreDataValue:
|
|
966
|
-
"""The parsed values from an ObjectStoreDataKey.
|
|
967
|
-
|
|
968
|
-
Attributes:
|
|
969
|
-
unknown: an unknown integer (possibly a sequence number?).
|
|
970
|
-
is_wrapped: True if the value was wrapped.
|
|
971
|
-
blob_size: the blob size, only valid if wrapped.
|
|
972
|
-
blob_offset: the blob offset, only valid if wrapped.
|
|
973
|
-
value: the blink serialized value, only valid if not wrapped.
|
|
974
|
-
"""
|
|
975
|
-
unkown: int
|
|
976
|
-
is_wrapped: bool
|
|
977
|
-
blob_size: Optional[int]
|
|
978
|
-
blob_offset: Optional[int]
|
|
979
|
-
value: Any
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
@dataclass
|
|
983
|
-
class ObjectStoreDataKey(BaseIndexedDBKey):
|
|
984
|
-
"""An IndexedDB object store data key.
|
|
985
|
-
|
|
986
|
-
Attributes:
|
|
987
|
-
encoded_user_key: the encoded user key.
|
|
988
|
-
"""
|
|
989
|
-
encoded_user_key: IDBKey
|
|
990
|
-
|
|
991
|
-
def DecodeValue(
|
|
992
|
-
self, decoder: utils.LevelDBDecoder) -> ObjectStoreDataValue:
|
|
993
|
-
"""Decodes the object store data value."""
|
|
994
|
-
_, unknown_integer = decoder.DecodeVarint()
|
|
995
|
-
|
|
996
|
-
_, wrapped_header_bytes = decoder.PeekBytes(3)
|
|
997
|
-
if len(wrapped_header_bytes) != 3:
|
|
998
|
-
raise errors.DecoderError('Insufficient bytes')
|
|
999
|
-
|
|
1000
|
-
if (wrapped_header_bytes[0] == definitions.BlinkSerializationTag.VERSION and
|
|
1001
|
-
wrapped_header_bytes[1] == 0x11 and
|
|
1002
|
-
wrapped_header_bytes[2] == 0x01):
|
|
1003
|
-
_, blob_size = decoder.DecodeVarint()
|
|
1004
|
-
_, blob_offset = decoder.DecodeVarint()
|
|
1005
|
-
return ObjectStoreDataValue(
|
|
1006
|
-
unkown=unknown_integer,
|
|
1007
|
-
is_wrapped=True,
|
|
1008
|
-
blob_size=blob_size,
|
|
1009
|
-
blob_offset=blob_offset,
|
|
1010
|
-
value=None)
|
|
1011
|
-
_, blink_bytes = decoder.ReadBytes()
|
|
1012
|
-
blink_value = blink.V8ScriptValueDecoder.FromBytes(blink_bytes)
|
|
1013
|
-
return ObjectStoreDataValue(
|
|
1014
|
-
unkown=unknown_integer,
|
|
1015
|
-
is_wrapped=False,
|
|
1016
|
-
blob_size=None,
|
|
1017
|
-
blob_offset=None,
|
|
1018
|
-
value=blink_value)
|
|
1019
|
-
|
|
1020
|
-
@classmethod
|
|
1021
|
-
def FromDecoder(
|
|
1022
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
1023
|
-
base_offset: int = 0
|
|
1024
|
-
) -> ObjectStoreDataKey:
|
|
1025
|
-
"""Decodes the object store data key."""
|
|
1026
|
-
if (key_prefix.GetKeyPrefixType() !=
|
|
1027
|
-
definitions.KeyPrefixType.OBJECT_STORE_DATA):
|
|
1028
|
-
raise errors.ParserError('Invalid KeyPrefix for ObjectStoreDataKey')
|
|
1029
|
-
offset = decoder.stream.tell()
|
|
1030
|
-
encoded_user_key = IDBKey.FromDecoder(decoder, offset)
|
|
1031
|
-
return cls(
|
|
1032
|
-
offset=base_offset + offset,
|
|
1033
|
-
key_prefix=key_prefix, encoded_user_key=encoded_user_key)
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
@dataclass
|
|
1037
|
-
class ExistsEntryKey(BaseIndexedDBKey):
|
|
1038
|
-
"""An IndexedDB exists entry key.
|
|
1039
|
-
|
|
1040
|
-
Attributes:
|
|
1041
|
-
encoded_user_key: the encoded user key.
|
|
1042
|
-
"""
|
|
1043
|
-
encoded_user_key: IDBKey
|
|
1044
|
-
|
|
1045
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> int:
|
|
1046
|
-
"""Decodes the exists entry value."""
|
|
1047
|
-
_, data = decoder.ReadBytes()
|
|
1048
|
-
return int.from_bytes(data, byteorder='little', signed=False)
|
|
1049
|
-
|
|
1050
|
-
@classmethod
|
|
1051
|
-
def FromDecoder(
|
|
1052
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
1053
|
-
base_offset: int = 0
|
|
1054
|
-
) -> ExistsEntryKey:
|
|
1055
|
-
"""Decodes the exists entry key."""
|
|
1056
|
-
offset = decoder.stream.tell()
|
|
1057
|
-
encoded_user_key = IDBKey.FromDecoder(decoder, offset)
|
|
1058
|
-
|
|
1059
|
-
return cls(
|
|
1060
|
-
offset=base_offset + offset,
|
|
1061
|
-
key_prefix=key_prefix, encoded_user_key=encoded_user_key)
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
@dataclass
|
|
1065
|
-
class IndexDataKey(BaseIndexedDBKey):
|
|
1066
|
-
"""An IndexedDB data key.
|
|
1067
|
-
|
|
1068
|
-
Attributes:
|
|
1069
|
-
encoded_user_key: the encoded user key.
|
|
1070
|
-
sequence_number: the sequence number of the data key.
|
|
1071
|
-
encoded_primary_key: the encoded primary key.
|
|
1072
|
-
"""
|
|
1073
|
-
encoded_user_key: IDBKey
|
|
1074
|
-
sequence_number: Optional[int]
|
|
1075
|
-
encoded_primary_key: Optional[IDBKey]
|
|
1076
|
-
|
|
1077
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Tuple[int, IDBKey]:
|
|
1078
|
-
"""Decodes the index data key value."""
|
|
1079
|
-
_, version = decoder.DecodeVarint()
|
|
1080
|
-
idb_key = IDBKey.FromDecoder(decoder)
|
|
1081
|
-
return version, idb_key
|
|
1082
|
-
|
|
1083
|
-
@classmethod
|
|
1084
|
-
def FromDecoder(cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
1085
|
-
base_offset: int = 0) -> IndexDataKey:
|
|
1086
|
-
"""Decodes the index data key."""
|
|
1087
|
-
offset = decoder.stream.tell()
|
|
1088
|
-
encoded_user_key = IDBKey.FromDecoder(decoder, offset)
|
|
1089
|
-
|
|
1090
|
-
if decoder.NumRemainingBytes() > 0:
|
|
1091
|
-
_, sequence_number = decoder.DecodeVarint()
|
|
1092
|
-
else:
|
|
1093
|
-
sequence_number = None
|
|
1094
|
-
|
|
1095
|
-
if decoder.NumRemainingBytes() > 0:
|
|
1096
|
-
encoded_primary_key_offset = decoder.stream.tell()
|
|
1097
|
-
encoded_primary_key = IDBKey.FromDecoder(
|
|
1098
|
-
decoder, encoded_primary_key_offset)
|
|
1099
|
-
else:
|
|
1100
|
-
encoded_primary_key = None
|
|
1101
|
-
|
|
1102
|
-
return cls(
|
|
1103
|
-
key_prefix=key_prefix,
|
|
1104
|
-
encoded_user_key=encoded_user_key,
|
|
1105
|
-
sequence_number=sequence_number,
|
|
1106
|
-
encoded_primary_key=encoded_primary_key,
|
|
1107
|
-
offset=base_offset + offset)
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
@dataclass
|
|
1111
|
-
class BlobEntryKey(BaseIndexedDBKey):
|
|
1112
|
-
"""An IndexedDB blob entry key.
|
|
1113
|
-
|
|
1114
|
-
Attributes:
|
|
1115
|
-
user_key: the user/primary key.
|
|
1116
|
-
"""
|
|
1117
|
-
user_key: IDBKey
|
|
1118
|
-
|
|
1119
|
-
def DecodeValue(
|
|
1120
|
-
self, decoder: utils.LevelDBDecoder) -> IndexedDBExternalObject:
|
|
1121
|
-
"""Decodes the blob entry value."""
|
|
1122
|
-
return IndexedDBExternalObject.FromDecoder(decoder)
|
|
1123
|
-
|
|
1124
|
-
@classmethod
|
|
1125
|
-
def FromDecoder(
|
|
1126
|
-
cls, decoder: utils.LevelDBDecoder, key_prefix: KeyPrefix,
|
|
1127
|
-
base_offset: int = 0
|
|
1128
|
-
) -> BlobEntryKey:
|
|
1129
|
-
"""Decodes the blob entry key."""
|
|
1130
|
-
offset = decoder.stream.tell()
|
|
1131
|
-
user_key = IDBKey.FromDecoder(decoder, offset)
|
|
1132
|
-
|
|
1133
|
-
return cls(key_prefix=key_prefix, user_key=user_key,
|
|
1134
|
-
offset=base_offset + offset)
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
@dataclass
|
|
1138
|
-
class IndexedDbKey(BaseIndexedDBKey):
|
|
1139
|
-
"""An IndexedDB key.
|
|
1140
|
-
|
|
1141
|
-
A factory class for parsing IndexedDB keys.
|
|
1142
|
-
"""
|
|
1143
|
-
|
|
1144
|
-
METADATA_TYPE_TO_CLASS = {
|
|
1145
|
-
definitions.KeyPrefixType.GLOBAL_METADATA: GlobalMetaDataKey,
|
|
1146
|
-
definitions.KeyPrefixType.DATABASE_METADATA: DatabaseMetaDataKey,
|
|
1147
|
-
definitions.KeyPrefixType.OBJECT_STORE_DATA: ObjectStoreDataKey,
|
|
1148
|
-
definitions.KeyPrefixType.EXISTS_ENTRY: ExistsEntryKey,
|
|
1149
|
-
definitions.KeyPrefixType.INDEX_DATA: IndexDataKey,
|
|
1150
|
-
definitions.KeyPrefixType.BLOB_ENTRY: BlobEntryKey,
|
|
1151
|
-
definitions.KeyPrefixType.INVALID_TYPE: None
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
def DecodeValue(self, decoder: utils.LevelDBDecoder) -> Any:
|
|
1155
|
-
"""Decodes the value from the current position of the LevelDBDecoder.
|
|
1156
|
-
|
|
1157
|
-
Args:
|
|
1158
|
-
decoder: the stream decoder
|
|
1159
|
-
"""
|
|
1160
|
-
|
|
1161
|
-
@classmethod
|
|
1162
|
-
def FromDecoder(
|
|
1163
|
-
cls,
|
|
1164
|
-
decoder: utils.LevelDBDecoder,
|
|
1165
|
-
key_prefix: KeyPrefix,
|
|
1166
|
-
base_offset: int = 0
|
|
1167
|
-
) -> Union[Type[DatabaseMetaDataKey], Type[ExistsEntryKey],
|
|
1168
|
-
Type[BlobEntryKey], Type[GlobalMetaDataKey],
|
|
1169
|
-
Type[IndexDataKey], Type[ObjectStoreDataKey]]:
|
|
1170
|
-
"""Decodes the IndexedDB key."""
|
|
1171
|
-
key_type = key_prefix.GetKeyPrefixType()
|
|
1172
|
-
key_class = cls.METADATA_TYPE_TO_CLASS.get(key_type)
|
|
1173
|
-
if not key_class:
|
|
1174
|
-
raise errors.ParserError('Unknown KeyPrefixType')
|
|
1175
|
-
return key_class.FromDecoder(
|
|
1176
|
-
decoder=decoder,
|
|
1177
|
-
key_prefix=key_prefix, #pytype: disable=bad-return-type
|
|
1178
|
-
base_offset=base_offset)
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
@dataclass
|
|
1182
|
-
class IndexMetaDataKey(BaseIndexedDBKey):
|
|
1183
|
-
"""An IndexedDB meta data key.
|
|
1184
|
-
|
|
1185
|
-
Attributes:
|
|
1186
|
-
object_store_id: the ID of the object store.
|
|
1187
|
-
index_id: the index ID.
|
|
1188
|
-
metadata_type: the metadata key type.
|
|
1189
|
-
"""
|
|
1190
|
-
object_store_id: int
|
|
1191
|
-
index_id: int
|
|
1192
|
-
metadata_type: definitions.IndexMetaDataKeyType
|
|
1193
|
-
|
|
1194
|
-
def DecodeValue(
|
|
1195
|
-
self, decoder: utils.LevelDBDecoder) -> Union[bool, IDBKeyPath, str]:
|
|
1196
|
-
"""Decodes the index metadata value."""
|
|
1197
|
-
if self.metadata_type == definitions.IndexMetaDataKeyType.INDEX_NAME:
|
|
1198
|
-
return decoder.DecodeString()[1]
|
|
1199
|
-
if self.metadata_type == definitions.IndexMetaDataKeyType.KEY_PATH:
|
|
1200
|
-
return IDBKeyPath.FromDecoder(decoder)
|
|
1201
|
-
if (self.metadata_type ==
|
|
1202
|
-
definitions.IndexMetaDataKeyType.MULTI_ENTRY_FLAG):
|
|
1203
|
-
return decoder.DecodeBool()[1]
|
|
1204
|
-
if self.metadata_type == definitions.IndexMetaDataKeyType.UNIQUE_FLAG:
|
|
1205
|
-
return decoder.DecodeBool()[1]
|
|
1206
|
-
raise errors.ParserError(
|
|
1207
|
-
f'Unknown index metadata type {self.metadata_type}')
|
|
1208
|
-
|
|
1209
|
-
@classmethod
|
|
1210
|
-
def FromDecoder(
|
|
1211
|
-
cls,
|
|
1212
|
-
decoder: utils.LevelDBDecoder,
|
|
1213
|
-
key_prefix: KeyPrefix, base_offset: int = 0
|
|
1214
|
-
) -> IndexMetaDataKey:
|
|
1215
|
-
"""Decodes the index metadata key."""
|
|
1216
|
-
offset, key_type = decoder.DecodeUint8()
|
|
1217
|
-
if key_type != definitions.DatabaseMetaDataKeyType.INDEX_META_DATA:
|
|
1218
|
-
raise errors.ParserError('Not an IndexMetaDataKey.')
|
|
1219
|
-
_, object_store_id = decoder.DecodeVarint()
|
|
1220
|
-
_, index_id = decoder.DecodeVarint()
|
|
1221
|
-
_, metadata_bytes = decoder.ReadBytes(1)
|
|
1222
|
-
metadata_type = definitions.IndexMetaDataKeyType(metadata_bytes[0])
|
|
1223
|
-
return cls(offset=base_offset + offset, key_prefix=key_prefix,
|
|
1224
|
-
object_store_id=object_store_id, index_id=index_id,
|
|
1225
|
-
metadata_type=metadata_type)
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
@dataclass
|
|
1229
|
-
class ExternalObjectEntry(utils.FromDecoderMixin):
|
|
1230
|
-
"""An IndexedDB external object entry.
|
|
1231
|
-
|
|
1232
|
-
Args:
|
|
1233
|
-
offset: the offset of the ExternalObjectEntry.
|
|
1234
|
-
object_type: the external object type.
|
|
1235
|
-
blob_number: the blob number if the object type is a blob or file,
|
|
1236
|
-
None otherwise.
|
|
1237
|
-
mime_type: the mime type if the object type is a blob or file, None
|
|
1238
|
-
otherwise.
|
|
1239
|
-
size: the size if the object type is a blob or file, None otherwise.
|
|
1240
|
-
filename: the filename if the object is a blob or file, None otherwise.
|
|
1241
|
-
last_modified: the last modified time if a blob or file, None otherwise.
|
|
1242
|
-
token: the token if a filesystem access handle, None otherwise.
|
|
1243
|
-
"""
|
|
1244
|
-
offset: int = field(compare=False)
|
|
1245
|
-
object_type: definitions.ExternalObjectType
|
|
1246
|
-
blob_number: Optional[int]
|
|
1247
|
-
mime_type: Optional[str]
|
|
1248
|
-
size: Optional[int]
|
|
1249
|
-
filename: Optional[str]
|
|
1250
|
-
last_modified: Optional[int] # microseconds
|
|
1251
|
-
token: Optional[bytes]
|
|
1252
|
-
|
|
1253
|
-
@classmethod
|
|
1254
|
-
def FromDecoder(
|
|
1255
|
-
cls,
|
|
1256
|
-
decoder: utils.LevelDBDecoder,
|
|
1257
|
-
base_offset: int = 0
|
|
1258
|
-
) -> ExternalObjectEntry:
|
|
1259
|
-
"""Decodes the external object entry."""
|
|
1260
|
-
offset, object_type_value = decoder.DecodeUint8()
|
|
1261
|
-
object_type = definitions.ExternalObjectType(object_type_value)
|
|
1262
|
-
if (object_type in
|
|
1263
|
-
(definitions.ExternalObjectType.BLOB,
|
|
1264
|
-
definitions.ExternalObjectType.FILE)):
|
|
1265
|
-
_, blob_number = decoder.DecodeVarint()
|
|
1266
|
-
_, mime_type = decoder.DecodeStringWithLength()
|
|
1267
|
-
_, size = decoder.DecodeVarint()
|
|
1268
|
-
if object_type == definitions.ExternalObjectType.FILE:
|
|
1269
|
-
_, filename = decoder.DecodeStringWithLength()
|
|
1270
|
-
_, last_modified = decoder.DecodeVarint()
|
|
1271
|
-
else:
|
|
1272
|
-
filename = None
|
|
1273
|
-
last_modified = None
|
|
1274
|
-
token = None
|
|
1275
|
-
elif (object_type ==
|
|
1276
|
-
definitions.ExternalObjectType.FILE_SYSTEM_ACCESS_HANDLE):
|
|
1277
|
-
blob_number = None
|
|
1278
|
-
mime_type = None
|
|
1279
|
-
size = None
|
|
1280
|
-
filename = None
|
|
1281
|
-
last_modified = None
|
|
1282
|
-
_, token = decoder.DecodeBlobWithLength()
|
|
1283
|
-
|
|
1284
|
-
return cls(offset=base_offset + offset, object_type=object_type,
|
|
1285
|
-
blob_number=blob_number, mime_type=mime_type, size=size,
|
|
1286
|
-
filename=filename, last_modified=last_modified, token=token)
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
@dataclass
|
|
1290
|
-
class IndexedDBExternalObject(utils.FromDecoderMixin):
|
|
1291
|
-
"""An IndexedDB external object.
|
|
1292
|
-
|
|
1293
|
-
Args:
|
|
1294
|
-
offset: the offset of the IndexedDBExternalObject.
|
|
1295
|
-
entries: a list of external objects.
|
|
1296
|
-
"""
|
|
1297
|
-
offset: int = field(compare=False)
|
|
1298
|
-
entries: list[ExternalObjectEntry]
|
|
1299
|
-
|
|
1300
|
-
@classmethod
|
|
1301
|
-
def FromDecoder(
|
|
1302
|
-
cls,
|
|
1303
|
-
decoder: utils.LevelDBDecoder,
|
|
1304
|
-
base_offset: int = 0
|
|
1305
|
-
) -> IndexedDBExternalObject:
|
|
1306
|
-
"""Decodes the external object."""
|
|
1307
|
-
entries = []
|
|
1308
|
-
offset = decoder.stream.tell()
|
|
1309
|
-
while decoder.NumRemainingBytes():
|
|
1310
|
-
entry = ExternalObjectEntry.FromDecoder(decoder, base_offset)
|
|
1311
|
-
entries.append(entry)
|
|
1312
|
-
|
|
1313
|
-
return cls(offset=base_offset + offset, entries=entries)
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
@dataclass
|
|
1317
|
-
class ObjectStore:
|
|
1318
|
-
"""An IndexedDB Object Store.
|
|
1319
|
-
|
|
1320
|
-
Attributes:
|
|
1321
|
-
id: the object store ID.
|
|
1322
|
-
name: the object store name.
|
|
1323
|
-
records: the records in the object store.
|
|
1324
|
-
"""
|
|
1325
|
-
id: int
|
|
1326
|
-
name: str
|
|
1327
|
-
records: list = field(default_factory=list, repr=False)
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
@dataclass
|
|
1331
|
-
class IndexedDBRecord:
|
|
1332
|
-
"""An IndexedDB Record.
|
|
1333
|
-
|
|
1334
|
-
Attributes:
|
|
1335
|
-
offset: the offset of the record.
|
|
1336
|
-
key: the key of the record.
|
|
1337
|
-
value: the value of the record.
|
|
1338
|
-
sequence_number: if available, the sequence number of the record.
|
|
1339
|
-
type: the type of the record.
|
|
1340
|
-
"""
|
|
1341
|
-
offset: int
|
|
1342
|
-
key: Any
|
|
1343
|
-
value: Any
|
|
1344
|
-
sequence_number: int
|
|
1345
|
-
type: int
|
|
1346
|
-
|
|
1347
|
-
@classmethod
|
|
1348
|
-
def FromLevelDBRecord(
|
|
1349
|
-
cls, record: Union[ldb.KeyValueRecord, log.ParsedInternalKey]
|
|
1350
|
-
) -> IndexedDBRecord:
|
|
1351
|
-
"""Returns an IndexedDBRecord from a ParsedInternalKey."""
|
|
1352
|
-
idb_key = IndexedDbKey.FromBytes(record.key, base_offset=record.offset)
|
|
1353
|
-
idb_value = idb_key.ParseValue(record.value)
|
|
1354
|
-
return cls(
|
|
1355
|
-
offset=record.offset,
|
|
1356
|
-
key=idb_key,
|
|
1357
|
-
value=idb_value,
|
|
1358
|
-
sequence_number=record.sequence_number if hasattr(
|
|
1359
|
-
record, 'sequence_number') else None,
|
|
1360
|
-
type=record.record_type)
|