Skip to content

Commit e990b53

Browse files
authored
Fix dynamic size errors for MetaType (#121)
1 parent 610ae67 commit e990b53

File tree

6 files changed

+51
-16
lines changed

6 files changed

+51
-16
lines changed

dissect/cstruct/compiler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
Structure,
2222
Union,
2323
Void,
24+
VoidArray,
2425
Wchar,
2526
WcharArray,
2627
)
@@ -48,6 +49,7 @@
4849
Void,
4950
Wchar,
5051
WcharArray,
52+
VoidArray,
5153
)
5254

5355
log = logging.getLogger(__name__)
@@ -365,7 +367,7 @@ def _generate_struct_info(cs: cstruct, fields: list[Field], align: bool = False)
365367
read_type = _get_read_type(cs, field.type)
366368

367369
# Drop voids
368-
if issubclass(read_type, Void):
370+
if issubclass(read_type, (Void, VoidArray)):
369371
continue
370372

371373
# Array of more complex types are handled elsewhere

dissect/cstruct/types/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from dissect.cstruct.types.packed import Packed
88
from dissect.cstruct.types.pointer import Pointer
99
from dissect.cstruct.types.structure import Field, Structure, Union
10-
from dissect.cstruct.types.void import Void
10+
from dissect.cstruct.types.void import Void, VoidArray
1111
from dissect.cstruct.types.wchar import Wchar, WcharArray
1212

1313
__all__ = [
@@ -27,6 +27,7 @@
2727
"Structure",
2828
"Union",
2929
"Void",
30+
"VoidArray",
3031
"Wchar",
3132
"WcharArray",
3233
]

dissect/cstruct/types/base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ def __getitem__(cls, num_entries: int | Expression | None) -> type[BaseArray]:
5454
"""Create a new array with the given number of entries."""
5555
return cls.cs._make_array(cls, num_entries)
5656

57+
def __bool__(cls) -> bool:
58+
"""Type class is always truthy."""
59+
return True
60+
5761
def __len__(cls) -> int:
5862
"""Return the byte size of the type."""
5963
# Python 3.9 compat thing for bound type vars

dissect/cstruct/types/void.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,44 @@
11
from __future__ import annotations
22

3-
from typing import Any, BinaryIO
3+
from typing import TYPE_CHECKING, Any, BinaryIO
44

5-
from dissect.cstruct.types.base import BaseType
5+
from dissect.cstruct.types.base import BaseArray, BaseType
6+
7+
if TYPE_CHECKING:
8+
from typing_extensions import Self
9+
10+
11+
class VoidArray(list, BaseArray):
12+
"""Array type representing void elements, primarily used for no-op reading and writing operations."""
13+
14+
@classmethod
15+
def __default__(cls) -> Self:
16+
return cls()
17+
18+
@classmethod
19+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Self:
20+
return cls()
21+
22+
@classmethod
23+
def _write(cls, stream: BinaryIO, data: bytes) -> int:
24+
return 0
625

726

827
class Void(BaseType):
928
"""Void type."""
1029

30+
ArrayType = VoidArray
31+
1132
def __bool__(self) -> bool:
1233
return False
1334

1435
def __eq__(self, value: object) -> bool:
1536
return isinstance(value, Void)
1637

1738
@classmethod
18-
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Void:
39+
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Self:
1940
return cls.__new__(cls)
2041

21-
@classmethod
22-
def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Void:
23-
return [cls.__new__(cls)]
24-
2542
@classmethod
2643
def _write(cls, stream: BinaryIO, data: Void) -> int:
2744
return 0

tests/test_types_base.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,12 @@ def _read(cls, stream: BinaryIO, context: dict | None = None) -> CustomType:
137137
assert isinstance(result.b, CustomType)
138138
assert result.a.value == b"ASDF"
139139
assert result.b.value == b"asdf"
140+
141+
142+
def test_truthy_type(cs: cstruct) -> None:
143+
static_type = cs.uint32
144+
dynamic_type = cs.uint32[None]
145+
146+
assert static_type
147+
# Should not raise a TypeError: Dynamic size
148+
assert dynamic_type

tests/test_types_void.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010

1111

1212
def test_void_read(cs: cstruct) -> None:
13-
assert not cs.void
13+
# The type itself is truthy, but an instance is not
14+
assert cs.void
15+
assert not cs.void()
1416

1517
stream = io.BytesIO(b"AAAA")
1618
assert not cs.void(stream)
@@ -23,11 +25,11 @@ def test_void_write(cs: cstruct) -> None:
2325

2426

2527
def test_void_array_read(cs: cstruct) -> None:
26-
assert not cs.void[4]
28+
assert not cs.void[4]()
2729

2830
stream = io.BytesIO(b"AAAA")
29-
assert not any(cs.void[4](stream))
30-
assert not any(cs.void[None](stream))
31+
assert not cs.void[4](stream)
32+
assert not cs.void[None](stream)
3133
assert stream.tell() == 0
3234

3335

@@ -41,7 +43,7 @@ def test_void_default(cs: cstruct) -> None:
4143
assert not cs.void()
4244
assert not cs.void.__default__()
4345

44-
assert cs.void[1].__default__() == [cs.void()]
46+
assert cs.void[1].__default__() == []
4547
assert cs.void[None].__default__() == []
4648

4749

@@ -61,8 +63,8 @@ def test_void_struct(cs: cstruct, compiled: bool) -> None:
6163

6264
obj = cs.test(stream)
6365
assert not obj.a
64-
assert not any(obj.b)
65-
assert not any(obj.c)
66+
assert not obj.b
67+
assert not obj.c
6668

6769
assert stream.tell() == 0
6870

0 commit comments

Comments
 (0)