Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/dissect/cstruct/types/pointer.py: 50%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

70 statements  

1from __future__ import annotations 

2 

3from typing import TYPE_CHECKING, Any, BinaryIO, Generic, TypeVar 

4 

5from dissect.cstruct.exceptions import NullPointerDereference 

6from dissect.cstruct.types.base import BaseType 

7from dissect.cstruct.types.char import Char 

8from dissect.cstruct.types.void import Void 

9 

10if TYPE_CHECKING: 

11 from typing_extensions import Self 

12 

13T = TypeVar("T", bound=BaseType) 

14 

15 

16class Pointer(int, BaseType, Generic[T]): 

17 """Pointer to some other type.""" 

18 

19 type: type[T] 

20 _stream: BinaryIO | None 

21 _context: dict[str, Any] | None 

22 _value: T | None 

23 

24 def __new__(cls, value: int, stream: BinaryIO | None, context: dict[str, Any] | None = None) -> Self: 

25 obj = super().__new__(cls, value) 

26 obj._stream = stream 

27 obj._context = context 

28 obj._value = None 

29 return obj 

30 

31 def __repr__(self) -> str: 

32 return f"<{self.type.__name__}* @ {self:#x}>" 

33 

34 def __str__(self) -> str: 

35 return str(self.dereference()) 

36 

37 def __getattr__(self, attr: str) -> Any: 

38 return getattr(self.dereference(), attr) 

39 

40 def __add__(self, other: int) -> Self: 

41 return type.__call__(self.__class__, int.__add__(self, other), self._stream, self._context) 

42 

43 def __sub__(self, other: int) -> Self: 

44 return type.__call__(self.__class__, int.__sub__(self, other), self._stream, self._context) 

45 

46 def __mul__(self, other: int) -> Self: 

47 return type.__call__(self.__class__, int.__mul__(self, other), self._stream, self._context) 

48 

49 def __floordiv__(self, other: int) -> Self: 

50 return type.__call__(self.__class__, int.__floordiv__(self, other), self._stream, self._context) 

51 

52 def __mod__(self, other: int) -> Self: 

53 return type.__call__(self.__class__, int.__mod__(self, other), self._stream, self._context) 

54 

55 def __pow__(self, other: int) -> Self: 

56 return type.__call__(self.__class__, int.__pow__(self, other), self._stream, self._context) 

57 

58 def __lshift__(self, other: int) -> Self: 

59 return type.__call__(self.__class__, int.__lshift__(self, other), self._stream, self._context) 

60 

61 def __rshift__(self, other: int) -> Self: 

62 return type.__call__(self.__class__, int.__rshift__(self, other), self._stream, self._context) 

63 

64 def __and__(self, other: int) -> Self: 

65 return type.__call__(self.__class__, int.__and__(self, other), self._stream, self._context) 

66 

67 def __xor__(self, other: int) -> Self: 

68 return type.__call__(self.__class__, int.__xor__(self, other), self._stream, self._context) 

69 

70 def __or__(self, other: int) -> Self: 

71 return type.__call__(self.__class__, int.__or__(self, other), self._stream, self._context) 

72 

73 @classmethod 

74 def __default__(cls) -> Self: 

75 return cls.__new__(cls, cls.cs.pointer.__default__(), None, None) 

76 

77 @classmethod 

78 def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Self: 

79 return cls.__new__(cls, cls.cs.pointer._read(stream, context), stream, context) 

80 

81 @classmethod 

82 def _write(cls, stream: BinaryIO, data: int) -> int: 

83 return cls.cs.pointer._write(stream, data) 

84 

85 def dereference(self) -> T: 

86 if self == 0 or self._stream is None: 

87 raise NullPointerDereference 

88 

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

90 # Read current position of file read/write pointer 

91 position = self._stream.tell() 

92 # Reposition the file read/write pointer 

93 self._stream.seek(self) 

94 

95 if issubclass(self.type, Char): 

96 # this makes the assumption that a char pointer is a null-terminated string 

97 value = self.type._read_0(self._stream, self._context) 

98 else: 

99 value = self.type._read(self._stream, self._context) 

100 

101 self._stream.seek(position) 

102 self._value = value 

103 

104 return self._value