fix: match a size-checked entry to its launcher

EmuDeck passes Complex_4627v1.03.bin as xemu's flash ROM
(emuDeckXemu.sh:60-61), and xemu's entry Complex_4627.bin states no hash,
only the sizes it maps. The layer matched entries by name or content
only, so without the alias the default name was still asked for. A
hashless entry that checks a size now takes a launcher file of a size
it accepts, when no other entry of that core accepts that size too.
This commit is contained in:
Abdessamad Derraz committed 2026-10-20 22:20:42 +02:00
1 parent 540374b40d
commit e787efca22
2 files changed
+52

No files matched your search

+22
View File
@@ -233,6 +233,8 @@ class _Candidate:
entry: dict
names: set[str]
by_content: bool
# Matched by the size the code checks, the entry naming no hash.
by_shape: bool = False
class LauncherLayer:
@@ -314,6 +316,22 @@ class LauncherLayer:
}
if content:
return _Candidate(entry, content, True)
# A hashless entry the code checks by size: EmuDeck passes
# Complex_4627v1.03.bin as xemu's flash ROM, and xemu's entry
# Complex_4627.bin states only the sizes it maps.
checks = entry.get("validation") or []
sized = any(entry.get(k) for k in ("size", "min_size", "max_size"))
if not _hashes(entry) and sized and "size" in checks:
shaped = {
place.fold(path.rsplit("/", 1)[-1])
for path in place.paths
if any(
name_match_size_ok(entry, record.get("size"))
for record in self.files_named(place, path.rsplit("/", 1)[-1])
)
}
if shaped:
return _Candidate(entry, shaped, False, by_shape=True)
return None
def platform_holds(self, place: LauncherPlace) -> bool:
@@ -360,6 +378,10 @@ class LauncherLayer:
for entry, report in members
if (candidate := self.match(place, entry)) is not None
]
# A size names one entry only when no other of the core's
# entries takes that size too.
if sum(c.by_shape for c, _ in matched) > 1:
matched = [(c, r) for c, r in matched if not c.by_shape]
if not matched:
continue
filled = self._fill(place, matched, reported_at, resolve_held, placed)
+30
View File
@@ -201,6 +201,36 @@ class LauncherLayerTest(unittest.TestCase):
added = [u["path"] for u in self._report() if u.get("launcher")]
self.assertNotIn("sub/fix.bin", added)
def test_a_hashless_entry_takes_a_launcher_file_of_a_size_it_checks(self) -> None:
"""EmuDeck passes Complex_4627v1.03.bin as xemu's flash ROM
(emuDeckXemu.sh:60-61), and xemu's Complex_4627.bin entry checks only
a size: matched neither by name nor by content, the default name was
still asked for."""
data = b"F" * 64
self.db["files"]["f" * 40] = {"path": os.path.join(self.bios_dir, "v103.bin"),
"name": "v103.bin", "md5": _md5(data), "sha1": "f" * 40,
"size": len(data), "crc32": ""}
with open(os.path.join(self.bios_dir, "v103.bin"), "wb") as fh:
fh.write(data)
self.db["indexes"]["by_name"]["v103.bin"] = ["f" * 40]
profile = {
"emulator": "FixEmu", "type": "standalone", "systems": ["test-sys"],
"files": [{"name": "flash.bin", "required": True, "size": [32, 64],
"validation": ["size"]},
{"name": "boot.bin", "required": True, "size": 8,
"validation": ["size"]}],
}
with open(os.path.join(self.emulators_dir, "fixemu.yml"), "w") as fh:
yaml.dump(profile, fh)
self.config["launchers"][2]["names"] = ["v103.bin"]
self.config["launchers"][2]["search_dir"] = "/userdata/bios"
_emulator_profiles_cache.clear()
self.profiles = load_emulator_profiles(self.emulators_dir)
report = {u["path"]: u for u in self._report()}
self.assertNotIn("flash.bin", report)
self.assertIn("v103.bin", report)
self.assertIn("boot.bin", report)
def test_no_place_is_filled_twice(self) -> None:
added = [u["path"] for u in self._report() if u.get("launcher")]
self.assertEqual(sorted(added), ["e.bin", "sub/fix.bin"])