建立 MAG160C 逆向工程交接仓库
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
"""
|
||||
Various containers.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import MutableMapping
|
||||
from functools import wraps
|
||||
from pprint import pformat
|
||||
from typing import IO, TYPE_CHECKING, Any, Literal, overload
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Callable, Iterator
|
||||
from typing import Concatenate, ParamSpec, TypeVar
|
||||
|
||||
from typing_extensions import Self # 3.11+
|
||||
|
||||
from ..core import Construct
|
||||
from .hex import HexString
|
||||
|
||||
_P = ParamSpec('_P')
|
||||
_R = TypeVar('_R')
|
||||
_T = TypeVar('_T')
|
||||
|
||||
|
||||
__all__ = [
|
||||
"recursion_lock",
|
||||
"Container", "FlagsContainer", "ListContainer", "LazyContainer",
|
||||
]
|
||||
|
||||
|
||||
def recursion_lock(
|
||||
retval: _R,
|
||||
lock_name: str = "__recursion_lock__",
|
||||
) -> Callable[[Callable[Concatenate[Any, _P], _T]], Callable[Concatenate[Any, _P], _T | _R]]:
|
||||
|
||||
def decorator(
|
||||
func: Callable[Concatenate[Any, _P], _T],
|
||||
) -> Callable[Concatenate[Any, _P], _T | _R]:
|
||||
@wraps(func)
|
||||
def wrapper(self: Any, *args: _P.args, **kw: _P.kwargs) -> _T | _R:
|
||||
if getattr(self, lock_name, False):
|
||||
return retval
|
||||
setattr(self, lock_name, True)
|
||||
try:
|
||||
return func(self, *args, **kw)
|
||||
finally:
|
||||
setattr(self, lock_name, False)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
class Container(MutableMapping[str, Any]):
|
||||
"""
|
||||
A generic container of attributes.
|
||||
|
||||
Containers are the common way to express parsed data.
|
||||
"""
|
||||
|
||||
def __init__(self, **kw: Any) -> None:
|
||||
self.__dict__ = kw
|
||||
|
||||
# The core dictionary interface.
|
||||
|
||||
@overload
|
||||
def __getitem__(self, name: Literal[
|
||||
"ch_addralign", "ch_size",
|
||||
"length",
|
||||
"n_descsz", "n_offset", "n_namesz",
|
||||
"sh_addralign", "sh_flags", "sh_size",
|
||||
"bloom_size", "nbuckets", "nchains",
|
||||
]) -> int: ...
|
||||
@overload
|
||||
def __getitem__(self, name: Literal[
|
||||
"ch_type",
|
||||
"sh_type",
|
||||
"n_name", "n_type",
|
||||
"tag", "vendor_name",
|
||||
]) -> str: ...
|
||||
@overload
|
||||
def __getitem__(self, name: Literal[
|
||||
"buckets", "chains",
|
||||
]) -> list[int]: ...
|
||||
@overload
|
||||
def __getitem__(self, name: str) -> Any: ...
|
||||
def __getitem__(self, name: str) -> Any:
|
||||
return self.__dict__[name]
|
||||
|
||||
def __delitem__(self, name: str) -> None:
|
||||
del self.__dict__[name]
|
||||
|
||||
def __setitem__(self, name: str, value: Any) -> None:
|
||||
self.__dict__[name] = value
|
||||
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
return iter(self.__dict__)
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self.__dict__.keys())
|
||||
|
||||
# Copy interface.
|
||||
|
||||
def copy(self) -> Self:
|
||||
return self.__class__(**self.__dict__)
|
||||
|
||||
__copy__ = copy
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "%s(%s)" % (self.__class__.__name__, repr(self.__dict__))
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "%s(%s)" % (self.__class__.__name__, str(self.__dict__))
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# elftools.construct.debug Probe.printout()
|
||||
stream_position: int
|
||||
following_stream_data: str | HexString
|
||||
context: Container
|
||||
stack: ListContainer
|
||||
# allow arbitray attributes
|
||||
def __setattr__(self, name: str, value: object) -> None: ...
|
||||
def __getattr__(self, name: str) -> Any: ...
|
||||
|
||||
class FlagsContainer(Container):
|
||||
"""
|
||||
A container providing pretty-printing for flags.
|
||||
|
||||
Only set flags are displayed.
|
||||
"""
|
||||
|
||||
@recursion_lock("<...>")
|
||||
def __str__(self) -> str:
|
||||
d = dict((k, self[k]) for k in self
|
||||
if self[k] and not k.startswith("_"))
|
||||
return "%s(%s)" % (self.__class__.__name__, pformat(d))
|
||||
|
||||
class ListContainer(list[Any]):
|
||||
"""
|
||||
A container for lists.
|
||||
"""
|
||||
|
||||
__slots__ = ("__recursion_lock__",)
|
||||
|
||||
@recursion_lock("[...]")
|
||||
def __str__(self) -> str:
|
||||
return pformat(self)
|
||||
|
||||
class LazyContainer:
|
||||
|
||||
__slots__ = ("subcon", "stream", "pos", "context", "_value")
|
||||
|
||||
def __init__(self, subcon: Construct, stream: IO[bytes], pos: int, context: Container) -> None:
|
||||
self.subcon = subcon
|
||||
self.stream = stream
|
||||
self.pos = pos
|
||||
self.context = context
|
||||
self._value = NotImplemented
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
return isinstance(other, LazyContainer) and self._value == other._value
|
||||
|
||||
def __ne__(self, other: object) -> bool:
|
||||
return not (self == other)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.__pretty_str__()
|
||||
|
||||
def __pretty_str__(self, nesting: int = 1, indentation: str = " ") -> str:
|
||||
if self._value is NotImplemented:
|
||||
text = "<unread>"
|
||||
elif hasattr(self._value, "__pretty_str__"):
|
||||
text = self._value.__pretty_str__(nesting, indentation)
|
||||
else:
|
||||
text = str(self._value)
|
||||
return "%s: %s" % (self.__class__.__name__, text)
|
||||
|
||||
def read(self) -> Any:
|
||||
self.stream.seek(self.pos)
|
||||
return self.subcon._parse(self.stream, self.context)
|
||||
|
||||
def dispose(self) -> None:
|
||||
del self.subcon
|
||||
del self.stream
|
||||
del self.context
|
||||
del self.pos
|
||||
|
||||
def _get_value(self) -> Any:
|
||||
if self._value is NotImplemented:
|
||||
self._value = self.read()
|
||||
return self._value
|
||||
|
||||
value = property(_get_value)
|
||||
|
||||
has_value = property(lambda self: self._value is not NotImplemented)
|
||||
Reference in New Issue
Block a user