Skip to content

Commit 6b45db8

Browse files
committed
Fix default initialization for various types
1 parent 09830d2 commit 6b45db8

19 files changed

Lines changed: 774 additions & 211 deletions

dissect/cstruct/types/base.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ def __call__(cls, *args, **kwargs) -> MetaType | BaseType:
3636
if len(args) == 1 and not isinstance(args[0], cls):
3737
stream = args[0]
3838

39-
if hasattr(stream, "read"):
39+
if _is_readable_type(stream):
4040
return cls._read(stream)
4141

4242
if issubclass(cls, bytes) and isinstance(stream, bytes) and len(stream) == cls.size:
4343
# Shortcut for char/bytes type
4444
return type.__call__(cls, *args, **kwargs)
4545

46-
if isinstance(stream, (bytes, memoryview, bytearray)):
46+
if _is_buffer_type(stream):
4747
return cls.reads(stream)
4848

4949
return type.__call__(cls, *args, **kwargs)
@@ -83,7 +83,7 @@ def read(cls, obj: BinaryIO | bytes) -> BaseType:
8383
Returns:
8484
The parsed value of this type.
8585
"""
86-
if isinstance(obj, (bytes, memoryview, bytearray)):
86+
if _is_buffer_type(obj):
8787
return cls.reads(obj)
8888

8989
return cls._read(obj)
@@ -179,7 +179,7 @@ def _write_0(cls, stream: BinaryIO, array: list[BaseType]) -> int:
179179
stream: The stream to read from.
180180
array: The array to write.
181181
"""
182-
return cls._write_array(stream, array + [cls()])
182+
return cls._write_array(stream, array + [cls.default()])
183183

184184

185185
class _overload:
@@ -225,6 +225,11 @@ class ArrayMetaType(MetaType):
225225
num_entries: int | Expression | None
226226
null_terminated: bool
227227

228+
def default(cls) -> BaseType:
229+
return type.__call__(
230+
cls, [cls.type.default() for _ in range(cls.num_entries if isinstance(cls.num_entries, int) else 0)]
231+
)
232+
228233
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Array:
229234
if cls.null_terminated:
230235
return cls.type._read_0(stream, context)
@@ -243,11 +248,6 @@ def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Array:
243248

244249
return cls.type._read_array(stream, num, context)
245250

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-
251251

252252
class Array(list, BaseType, metaclass=ArrayMetaType):
253253
"""Implements a fixed or dynamically sized array type.
@@ -275,5 +275,13 @@ def _write(cls, stream: BinaryIO, data: list[Any]) -> int:
275275
return cls.type._write_array(stream, data)
276276

277277

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+
278286
# As mentioned in the BaseType class, we correctly set the type here
279287
MetaType.ArrayType = Array

dissect/cstruct/types/enum.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __call__(
2727
) -> EnumMetaType:
2828
if name is None:
2929
if value is None:
30-
value = cls.type()
30+
value = cls.type.default()
3131

3232
if not isinstance(value, int):
3333
# value is a parsable value
@@ -82,7 +82,7 @@ def _write_array(cls, stream: BinaryIO, array: list[Enum]) -> int:
8282

8383
def _write_0(cls, stream: BinaryIO, array: list[BaseType]) -> int:
8484
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()])
8686

8787

8888
def _fix_alias_members(cls: type[Enum]) -> None:

dissect/cstruct/types/pointer.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class Pointer(int, BaseType):
1616
_context: dict[str, Any]
1717
_value: BaseType
1818

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) -> Pointer:
2020
obj = super().__new__(cls, value)
2121
obj._stream = stream
2222
obj._context = context
@@ -65,6 +65,10 @@ def __xor__(self, other: int) -> Pointer:
6565
def __or__(self, other: int) -> Pointer:
6666
return type.__call__(self.__class__, int.__or__(self, other), self._stream, self._context)
6767

68+
@classmethod
69+
def default(cls) -> Pointer:
70+
return cls.__new__(cls, cls.cs.pointer.default(), None, None)
71+
6872
@classmethod
6973
def _read(cls, stream: BinaryIO, context: dict[str, Any] = None) -> Pointer:
7074
return cls.__new__(cls, cls.cs.pointer._read(stream, context), stream, context)
@@ -74,7 +78,7 @@ def _write(cls, stream: BinaryIO, data: int) -> int:
7478
return cls.cs.pointer._write(stream, data)
7579

7680
def dereference(self) -> Any:
77-
if self == 0:
81+
if self == 0 or self._stream is None:
7882
raise NullPointerDereference()
7983

8084
if self._value is None and not issubclass(self.type, Void):

0 commit comments

Comments
 (0)