-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(#109) parser / generator for MRVN-Radiant compiler signature
- Loading branch information
1 parent
98726d9
commit 5d92a20
Showing
2 changed files
with
86 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from __future__ import annotations | ||
from datetime import datetime | ||
import re | ||
from typing import Union | ||
|
||
|
||
class MRVNRadiant: | ||
motd: str = "Built with love using MRVN-Radiant :)" # remap.h REMAP_MOTD | ||
version: str | ||
time: datetime | ||
_time_format: str = "%a %b %d %H:%M:%S %Y" | ||
|
||
def __init__(self, version: str, time: datetime = None, motd=motd): | ||
self.motd = motd | ||
self.version = version | ||
self.time = datetime.now() if time is None else time | ||
|
||
def __repr__(self) -> str: | ||
time = self.time.strftime(self._time_format) | ||
return f"<MRVN-Radiant compiler signature (version: {self.version}, time: {time})>" | ||
|
||
def __str__(self) -> str: | ||
lines = [self.motd, | ||
f"Version: {self.version}", | ||
f"Time: {self.time.strftime(self._time_format)}"] | ||
return "\n".join(lines) | ||
|
||
@classmethod | ||
def from_bytes(cls, raw_signature) -> MRVNRadiant: | ||
motd, version, time = (raw_signature[i * 64:(i + 1) * 64].rstrip(b"\0").decode() for i in range(3)) | ||
assert re.match(r"Built with love using MRVN-[rR]adiant :\)", motd) | ||
assert version.startswith("Version:") | ||
version = re.match(r"Version:\s+(.*)", version).groups()[0] | ||
# TODO: if version != "Dev build": parse SemVer & git hash | ||
assert time.startswith("Time:") | ||
time = datetime.strptime(re.match(r"Time:\s+(.*)\n", time).groups()[0], cls._time_format) | ||
# ^ "Wed Jun 07 19:37:23 2023" -> datetime.datetime | ||
return cls(version, time, motd) | ||
|
||
def as_bytes(self) -> bytes: | ||
lines = str(self).split("\n") | ||
lines[-1] += "\n" | ||
return b"".join([L.encode() + b"\0" * (64 - len(L)) for L in lines]) | ||
|
||
|
||
AnySignatureClass = Union[MRVNRadiant] | ||
|
||
|
||
def identify(raw_signature: bytes) -> Union[AnySignatureClass, bytes]: | ||
"""relying on .from_bytes() checks to determine SignatureClass""" | ||
for SignatureClass in (MRVNRadiant,): | ||
try: | ||
signature = SignatureClass.from_bytes(raw_signature) | ||
except Exception: | ||
# AssertionError: some check fails | ||
# AttributeError: re.match returns None | ||
pass | ||
else: | ||
return signature | ||
return raw_signature |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
"""tests for bsp_tool/signature.py""" | ||
from .. import utils | ||
from bsp_tool import RespawnBsp | ||
from bsp_tool.branches.respawn import titanfall2 | ||
from bsp_tool.extensions import compiler_signature | ||
|
||
import pytest | ||
|
||
|
||
bsps = utils.get_test_maps(RespawnBsp, {titanfall2: ["Titanfall 2"]}) | ||
bsps = [b for b in bsps if b.signature != b""] | ||
|
||
|
||
@pytest.mark.parametrize("bsp", bsps, ids=[f"Titanfall 2/{b.filename}" for b in bsps]) | ||
def test_MRVNRadiant(bsp): | ||
"""parse & replicate""" | ||
signature = compiler_signature.MRVNRadiant.from_bytes(bsp.signature) | ||
assert signature.as_bytes() == bsp.signature | ||
|
||
|
||
bsp_signature_classes = [(bsp, compiler_signature.MRVNRadiant) for bsp in bsps] | ||
|
||
|
||
@pytest.mark.parametrize("bsp,SignatureClass", bsp_signature_classes, ids=[f"Titanfall 2/{b.filename}" for b in bsps]) | ||
def test_identify(bsp, SignatureClass): | ||
assert isinstance(compiler_signature.identify(bsp.signature), SignatureClass) |