dissect.cstruct 4.2.dev1__py3-none-any.whl → 4.3.dev2__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.
- dissect/cstruct/cstruct.py +1 -1
- dissect/cstruct/types/base.py +23 -15
- dissect/cstruct/types/char.py +6 -6
- dissect/cstruct/types/enum.py +5 -5
- dissect/cstruct/types/int.py +2 -2
- dissect/cstruct/types/leb128.py +2 -2
- dissect/cstruct/types/packed.py +3 -3
- dissect/cstruct/types/pointer.py +9 -5
- dissect/cstruct/types/structure.py +201 -70
- dissect/cstruct/types/void.py +8 -1
- dissect/cstruct/types/wchar.py +6 -6
- {dissect.cstruct-4.2.dev1.dist-info → dissect.cstruct-4.3.dev2.dist-info}/METADATA +1 -1
- dissect.cstruct-4.3.dev2.dist-info/RECORD +26 -0
- {dissect.cstruct-4.2.dev1.dist-info → dissect.cstruct-4.3.dev2.dist-info}/WHEEL +1 -1
- dissect.cstruct-4.2.dev1.dist-info/RECORD +0 -26
- {dissect.cstruct-4.2.dev1.dist-info → dissect.cstruct-4.3.dev2.dist-info}/COPYRIGHT +0 -0
- {dissect.cstruct-4.2.dev1.dist-info → dissect.cstruct-4.3.dev2.dist-info}/LICENSE +0 -0
- {dissect.cstruct-4.2.dev1.dist-info → dissect.cstruct-4.3.dev2.dist-info}/top_level.txt +0 -0
dissect/cstruct/cstruct.py
CHANGED
dissect/cstruct/types/base.py
CHANGED
|
@@ -36,14 +36,14 @@ class MetaType(type):
|
|
|
36
36
|
if len(args) == 1 and not isinstance(args[0], cls):
|
|
37
37
|
stream = args[0]
|
|
38
38
|
|
|
39
|
-
if
|
|
39
|
+
if _is_readable_type(stream):
|
|
40
40
|
return cls._read(stream)
|
|
41
41
|
|
|
42
42
|
if issubclass(cls, bytes) and isinstance(stream, bytes) and len(stream) == cls.size:
|
|
43
43
|
# Shortcut for char/bytes type
|
|
44
44
|
return type.__call__(cls, *args, **kwargs)
|
|
45
45
|
|
|
46
|
-
if
|
|
46
|
+
if _is_buffer_type(stream):
|
|
47
47
|
return cls.reads(stream)
|
|
48
48
|
|
|
49
49
|
return type.__call__(cls, *args, **kwargs)
|
|
@@ -59,7 +59,7 @@ class MetaType(type):
|
|
|
59
59
|
|
|
60
60
|
return cls.size
|
|
61
61
|
|
|
62
|
-
def
|
|
62
|
+
def __default__(cls) -> BaseType:
|
|
63
63
|
"""Return the default value of this type."""
|
|
64
64
|
return cls()
|
|
65
65
|
|
|
@@ -83,7 +83,7 @@ class MetaType(type):
|
|
|
83
83
|
Returns:
|
|
84
84
|
The parsed value of this type.
|
|
85
85
|
"""
|
|
86
|
-
if
|
|
86
|
+
if _is_buffer_type(obj):
|
|
87
87
|
return cls.reads(obj)
|
|
88
88
|
|
|
89
89
|
return cls._read(obj)
|
|
@@ -113,7 +113,7 @@ class MetaType(type):
|
|
|
113
113
|
cls._write(out, value)
|
|
114
114
|
return out.getvalue()
|
|
115
115
|
|
|
116
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> BaseType:
|
|
116
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> BaseType:
|
|
117
117
|
"""Internal function for reading value.
|
|
118
118
|
|
|
119
119
|
Must be implemented per type.
|
|
@@ -124,7 +124,7 @@ class MetaType(type):
|
|
|
124
124
|
"""
|
|
125
125
|
raise NotImplementedError()
|
|
126
126
|
|
|
127
|
-
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] = None) -> list[BaseType]:
|
|
127
|
+
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] | None = None) -> list[BaseType]:
|
|
128
128
|
"""Internal function for reading array values.
|
|
129
129
|
|
|
130
130
|
Allows type implementations to do optimized reading for their type.
|
|
@@ -145,7 +145,7 @@ class MetaType(type):
|
|
|
145
145
|
|
|
146
146
|
return [cls._read(stream, context) for _ in range(count)]
|
|
147
147
|
|
|
148
|
-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] = None) -> list[BaseType]:
|
|
148
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> list[BaseType]:
|
|
149
149
|
"""Internal function for reading null-terminated data.
|
|
150
150
|
|
|
151
151
|
"Null" is type specific, so must be implemented per type.
|
|
@@ -179,7 +179,7 @@ class MetaType(type):
|
|
|
179
179
|
stream: The stream to read from.
|
|
180
180
|
array: The array to write.
|
|
181
181
|
"""
|
|
182
|
-
return cls._write_array(stream, array + [cls()])
|
|
182
|
+
return cls._write_array(stream, array + [cls.__default__()])
|
|
183
183
|
|
|
184
184
|
|
|
185
185
|
class _overload:
|
|
@@ -225,7 +225,12 @@ class ArrayMetaType(MetaType):
|
|
|
225
225
|
num_entries: int | Expression | None
|
|
226
226
|
null_terminated: bool
|
|
227
227
|
|
|
228
|
-
def
|
|
228
|
+
def __default__(cls) -> BaseType:
|
|
229
|
+
return type.__call__(
|
|
230
|
+
cls, [cls.type.__default__()] * (cls.num_entries if isinstance(cls.num_entries, int) else 0)
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Array:
|
|
229
234
|
if cls.null_terminated:
|
|
230
235
|
return cls.type._read_0(stream, context)
|
|
231
236
|
|
|
@@ -243,11 +248,6 @@ class ArrayMetaType(MetaType):
|
|
|
243
248
|
|
|
244
249
|
return cls.type._read_array(stream, num, context)
|
|
245
250
|
|
|
246
|
-
def default(cls) -> BaseType:
|
|
247
|
-
return type.__call__(
|
|
248
|
-
cls, [cls.type.default() for _ in range(0 if cls.dynamic or cls.null_terminated else cls.num_entries)]
|
|
249
|
-
)
|
|
250
|
-
|
|
251
251
|
|
|
252
252
|
class Array(list, BaseType, metaclass=ArrayMetaType):
|
|
253
253
|
"""Implements a fixed or dynamically sized array type.
|
|
@@ -261,7 +261,7 @@ class Array(list, BaseType, metaclass=ArrayMetaType):
|
|
|
261
261
|
"""
|
|
262
262
|
|
|
263
263
|
@classmethod
|
|
264
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Array:
|
|
264
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Array:
|
|
265
265
|
return cls(ArrayMetaType._read(cls, stream, context))
|
|
266
266
|
|
|
267
267
|
@classmethod
|
|
@@ -275,5 +275,13 @@ class Array(list, BaseType, metaclass=ArrayMetaType):
|
|
|
275
275
|
return cls.type._write_array(stream, data)
|
|
276
276
|
|
|
277
277
|
|
|
278
|
+
def _is_readable_type(value: Any) -> bool:
|
|
279
|
+
return hasattr(value, "read")
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _is_buffer_type(value: Any) -> bool:
|
|
283
|
+
return isinstance(value, (bytes, memoryview, bytearray))
|
|
284
|
+
|
|
285
|
+
|
|
278
286
|
# As mentioned in the BaseType class, we correctly set the type here
|
|
279
287
|
MetaType.ArrayType = Array
|
dissect/cstruct/types/char.py
CHANGED
|
@@ -9,7 +9,7 @@ class CharArray(bytes, BaseType, metaclass=ArrayMetaType):
|
|
|
9
9
|
"""Character array type for reading and writing byte strings."""
|
|
10
10
|
|
|
11
11
|
@classmethod
|
|
12
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> CharArray:
|
|
12
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> CharArray:
|
|
13
13
|
return type.__call__(cls, ArrayMetaType._read(cls, stream, context))
|
|
14
14
|
|
|
15
15
|
@classmethod
|
|
@@ -25,7 +25,7 @@ class CharArray(bytes, BaseType, metaclass=ArrayMetaType):
|
|
|
25
25
|
return stream.write(data)
|
|
26
26
|
|
|
27
27
|
@classmethod
|
|
28
|
-
def
|
|
28
|
+
def __default__(cls) -> CharArray:
|
|
29
29
|
return type.__call__(cls, b"\x00" * (0 if cls.dynamic or cls.null_terminated else cls.num_entries))
|
|
30
30
|
|
|
31
31
|
|
|
@@ -35,11 +35,11 @@ class Char(bytes, BaseType):
|
|
|
35
35
|
ArrayType = CharArray
|
|
36
36
|
|
|
37
37
|
@classmethod
|
|
38
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Char:
|
|
38
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Char:
|
|
39
39
|
return cls._read_array(stream, 1, context)
|
|
40
40
|
|
|
41
41
|
@classmethod
|
|
42
|
-
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] = None) -> Char:
|
|
42
|
+
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] | None = None) -> Char:
|
|
43
43
|
if count == 0:
|
|
44
44
|
return type.__call__(cls, b"")
|
|
45
45
|
|
|
@@ -50,7 +50,7 @@ class Char(bytes, BaseType):
|
|
|
50
50
|
return type.__call__(cls, data)
|
|
51
51
|
|
|
52
52
|
@classmethod
|
|
53
|
-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Char:
|
|
53
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Char:
|
|
54
54
|
buf = []
|
|
55
55
|
while True:
|
|
56
56
|
byte = stream.read(1)
|
|
@@ -75,5 +75,5 @@ class Char(bytes, BaseType):
|
|
|
75
75
|
return stream.write(data)
|
|
76
76
|
|
|
77
77
|
@classmethod
|
|
78
|
-
def
|
|
78
|
+
def __default__(cls) -> Char:
|
|
79
79
|
return type.__call__(cls, b"\x00")
|
dissect/cstruct/types/enum.py
CHANGED
|
@@ -27,7 +27,7 @@ class EnumMetaType(EnumMeta, MetaType):
|
|
|
27
27
|
) -> EnumMetaType:
|
|
28
28
|
if name is None:
|
|
29
29
|
if value is None:
|
|
30
|
-
value = cls.type()
|
|
30
|
+
value = cls.type.__default__()
|
|
31
31
|
|
|
32
32
|
if not isinstance(value, int):
|
|
33
33
|
# value is a parsable value
|
|
@@ -64,13 +64,13 @@ class EnumMetaType(EnumMeta, MetaType):
|
|
|
64
64
|
return True
|
|
65
65
|
return value in cls._value2member_map_
|
|
66
66
|
|
|
67
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Enum:
|
|
67
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Enum:
|
|
68
68
|
return cls(cls.type._read(stream, context))
|
|
69
69
|
|
|
70
|
-
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] = None) -> list[Enum]:
|
|
70
|
+
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] | None = None) -> list[Enum]:
|
|
71
71
|
return list(map(cls, cls.type._read_array(stream, count, context)))
|
|
72
72
|
|
|
73
|
-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] = None) -> list[Enum]:
|
|
73
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> list[Enum]:
|
|
74
74
|
return list(map(cls, cls.type._read_0(stream, context)))
|
|
75
75
|
|
|
76
76
|
def _write(cls, stream: BinaryIO, data: Enum) -> int:
|
|
@@ -82,7 +82,7 @@ class EnumMetaType(EnumMeta, MetaType):
|
|
|
82
82
|
|
|
83
83
|
def _write_0(cls, stream: BinaryIO, array: list[BaseType]) -> int:
|
|
84
84
|
data = [entry.value if isinstance(entry, Enum) else entry for entry in array]
|
|
85
|
-
return cls._write_array(stream, data + [cls.type()])
|
|
85
|
+
return cls._write_array(stream, data + [cls.type.__default__()])
|
|
86
86
|
|
|
87
87
|
|
|
88
88
|
def _fix_alias_members(cls: type[Enum]) -> None:
|
dissect/cstruct/types/int.py
CHANGED
|
@@ -12,7 +12,7 @@ class Int(int, BaseType):
|
|
|
12
12
|
signed: bool
|
|
13
13
|
|
|
14
14
|
@classmethod
|
|
15
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Int:
|
|
15
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Int:
|
|
16
16
|
data = stream.read(cls.size)
|
|
17
17
|
|
|
18
18
|
if len(data) != cls.size:
|
|
@@ -21,7 +21,7 @@ class Int(int, BaseType):
|
|
|
21
21
|
return cls.from_bytes(data, ENDIANNESS_MAP[cls.cs.endian], signed=cls.signed)
|
|
22
22
|
|
|
23
23
|
@classmethod
|
|
24
|
-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Int:
|
|
24
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Int:
|
|
25
25
|
result = []
|
|
26
26
|
|
|
27
27
|
while True:
|
dissect/cstruct/types/leb128.py
CHANGED
|
@@ -14,7 +14,7 @@ class LEB128(int, BaseType):
|
|
|
14
14
|
signed: bool
|
|
15
15
|
|
|
16
16
|
@classmethod
|
|
17
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> LEB128:
|
|
17
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> LEB128:
|
|
18
18
|
result = 0
|
|
19
19
|
shift = 0
|
|
20
20
|
while True:
|
|
@@ -35,7 +35,7 @@ class LEB128(int, BaseType):
|
|
|
35
35
|
return cls.__new__(cls, result)
|
|
36
36
|
|
|
37
37
|
@classmethod
|
|
38
|
-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] = None) -> LEB128:
|
|
38
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> LEB128:
|
|
39
39
|
result = []
|
|
40
40
|
|
|
41
41
|
while True:
|
dissect/cstruct/types/packed.py
CHANGED
|
@@ -18,11 +18,11 @@ class Packed(BaseType):
|
|
|
18
18
|
packchar: str
|
|
19
19
|
|
|
20
20
|
@classmethod
|
|
21
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Packed:
|
|
21
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Packed:
|
|
22
22
|
return cls._read_array(stream, 1, context)[0]
|
|
23
23
|
|
|
24
24
|
@classmethod
|
|
25
|
-
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] = None) -> list[Packed]:
|
|
25
|
+
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] | None = None) -> list[Packed]:
|
|
26
26
|
if count == EOF:
|
|
27
27
|
data = stream.read()
|
|
28
28
|
length = len(data)
|
|
@@ -39,7 +39,7 @@ class Packed(BaseType):
|
|
|
39
39
|
return [cls.__new__(cls, value) for value in fmt.unpack(data)]
|
|
40
40
|
|
|
41
41
|
@classmethod
|
|
42
|
-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Packed:
|
|
42
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Packed:
|
|
43
43
|
result = []
|
|
44
44
|
|
|
45
45
|
fmt = _struct(cls.cs.endian, cls.packchar)
|
dissect/cstruct/types/pointer.py
CHANGED
|
@@ -12,11 +12,11 @@ class Pointer(int, BaseType):
|
|
|
12
12
|
"""Pointer to some other type."""
|
|
13
13
|
|
|
14
14
|
type: MetaType
|
|
15
|
-
_stream: BinaryIO
|
|
16
|
-
_context: dict[str, Any]
|
|
15
|
+
_stream: BinaryIO | None
|
|
16
|
+
_context: dict[str, Any] | None
|
|
17
17
|
_value: BaseType
|
|
18
18
|
|
|
19
|
-
def __new__(cls, value: int, stream: BinaryIO, context: dict[str, Any] = None) -> Pointer:
|
|
19
|
+
def __new__(cls, value: int, stream: BinaryIO | None, context: dict[str, Any] | None = None) -> Pointer:
|
|
20
20
|
obj = super().__new__(cls, value)
|
|
21
21
|
obj._stream = stream
|
|
22
22
|
obj._context = context
|
|
@@ -66,7 +66,11 @@ class Pointer(int, BaseType):
|
|
|
66
66
|
return type.__call__(self.__class__, int.__or__(self, other), self._stream, self._context)
|
|
67
67
|
|
|
68
68
|
@classmethod
|
|
69
|
-
def
|
|
69
|
+
def __default__(cls) -> Pointer:
|
|
70
|
+
return cls.__new__(cls, cls.cs.pointer.__default__(), None, None)
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Pointer:
|
|
70
74
|
return cls.__new__(cls, cls.cs.pointer._read(stream, context), stream, context)
|
|
71
75
|
|
|
72
76
|
@classmethod
|
|
@@ -74,7 +78,7 @@ class Pointer(int, BaseType):
|
|
|
74
78
|
return cls.cs.pointer._write(stream, data)
|
|
75
79
|
|
|
76
80
|
def dereference(self) -> Any:
|
|
77
|
-
if self == 0:
|
|
81
|
+
if self == 0 or self._stream is None:
|
|
78
82
|
raise NullPointerDereference()
|
|
79
83
|
|
|
80
84
|
if self._value is None and not issubclass(self.type, Void):
|
|
@@ -4,13 +4,19 @@ import io
|
|
|
4
4
|
from contextlib import contextmanager
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from functools import lru_cache
|
|
7
|
+
from itertools import chain
|
|
7
8
|
from operator import attrgetter
|
|
8
9
|
from textwrap import dedent
|
|
9
10
|
from types import FunctionType
|
|
10
|
-
from typing import Any, BinaryIO, Callable,
|
|
11
|
+
from typing import Any, BinaryIO, Callable, Iterator
|
|
11
12
|
|
|
12
13
|
from dissect.cstruct.bitbuffer import BitBuffer
|
|
13
|
-
from dissect.cstruct.types.base import
|
|
14
|
+
from dissect.cstruct.types.base import (
|
|
15
|
+
BaseType,
|
|
16
|
+
MetaType,
|
|
17
|
+
_is_buffer_type,
|
|
18
|
+
_is_readable_type,
|
|
19
|
+
)
|
|
14
20
|
from dissect.cstruct.types.enum import EnumMetaType
|
|
15
21
|
from dissect.cstruct.types.pointer import Pointer
|
|
16
22
|
|
|
@@ -65,7 +71,7 @@ class StructureMetaType(MetaType):
|
|
|
65
71
|
# Shortcut for single char/bytes type
|
|
66
72
|
return type.__call__(cls, *args, **kwargs)
|
|
67
73
|
elif not args and not kwargs:
|
|
68
|
-
obj =
|
|
74
|
+
obj = type.__call__(cls)
|
|
69
75
|
object.__setattr__(obj, "_values", {})
|
|
70
76
|
object.__setattr__(obj, "_sizes", {})
|
|
71
77
|
return obj
|
|
@@ -77,7 +83,6 @@ class StructureMetaType(MetaType):
|
|
|
77
83
|
|
|
78
84
|
lookup = {}
|
|
79
85
|
raw_lookup = {}
|
|
80
|
-
init_names = []
|
|
81
86
|
field_names = []
|
|
82
87
|
for field in fields:
|
|
83
88
|
if field.name in lookup and field.name != "_":
|
|
@@ -94,25 +99,21 @@ class StructureMetaType(MetaType):
|
|
|
94
99
|
|
|
95
100
|
raw_lookup[field.name] = field
|
|
96
101
|
|
|
97
|
-
num_fields = len(lookup)
|
|
98
102
|
field_names = lookup.keys()
|
|
99
|
-
init_names = raw_lookup.keys()
|
|
100
103
|
classdict["fields"] = lookup
|
|
101
104
|
classdict["lookup"] = raw_lookup
|
|
102
105
|
classdict["__fields__"] = fields
|
|
103
|
-
classdict["__bool__"] =
|
|
106
|
+
classdict["__bool__"] = _generate__bool__(field_names)
|
|
104
107
|
|
|
105
108
|
if issubclass(cls, UnionMetaType) or isinstance(cls, UnionMetaType):
|
|
106
|
-
classdict["__init__"] =
|
|
107
|
-
_make_setattr__init__(len(init_names)), init_names
|
|
108
|
-
)
|
|
109
|
+
classdict["__init__"] = _generate_union__init__(raw_lookup.values())
|
|
109
110
|
# Not a great way to do this but it works for now
|
|
110
111
|
classdict["__eq__"] = Union.__eq__
|
|
111
112
|
else:
|
|
112
|
-
classdict["__init__"] =
|
|
113
|
-
classdict["__eq__"] =
|
|
113
|
+
classdict["__init__"] = _generate_structure__init__(raw_lookup.values())
|
|
114
|
+
classdict["__eq__"] = _generate__eq__(field_names)
|
|
114
115
|
|
|
115
|
-
classdict["__hash__"] =
|
|
116
|
+
classdict["__hash__"] = _generate__hash__(field_names)
|
|
116
117
|
|
|
117
118
|
# If we're calling this as a class method or a function on the metaclass
|
|
118
119
|
if issubclass(cls, type):
|
|
@@ -229,7 +230,7 @@ class StructureMetaType(MetaType):
|
|
|
229
230
|
# The structure size is whatever the currently calculated offset is
|
|
230
231
|
return offset, alignment
|
|
231
232
|
|
|
232
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Structure:
|
|
233
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Structure:
|
|
233
234
|
bit_buffer = BitBuffer(stream, cls.cs.endian)
|
|
234
235
|
struct_start = stream.tell()
|
|
235
236
|
|
|
@@ -271,12 +272,14 @@ class StructureMetaType(MetaType):
|
|
|
271
272
|
# Align the stream
|
|
272
273
|
stream.seek(-stream.tell() & (cls.alignment - 1), io.SEEK_CUR)
|
|
273
274
|
|
|
274
|
-
|
|
275
|
+
# Using type.__call__ directly calls the __init__ method of the class
|
|
276
|
+
# This is faster than calling cls() and bypasses the metaclass __call__ method
|
|
277
|
+
obj = type.__call__(cls, **result)
|
|
275
278
|
obj._sizes = sizes
|
|
276
279
|
obj._values = result
|
|
277
280
|
return obj
|
|
278
281
|
|
|
279
|
-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] = None) -> list[Structure]:
|
|
282
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> list[Structure]:
|
|
280
283
|
result = []
|
|
281
284
|
|
|
282
285
|
while obj := cls._read(stream, context):
|
|
@@ -322,7 +325,7 @@ class StructureMetaType(MetaType):
|
|
|
322
325
|
|
|
323
326
|
value = getattr(data, field.name, None)
|
|
324
327
|
if value is None:
|
|
325
|
-
value = field_type()
|
|
328
|
+
value = field_type.__default__()
|
|
326
329
|
|
|
327
330
|
if field.bits:
|
|
328
331
|
if isinstance(field_type, EnumMetaType):
|
|
@@ -350,7 +353,7 @@ class StructureMetaType(MetaType):
|
|
|
350
353
|
cls.commit()
|
|
351
354
|
|
|
352
355
|
@contextmanager
|
|
353
|
-
def start_update(cls) ->
|
|
356
|
+
def start_update(cls) -> Iterator[None]:
|
|
354
357
|
try:
|
|
355
358
|
cls.__updating__ = True
|
|
356
359
|
yield
|
|
@@ -397,11 +400,27 @@ class UnionMetaType(StructureMetaType):
|
|
|
397
400
|
"""Base metaclass for cstruct union type classes."""
|
|
398
401
|
|
|
399
402
|
def __call__(cls, *args, **kwargs) -> Union:
|
|
400
|
-
obj = super().__call__(*args, **kwargs)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
403
|
+
obj: Union = super().__call__(*args, **kwargs)
|
|
404
|
+
|
|
405
|
+
# Calling with non-stream args or kwargs means we are initializing with values
|
|
406
|
+
if (args and not (len(args) == 1 and (_is_readable_type(args[0]) or _is_buffer_type(args[0])))) or kwargs:
|
|
407
|
+
# We don't support user initialization of dynamic unions yet
|
|
408
|
+
if cls.dynamic:
|
|
409
|
+
raise NotImplementedError("Initializing a dynamic union is not yet supported")
|
|
410
|
+
|
|
411
|
+
# User (partial) initialization, rebuild the union
|
|
412
|
+
# First user-provided field is the one used to rebuild the union
|
|
413
|
+
arg_fields = (field.name for _, field in zip(args, cls.__fields__))
|
|
414
|
+
kwarg_fields = (name for name in kwargs if name in cls.lookup)
|
|
415
|
+
if (first_field := next(chain(arg_fields, kwarg_fields), None)) is not None:
|
|
416
|
+
obj._rebuild(first_field)
|
|
417
|
+
elif not args and not kwargs:
|
|
418
|
+
# Initialized with default values
|
|
419
|
+
# Note that we proxify here in case we have a default initialization (cls())
|
|
420
|
+
# We don't proxify in case we read from a stream, as we do that later on in _read at a more appropriate time
|
|
421
|
+
# Same with (partial) user initialization, we do that after rebuilding the union
|
|
404
422
|
obj._proxify()
|
|
423
|
+
|
|
405
424
|
return obj
|
|
406
425
|
|
|
407
426
|
def _calculate_size_and_offsets(cls, fields: list[Field], align: bool = False) -> tuple[int | None, int]:
|
|
@@ -425,7 +444,9 @@ class UnionMetaType(StructureMetaType):
|
|
|
425
444
|
|
|
426
445
|
return size, alignment
|
|
427
446
|
|
|
428
|
-
def _read_fields(
|
|
447
|
+
def _read_fields(
|
|
448
|
+
cls, stream: BinaryIO, context: dict[str, Any] | None = None
|
|
449
|
+
) -> tuple[dict[str, Any], dict[str, int]]:
|
|
429
450
|
result = {}
|
|
430
451
|
sizes = {}
|
|
431
452
|
|
|
@@ -451,7 +472,7 @@ class UnionMetaType(StructureMetaType):
|
|
|
451
472
|
|
|
452
473
|
return result, sizes
|
|
453
474
|
|
|
454
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Union:
|
|
475
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Union:
|
|
455
476
|
if cls.size is None:
|
|
456
477
|
start = stream.tell()
|
|
457
478
|
result, sizes = cls._read_fields(stream, context)
|
|
@@ -463,7 +484,12 @@ class UnionMetaType(StructureMetaType):
|
|
|
463
484
|
sizes = {}
|
|
464
485
|
buf = stream.read(cls.size)
|
|
465
486
|
|
|
466
|
-
|
|
487
|
+
# Create the object and set the values
|
|
488
|
+
# Using type.__call__ directly calls the __init__ method of the class
|
|
489
|
+
# This is faster than calling cls() and bypasses the metaclass __call__ method
|
|
490
|
+
# It also makes it easier to differentiate between user-initialization of the class
|
|
491
|
+
# and initialization from a stream read
|
|
492
|
+
obj: Union = type.__call__(cls, **result)
|
|
467
493
|
object.__setattr__(obj, "_values", result)
|
|
468
494
|
object.__setattr__(obj, "_sizes", sizes)
|
|
469
495
|
object.__setattr__(obj, "_buf", buf)
|
|
@@ -471,14 +497,20 @@ class UnionMetaType(StructureMetaType):
|
|
|
471
497
|
if cls.size is not None:
|
|
472
498
|
obj._update()
|
|
473
499
|
|
|
500
|
+
# Proxify any nested structures
|
|
501
|
+
obj._proxify()
|
|
502
|
+
|
|
474
503
|
return obj
|
|
475
504
|
|
|
476
505
|
def _write(cls, stream: BinaryIO, data: Union) -> int:
|
|
506
|
+
if cls.dynamic:
|
|
507
|
+
raise NotImplementedError("Writing dynamic unions is not yet supported")
|
|
508
|
+
|
|
477
509
|
offset = stream.tell()
|
|
478
510
|
expected_offset = offset + len(cls)
|
|
479
511
|
|
|
480
512
|
# Sort by largest field
|
|
481
|
-
fields = sorted(cls.__fields__, key=lambda e:
|
|
513
|
+
fields = sorted(cls.__fields__, key=lambda e: e.type.size or 0, reverse=True)
|
|
482
514
|
anonymous_struct = False
|
|
483
515
|
|
|
484
516
|
# Try to write by largest field
|
|
@@ -488,12 +520,8 @@ class UnionMetaType(StructureMetaType):
|
|
|
488
520
|
anonymous_struct = field.type
|
|
489
521
|
continue
|
|
490
522
|
|
|
491
|
-
#
|
|
492
|
-
|
|
493
|
-
continue
|
|
494
|
-
|
|
495
|
-
# We have a value, write it
|
|
496
|
-
field.type._write(stream, value)
|
|
523
|
+
# Write the value
|
|
524
|
+
field.type._write(stream, getattr(data, field.name))
|
|
497
525
|
break
|
|
498
526
|
|
|
499
527
|
# If we haven't written anything yet and we initially skipped an anonymous struct, write it now
|
|
@@ -527,14 +555,21 @@ class Union(Structure, metaclass=UnionMetaType):
|
|
|
527
555
|
cur_buf = b"\x00" * self.__class__.size
|
|
528
556
|
|
|
529
557
|
buf = io.BytesIO(cur_buf)
|
|
530
|
-
field = self.__class__.
|
|
558
|
+
field = self.__class__.lookup[attr]
|
|
531
559
|
if field.offset:
|
|
532
560
|
buf.seek(field.offset)
|
|
533
|
-
|
|
561
|
+
|
|
562
|
+
if (value := getattr(self, attr)) is None:
|
|
563
|
+
value = field.type.__default__()
|
|
564
|
+
|
|
565
|
+
field.type._write(buf, value)
|
|
534
566
|
|
|
535
567
|
object.__setattr__(self, "_buf", buf.getvalue())
|
|
536
568
|
self._update()
|
|
537
569
|
|
|
570
|
+
# (Re-)proxify all values
|
|
571
|
+
self._proxify()
|
|
572
|
+
|
|
538
573
|
def _update(self) -> None:
|
|
539
574
|
result, sizes = self.__class__._read_fields(io.BytesIO(self._buf))
|
|
540
575
|
self.__dict__.update(result)
|
|
@@ -596,65 +631,71 @@ def attrsetter(path: str) -> Callable[[Any], Any]:
|
|
|
596
631
|
|
|
597
632
|
|
|
598
633
|
def _codegen(func: FunctionType) -> FunctionType:
|
|
599
|
-
|
|
600
|
-
@lru_cache
|
|
601
|
-
def make_func_code(num_fields: int) -> FunctionType:
|
|
602
|
-
names = [f"_{n}" for n in range(num_fields)]
|
|
603
|
-
exec(func(names), {}, d := {})
|
|
604
|
-
return d.popitem()[1]
|
|
634
|
+
"""Decorator that generates a template function with a specified number of fields.
|
|
605
635
|
|
|
606
|
-
|
|
636
|
+
This code is a little complex but allows use to cache generated functions for a specific number of fields.
|
|
637
|
+
For example, if we generate a structure with 10 fields, we can cache the generated code for that structure.
|
|
638
|
+
We can then reuse that code and patch it with the correct field names when we create a new structure with 10 fields.
|
|
607
639
|
|
|
640
|
+
The functions that are decorated with this decorator should take a list of field names and return a string of code.
|
|
641
|
+
The decorated function is needs to be called with the number of fields, instead of the field names.
|
|
642
|
+
The confusing part is that that the original function takes field names, but you then call it with
|
|
643
|
+
the number of fields instead.
|
|
608
644
|
|
|
609
|
-
|
|
610
|
-
return type(func)(
|
|
611
|
-
func.__code__.replace(
|
|
612
|
-
co_names=(*func.__code__.co_names[:start], *fields),
|
|
613
|
-
co_varnames=("self", *fields),
|
|
614
|
-
),
|
|
615
|
-
func.__globals__,
|
|
616
|
-
argdefs=func.__defaults__,
|
|
617
|
-
)
|
|
645
|
+
Inspired by https://github.com/dabeaz/dataklasses.
|
|
618
646
|
|
|
647
|
+
Args:
|
|
648
|
+
func: The decorated function that takes a list of field names and returns a string of code.
|
|
619
649
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
co_consts=(None, *fields),
|
|
624
|
-
co_varnames=("self", *fields),
|
|
625
|
-
),
|
|
626
|
-
func.__globals__,
|
|
627
|
-
argdefs=func.__defaults__,
|
|
628
|
-
)
|
|
650
|
+
Returns:
|
|
651
|
+
A cached function that generates the desired function code, to be called with the number of fields.
|
|
652
|
+
"""
|
|
629
653
|
|
|
654
|
+
def make_func_code(num_fields: int) -> FunctionType:
|
|
655
|
+
exec(func([f"_{n}" for n in range(num_fields)]), {}, d := {})
|
|
656
|
+
return d.popitem()[1]
|
|
630
657
|
|
|
631
|
-
|
|
632
|
-
return
|
|
633
|
-
func.__code__.replace(co_names=(*func.__code__.co_names[:start], *fields)),
|
|
634
|
-
func.__globals__,
|
|
635
|
-
)
|
|
658
|
+
make_func_code.__wrapped__ = func
|
|
659
|
+
return lru_cache(make_func_code)
|
|
636
660
|
|
|
637
661
|
|
|
638
662
|
@_codegen
|
|
639
|
-
def
|
|
663
|
+
def _make_structure__init__(fields: list[str]) -> str:
|
|
664
|
+
"""Generates an ``__init__`` method for a structure with the specified fields.
|
|
665
|
+
|
|
666
|
+
Args:
|
|
667
|
+
fields: List of field names.
|
|
668
|
+
"""
|
|
640
669
|
field_args = ", ".join(f"{field} = None" for field in fields)
|
|
641
|
-
field_init = "\n".join(f" self.{name} = {name}" for name in fields)
|
|
670
|
+
field_init = "\n".join(f" self.{name} = {name} if {name} is not None else {i}" for i, name in enumerate(fields))
|
|
642
671
|
|
|
643
|
-
code = f"def __init__(self{', ' + field_args
|
|
672
|
+
code = f"def __init__(self{', ' + field_args or ''}):\n"
|
|
644
673
|
return code + (field_init or " pass")
|
|
645
674
|
|
|
646
675
|
|
|
647
676
|
@_codegen
|
|
648
|
-
def
|
|
677
|
+
def _make_union__init__(fields: list[str]) -> str:
|
|
678
|
+
"""Generates an ``__init__`` method for a class with the specified fields using setattr.
|
|
679
|
+
|
|
680
|
+
Args:
|
|
681
|
+
fields: List of field names.
|
|
682
|
+
"""
|
|
649
683
|
field_args = ", ".join(f"{field} = None" for field in fields)
|
|
650
|
-
field_init = "\n".join(
|
|
684
|
+
field_init = "\n".join(
|
|
685
|
+
f" object.__setattr__(self, '{name}', {name} if {name} is not None else {i})" for i, name in enumerate(fields)
|
|
686
|
+
)
|
|
651
687
|
|
|
652
|
-
code = f"def __init__(self{', ' + field_args
|
|
688
|
+
code = f"def __init__(self{', ' + field_args or ''}):\n"
|
|
653
689
|
return code + (field_init or " pass")
|
|
654
690
|
|
|
655
691
|
|
|
656
692
|
@_codegen
|
|
657
693
|
def _make__eq__(fields: list[str]) -> str:
|
|
694
|
+
"""Generates an ``__eq__`` method for a class with the specified fields.
|
|
695
|
+
|
|
696
|
+
Args:
|
|
697
|
+
fields: List of field names.
|
|
698
|
+
"""
|
|
658
699
|
self_vals = ",".join(f"self.{name}" for name in fields)
|
|
659
700
|
other_vals = ",".join(f"other.{name}" for name in fields)
|
|
660
701
|
|
|
@@ -676,6 +717,11 @@ def _make__eq__(fields: list[str]) -> str:
|
|
|
676
717
|
|
|
677
718
|
@_codegen
|
|
678
719
|
def _make__bool__(fields: list[str]) -> str:
|
|
720
|
+
"""Generates a ``__bool__`` method for a class with the specified fields.
|
|
721
|
+
|
|
722
|
+
Args:
|
|
723
|
+
fields: List of field names.
|
|
724
|
+
"""
|
|
679
725
|
vals = ", ".join(f"self.{name}" for name in fields)
|
|
680
726
|
|
|
681
727
|
code = f"""
|
|
@@ -688,6 +734,11 @@ def _make__bool__(fields: list[str]) -> str:
|
|
|
688
734
|
|
|
689
735
|
@_codegen
|
|
690
736
|
def _make__hash__(fields: list[str]) -> str:
|
|
737
|
+
"""Generates a ``__hash__`` method for a class with the specified fields.
|
|
738
|
+
|
|
739
|
+
Args:
|
|
740
|
+
fields: List of field names.
|
|
741
|
+
"""
|
|
691
742
|
vals = ", ".join(f"self.{name}" for name in fields)
|
|
692
743
|
|
|
693
744
|
code = f"""
|
|
@@ -696,3 +747,83 @@ def _make__hash__(fields: list[str]) -> str:
|
|
|
696
747
|
"""
|
|
697
748
|
|
|
698
749
|
return dedent(code)
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
def _patch_attributes(func: FunctionType, fields: list[str], start: int = 0) -> FunctionType:
|
|
753
|
+
"""Patches a function's attributes.
|
|
754
|
+
|
|
755
|
+
Args:
|
|
756
|
+
func: The function to patch.
|
|
757
|
+
fields: List of field names to add.
|
|
758
|
+
start: The starting index for patching. Defaults to 0.
|
|
759
|
+
"""
|
|
760
|
+
return type(func)(
|
|
761
|
+
func.__code__.replace(co_names=(*func.__code__.co_names[:start], *fields)),
|
|
762
|
+
func.__globals__,
|
|
763
|
+
)
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
def _generate_structure__init__(fields: list[Field]) -> FunctionType:
|
|
767
|
+
"""Generates an ``__init__`` method for a structure with the specified fields.
|
|
768
|
+
|
|
769
|
+
Args:
|
|
770
|
+
fields: List of field names.
|
|
771
|
+
"""
|
|
772
|
+
field_names = [field.name for field in fields]
|
|
773
|
+
|
|
774
|
+
template: FunctionType = _make_structure__init__(len(field_names))
|
|
775
|
+
return type(template)(
|
|
776
|
+
template.__code__.replace(
|
|
777
|
+
co_consts=(None, *[field.type.__default__() for field in fields]),
|
|
778
|
+
co_names=(*field_names,),
|
|
779
|
+
co_varnames=("self", *field_names),
|
|
780
|
+
),
|
|
781
|
+
template.__globals__,
|
|
782
|
+
argdefs=template.__defaults__,
|
|
783
|
+
)
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
def _generate_union__init__(fields: list[Field]) -> FunctionType:
|
|
787
|
+
"""Generates an ``__init__`` method for a union with the specified fields.
|
|
788
|
+
|
|
789
|
+
Args:
|
|
790
|
+
fields: List of field names.
|
|
791
|
+
"""
|
|
792
|
+
field_names = [field.name for field in fields]
|
|
793
|
+
|
|
794
|
+
template: FunctionType = _make_union__init__(len(field_names))
|
|
795
|
+
return type(template)(
|
|
796
|
+
template.__code__.replace(
|
|
797
|
+
co_consts=(None, *sum([(field.name, field.type.__default__()) for field in fields], ())),
|
|
798
|
+
co_varnames=("self", *field_names),
|
|
799
|
+
),
|
|
800
|
+
template.__globals__,
|
|
801
|
+
argdefs=template.__defaults__,
|
|
802
|
+
)
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
def _generate__eq__(fields: list[str]) -> FunctionType:
|
|
806
|
+
"""Generates an ``__eq__`` method for a class with the specified fields.
|
|
807
|
+
|
|
808
|
+
Args:
|
|
809
|
+
fields: List of field names.
|
|
810
|
+
"""
|
|
811
|
+
return _patch_attributes(_make__eq__(len(fields)), fields, 1)
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
def _generate__bool__(fields: list[str]) -> FunctionType:
|
|
815
|
+
"""Generates a ``__bool__`` method for a class with the specified fields.
|
|
816
|
+
|
|
817
|
+
Args:
|
|
818
|
+
fields: List of field names.
|
|
819
|
+
"""
|
|
820
|
+
return _patch_attributes(_make__bool__(len(fields)), fields, 1)
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
def _generate__hash__(fields: list[str]) -> FunctionType:
|
|
824
|
+
"""Generates a ``__hash__`` method for a class with the specified fields.
|
|
825
|
+
|
|
826
|
+
Args:
|
|
827
|
+
fields: List of field names.
|
|
828
|
+
"""
|
|
829
|
+
return _patch_attributes(_make__hash__(len(fields)), fields, 1)
|
dissect/cstruct/types/void.py
CHANGED
|
@@ -11,10 +11,17 @@ class Void(BaseType):
|
|
|
11
11
|
def __bool__(self) -> bool:
|
|
12
12
|
return False
|
|
13
13
|
|
|
14
|
+
def __eq__(self, value: object) -> bool:
|
|
15
|
+
return isinstance(value, Void)
|
|
16
|
+
|
|
14
17
|
@classmethod
|
|
15
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Void:
|
|
18
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Void:
|
|
16
19
|
return cls.__new__(cls)
|
|
17
20
|
|
|
21
|
+
@classmethod
|
|
22
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Void:
|
|
23
|
+
return [cls.__new__(cls)]
|
|
24
|
+
|
|
18
25
|
@classmethod
|
|
19
26
|
def _write(cls, stream: BinaryIO, data: Void) -> int:
|
|
20
27
|
return 0
|
dissect/cstruct/types/wchar.py
CHANGED
|
@@ -10,7 +10,7 @@ class WcharArray(str, BaseType, metaclass=ArrayMetaType):
|
|
|
10
10
|
"""Wide-character array type for reading and writing UTF-16 strings."""
|
|
11
11
|
|
|
12
12
|
@classmethod
|
|
13
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> WcharArray:
|
|
13
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> WcharArray:
|
|
14
14
|
return type.__call__(cls, ArrayMetaType._read(cls, stream, context))
|
|
15
15
|
|
|
16
16
|
@classmethod
|
|
@@ -20,7 +20,7 @@ class WcharArray(str, BaseType, metaclass=ArrayMetaType):
|
|
|
20
20
|
return stream.write(data.encode(Wchar.__encoding_map__[cls.cs.endian]))
|
|
21
21
|
|
|
22
22
|
@classmethod
|
|
23
|
-
def
|
|
23
|
+
def __default__(cls) -> WcharArray:
|
|
24
24
|
return type.__call__(cls, "\x00" * (0 if cls.dynamic or cls.null_terminated else cls.num_entries))
|
|
25
25
|
|
|
26
26
|
|
|
@@ -38,11 +38,11 @@ class Wchar(str, BaseType):
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
@classmethod
|
|
41
|
-
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Wchar:
|
|
41
|
+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Wchar:
|
|
42
42
|
return cls._read_array(stream, 1, context)
|
|
43
43
|
|
|
44
44
|
@classmethod
|
|
45
|
-
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] = None) -> Wchar:
|
|
45
|
+
def _read_array(cls, stream: BinaryIO, count: int, context: dict[str, Any] | None = None) -> Wchar:
|
|
46
46
|
if count == 0:
|
|
47
47
|
return type.__call__(cls, "")
|
|
48
48
|
|
|
@@ -56,7 +56,7 @@ class Wchar(str, BaseType):
|
|
|
56
56
|
return type.__call__(cls, data.decode(cls.__encoding_map__[cls.cs.endian]))
|
|
57
57
|
|
|
58
58
|
@classmethod
|
|
59
|
-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Wchar:
|
|
59
|
+
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Wchar:
|
|
60
60
|
buf = []
|
|
61
61
|
while True:
|
|
62
62
|
point = stream.read(2)
|
|
@@ -75,5 +75,5 @@ class Wchar(str, BaseType):
|
|
|
75
75
|
return stream.write(data.encode(cls.__encoding_map__[cls.cs.endian]))
|
|
76
76
|
|
|
77
77
|
@classmethod
|
|
78
|
-
def
|
|
78
|
+
def __default__(cls) -> Wchar:
|
|
79
79
|
return type.__call__(cls, "\x00")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dissect.cstruct
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.dev2
|
|
4
4
|
Summary: A Dissect module implementing a parser for C-like structures: structure parsing in Python made easy
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Apache License 2.0
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
dissect/cstruct/__init__.py,sha256=E8HT9kh67nPR6cnUmTmTJIdGANNfInG_htxb8mPjSik,1344
|
|
2
|
+
dissect/cstruct/bitbuffer.py,sha256=phqKSE-BS8crZ_sdzssF3E831bD5Gk8LOXIE7iQJXa8,2218
|
|
3
|
+
dissect/cstruct/compiler.py,sha256=dB7Wi1GC0pYoVe5x3olZDmAT3ypbyV-1h-BMefJk5dU,13991
|
|
4
|
+
dissect/cstruct/cstruct.py,sha256=2Hu0HSFucV1pY2QAnteqHnpob9jmqPr_glfnGZigfjo,14858
|
|
5
|
+
dissect/cstruct/exceptions.py,sha256=WqsUW4OiIpRLQLvixfLrfKl0rtvU1qx7pvfBrz9Sz-I,293
|
|
6
|
+
dissect/cstruct/expression.py,sha256=giBNkbFgsbsw2K2EvQi42GRlm9Z97UvhDhcHnNMG2dg,10763
|
|
7
|
+
dissect/cstruct/parser.py,sha256=kL9caswfpm6ltXoJfetf5UjEfOLIqj7WGMqdID8C2W4,20893
|
|
8
|
+
dissect/cstruct/utils.py,sha256=ze_i59PRxQ1q0xl-wsV_ZLKSnBirT71fvxfKEshgc18,10386
|
|
9
|
+
dissect/cstruct/types/__init__.py,sha256=basF3huZ-jOg4FqGQGW7-SmYDN2GuMuCQN21asLtelQ,855
|
|
10
|
+
dissect/cstruct/types/base.py,sha256=PB_H7PRt0pLehThnQQVNFBmKIfQRnlfXYfw7pNZdBaQ,9120
|
|
11
|
+
dissect/cstruct/types/char.py,sha256=XWBtODCWKYtZYml5MKlvxrnRyH2emiGa_To7RrwJc_Y,2433
|
|
12
|
+
dissect/cstruct/types/enum.py,sha256=OyW1HmdTg7B1_FNMckez1vOTlwAfPKj6cfM9ITAxEkw,6746
|
|
13
|
+
dissect/cstruct/types/flag.py,sha256=EOJVk-5G7aUtD6plg7_Y6yxoAcrAQCNMjxoUePEQukk,2345
|
|
14
|
+
dissect/cstruct/types/int.py,sha256=ihV8v6eR1k2Pnc7dAroxQOGhjQ0Um1coiJMAVHYqWn4,1081
|
|
15
|
+
dissect/cstruct/types/leb128.py,sha256=OYwwwGSTU2npHZVZxMV9PTseug7hBoy1A44Uj_dhtNs,2182
|
|
16
|
+
dissect/cstruct/types/packed.py,sha256=V0rEpxHJ3GOlUv9rzi94U8GyN6ArxW7CSPhBPk90qSc,1994
|
|
17
|
+
dissect/cstruct/types/pointer.py,sha256=2Ve0b6VxGpckK2CtHtTzQyU5tSSotnPZFu7ZoP9WqMI,3832
|
|
18
|
+
dissect/cstruct/types/structure.py,sha256=_9JCSjj_BsHr16HYwv6IAXHLt1B4yH0n3S8D2WclBmU,29481
|
|
19
|
+
dissect/cstruct/types/void.py,sha256=VL2qJ86rq-oBUnkBprNsPPgPGgHV6UENRJTQ2jw0rxc,669
|
|
20
|
+
dissect/cstruct/types/wchar.py,sha256=ZL54AuYndQLj46-QgxSFbmd18saRgYwyJaNTwxZCsqU,2572
|
|
21
|
+
dissect.cstruct-4.3.dev2.dist-info/COPYRIGHT,sha256=H-18RXfshdH9AdHwW2eO1Xa-5s6tY5eipHh5c0whDu4,316
|
|
22
|
+
dissect.cstruct-4.3.dev2.dist-info/LICENSE,sha256=PhUqiw6jAh2KbBdVRPBq_hfAvfcTBin7nZ3CK7NQbTM,11341
|
|
23
|
+
dissect.cstruct-4.3.dev2.dist-info/METADATA,sha256=jyWC9013BoKf9h7vS1EAeFY1pHdV3GlhH6ATVA9MaOw,8558
|
|
24
|
+
dissect.cstruct-4.3.dev2.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
25
|
+
dissect.cstruct-4.3.dev2.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
|
26
|
+
dissect.cstruct-4.3.dev2.dist-info/RECORD,,
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
dissect/cstruct/__init__.py,sha256=E8HT9kh67nPR6cnUmTmTJIdGANNfInG_htxb8mPjSik,1344
|
|
2
|
-
dissect/cstruct/bitbuffer.py,sha256=phqKSE-BS8crZ_sdzssF3E831bD5Gk8LOXIE7iQJXa8,2218
|
|
3
|
-
dissect/cstruct/compiler.py,sha256=dB7Wi1GC0pYoVe5x3olZDmAT3ypbyV-1h-BMefJk5dU,13991
|
|
4
|
-
dissect/cstruct/cstruct.py,sha256=W-17FFc8OM2je7VTMMVQc-hivCAjaRj9qSdf4cEDrCY,14851
|
|
5
|
-
dissect/cstruct/exceptions.py,sha256=WqsUW4OiIpRLQLvixfLrfKl0rtvU1qx7pvfBrz9Sz-I,293
|
|
6
|
-
dissect/cstruct/expression.py,sha256=giBNkbFgsbsw2K2EvQi42GRlm9Z97UvhDhcHnNMG2dg,10763
|
|
7
|
-
dissect/cstruct/parser.py,sha256=kL9caswfpm6ltXoJfetf5UjEfOLIqj7WGMqdID8C2W4,20893
|
|
8
|
-
dissect/cstruct/utils.py,sha256=ze_i59PRxQ1q0xl-wsV_ZLKSnBirT71fvxfKEshgc18,10386
|
|
9
|
-
dissect/cstruct/types/__init__.py,sha256=basF3huZ-jOg4FqGQGW7-SmYDN2GuMuCQN21asLtelQ,855
|
|
10
|
-
dissect/cstruct/types/base.py,sha256=qZeXn1MAEb-vOlF4HdeqbMHx4-Mr5lTcHYt_s0lhu9g,8944
|
|
11
|
-
dissect/cstruct/types/char.py,sha256=M_QmYL8c96bIO8r2nxHC26zXoPjO2dMtehoWtZJL2M8,2397
|
|
12
|
-
dissect/cstruct/types/enum.py,sha256=1P-GUSRLWAKRcn55XhPYvK9KVMdX3x7GdmdDUy2HuEQ,6701
|
|
13
|
-
dissect/cstruct/types/flag.py,sha256=EOJVk-5G7aUtD6plg7_Y6yxoAcrAQCNMjxoUePEQukk,2345
|
|
14
|
-
dissect/cstruct/types/int.py,sha256=pBdr9InRY3EMHlULBmzBZCI2Qdh2XygsUelDWBrIRhc,1067
|
|
15
|
-
dissect/cstruct/types/leb128.py,sha256=yHkWqcGEWkf-8ZzfLv_5p937fzrMRvlZXwxowEl36CU,2168
|
|
16
|
-
dissect/cstruct/types/packed.py,sha256=gmNxtNRf9feY8k_7UYMGADe31dtXkw5fQYG1CtyvJBo,1973
|
|
17
|
-
dissect/cstruct/types/pointer.py,sha256=kWfEBCgW7TDnJihZiDGUlldD3QSxVY19r8LGz7olswk,3644
|
|
18
|
-
dissect/cstruct/types/structure.py,sha256=3pdEg_Jc4py7xzkcp06r4LtH-L_uhdlFhuhdP-zX3ww,24426
|
|
19
|
-
dissect/cstruct/types/void.py,sha256=RGBlM1yBYCFUM9yLyOETMZBd_nEp9-6vH5xFXaphK8o,438
|
|
20
|
-
dissect/cstruct/types/wchar.py,sha256=5kap4GDypRmt5IoLhMnREbWaWTEMhY_xVLCFginbwFo,2536
|
|
21
|
-
dissect.cstruct-4.2.dev1.dist-info/COPYRIGHT,sha256=H-18RXfshdH9AdHwW2eO1Xa-5s6tY5eipHh5c0whDu4,316
|
|
22
|
-
dissect.cstruct-4.2.dev1.dist-info/LICENSE,sha256=PhUqiw6jAh2KbBdVRPBq_hfAvfcTBin7nZ3CK7NQbTM,11341
|
|
23
|
-
dissect.cstruct-4.2.dev1.dist-info/METADATA,sha256=93eUYeGsSm9i_1aKIm5qc_tEV5RRTkJJTduscjrFZic,8558
|
|
24
|
-
dissect.cstruct-4.2.dev1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
|
25
|
-
dissect.cstruct-4.2.dev1.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
|
26
|
-
dissect.cstruct-4.2.dev1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|