-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathpointer.py
More file actions
99 lines (71 loc) · 3.73 KB
/
Copy pathpointer.py
File metadata and controls
99 lines (71 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from __future__ import annotations
from typing import Any, BinaryIO
from dissect.cstruct.exceptions import NullPointerDereference
from dissect.cstruct.types.base import BaseType, MetaType
from dissect.cstruct.types.char import Char
from dissect.cstruct.types.void import Void
class Pointer(int, BaseType):
"""Pointer to some other type."""
type: MetaType
_stream: BinaryIO | None
_context: dict[str, Any] | None
_value: BaseType
def __new__(cls, value: int, stream: BinaryIO | None, context: dict[str, Any] | None = None) -> Pointer:
obj = super().__new__(cls, value)
obj._stream = stream
obj._context = context
obj._value = None
return obj
def __repr__(self) -> str:
return f"<{self.type.__name__}* @ {self:#x}>"
def __str__(self) -> str:
return str(self.dereference())
def __getattr__(self, attr: str) -> Any:
return getattr(self.dereference(), attr)
def __add__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__add__(self, other), self._stream, self._context)
def __sub__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__sub__(self, other), self._stream, self._context)
def __mul__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__mul__(self, other), self._stream, self._context)
def __floordiv__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__floordiv__(self, other), self._stream, self._context)
def __mod__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__mod__(self, other), self._stream, self._context)
def __pow__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__pow__(self, other), self._stream, self._context)
def __lshift__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__lshift__(self, other), self._stream, self._context)
def __rshift__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__rshift__(self, other), self._stream, self._context)
def __and__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__and__(self, other), self._stream, self._context)
def __xor__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__xor__(self, other), self._stream, self._context)
def __or__(self, other: int) -> Pointer:
return type.__call__(self.__class__, int.__or__(self, other), self._stream, self._context)
@classmethod
def default(cls) -> Pointer:
return cls.__new__(cls, cls.cs.pointer.default(), None, None)
@classmethod
def _read(cls, stream: BinaryIO, context: dict[str, Any] | None = None) -> Pointer:
return cls.__new__(cls, cls.cs.pointer._read(stream, context), stream, context)
@classmethod
def _write(cls, stream: BinaryIO, data: int) -> int:
return cls.cs.pointer._write(stream, data)
def dereference(self) -> Any:
if self == 0 or self._stream is None:
raise NullPointerDereference()
if self._value is None and not issubclass(self.type, Void):
# Read current position of file read/write pointer
position = self._stream.tell()
# Reposition the file read/write pointer
self._stream.seek(self)
if issubclass(self.type, Char):
# this makes the assumption that a char pointer is a null-terminated string
value = self.type._read_0(self._stream, self._context)
else:
value = self.type._read(self._stream, self._context)
self._stream.seek(position)
self._value = value
return self._value