dissect.cstruct 5.0.dev8__py3-none-any.whl → 5.0.dev9__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.
@@ -1,12 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import functools
4
+ import warnings
4
5
  from io import BytesIO
5
6
  from typing import TYPE_CHECKING, Any, BinaryIO, ClassVar, TypeVar
6
7
 
7
8
  from dissect.cstruct.exception import ArraySizeError
8
9
  from dissect.cstruct.expression import Expression
9
- from dissect.cstruct.util import normalize_endianness
10
+ from dissect.cstruct.util import classproperty, normalize_endianness
10
11
 
11
12
  if TYPE_CHECKING:
12
13
  from collections.abc import Callable
@@ -22,17 +23,17 @@ EOF = -0xE0F # Negative counts are illegal anyway, so abuse that for our EOF se
22
23
  class MetaType(type):
23
24
  """Base metaclass for cstruct type classes."""
24
25
 
25
- cs: cstruct
26
+ __cs__: cstruct
26
27
  """The cstruct instance this type class belongs to."""
27
- size: int | None
28
+ __size__: int | None
28
29
  """The size of the type in bytes. Can be ``None`` for dynamic sized types."""
29
- dynamic: bool
30
+ __dynamic__: bool
30
31
  """Whether or not the type is dynamically sized."""
31
- alignment: int | None
32
+ __alignment__: int | None
32
33
  """The alignment of the type in bytes. A value of ``None`` will be treated as 1-byte aligned."""
33
34
 
34
35
  # This must be the actual type, but since Array is a subclass of BaseType, we correct this at the bottom of the file
35
- ArrayType: type[BaseArray] = "Array"
36
+ __ArrayType__: type[BaseArray] = "Array"
36
37
  """The array type for this type class."""
37
38
 
38
39
  def __call__(cls, *args, **kwargs) -> Self: # type: ignore
@@ -42,10 +43,12 @@ class MetaType(type):
42
43
  stream = args[0]
43
44
 
44
45
  if _is_readable_type(stream):
45
- endian = normalize_endianness(endian) if (endian := kwargs.get("endian")) is not None else cls.cs.endian
46
+ endian = (
47
+ normalize_endianness(endian) if (endian := kwargs.get("endian")) is not None else cls.__cs__.endian
48
+ )
46
49
  return cls._read(stream, endian=endian)
47
50
 
48
- if issubclass(cls, bytes) and isinstance(stream, bytes) and len(stream) == cls.size:
51
+ if issubclass(cls, bytes) and isinstance(stream, bytes) and len(stream) == cls.__size__:
49
52
  # Shortcut for char/bytes type
50
53
  return type.__call__(cls, *args, **kwargs)
51
54
 
@@ -56,7 +59,7 @@ class MetaType(type):
56
59
 
57
60
  def __getitem__(cls, num_entries: int | Expression | None) -> type[BaseArray]:
58
61
  """Create a new array with the given number of entries."""
59
- return cls.cs._make_array(cls, num_entries)
62
+ return cls.__cs__._make_array(cls, num_entries)
60
63
 
61
64
  def __bool__(cls) -> bool:
62
65
  """Type class is always truthy."""
@@ -64,10 +67,10 @@ class MetaType(type):
64
67
 
65
68
  def __len__(cls) -> int:
66
69
  """Return the byte size of the type."""
67
- if cls.size is None:
70
+ if cls.__size__ is None:
68
71
  raise TypeError("Dynamic size")
69
72
 
70
- return cls.size
73
+ return cls.__size__
71
74
 
72
75
  def __default__(cls) -> Self: # type: ignore
73
76
  """Return the default value of this type."""
@@ -84,7 +87,7 @@ class MetaType(type):
84
87
  Returns:
85
88
  The parsed value of this type.
86
89
  """
87
- endian = normalize_endianness(endian) if endian is not None else cls.cs.endian
90
+ endian = normalize_endianness(endian) if endian is not None else cls.__cs__.endian
88
91
  return cls._read(BytesIO(data), endian=endian)
89
92
 
90
93
  def read(cls, obj: BinaryIO | bytes | memoryview | bytearray, *, endian: AllowedEndianness | None = None) -> Self: # type: ignore
@@ -104,7 +107,7 @@ class MetaType(type):
104
107
  if not _is_readable_type(obj):
105
108
  raise TypeError("Invalid object type")
106
109
 
107
- endian = normalize_endianness(endian) if endian is not None else cls.cs.endian
110
+ endian = normalize_endianness(endian) if endian is not None else cls.__cs__.endian
108
111
  return cls._read(obj, endian=endian)
109
112
 
110
113
  def write(cls, stream: BinaryIO, value: Any, *, endian: AllowedEndianness | None = None) -> int:
@@ -119,7 +122,7 @@ class MetaType(type):
119
122
  Returns:
120
123
  The amount of bytes written.
121
124
  """
122
- endian = normalize_endianness(endian) if endian is not None else cls.cs.endian
125
+ endian = normalize_endianness(endian) if endian is not None else cls.__cs__.endian
123
126
  return cls._write(stream, value, endian=endian)
124
127
 
125
128
  def dumps(cls, value: Any, *, endian: AllowedEndianness | None = None) -> bytes:
@@ -133,7 +136,7 @@ class MetaType(type):
133
136
  Returns:
134
137
  The raw bytes of this type.
135
138
  """
136
- endian = normalize_endianness(endian) if endian is not None else cls.cs.endian
139
+ endian = normalize_endianness(endian) if endian is not None else cls.__cs__.endian
137
140
 
138
141
  out = BytesIO()
139
142
  cls._write(out, value, endian=endian)
@@ -211,6 +214,56 @@ class MetaType(type):
211
214
  """
212
215
  return cls._write_array(stream, [*array, cls.__default__()], endian=endian)
213
216
 
217
+ @property
218
+ def cs(cls) -> cstruct:
219
+ """Access the cstruct object for this type."""
220
+ warnings.warn(
221
+ "The 'cs' property is deprecated, use '__cs__' instead.",
222
+ DeprecationWarning,
223
+ stacklevel=2,
224
+ )
225
+ return cls.__cs__
226
+
227
+ @property
228
+ def size(cls) -> int | None:
229
+ """Access the size of this type."""
230
+ warnings.warn(
231
+ "The 'size' property is deprecated, use '__size__', len(cls) or sizeof(cls) instead.",
232
+ DeprecationWarning,
233
+ stacklevel=2,
234
+ )
235
+ return cls.__size__
236
+
237
+ @property
238
+ def dynamic(cls) -> bool:
239
+ """Access whether this type is dynamically sized."""
240
+ warnings.warn(
241
+ "The 'dynamic' property is deprecated, use '__dynamic__' instead.",
242
+ DeprecationWarning,
243
+ stacklevel=2,
244
+ )
245
+ return cls.__dynamic__
246
+
247
+ @property
248
+ def alignment(cls) -> int | None:
249
+ """Access the alignment of this type."""
250
+ warnings.warn(
251
+ "The 'alignment' property is deprecated, use '__alignment__' instead.",
252
+ DeprecationWarning,
253
+ stacklevel=2,
254
+ )
255
+ return cls.__alignment__
256
+
257
+ @property
258
+ def ArrayType(cls) -> type[BaseArray]:
259
+ """Access the array type of this type."""
260
+ warnings.warn(
261
+ "The 'ArrayType' property is deprecated, use '__ArrayType__' instead.",
262
+ DeprecationWarning,
263
+ stacklevel=2,
264
+ )
265
+ return cls.__ArrayType__
266
+
214
267
 
215
268
  class _overload:
216
269
  """Descriptor to use on the ``write`` and ``dumps`` methods on cstruct types.
@@ -241,10 +294,10 @@ class BaseType(metaclass=MetaType):
241
294
 
242
295
  def __len__(self) -> int:
243
296
  """Return the byte size of the type."""
244
- if self.__class__.size is None:
297
+ if self.__class__.__size__ is None:
245
298
  raise TypeError("Dynamic size")
246
299
 
247
- return self.__class__.size
300
+ return self.__class__.__size__
248
301
 
249
302
 
250
303
  T = TypeVar("T", bound=BaseType)
@@ -261,46 +314,76 @@ class BaseArray(BaseType):
261
314
  x[expr] -> expr -> dynamic length.
262
315
  """
263
316
 
264
- type: ClassVar[type[BaseType]]
265
- num_entries: ClassVar[int | Expression | None]
266
- null_terminated: ClassVar[bool]
317
+ __type__: ClassVar[type[BaseType]]
318
+ __num_entries__: ClassVar[int | Expression | None]
319
+ __null_terminated__: ClassVar[bool]
267
320
 
268
321
  @classmethod
269
322
  def __default__(cls) -> BaseType:
270
323
  return type.__call__(
271
- cls, [cls.type.__default__()] * (cls.num_entries if isinstance(cls.num_entries, int) else 0)
324
+ cls, [cls.__type__.__default__()] * (cls.__num_entries__ if isinstance(cls.__num_entries__, int) else 0)
272
325
  )
273
326
 
274
327
  @classmethod
275
328
  def _read(cls, stream: BinaryIO, *, context: dict[str, Any] | None = None, endian: Endianness) -> list[BaseType]:
276
- if cls.null_terminated:
277
- return cls.type._read_0(stream, context=context, endian=endian)
329
+ if cls.__null_terminated__:
330
+ return cls.__type__._read_0(stream, context=context, endian=endian)
278
331
 
279
- if isinstance(cls.num_entries, int):
280
- num = max(0, cls.num_entries)
281
- elif cls.num_entries is None:
332
+ if isinstance(cls.__num_entries__, int):
333
+ num = max(0, cls.__num_entries__)
334
+ elif cls.__num_entries__ is None:
282
335
  num = EOF
283
- elif isinstance(cls.num_entries, Expression):
336
+ elif isinstance(cls.__num_entries__, Expression):
284
337
  try:
285
- num = max(0, cls.num_entries.evaluate(cls.cs, context))
338
+ num = max(0, cls.__num_entries__.evaluate(cls.__cs__, context))
286
339
  except Exception:
287
- if cls.num_entries.expression != "EOF":
340
+ if cls.__num_entries__.expression != "EOF":
288
341
  raise
289
342
  num = EOF
290
343
 
291
- return cls.type._read_array(stream, num, context=context, endian=endian)
344
+ return cls.__type__._read_array(stream, num, context=context, endian=endian)
292
345
 
293
346
  @classmethod
294
347
  def _write(cls, stream: BinaryIO, data: list[Any], *, endian: Endianness) -> int:
295
- if cls.null_terminated:
296
- return cls.type._write_0(stream, data, endian=endian)
348
+ if cls.__null_terminated__:
349
+ return cls.__type__._write_0(stream, data, endian=endian)
297
350
 
298
- if not cls.dynamic and (remaining := cls.num_entries - (actual_size := len(data))):
351
+ if not cls.__dynamic__ and (remaining := cls.__num_entries__ - (actual_size := len(data))):
299
352
  if remaining < 0:
300
- raise ArraySizeError(f"Expected static array size {cls.num_entries}, got {actual_size} instead.")
301
- data = data + [cls.type.__default__()] * remaining
302
-
303
- return cls.type._write_array(stream, data, endian=endian)
353
+ raise ArraySizeError(f"Expected static array size {cls.__num_entries__}, got {actual_size} instead.")
354
+ data = data + [cls.__type__.__default__()] * remaining
355
+
356
+ return cls.__type__._write_array(stream, data, endian=endian)
357
+
358
+ @classproperty
359
+ def type(cls) -> type[BaseType]:
360
+ """Access the array element type."""
361
+ warnings.warn(
362
+ "The 'type' property is deprecated, use '__type__' instead.",
363
+ DeprecationWarning,
364
+ stacklevel=2,
365
+ )
366
+ return cls.__type__
367
+
368
+ @classproperty
369
+ def num_entries(cls) -> int | Expression | None:
370
+ """Access the number of entries for this array type."""
371
+ warnings.warn(
372
+ "The 'num_entries' property is deprecated, use '__num_entries__' instead.",
373
+ DeprecationWarning,
374
+ stacklevel=2,
375
+ )
376
+ return cls.__num_entries__
377
+
378
+ @classproperty
379
+ def null_terminated(cls) -> bool:
380
+ """Access whether this array type is null-terminated."""
381
+ warnings.warn(
382
+ "The 'null_terminated' property is deprecated, use '__null_terminated__' instead.",
383
+ DeprecationWarning,
384
+ stacklevel=2,
385
+ )
386
+ return cls.__null_terminated__
304
387
 
305
388
 
306
389
  class Array(list[T], BaseArray):
@@ -330,4 +413,4 @@ def _is_eof(stream: BinaryIO) -> bool:
330
413
 
331
414
 
332
415
  # As mentioned in the BaseType class, we correctly set the type here
333
- MetaType.ArrayType = Array
416
+ MetaType.__ArrayType__ = Array
@@ -16,7 +16,7 @@ class CharArray(bytes, BaseArray):
16
16
 
17
17
  @classmethod
18
18
  def __default__(cls) -> Self:
19
- return type.__call__(cls, b"\x00" * (0 if cls.dynamic or cls.null_terminated else cls.num_entries))
19
+ return type.__call__(cls, b"\x00" * (0 if cls.__dynamic__ or cls.__null_terminated__ else cls.__num_entries__))
20
20
 
21
21
  @classmethod
22
22
  def _read(cls, stream: BinaryIO, *, context: dict[str, Any] | None = None, endian: Endianness) -> Self:
@@ -29,12 +29,12 @@ class CharArray(bytes, BaseArray):
29
29
  elif isinstance(data, str):
30
30
  data = data.encode("latin-1")
31
31
 
32
- if cls.null_terminated:
32
+ if cls.__null_terminated__:
33
33
  data += b"\x00"
34
34
 
35
- if not cls.dynamic and (remaining := cls.num_entries - (actual_size := len(data))):
35
+ if not cls.__dynamic__ and (remaining := cls.__num_entries__ - (actual_size := len(data))):
36
36
  if remaining < 0:
37
- raise ArraySizeError(f"Expected static array size {cls.num_entries}, got {actual_size} instead.")
37
+ raise ArraySizeError(f"Expected static array size {cls.__num_entries__}, got {actual_size} instead.")
38
38
  data += b"\x00" * remaining
39
39
 
40
40
  return stream.write(data)
@@ -43,7 +43,7 @@ class CharArray(bytes, BaseArray):
43
43
  class Char(bytes, BaseType):
44
44
  """Character type for reading and writing bytes."""
45
45
 
46
- ArrayType = CharArray
46
+ __ArrayType__ = CharArray
47
47
 
48
48
  @classmethod
49
49
  def __default__(cls) -> Self:
@@ -21,7 +21,7 @@ _S = TypeVar("_S")
21
21
 
22
22
 
23
23
  class EnumMetaType(EnumMeta, MetaType):
24
- type: type[BaseType]
24
+ __type__: type[BaseType]
25
25
 
26
26
  @overload
27
27
  def __call__(cls, value: cstruct, name: str, type_: type[BaseType], *args, **kwargs) -> type[Enum]: ...
@@ -39,11 +39,11 @@ class EnumMetaType(EnumMeta, MetaType):
39
39
  ) -> Enum | type[Enum]:
40
40
  if name is None:
41
41
  if value is None:
42
- value = cls.type.__default__()
42
+ value = cls.__type__.__default__()
43
43
 
44
44
  if not isinstance(value, int):
45
45
  # value is a parsable value
46
- value = cls.type(value)
46
+ value = cls.__type__(value)
47
47
 
48
48
  return super().__call__(value)
49
49
 
@@ -54,11 +54,11 @@ class EnumMetaType(EnumMeta, MetaType):
54
54
  raise TypeError("Enum can only be created from int type")
55
55
 
56
56
  enum_cls = super().__call__(name, *args, **kwargs)
57
- enum_cls.cs = cs
58
- enum_cls.type = type_
59
- enum_cls.size = type_.size
60
- enum_cls.dynamic = type_.dynamic
61
- enum_cls.alignment = type_.alignment
57
+ enum_cls.__cs__ = cs
58
+ enum_cls.__type__ = type_
59
+ enum_cls.__size__ = type_.__size__
60
+ enum_cls.__dynamic__ = type_.__dynamic__
61
+ enum_cls.__alignment__ = type_.__alignment__
62
62
 
63
63
  _fix_alias_members(enum_cls)
64
64
 
@@ -85,26 +85,26 @@ class EnumMetaType(EnumMeta, MetaType):
85
85
  return value in cls._value2member_map_
86
86
 
87
87
  def _read(cls, stream: BinaryIO, *, context: dict[str, Any] | None = None, endian: Endianness) -> Self:
88
- return cls(cls.type._read(stream, context=context, endian=endian))
88
+ return cls(cls.__type__._read(stream, context=context, endian=endian))
89
89
 
90
90
  def _read_array(
91
91
  cls, stream: BinaryIO, count: int, *, context: dict[str, Any] | None = None, endian: Endianness
92
92
  ) -> list[Self]:
93
- return list(map(cls, cls.type._read_array(stream, count, context=context, endian=endian)))
93
+ return list(map(cls, cls.__type__._read_array(stream, count, context=context, endian=endian)))
94
94
 
95
95
  def _read_0(cls, stream: BinaryIO, *, context: dict[str, Any] | None = None, endian: Endianness) -> list[Self]:
96
- return list(map(cls, cls.type._read_0(stream, context=context, endian=endian)))
96
+ return list(map(cls, cls.__type__._read_0(stream, context=context, endian=endian)))
97
97
 
98
98
  def _write(cls, stream: BinaryIO, data: Enum, *, endian: Endianness) -> int:
99
- return cls.type._write(stream, data.value, endian=endian)
99
+ return cls.__type__._write(stream, data.value, endian=endian)
100
100
 
101
101
  def _write_array(cls, stream: BinaryIO, array: list[BaseType | int], *, endian: Endianness) -> int:
102
102
  data = [entry.value if isinstance(entry, _Enum) else entry for entry in array]
103
- return cls.type._write_array(stream, data, endian=endian)
103
+ return cls.__type__._write_array(stream, data, endian=endian)
104
104
 
105
105
  def _write_0(cls, stream: BinaryIO, array: list[BaseType | int], *, endian: Endianness) -> int:
106
106
  data = [entry.value if isinstance(entry, _Enum) else entry for entry in array]
107
- return cls._write_array(stream, [*data, cls.type.__default__()], endian=endian)
107
+ return cls._write_array(stream, [*data, cls.__type__.__default__()], endian=endian)
108
108
 
109
109
  def cdef(cls) -> str:
110
110
  """Render this enum (or flag) back to its C-style definition.
@@ -113,7 +113,7 @@ class EnumMetaType(EnumMeta, MetaType):
113
113
  The C-style definition as a string.
114
114
  """
115
115
  keyword = "flag" if issubclass(cls, IntFlag) else "enum"
116
- underlying = cls.type.__name__
116
+ underlying = cls.__type__.__name__
117
117
  title = f"{keyword} {cls.__name__} : {underlying}" if cls.__name__ else f"{keyword} : {underlying}"
118
118
 
119
119
  lines = [f"{title} {{"]
@@ -18,10 +18,10 @@ class Int(int, BaseType):
18
18
 
19
19
  @classmethod
20
20
  def _read(cls, stream: BinaryIO, *, context: dict[str, Any] | None = None, endian: Endianness) -> Self:
21
- data = stream.read(cls.size)
21
+ data = stream.read(cls.__size__)
22
22
 
23
- if len(data) != cls.size:
24
- raise EOFError(f"Read {len(data)} bytes, but expected {cls.size}")
23
+ if len(data) != cls.__size__:
24
+ raise EOFError(f"Read {len(data)} bytes, but expected {cls.__size__}")
25
25
 
26
26
  return cls.from_bytes(data, ENDIANNESS_TO_BYTEORDER_MAP[endian], signed=cls.signed)
27
27
 
@@ -39,4 +39,4 @@ class Int(int, BaseType):
39
39
 
40
40
  @classmethod
41
41
  def _write(cls, stream: BinaryIO, data: int, *, endian: Endianness) -> int:
42
- return stream.write(data.to_bytes(cls.size, ENDIANNESS_TO_BYTEORDER_MAP[endian], signed=cls.signed))
42
+ return stream.write(data.to_bytes(cls.__size__, ENDIANNESS_TO_BYTEORDER_MAP[endian], signed=cls.signed))
@@ -1,9 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import warnings
3
4
  from typing import TYPE_CHECKING, Any, BinaryIO, Generic, TypeVar
4
5
 
5
6
  from dissect.cstruct.types.base import EOF, BaseType
6
- from dissect.cstruct.util import _struct
7
+ from dissect.cstruct.util import _struct, classproperty
7
8
 
8
9
  if TYPE_CHECKING:
9
10
  from typing_extensions import Self
@@ -17,16 +18,16 @@ T = TypeVar("T", int, float)
17
18
  class Packed(BaseType, Generic[T]):
18
19
  """Packed type for Python struct (un)packing."""
19
20
 
20
- packchar: str
21
+ __fmt__: str
21
22
 
22
23
  @classmethod
23
24
  def _read(cls, stream: BinaryIO, *, context: dict[str, Any] | None = None, endian: Endianness) -> Self:
24
- data = stream.read(cls.size)
25
+ data = stream.read(cls.__size__)
25
26
 
26
- if len(data) != cls.size:
27
- raise EOFError(f"Read {len(data)} bytes, but expected {cls.size}")
27
+ if len(data) != cls.__size__:
28
+ raise EOFError(f"Read {len(data)} bytes, but expected {cls.__size__}")
28
29
 
29
- return cls.__new__(cls, _struct(endian, cls.packchar).unpack(data)[0])
30
+ return cls.__new__(cls, _struct(endian, cls.__fmt__).unpack(data)[0])
30
31
 
31
32
  @classmethod
32
33
  def _read_array(
@@ -35,12 +36,12 @@ class Packed(BaseType, Generic[T]):
35
36
  if count == EOF:
36
37
  data = stream.read()
37
38
  length = len(data)
38
- count = length // cls.size
39
+ count = length // cls.__size__
39
40
  else:
40
- length = cls.size * count
41
+ length = cls.__size__ * count
41
42
  data = stream.read(length)
42
43
 
43
- fmt = _struct(endian, f"{count}{cls.packchar}")
44
+ fmt = _struct(endian, f"{count}{cls.__fmt__}")
44
45
 
45
46
  if len(data) != length:
46
47
  raise EOFError(f"Read {len(data)} bytes, but expected {length}")
@@ -51,12 +52,12 @@ class Packed(BaseType, Generic[T]):
51
52
  def _read_0(cls, stream: BinaryIO, context: dict[str, Any] | None = None, *, endian: Endianness) -> Self:
52
53
  result = []
53
54
 
54
- fmt = _struct(endian, cls.packchar)
55
+ fmt = _struct(endian, cls.__fmt__)
55
56
  while True:
56
- data = stream.read(cls.size)
57
+ data = stream.read(cls.__size__)
57
58
 
58
- if len(data) != cls.size:
59
- raise EOFError(f"Read {len(data)} bytes, but expected {cls.size}")
59
+ if len(data) != cls.__size__:
60
+ raise EOFError(f"Read {len(data)} bytes, but expected {cls.__size__}")
60
61
 
61
62
  if (value := fmt.unpack(data)[0]) == 0:
62
63
  break
@@ -67,8 +68,18 @@ class Packed(BaseType, Generic[T]):
67
68
 
68
69
  @classmethod
69
70
  def _write(cls, stream: BinaryIO, data: Packed[T], *, endian: Endianness) -> int:
70
- return stream.write(_struct(endian, cls.packchar).pack(data))
71
+ return stream.write(_struct(endian, cls.__fmt__).pack(data))
71
72
 
72
73
  @classmethod
73
74
  def _write_array(cls, stream: BinaryIO, data: list[Packed[T]], *, endian: Endianness) -> int:
74
- return stream.write(_struct(endian, f"{len(data)}{cls.packchar}").pack(*data))
75
+ return stream.write(_struct(endian, f"{len(data)}{cls.__fmt__}").pack(*data))
76
+
77
+ @classproperty
78
+ def packchar(cls) -> str:
79
+ """Access the struct packing character of packed integer/float types."""
80
+ warnings.warn(
81
+ "The 'packchar' property is deprecated, use '__fmt__' instead.",
82
+ DeprecationWarning,
83
+ stacklevel=2,
84
+ )
85
+ return cls.__fmt__
@@ -21,23 +21,23 @@ T = TypeVar("T", bound=BaseType)
21
21
  class Pointer(int, BaseType, Generic[T]):
22
22
  """Pointer to some other type."""
23
23
 
24
- type: type[T]
25
- _stream: BinaryIO | None
26
- _context: dict[str, Any] | None
27
- _endian: Endianness
24
+ __type__: type[T]
25
+ __stream: BinaryIO | None
26
+ __context: dict[str, Any] | None
27
+ __endian: Endianness
28
28
 
29
29
  def __new__(
30
30
  cls, value: int, stream: BinaryIO | None, *, context: dict[str, Any] | None = None, endian: Endianness
31
31
  ) -> Self:
32
32
  obj = super().__new__(cls, value)
33
- obj._stream = stream
34
- obj._context = context
35
- obj._endian = endian
33
+ obj.__stream = stream
34
+ obj.__context = context
35
+ obj.__endian = endian
36
36
  obj.dereference = cache(obj.dereference)
37
37
  return obj
38
38
 
39
39
  def __repr__(self) -> str:
40
- return f"<{self.type.__name__}* @ {self:#x}>"
40
+ return f"<{self.__type__.__name__}* @ {self:#x}>"
41
41
 
42
42
  def __str__(self) -> str:
43
43
  return str(self.dereference())
@@ -51,9 +51,9 @@ class Pointer(int, BaseType, Generic[T]):
51
51
  return type.__call__(
52
52
  self.__class__,
53
53
  op(self, other),
54
- self._stream,
55
- context=self._context,
56
- endian=self._endian,
54
+ self.__stream,
55
+ context=self.__context,
56
+ endian=self.__endian,
57
57
  )
58
58
 
59
59
  return method
@@ -74,17 +74,17 @@ class Pointer(int, BaseType, Generic[T]):
74
74
  def __default__(cls) -> Self:
75
75
  return cls.__new__(
76
76
  cls,
77
- cls.cs.pointer.__default__(),
77
+ cls.__cs__.pointer.__default__(),
78
78
  None,
79
79
  context=None,
80
- endian=cls.cs.endian,
80
+ endian=cls.__cs__.endian,
81
81
  )
82
82
 
83
83
  @classmethod
84
84
  def _read(cls, stream: BinaryIO, *, context: dict[str, Any] | None = None, endian: Endianness) -> Self:
85
85
  return cls.__new__(
86
86
  cls,
87
- cls.cs.pointer._read(stream, context=context, endian=endian),
87
+ cls.__cs__.pointer._read(stream, context=context, endian=endian),
88
88
  stream,
89
89
  context=context,
90
90
  endian=endian,
@@ -92,7 +92,7 @@ class Pointer(int, BaseType, Generic[T]):
92
92
 
93
93
  @classmethod
94
94
  def _write(cls, stream: BinaryIO, data: int, *, endian: Endianness) -> int:
95
- return cls.cs.pointer._write(stream, data, endian=endian)
95
+ return cls.__cs__.pointer._write(stream, data, endian=endian)
96
96
 
97
97
  def dereference(self, *, endian: AllowedEndianness | None = None) -> T | None:
98
98
  """Dereference the pointer and read the value it points to.
@@ -101,22 +101,22 @@ class Pointer(int, BaseType, Generic[T]):
101
101
  endian: Optional endianness to use when reading the value.
102
102
  If not provided, the endianness used when reading the pointer itself will be used.
103
103
  """
104
- if self == 0 or self._stream is None:
104
+ if self == 0 or self.__stream is None:
105
105
  raise NullPointerDereference
106
106
 
107
- endian = normalize_endianness(endian) if endian is not None else self._endian
108
- if issubclass(self.type, Void):
107
+ endian = normalize_endianness(endian) if endian is not None else self.__endian
108
+ if issubclass(self.__type__, Void):
109
109
  return None
110
110
 
111
- position = self._stream.tell()
112
- self._stream.seek(self)
111
+ position = self.__stream.tell()
112
+ self.__stream.seek(self)
113
113
 
114
- if issubclass(self.type, Char):
114
+ if issubclass(self.__type__, Char):
115
115
  # This makes the assumption that a char pointer is a null-terminated string
116
- value = self.type._read_0(self._stream, context=self._context, endian=endian)
116
+ value = self.__type__._read_0(self.__stream, context=self.__context, endian=endian)
117
117
  else:
118
- value = self.type._read(self._stream, context=self._context, endian=endian)
118
+ value = self.__type__._read(self.__stream, context=self.__context, endian=endian)
119
119
 
120
120
  # Restore the stream position after reading the value
121
- self._stream.seek(position)
121
+ self.__stream.seek(position)
122
122
  return value