Skip to content

Commit 46b850f

Browse files
authored
Move all internal attributes to dunder attributes (#165)
1 parent 3032ad7 commit 46b850f

25 files changed

Lines changed: 590 additions & 368 deletions

‎dissect/cstruct/bitbuffer.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ def __init__(self, stream: BinaryIO, *, endian: str):
1919

2020
def read(self, field_type: type[BaseType], bits: int) -> int:
2121
if self._remaining == 0 or self._type != field_type:
22-
if field_type.size is None:
22+
if field_type.__size__ is None:
2323
raise ValueError("Reading variable-length fields is unsupported")
2424

2525
self._type = field_type
26-
self._remaining = field_type.size * 8
26+
self._remaining = field_type.__size__ * 8
2727
self._buffer = field_type._read(self.stream, endian=self.endian)
2828

2929
if isinstance(self._buffer, bytes):
@@ -51,17 +51,17 @@ def write(self, field_type: type[BaseType], data: int, bits: int) -> None:
5151
if self._type:
5252
self.flush()
5353

54-
if field_type.size is None:
54+
if field_type.__size__ is None:
5555
raise ValueError("Writing variable-length fields is unsupported")
5656

57-
self._remaining = field_type.size * 8
57+
self._remaining = field_type.__size__ * 8
5858
self._type = field_type
5959

60-
if self._type is None or self._type.size is None:
60+
if self._type is None or self._type.__size__ is None:
6161
raise ValueError("Invalid state")
6262

6363
if self.endian == "<":
64-
self._buffer |= data << (self._type.size * 8 - self._remaining)
64+
self._buffer |= data << (self._type.__size__ * 8 - self._remaining)
6565
else:
6666
self._buffer |= data << (self._remaining - bits)
6767

‎dissect/cstruct/compiler.py‎

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858

5959

6060
def compile(structure: type[Structure]) -> type[Structure]:
61-
return Compiler(structure.cs).compile(structure)
61+
return Compiler(structure.__cs__).compile(structure)
6262

6363

6464
class Compiler:
@@ -163,7 +163,7 @@ def align_to_field(field: Field) -> Iterator[str]:
163163
field_type = field.type
164164

165165
if isinstance(field_type, EnumMetaType):
166-
field_type = field_type.type
166+
field_type = field_type.__type__
167167

168168
if not issubclass(field_type, SUPPORTED_TYPES):
169169
raise TypeError(f"Unsupported type for compiler: {field_type}")
@@ -188,7 +188,7 @@ def align_to_field(field: Field) -> Iterator[str]:
188188

189189
# Array of structures and multi-dimensional arrays
190190
elif issubclass(field_type, (Array, CharArray, WcharArray)) and (
191-
issubclass(field_type.type, Structure) or issubclass(field_type.type, BaseArray) or is_dynamic
191+
issubclass(field_type.__type__, Structure) or issubclass(field_type.__type__, BaseArray) or is_dynamic
192192
):
193193
yield from flush()
194194
yield from align_to_field(field)
@@ -222,22 +222,22 @@ def align_to_field(field: Field) -> Iterator[str]:
222222
yield from flush()
223223

224224
if self.align:
225-
yield f"stream.seek(-stream.tell() & (cls.alignment - 1), {io.SEEK_CUR})"
225+
yield f"stream.seek(-stream.tell() & (cls.__alignment__ - 1), {io.SEEK_CUR})"
226226

227227
def _generate_structure(self, field: Field) -> Iterator[str]:
228228
template = f"""
229-
{"_s = stream.tell()" if field.type.dynamic else ""}
229+
{"_s = stream.tell()" if field.type.__dynamic__ else ""}
230230
r["{field._name}"] = {self._map_field(field)}._read(stream, context=r, endian=endian)
231-
{f's["{field._name}"] = stream.tell() - _s' if field.type.dynamic else ""}
231+
{f's["{field._name}"] = stream.tell() - _s' if field.type.__dynamic__ else ""}
232232
"""
233233

234234
yield dedent(template)
235235

236236
def _generate_array(self, field: Field) -> Iterator[str]:
237237
template = f"""
238-
{"_s = stream.tell()" if field.type.dynamic else ""}
238+
{"_s = stream.tell()" if field.type.__dynamic__ else ""}
239239
r["{field._name}"] = {self._map_field(field)}._read(stream, context=r, endian=endian)
240-
{f's["{field._name}"] = stream.tell() - _s' if field.type.dynamic else ""}
240+
{f's["{field._name}"] = stream.tell() - _s' if field.type.__dynamic__ else ""}
241241
"""
242242

243243
yield dedent(template)
@@ -247,12 +247,12 @@ def _generate_bits(self, field: Field) -> Iterator[str]:
247247
read_type = "_t"
248248
field_type = field.type
249249
if issubclass(field_type, (Enum, Flag)):
250-
read_type += ".type"
251-
field_type = field_type.type
250+
read_type += ".__type__"
251+
field_type = field_type.__type__
252252

253253
if issubclass(field_type, Char):
254-
field_type = field_type.cs.uint8
255-
lookup = "cls.cs.uint8"
254+
field_type = field_type.__cs__.uint8
255+
lookup = "cls.__cs__.uint8"
256256

257257
template = f"""
258258
_t = {lookup}
@@ -277,17 +277,17 @@ def _generate_packed(self, fields: list[Field]) -> Iterator[str]:
277277
read_type = _get_read_type(self.cs, field_type)
278278

279279
if issubclass(field_type, (Array, CharArray, WcharArray)):
280-
count = field_type.num_entries
281-
read_type = _get_read_type(self.cs, field_type.type)
280+
count = field_type.__num_entries__
281+
read_type = _get_read_type(self.cs, field_type.__type__)
282282

283283
if issubclass(read_type, (Char, Wchar, Int)):
284-
count *= read_type.size
284+
count *= read_type.__size__
285285
getter = f"buf[{size}:{size + count}]"
286286
else:
287287
getter = f"data[{slice_index}:{slice_index + count}]"
288288
slice_index += count
289289
elif issubclass(read_type, (Char, Wchar, Int)):
290-
getter = f"buf[{size}:{size + read_type.size}]"
290+
getter = f"buf[{size}:{size + read_type.__size__}]"
291291
else:
292292
getter = f"data[{slice_index}]"
293293
slice_index += 1
@@ -302,13 +302,13 @@ def _generate_packed(self, fields: list[Field]) -> Iterator[str]:
302302
# Create the final reading code
303303
if issubclass(field_type, Array):
304304
reads.append(f"_t = {self._map_field(field)}")
305-
reads.append("_et = _t.type")
305+
reads.append("_et = _t.__type__")
306306

307-
if issubclass(field_type.type, Int):
307+
if issubclass(field_type.__type__, Int):
308308
reads.append(f"_b = {getter}")
309-
item_parser = parser_template.format(type="_et", getter=f"_b[i:i + {field_type.type.size}]")
310-
list_comp = f"[{item_parser} for i in range(0, {count}, {field_type.type.size})]"
311-
elif issubclass(field_type.type, Pointer):
309+
item_parser = parser_template.format(type="_et", getter=f"_b[i:i + {field_type.__type__.__size__}]")
310+
list_comp = f"[{item_parser} for i in range(0, {count}, {field_type.__type__.__size__})]"
311+
elif issubclass(field_type.__type__, Pointer):
312312
item_parser = "_et.__new__(_et, e, stream, context=r, endian=endian)"
313313
list_comp = f"[{item_parser} for e in {getter}]"
314314
else:
@@ -327,7 +327,7 @@ def _generate_packed(self, fields: list[Field]) -> Iterator[str]:
327327
reads.append(f'r["{field._name}"] = {parser}')
328328
reads.append("") # Generates a newline in the resulting code
329329

330-
size += field_type.size
330+
size += field_type.__size__
331331

332332
fmt = _optimize_struct_fmt(info)
333333
if fmt == "x" or (len(fmt) == 2 and fmt[1] == "x"):
@@ -370,19 +370,19 @@ def _generate_struct_info(cs: cstruct, fields: list[Field], align: bool = False)
370370

371371
# Array of more complex types are handled elsewhere
372372
if issubclass(read_type, (Array, CharArray, WcharArray)):
373-
count = read_type.num_entries
374-
read_type = _get_read_type(cs, read_type.type)
373+
count = read_type.__num_entries__
374+
read_type = _get_read_type(cs, read_type.__type__)
375375

376376
# Take the pack char for Packed
377377
if issubclass(read_type, Packed):
378-
yield field, count, read_type.packchar
378+
yield field, count, read_type.__fmt__
379379

380380
# Other types are byte based
381381
# We don't actually unpack anything here but slice directly out of the buffer
382382
elif issubclass(read_type, (Char, Wchar, Int)):
383-
yield field, count * read_type.size, "x"
383+
yield field, count * read_type.__size__, "x"
384384

385-
size = count * read_type.size
385+
size = count * read_type.__size__
386386
imaginary_offset += size
387387
if current_offset is not None:
388388
current_offset += size
@@ -416,7 +416,7 @@ def _optimize_struct_fmt(info: Iterator[tuple[Field, int, str]]) -> str:
416416

417417
def _get_read_type(cs: cstruct, type_: type[BaseType]) -> type[BaseType]:
418418
if issubclass(type_, (Enum, Flag)):
419-
type_ = type_.type
419+
type_ = type_.__type__
420420

421421
if issubclass(type_, Pointer):
422422
type_ = cs.pointer

‎dissect/cstruct/cstruct.py‎

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,28 @@ def __init__(self, load: str = "", *, endian: AllowedEndianness = "<", pointer:
206206
if load:
207207
self.load(load)
208208

209-
def __getattr__(self, attr: str) -> Any:
209+
def __getattr__(
210+
self, attr: str
211+
) -> (
212+
type[
213+
LEB128
214+
| BaseType
215+
| Char
216+
| Enum
217+
| Flag
218+
| Int
219+
| Packed[int]
220+
| Packed[float]
221+
| Pointer
222+
| Structure
223+
| Union
224+
| Void
225+
| Wchar
226+
]
227+
| int
228+
| str
229+
| bytes
230+
):
210231
try:
211232
return self.consts[attr]
212233
except KeyError:
@@ -227,7 +248,7 @@ def __copy__(self) -> cstruct:
227248
# Update types to point to the new cstruct instance
228249
for name, type_ in self.types.items():
229250
new_type = copy.copy(type_)
230-
new_type.cs = cs
251+
new_type.__cs__ = cs
231252
cs.add_type(name, new_type, replace=True)
232253

233254
for name, value in self.consts.items():
@@ -288,8 +309,10 @@ def add_custom_type(
288309
"""
289310
# In cstruct 5.0 we changed the function signature of _read and _write
290311
# Check if the function signature is compatible, and warn if not
291-
for type_to_check in (type_, type_.ArrayType):
292-
type_name = type_.__name__ + (f".{type_.ArrayType.__name__}" if type_to_check is type_.ArrayType else "")
312+
for type_to_check in (type_, type_.__ArrayType__):
313+
type_name = type_.__name__ + (
314+
f".{type_.__ArrayType__.__name__}" if type_to_check is type_.__ArrayType__ else ""
315+
)
293316

294317
for method in ("_read", "_read_array", "_read_0", "_write", "_write_array", "_write_0"):
295318
if not hasattr(type_to_check, method):
@@ -481,10 +504,10 @@ def _make_type(
481504
attrs = attrs or {}
482505
attrs.update(
483506
{
484-
"cs": self,
485-
"size": size,
486-
"dynamic": size is None,
487-
"alignment": alignment or size,
507+
"__cs__": self,
508+
"__size__": size,
509+
"__dynamic__": size is None,
510+
"__alignment__": alignment or size,
488511
}
489512
)
490513
return types.new_class(name, bases, {}, lambda ns: ns.update(attrs))
@@ -494,37 +517,37 @@ def _make_array(self, type_: T, num_entries: int | Expression | None) -> type[Ar
494517
if num_entries is None:
495518
null_terminated = True
496519
size = None
497-
elif isinstance(num_entries, Expression) or type_.dynamic:
520+
elif isinstance(num_entries, Expression) or type_.__dynamic__:
498521
size = None
499522
else:
500-
if type_.size is None:
523+
if type_.__size__ is None:
501524
raise ValueError(f"Cannot create array of dynamic type: {type_.__name__}")
502-
size = num_entries * type_.size
525+
size = num_entries * type_.__size__
503526

504527
name = f"{type_.__name__}[]" if null_terminated else f"{type_.__name__}[{num_entries}]"
505528

506-
bases = (type_.ArrayType,)
529+
bases = (type_.__ArrayType__,)
507530

508531
attrs = {
509-
"type": type_,
510-
"num_entries": num_entries,
511-
"null_terminated": null_terminated,
532+
"__type__": type_,
533+
"__num_entries__": num_entries,
534+
"__null_terminated__": null_terminated,
512535
}
513536

514-
return cast("type[Array]", self._make_type(name, bases, size, alignment=type_.alignment, attrs=attrs))
537+
return cast("type[Array]", self._make_type(name, bases, size, alignment=type_.__alignment__, attrs=attrs))
515538

516539
def _make_int_type(self, name: str, size: int, signed: bool, *, alignment: int | None = None) -> type[Int]:
517540
return cast("type[Int]", self._make_type(name, (Int,), size, alignment=alignment, attrs={"signed": signed}))
518541

519-
def _make_packed_type(self, name: str, packchar: str, base: type, *, alignment: int | None = None) -> type[Packed]:
542+
def _make_packed_type(self, name: str, fmt: str, base: type, *, alignment: int | None = None) -> type[Packed]:
520543
return cast(
521544
"type[Packed]",
522545
self._make_type(
523546
name,
524547
(base, Packed),
525-
struct.calcsize(packchar),
548+
struct.calcsize(fmt),
526549
alignment=alignment,
527-
attrs={"packchar": packchar},
550+
attrs={"__fmt__": fmt},
528551
),
529552
)
530553

@@ -538,9 +561,9 @@ def _make_pointer(self, target: type[BaseType]) -> type[Pointer]:
538561
return self._make_type(
539562
f"{target.__name__}*",
540563
(Pointer,),
541-
self.pointer.size,
542-
alignment=self.pointer.alignment,
543-
attrs={"type": target},
564+
self.pointer.__size__,
565+
alignment=self.pointer.__alignment__,
566+
attrs={"__type__": target},
544567
)
545568

546569
def _make_struct(
@@ -557,7 +580,7 @@ def _make_struct(
557580
(base,),
558581
None,
559582
attrs={
560-
"fields": fields,
583+
"__members__": fields,
561584
"__align__": align,
562585
"__anonymous__": anonymous,
563586
},
@@ -568,6 +591,15 @@ def _make_union(
568591
) -> type[Structure]:
569592
return self._make_struct(name, fields, align=align, anonymous=anonymous, base=Union)
570593

594+
@property
595+
def typedefs(self) -> dict[str, type[BaseType]]:
596+
warnings.warn(
597+
"The 'typedefs' property is deprecated, use 'types' instead.",
598+
DeprecationWarning,
599+
stacklevel=2,
600+
)
601+
return self.types
602+
571603
if TYPE_CHECKING:
572604
# ruff: noqa: PYI042
573605
_int = int
@@ -749,8 +781,8 @@ def ctypes_type(type_: type[BaseType]) -> Any:
749781
"d": _ctypes.c_double,
750782
}
751783

752-
if issubclass(type_, Packed) and type_.packchar in mapping:
753-
return mapping[type_.packchar]
784+
if issubclass(type_, Packed) and type_.__fmt__ in mapping:
785+
return mapping[type_.__fmt__]
754786

755787
if issubclass(type_, Char):
756788
return _ctypes.c_char
@@ -759,11 +791,11 @@ def ctypes_type(type_: type[BaseType]) -> Any:
759791
return _ctypes.c_wchar
760792

761793
if issubclass(type_, BaseArray):
762-
subtype = ctypes_type(type_.type)
763-
return subtype * type_.num_entries
794+
subtype = ctypes_type(type_.__type__)
795+
return subtype * type_.__num_entries__
764796

765797
if issubclass(type_, Pointer):
766-
subtype = ctypes_type(type_.type)
798+
subtype = ctypes_type(type_.__type__)
767799
return _ctypes.POINTER(subtype)
768800

769801
if issubclass(type_, Structure):

0 commit comments

Comments
 (0)