mirror of
https://github.com/BigfootACA/arch-image-builder.git
synced 2024-11-11 10:37:52 +08:00
119 lines
2.9 KiB
Python
119 lines
2.9 KiB
Python
|
import ctypes
|
||
|
from binascii import crc32
|
||
|
from logging import getLogger
|
||
|
from builder.lib.serializable import Serializable, SerializableDict
|
||
|
from uuid import UUID, uuid4
|
||
|
log = getLogger(__name__)
|
||
|
|
||
|
|
||
|
class EfiTableHeader(ctypes.Structure, SerializableDict):
|
||
|
_fields_ = [
|
||
|
("signature", ctypes.c_uint64),
|
||
|
("revision", ctypes.c_uint32),
|
||
|
("header_size", ctypes.c_uint32),
|
||
|
("crc32", ctypes.c_uint32),
|
||
|
("reserved", ctypes.c_uint32),
|
||
|
]
|
||
|
|
||
|
def set_signature(self, value: str | int | bytes):
|
||
|
vt = type(value)
|
||
|
if vt is str: r = int.from_bytes(value.encode(), "little")
|
||
|
elif vt is bytes: r = int.from_bytes(value, "little")
|
||
|
elif vt is int: r = value
|
||
|
else: raise TypeError("bad value type")
|
||
|
self.signature = r
|
||
|
|
||
|
def get_signature(self) -> bytes:
|
||
|
return ctypes.string_at(ctypes.byref(self), 8)
|
||
|
|
||
|
def get_revision(self) -> tuple[int, int]:
|
||
|
return (
|
||
|
self.revision >> 0x10 & 0xFFFF,
|
||
|
self.revision & 0xFFFF,
|
||
|
)
|
||
|
|
||
|
def calc_crc32(self, data: bytes = None) -> int:
|
||
|
orig = self.crc32
|
||
|
self.crc32 = 0
|
||
|
if data is None: data = ctypes.string_at(
|
||
|
ctypes.byref(self), self.header_size
|
||
|
)
|
||
|
value = crc32(data, 0)
|
||
|
self.crc32 = orig
|
||
|
return value
|
||
|
|
||
|
def update_crc32(self, data: bytes = None):
|
||
|
self.crc32 = self.calc_crc32(data)
|
||
|
|
||
|
def check_signature(self, value: str | int | bytes) -> bool:
|
||
|
vt = type(value)
|
||
|
if vt is int: return self.signature == value
|
||
|
b = self.get_signature()
|
||
|
if vt is bytes: return b == value
|
||
|
if vt is str: return b == value.encode()
|
||
|
raise TypeError("bad value type")
|
||
|
|
||
|
def check_revision(self, major: int, minor: int) -> bool:
|
||
|
rev = self.get_revision()
|
||
|
return rev[0] == major and rev[1] == minor
|
||
|
|
||
|
def check_crc32(self) -> bool:
|
||
|
return self.calc_crc32() == self.crc32
|
||
|
|
||
|
def to_dict(self) -> dict:
|
||
|
return {
|
||
|
"signature": self.get_signature().decode(),
|
||
|
"revision": ".".join(map(str, self.get_revision())),
|
||
|
"header_size": self.header_size,
|
||
|
"crc32": self.crc32,
|
||
|
}
|
||
|
|
||
|
|
||
|
class EfiGUID(ctypes.Structure, Serializable):
|
||
|
_fields_ = [
|
||
|
("d1", ctypes.c_uint32),
|
||
|
("d2", ctypes.c_uint16),
|
||
|
("d3", ctypes.c_uint16),
|
||
|
("d4", ctypes.c_uint8 * 8),
|
||
|
]
|
||
|
|
||
|
def to_uuid(self) -> UUID:
|
||
|
u = bytes()
|
||
|
u += int.to_bytes(self.d1, 4)
|
||
|
u += int.to_bytes(self.d2, 2)
|
||
|
u += int.to_bytes(self.d3, 2)
|
||
|
u += bytes().join(int.to_bytes(i) for i in self.d4)
|
||
|
return UUID(bytes=u)
|
||
|
|
||
|
def set_uuid(self, u: UUID):
|
||
|
u = u.bytes
|
||
|
self.d1 = int.from_bytes(u[0:4])
|
||
|
self.d2 = int.from_bytes(u[4:6])
|
||
|
self.d3 = int.from_bytes(u[6:8])
|
||
|
for i in range(8):
|
||
|
self.d4[i] = int.from_bytes(u[i+8:i+9])
|
||
|
|
||
|
@staticmethod
|
||
|
def from_uuid(u: UUID):
|
||
|
if u is None: return None
|
||
|
g = EfiGUID()
|
||
|
g.set_uuid(u)
|
||
|
return g
|
||
|
|
||
|
@staticmethod
|
||
|
def generate():
|
||
|
return EfiGUID.from_uuid(uuid4())
|
||
|
|
||
|
def serialize(self) -> str:
|
||
|
return str(self.to_uuid())
|
||
|
|
||
|
def unserialize(self, o: str):
|
||
|
self.from_uuid(UUID(o))
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
return self.serialize()
|
||
|
|
||
|
|
||
|
assert(ctypes.sizeof(EfiTableHeader()) == 24)
|
||
|
assert(ctypes.sizeof(EfiGUID()) == 16)
|