diff --git a/scripts/exporter/base_exporter.py b/scripts/exporter/base_exporter.py index d3f37166..8e022454 100644 --- a/scripts/exporter/base_exporter.py +++ b/scripts/exporter/base_exporter.py @@ -16,6 +16,10 @@ from .baseline import NativeFile, NativeSystem, Report class BaseExporter(ABC): """Base class for writing a platform's own BIOS file, corrected.""" + # A hash field the checker compares to one value: an addition the + # truth accepts under several cannot be written whole. + SINGLE_HASH_FIELD: str | None = None + @staticmethod @abstractmethod def platform_name() -> str: @@ -145,6 +149,11 @@ class BaseExporter(ABC): return True if not cls.can_add() or (cls.keys_by_system() and fe.foreign_system): return False + single = cls.SINGLE_HASH_FIELD + if single and len(set(fe.hashes(single))) > 1: + # One value checked: written with the first, the addition + # refuses every other dump the core accepts. + return False require = require or cls.requires() return not require or bool(fe.hash(require)) diff --git a/scripts/exporter/batocera_exporter.py b/scripts/exporter/batocera_exporter.py index 16b22292..0ebc6481 100644 --- a/scripts/exporter/batocera_exporter.py +++ b/scripts/exporter/batocera_exporter.py @@ -25,6 +25,11 @@ _INDENT = " " * 4 class Exporter(BaseExporter): """Write Batocera's batocera-systems, corrected.""" + # checkBios compares one md5 for a plain file; altmd5 is read only for + # a zippedFile: retrodream's boot.bin written with the first of four + # md5 refused the three other dumps the core accepts. + SINGLE_HASH_FIELD = "md5" + # checkBios reads emulator names from es_systems, and Batocera's # standalone_cores are those names. ROCKNIX's list holds package names # (duckstation-sa), which its checker does not know. @@ -58,14 +63,7 @@ class Exporter(BaseExporter): @classmethod def writable(cls, fe: NativeFile, require: str = "") -> bool: - """An addition the format can state whole. - - checkBios compares one md5 for a plain file (altmd5 is read only for - a zippedFile): written with the first of four, retrodream's boot.bin - refused the three other dumps the core accepts. - """ - if fe.platform is None and len(set(fe.hashes("md5"))) > 1: - return False + """An addition the format can state whole.""" if fe.platform is None and not cls._usable_runners(fe): # Written without its core's emulator and core, checkBios asks # every build for it (the defect _runner_keys repairs for the diff --git a/scripts/exporter/retrobat_exporter.py b/scripts/exporter/retrobat_exporter.py index 48f74280..5f5b96ed 100644 --- a/scripts/exporter/retrobat_exporter.py +++ b/scripts/exporter/retrobat_exporter.py @@ -21,6 +21,9 @@ SOURCE_URL = ( class Exporter(BaseExporter): """Write RetroBat's batocera-systems.json, corrected.""" + # One md5 per entry, compared as Batocera's checkBios does. + SINGLE_HASH_FIELD = "md5" + @staticmethod def platform_name() -> str: return "retrobat" diff --git a/tests/test_export_counts.py b/tests/test_export_counts.py index 9e435b60..7e94a6b3 100644 --- a/tests/test_export_counts.py +++ b/tests/test_export_counts.py @@ -336,6 +336,16 @@ class OneMd5FormatsAddWhole(unittest.TestCase): self.assertFalse(Batocera.writable(several)) self.assertTrue(Batocera.writable(single)) + def test_retrobat_refuses_it_too(self): + # RetroBat's batocera-systems.json holds one md5 per entry: the + # addition was written with the first and counted added. + from exporter.retrobat_exporter import Exporter as RetroBat # noqa: PLC0415 + + several = NativeFile("boot.bin", "boot.bin", "dc", truth={"md5": [A, B, C]}) + single = NativeFile("boot2.bin", "boot2.bin", "dc", truth={"md5": A}) + self.assertFalse(RetroBat.writable(several)) + self.assertTrue(RetroBat.writable(single)) + class BizHawkKeepsItsOwnHashes(unittest.TestCase): def test_a_declared_sha1_is_not_replaced(self):