dfindexeddb 20240402__py3-none-any.whl → 20240501__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.
@@ -0,0 +1,693 @@
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
+ """Parsers for WebKit encoded JavaScript values."""
16
+ from __future__ import annotations
17
+
18
+ from dataclasses import dataclass
19
+ from datetime import datetime
20
+ import io
21
+ import plistlib
22
+ from typing import Any, Dict, List, Tuple, Union
23
+
24
+ from dfindexeddb import errors
25
+ from dfindexeddb import utils
26
+ from dfindexeddb.indexeddb.safari import definitions
27
+
28
+
29
+ @dataclass
30
+ class ArrayBufferView:
31
+ """A parsed JavaScript ArrayBufferView.
32
+
33
+ Attributes:
34
+ array_buffer_view_subtag: the sub tag.
35
+ buffer: the buffer.
36
+ offset: the offset of the view.
37
+ length: the length of the view.
38
+ """
39
+ array_buffer_view_subtag: definitions.ArrayBufferViewSubtag
40
+ buffer: bytes
41
+ offset: int
42
+ length: int
43
+
44
+
45
+ @dataclass
46
+ class ResizableArrayBuffer:
47
+ """A parsed Resizable Array Buffer.
48
+
49
+ Attributes:
50
+ buffer: the buffer.
51
+ max_length: the maximum length of the buffer (for resizing).
52
+ """
53
+ buffer: bytes
54
+ max_length: int
55
+
56
+
57
+ @dataclass
58
+ class FileData:
59
+ """A parsed FileData.
60
+
61
+ Attributes:
62
+ path: the path.
63
+ url: the URL.
64
+ type: the type.
65
+ name: the file name.
66
+ last_modified: the last modified timestamp.
67
+ """
68
+ path: str
69
+ url: str
70
+ type: str
71
+ name: str
72
+ last_modified: float
73
+
74
+
75
+ @dataclass
76
+ class FileList:
77
+ """A parsed FileList.
78
+
79
+ Attributes:
80
+ files: the list of files.
81
+ """
82
+ files: List[FileData]
83
+
84
+
85
+ class JSArray(list):
86
+ """A parsed JavaScript array.
87
+
88
+ This is a wrapper around a standard Python list to allow assigning arbitrary
89
+ properties as is possible in the JavaScript equivalent.
90
+ """
91
+
92
+ def __repr__(self):
93
+ array_entries = ", ".join([str(entry) for entry in list(self)])
94
+ properties = ", ".join(
95
+ f'{key}: {value}' for key, value in self.properties.items())
96
+ return f'[{array_entries}, {properties}]'
97
+
98
+ @property
99
+ def properties(self) -> Dict[str, Any]:
100
+ """Returns the object properties."""
101
+ return self.__dict__
102
+
103
+ def __contains__(self, item):
104
+ return item in self.__dict__
105
+
106
+ def __getitem__(self, name):
107
+ return self.__dict__[name]
108
+
109
+
110
+ class JSSet(set):
111
+ """A parsed JavaScript set.
112
+
113
+ This is a wrapper around a standard Python set to allow assigning arbitrary
114
+ properties as is possible in the JavaScript equivalent.
115
+ """
116
+
117
+ def __repr__(self):
118
+ set_entries = ", ".join([str(entry) for entry in list(self)])
119
+ properties = ", ".join(
120
+ f'{key}: {value}' for key, value in self.properties.items())
121
+ return f'[{set_entries}, {properties}]'
122
+
123
+ @property
124
+ def properties(self) -> Dict[str, Any]:
125
+ """Returns the object properties."""
126
+ return self.__dict__
127
+
128
+ def __contains__(self, item):
129
+ return item in self.__dict__
130
+
131
+ def __getitem__(self, name):
132
+ return self.__dict__[name]
133
+
134
+
135
+ @dataclass
136
+ class Null:
137
+ """A parsed JavaScript Null."""
138
+
139
+
140
+ @dataclass
141
+ class RegExp:
142
+ """A parsed JavaScript RegExp.
143
+
144
+ Attributes:
145
+ pattern: the pattern.
146
+ flags: the flags.
147
+ """
148
+ pattern: str
149
+ flags: str
150
+
151
+
152
+ @dataclass(frozen=True)
153
+ class Undefined:
154
+ """A parsed JavaScript undef."""
155
+
156
+
157
+ @dataclass
158
+ class IDBKeyData(utils.FromDecoderMixin):
159
+ """An IDBKeyData.
160
+
161
+ Attributes:
162
+ offset: the offset at which the IDBKeyData was parsed.
163
+ key_type: the IDB Key Type.
164
+ data: the key data.
165
+ """
166
+ offset: int
167
+ key_type: definitions.SIDBKeyType
168
+ data: Union[float, datetime, str, bytes, list]
169
+
170
+ @classmethod
171
+ def FromDecoder(
172
+ cls, decoder: utils.StreamDecoder, base_offset: int = 0) -> IDBKeyData:
173
+ """Decodes an IDBKeyData from the current position of decoder.
174
+
175
+ Refer to IDBSerialization.cpp for the encoding scheme.
176
+
177
+ Args:
178
+ decoder: the decoder
179
+
180
+ Returns:
181
+ the IDBKeyData.
182
+
183
+ Raises:
184
+ ParserError: when the key version is not found or an unknown key type is
185
+ encountered or an old-style PropertyList key type is found.
186
+ """
187
+ def _DecodeKeyBuffer(key_type):
188
+ if key_type == definitions.SIDBKeyType.MIN:
189
+ data = None
190
+ if key_type == definitions.SIDBKeyType.NUMBER:
191
+ _, data = decoder.DecodeDouble()
192
+ elif key_type == definitions.SIDBKeyType.DATE:
193
+ _, timestamp = decoder.DecodeDouble()
194
+ data = datetime.utcfromtimestamp(timestamp/1000)
195
+ elif key_type == definitions.SIDBKeyType.STRING:
196
+ _, length = decoder.DecodeUint32()
197
+ _, raw_data = decoder.ReadBytes(length*2)
198
+ data = raw_data.decode('utf-16-le')
199
+ elif key_type == definitions.SIDBKeyType.BINARY:
200
+ _, length = decoder.DecodeUint32()
201
+ _, data = decoder.ReadBytes(length)
202
+ elif key_type == definitions.SIDBKeyType.ARRAY:
203
+ _, length = decoder.DecodeUint64()
204
+ data = []
205
+ for _ in range(length):
206
+ _, key_type = decoder.DecodeUint8()
207
+ element = _DecodeKeyBuffer(key_type)
208
+ data.append(element)
209
+ else:
210
+ raise errors.ParserError('Unknown definitions.SIDBKeyType found.')
211
+ return data
212
+
213
+ offset, version_header = decoder.DecodeUint8()
214
+ if version_header != definitions.SIDBKeyVersion:
215
+ raise errors.ParserError('SIDBKeyVersion not found.')
216
+
217
+ _, raw_key_type = decoder.DecodeUint8()
218
+ key_type = definitions.SIDBKeyType(raw_key_type)
219
+
220
+ # "Old-style key is characterized by this magic character that
221
+ # begins serialized PropertyLists
222
+ if key_type == b'b':
223
+ raise errors.ParserError('Old-style PropertyList key type found.')
224
+ data = _DecodeKeyBuffer(key_type)
225
+
226
+ return cls(
227
+ offset=offset+base_offset,
228
+ key_type=key_type,
229
+ data=data)
230
+
231
+
232
+ class SerializedScriptValueDecoder():
233
+ """Decodes a Serialized Script Value from a stream of bytes.
234
+
235
+ Attributes:
236
+ decoder: the stream decoder for the given byte stream.
237
+ version: the parsed serialized script version.
238
+ constant_pool: the constant pool.
239
+ object_pool: the object pool.
240
+ """
241
+ def __init__(self, stream: io.BytesIO):
242
+ self.decoder = utils.StreamDecoder(stream)
243
+ self.version = None
244
+ self.constant_pool = []
245
+ self.object_pool = []
246
+
247
+ def PeekTag(self) -> int:
248
+ """Peeks a tag from the current position."""
249
+ _, peeked_bytes = self.decoder.PeekBytes(4)
250
+ return int.from_bytes(peeked_bytes, byteorder='little')
251
+
252
+ def PeekSerializationTag(self) -> definitions.SerializationTag:
253
+ """Peeks a SerializationTag from the current position.
254
+
255
+ Raises:
256
+ ParserError if an invalid SerializationTag was parsed.
257
+ """
258
+ offset, terminal_byte = self.decoder.PeekBytes(1)
259
+ try:
260
+ return definitions.SerializationTag(terminal_byte[0])
261
+ except ValueError as error:
262
+ raise errors.ParserError(
263
+ f'Invalid SerializationTag {terminal_byte} at offset {offset}'
264
+ ) from error
265
+
266
+ def DecodeSerializationTag(self) -> Tuple[int, definitions.SerializationTag]:
267
+ """Decodes a SerializationTag.
268
+
269
+ Returns:
270
+ a tuple of the offset and the serialization tag.
271
+
272
+ Raises:
273
+ ParserError if an invalid terminal value was encountered.
274
+ """
275
+ offset, terminal_byte = self.decoder.DecodeUint8()
276
+ try:
277
+ return offset, definitions.SerializationTag(terminal_byte)
278
+ except ValueError as error:
279
+ raise errors.ParserError(
280
+ f'Invalid terminal {terminal_byte} at offset {offset}') from error
281
+
282
+ def DecodeArray(self) -> JSArray:
283
+ """Decodes an Array value.
284
+
285
+ Returns:
286
+ the JavaScript array.
287
+
288
+ Raises:
289
+ ParserError if an invalid Terminator tag was found.
290
+ """
291
+ _, length = self.decoder.DecodeUint32()
292
+ array = JSArray()
293
+ for _ in range(length):
294
+ _, _ = self.decoder.DecodeUint32()
295
+ _, value = self.DecodeValue()
296
+ array.append(value)
297
+
298
+ offset, terminator_tag = self.decoder.DecodeUint32()
299
+ if terminator_tag != definitions.TerminatorTag:
300
+ raise errors.ParserError(f'Terminator tag not found at offset {offset}.')
301
+
302
+ offset, tag = self.decoder.DecodeUint32()
303
+ if tag == definitions.NonIndexPropertiesTag:
304
+ while tag != definitions.TerminatorTag:
305
+ name = self.DecodeStringData()
306
+ _, value = self.DecodeValue()
307
+ _, tag = self.decoder.DecodeUint32()
308
+ array.properties[name] = value
309
+ elif tag != definitions.TerminatorTag:
310
+ raise errors.ParserError(f'Terminator tag not found at offset {offset}.')
311
+ return array
312
+
313
+ def DecodeObject(self) -> Dict[str, Any]:
314
+ """Decodes an Object value."""
315
+ tag = self.PeekTag()
316
+ js_object = {}
317
+ while tag != definitions.TerminatorTag:
318
+ name = self.DecodeStringData()
319
+ _, value = self.DecodeValue()
320
+ js_object[name] = value
321
+ tag = self.PeekTag()
322
+ _ = self.decoder.DecodeUint32()
323
+ self.object_pool.append(js_object)
324
+ return js_object
325
+
326
+ def DecodeStringData(self) -> str:
327
+ """Decodes a StringData value.
328
+
329
+ Returns:
330
+ A JavaScript array.
331
+
332
+ Raises:
333
+ ParserError if an:
334
+ * unexpected TerminatorTag is found
335
+ * unexpected constant pool size value is found
336
+ * disallowed string length is found.
337
+ * unable to to decode a buffer as utf-16-le.
338
+ """
339
+ peeked_tag = self.PeekTag()
340
+ if peeked_tag == definitions.TerminatorTag:
341
+ raise errors.ParserError('Unexpected TerminatorTag found')
342
+
343
+ if peeked_tag == definitions.StringPoolTag:
344
+ _ = self.decoder.DecodeUint32()
345
+ if len(self.constant_pool) < 0xff:
346
+ _, cp_index = self.decoder.DecodeUint8()
347
+ elif len(self.constant_pool) < 0xffff:
348
+ _, cp_index = self.decoder.DecodeUint16()
349
+ elif len(self.constant_pool) < 0xffffffff:
350
+ _, cp_index = self.decoder.DecodeUint32()
351
+ else:
352
+ raise errors.ParserError('Unexpected constant pool size value.')
353
+ return self.constant_pool[cp_index]
354
+
355
+ _, length_with_8bit_flag = self.decoder.DecodeUint32()
356
+ if length_with_8bit_flag == definitions.TerminatorTag:
357
+ raise errors.ParserError('Disallowed string length found.')
358
+
359
+ length = length_with_8bit_flag & 0x7FFFFFFF
360
+ is_8bit = length_with_8bit_flag & definitions.StringDataIs8BitFlag
361
+
362
+ if is_8bit:
363
+ _, characters = self.decoder.ReadBytes(length)
364
+ value = characters.decode('latin-1')
365
+ else:
366
+ _, characters = self.decoder.ReadBytes(2*length)
367
+ try:
368
+ value = characters.decode('utf-16-le')
369
+ except UnicodeDecodeError:
370
+ raise errors.ParserError(
371
+ f'Unable to decode {len(characters)} characters as utf-16-le')
372
+ self.constant_pool.append(value)
373
+ return value
374
+
375
+ def DecodeDate(self) -> datetime:
376
+ """Decodes a Date value."""
377
+ _, timestamp = self.decoder.DecodeDouble()
378
+ value = datetime.utcfromtimestamp(timestamp/1000)
379
+ return value
380
+
381
+ def DecodeFileData(self) -> FileData:
382
+ """Decodes a FileData value."""
383
+ path = self.DecodeStringData()
384
+ url = self.DecodeStringData()
385
+ file_type = self.DecodeStringData()
386
+ name = self.DecodeStringData()
387
+ _, last_modified = self.decoder.DecodeDouble()
388
+
389
+ return FileData(
390
+ path=path,
391
+ url=url,
392
+ type=file_type,
393
+ name=name,
394
+ last_modified=last_modified)
395
+
396
+ def DecodeFileList(self) -> FileList:
397
+ """Decodes a FileList value."""
398
+ _, length = self.decoder.DecodeUint32()
399
+ file_list = []
400
+ for _ in range(length):
401
+ file_list.append(self.DecodeFileData())
402
+ return FileList(files=file_list)
403
+
404
+ def DecodeImageData(self) -> Dict[str, Any]:
405
+ """Decodes an ImageData value."""
406
+ _, width = self.decoder.DecodeUint32()
407
+ _, height = self.decoder.DecodeUint32()
408
+ _, length = self.decoder.DecodeUint32()
409
+ data = self.decoder.ReadBytes(length)
410
+
411
+ if self.version > 7:
412
+ _, color_space = self.decoder.DecodeUint8()
413
+ else:
414
+ color_space = None
415
+
416
+ # TODO: make this a dataclass?
417
+ return {
418
+ 'width': width,
419
+ 'height': height,
420
+ 'length': length,
421
+ 'data': data,
422
+ 'color_space': color_space
423
+ }
424
+
425
+ def DecodeBlob(self) -> Dict[str, Any]:
426
+ """Decodes a Blob value."""
427
+ url = self.DecodeStringData()
428
+ blob_type = self.DecodeStringData()
429
+ size = self.decoder.DecodeUint64()
430
+ if self.version >= 11:
431
+ _, memory_cost = self.decoder.DecodeUint64()
432
+ else:
433
+ memory_cost = None
434
+
435
+ # TODO: make this a dataclass?
436
+ return {
437
+ 'url': url,
438
+ 'blob_type': blob_type,
439
+ 'size': size,
440
+ 'memory_cost': memory_cost
441
+ }
442
+
443
+ def DecodeRegExp(self) -> RegExp:
444
+ """Decodes a RegExp value."""
445
+ pattern = self.DecodeStringData()
446
+ flags = self.DecodeStringData()
447
+ return RegExp(pattern=pattern, flags=flags)
448
+
449
+ def DecodeMapData(self) -> dict:
450
+ """Decodes a Map value."""
451
+ tag = self.PeekSerializationTag()
452
+ js_map = {} # TODO: make this into a JSMap (like JSArray/JSSet)
453
+
454
+ while tag != definitions.SerializationTag.NON_MAP_PROPERTIES:
455
+ _, key = self.DecodeValue()
456
+ _, value = self.DecodeValue()
457
+ js_map[key] = value
458
+ tag = self.PeekSerializationTag()
459
+
460
+ # consume the NonMapPropertiesTag
461
+ _, tag = self.DecodeSerializationTag()
462
+
463
+ pool_tag = self.PeekTag()
464
+ while pool_tag != definitions.TerminatorTag:
465
+ name = self.DecodeStringData()
466
+ value = self.DecodeValue()
467
+ js_map[name] = value
468
+ pool_tag = self.PeekTag()
469
+
470
+ _, tag = self.decoder.DecodeUint32()
471
+
472
+ return js_map
473
+
474
+ def DecodeSetData(self) -> JSSet:
475
+ """Decodes a SetData value."""
476
+ tag = self.PeekSerializationTag()
477
+ js_set = JSSet()
478
+
479
+ while tag != definitions.SerializationTag.NON_SET_PROPERTIES:
480
+ _, key = self.DecodeValue()
481
+ js_set.add(key)
482
+ tag = self.PeekSerializationTag()
483
+
484
+ # consume the NonSetPropertiesTag
485
+ _, tag = self.DecodeSerializationTag()
486
+
487
+ pool_tag = self.PeekTag()
488
+ while pool_tag != definitions.TerminatorTag:
489
+ name = self.DecodeStringData()
490
+ value = self.DecodeValue()
491
+ js_set.properties[name] = value
492
+ pool_tag = self.decoder.PeekBytes(4)
493
+
494
+ # consume the TerminatorTag
495
+ _, tag = self.decoder.DecodeUint32()
496
+ return js_set
497
+
498
+ def DecodeCryptoKey(self) -> bytes:
499
+ """Decodes a CryptoKey value."""
500
+ _, wrapped_key_length = self.decoder.DecodeUint32()
501
+ _, wrapped_key = self.decoder.ReadBytes(wrapped_key_length)
502
+ key = plistlib.loads(wrapped_key) # TODO: unwrap the wrapped key.
503
+ return key
504
+
505
+ def DecodeBigIntData(self) -> int:
506
+ """Decodes a BigIntData value."""
507
+ _, sign = self.decoder.DecodeUint8()
508
+ _, number_of_elements = self.decoder.DecodeUint32()
509
+ contents = []
510
+ for _ in range(number_of_elements):
511
+ _, element = self.decoder.ReadBytes(8)
512
+ contents.extend(element)
513
+ value = int.from_bytes(contents, byteorder='little', signed=bool(sign))
514
+ return value
515
+
516
+ def DecodeArrayBuffer(self) -> bytes:
517
+ """Decodes an ArrayBuffer value."""
518
+ _, byte_length = self.decoder.DecodeUint64()
519
+ _, buffer = self.decoder.ReadBytes(byte_length)
520
+ self.object_pool.append(buffer)
521
+ return buffer
522
+
523
+ def DecodeResizableArrayBuffer(self) -> ResizableArrayBuffer:
524
+ """Decodes an ArrayBuffer value."""
525
+ _, byte_length = self.decoder.DecodeUint64()
526
+ _, max_length = self.decoder.DecodeUint64()
527
+ _, buffer = self.decoder.ReadBytes(byte_length)
528
+ self.object_pool.append(buffer)
529
+ return ResizableArrayBuffer(buffer=buffer, max_length=max_length)
530
+
531
+ def DecodeArrayBufferTransfer(self) -> int:
532
+ """Decodes an ArrayBufferTransfer value."""
533
+ _, value = self.decoder.DecodeUint32()
534
+ return value
535
+
536
+ def DecodeSharedArrayBuffer(self) -> int:
537
+ """Decodes an SharedArrayBuffer value."""
538
+ _, value = self.decoder.DecodeUint32()
539
+ return value
540
+
541
+ def DecodeObjectReference(self) -> Any:
542
+ """Decodes an ObjectReference value."""
543
+ _, object_ref = self.decoder.DecodeUint8()
544
+ return self.object_pool[object_ref - 1]
545
+
546
+ def DecodeArrayBufferView(self) -> ArrayBufferView:
547
+ """Decodes an ArrayBufferView value.
548
+
549
+ Returns:
550
+ an ArrayBufferView.
551
+
552
+ Raises:
553
+ ParserError if an unexpected serialization tag is found.
554
+ """
555
+ _, array_buffer_view_subtag = self.decoder.DecodeUint8()
556
+ array_buffer_view_subtag = definitions.ArrayBufferViewSubtag(
557
+ array_buffer_view_subtag)
558
+ _, byte_offset = self.decoder.DecodeUint64()
559
+ _, byte_length = self.decoder.DecodeUint64()
560
+ _, next_serialization_tag = self.DecodeSerializationTag()
561
+
562
+ if next_serialization_tag == definitions.SerializationTag.ARRAY_BUFFER:
563
+ value = self.DecodeArrayBuffer()
564
+ elif (next_serialization_tag ==
565
+ definitions.SerializationTag.OBJECT_REFERENCE):
566
+ value = self.DecodeObjectReference()
567
+ else:
568
+ raise errors.ParserError(
569
+ f'Unexpected serialization tag {next_serialization_tag}.')
570
+ return ArrayBufferView(
571
+ array_buffer_view_subtag=array_buffer_view_subtag,
572
+ buffer=value,
573
+ offset=byte_offset,
574
+ length=byte_length)
575
+
576
+ def DecodeSerializedValue(self) -> Any:
577
+ """Decodes a serialized value.
578
+
579
+ Returns:
580
+ the serialized value.
581
+
582
+ Raises:
583
+ ParserError when CurrentVersion is not found.
584
+ """
585
+ _, current_version = self.decoder.DecodeUint32()
586
+ if current_version != definitions.CurrentVersion:
587
+ raise errors.ParserError(
588
+ f'{current_version} is not the expected CurrentVersion')
589
+ _, value = self.DecodeValue()
590
+ return value
591
+
592
+ def DecodeValue(self) -> Tuple[int, Any]:
593
+ """Decodes a value.
594
+
595
+ Returns:
596
+ the offset and parsed value.
597
+
598
+ Raises:
599
+ ParserError when an unhandled SerializationTag is found.
600
+ """
601
+ offset, tag = self.DecodeSerializationTag()
602
+ if tag == definitions.SerializationTag.ARRAY:
603
+ value = self.DecodeArray()
604
+ elif tag == definitions.SerializationTag.OBJECT:
605
+ value = self.DecodeObject()
606
+ elif tag == definitions.SerializationTag.UNDEFINED:
607
+ value = Undefined()
608
+ elif tag == definitions.SerializationTag.NULL:
609
+ value = Null()
610
+ elif tag == definitions.SerializationTag.INT:
611
+ _, value = self.decoder.DecodeInt32()
612
+ elif tag == definitions.SerializationTag.ZERO:
613
+ value = 0
614
+ elif tag == definitions.SerializationTag.ONE:
615
+ value = 1
616
+ elif tag == definitions.SerializationTag.FALSE:
617
+ value = False
618
+ elif tag == definitions.SerializationTag.TRUE:
619
+ value = True
620
+ elif tag == definitions.SerializationTag.DOUBLE:
621
+ _, value = self.decoder.DecodeDouble()
622
+ elif tag == definitions.SerializationTag.DATE:
623
+ value = self.DecodeDate()
624
+ elif tag == definitions.SerializationTag.FILE:
625
+ value = self.DecodeFileData()
626
+ elif tag == definitions.SerializationTag.FILE_LIST:
627
+ value = self.DecodeFileList()
628
+ elif tag == definitions.SerializationTag.IMAGE_DATA:
629
+ value = self.DecodeImageData()
630
+ elif tag == definitions.SerializationTag.BLOB:
631
+ value = self.DecodeBlob()
632
+ elif tag == definitions.SerializationTag.STRING:
633
+ value = self.DecodeStringData()
634
+ elif tag == definitions.SerializationTag.EMPTY_STRING:
635
+ value = ''
636
+ elif tag == definitions.SerializationTag.REG_EXP:
637
+ value = self.DecodeRegExp()
638
+ elif tag == definitions.SerializationTag.OBJECT_REFERENCE:
639
+ value = self.DecodeObjectReference()
640
+ elif tag == definitions.SerializationTag.ARRAY_BUFFER:
641
+ value = self.DecodeArrayBuffer()
642
+ elif tag == definitions.SerializationTag.ARRAY_BUFFER_VIEW:
643
+ value = self.DecodeArrayBufferView()
644
+ elif tag == definitions.SerializationTag.ARRAY_BUFFER_TRANSFER:
645
+ value = self.DecodeArrayBufferTransfer()
646
+ elif tag == definitions.SerializationTag.TRUE_OBJECT:
647
+ self.object_pool.append(True)
648
+ value = True
649
+ elif tag == definitions.SerializationTag.FALSE_OBJECT:
650
+ self.object_pool.append(False)
651
+ value = False
652
+ elif tag == definitions.SerializationTag.STRING_OBJECT:
653
+ value = self.DecodeStringData()
654
+ self.object_pool.append(value)
655
+ elif tag == definitions.SerializationTag.EMPTY_STRING_OBJECT:
656
+ value = ''
657
+ self.object_pool.append(value)
658
+ elif tag == definitions.SerializationTag.NUMBER_OBJECT:
659
+ _, value = self.decoder.DecodeDouble()
660
+ self.object_pool.append(value)
661
+ elif tag == definitions.SerializationTag.SET_OBJECT:
662
+ value = self.DecodeSetData()
663
+ elif tag == definitions.SerializationTag.MAP_OBJECT:
664
+ value = self.DecodeMapData()
665
+ elif tag == definitions.SerializationTag.CRYPTO_KEY:
666
+ value = self.DecodeCryptoKey()
667
+ elif tag == definitions.SerializationTag.SHARED_ARRAY_BUFFER:
668
+ value = self.DecodeSharedArrayBuffer()
669
+ elif tag == definitions.SerializationTag.BIGINT:
670
+ value = self.DecodeBigIntData()
671
+ elif tag == definitions.SerializationTag.BIGINT_OBJECT:
672
+ value = self.DecodeBigIntData()
673
+ self.object_pool.append(value)
674
+ else:
675
+ raise errors.ParserError(f'Unhandled Serialization Tag {tag.name} found.')
676
+ return offset, value
677
+
678
+ @classmethod
679
+ def FromBytes(cls, data: bytes) -> Any:
680
+ """Returns a deserialized JavaScript object from the data.
681
+
682
+ Args:
683
+ data: the data to deserialize/parse.
684
+
685
+ Returns:
686
+ A python representation of the parsed JavaScript object.
687
+
688
+ Raises:
689
+ errors.ParserError: if there is an invalid V8 JavaScript header.
690
+ """
691
+ stream = io.BytesIO(data)
692
+ deserializer = cls(stream)
693
+ return deserializer.DecodeSerializedValue()