mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-06 01:53:56 -06:00
fix: serve a data dir file at its platform path
AmberELEC and EmuELEC declare blueMSX's Machines/<model>/config.ini and Shared Roms/RS232.ROM with no hash. The name step served msx-emu's ColecoVision config.ini in 192 machine folders and the 16 KB RS232.ROM, while data/bluemsx held blueMSX's own file at that very path. A platform declaration with no hash now reads its destination's tail in the data directories before the name step. Profile entries keep the foreign-tree redirect, so Dolphin's dsp_coef.bin dump still outranks the free copy. Manifests: amberelec and emuelec omit 192 config.ini entries (held in data/bluemsx only, so the installer has no URL) and serve colecodb.xml, MSX2+/config.ini, MSXturboR/config.ini and RS232.ROM from blueMSX's bytes.
This commit is contained in:
1 parent
c624a820f0
commit
3b0112001e
5 files changed
+7214
-4264
No files matched your search
+3555
-2131
File diff suppressed because it is too large.
Load diff
+3556
-2132
File diff suppressed because it is too large.
Load diff
@@ -9,6 +9,7 @@ from __future__ import annotations
|
||||
from collections.abc import Callable, Iterable
|
||||
from collections import Counter
|
||||
|
||||
import filecmp
|
||||
import hashlib
|
||||
import functools
|
||||
import json
|
||||
@@ -889,6 +890,38 @@ def _resolve_in_data_dirs(
|
||||
return None, mismatch
|
||||
|
||||
|
||||
def _data_dir_tail(
|
||||
dest_hint: str, data_dir_registry: dict, file_entry: dict, db: dict
|
||||
) -> str | None:
|
||||
"""The cached data-directory file at the destination's own tail.
|
||||
|
||||
The full destination first, then without its leading segment, never
|
||||
down to the bare name. A shortened tail two caches hold with different
|
||||
bytes proves nothing. The size and Adler-32 the code checks still bound
|
||||
the file, as on every name or path step without a hash.
|
||||
"""
|
||||
parts = dest_hint.split("/")
|
||||
for start in range(min(2, len(parts) - 1)):
|
||||
tail = "/".join(parts[start:])
|
||||
hits = [
|
||||
os.path.join(cache_dir, tail)
|
||||
for cache_dir in (
|
||||
dd_entry.get("local_cache", "") for dd_entry in data_dir_registry.values()
|
||||
)
|
||||
if cache_dir and os.path.isfile(os.path.join(cache_dir, tail))
|
||||
]
|
||||
if start and any(
|
||||
not filecmp.cmp(hits[0], other, shallow=False) for other in hits[1:]
|
||||
):
|
||||
continue
|
||||
for candidate in hits:
|
||||
if name_match_size_ok(
|
||||
file_entry, os.path.getsize(candidate)
|
||||
) and adler32_fits(file_entry, candidate, db):
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
# Basename index per data-directory cache. Walking the whole tree again for
|
||||
# every unresolved name made resolution O(names x tree) on each pack build.
|
||||
_data_dir_index: dict[str, dict[str, list[tuple[int, str]]]] = {}
|
||||
@@ -1504,6 +1537,27 @@ def resolve_local_file(
|
||||
if status:
|
||||
return path, status
|
||||
|
||||
# 2c. The same tail in a data directory. by_path_suffix indexes bios/
|
||||
# only, so AmberELEC's Machines/MSX - Arabic/config.ini fell through to
|
||||
# the name step and got msx-emu's ColecoVision config.ini, while
|
||||
# data/bluemsx held blueMSX's own at that very path. A platform
|
||||
# declaration is resolved without a hint, and its destination is that
|
||||
# path. The descent and the ambiguity rule are those of the bios/ tails.
|
||||
# A profile's entry is not asked here: it names its owner, the name step
|
||||
# sends it to its data directories when another emulator's copy answers,
|
||||
# and a dump it declares outranks the free one its tree bundles at the
|
||||
# same path (Dolphin's dsp_coef.bin over Sys/GC's).
|
||||
tail_hint = dest_hint or str(file_entry.get("destination") or "")
|
||||
if (
|
||||
tail_hint
|
||||
and data_dir_registry
|
||||
and not has_strong_hash
|
||||
and not _owner_tokens(file_entry)
|
||||
):
|
||||
hit = _data_dir_tail(tail_hint, data_dir_registry, file_entry, db)
|
||||
if hit:
|
||||
return hit, "path_exact"
|
||||
|
||||
# 3. No MD5 = any file with that name or alias (existence check)
|
||||
def _size_ok(match_sha1: str) -> bool:
|
||||
record = files_db.get(match_sha1, {})
|
||||
|
||||
@@ -93,6 +93,54 @@ class ForeignTreeNames(unittest.TestCase):
|
||||
self.assertEqual(status, "data_dir")
|
||||
self.assertEqual(Path(path).read_bytes(), b"B" * 64)
|
||||
|
||||
def _bluemsx_cache(self, rel: str, data: bytes) -> dict:
|
||||
cache = self.root / "data" / "bluemsx"
|
||||
(cache / rel).parent.mkdir(parents=True, exist_ok=True)
|
||||
(cache / rel).write_bytes(data)
|
||||
return {"bluemsx": {"local_cache": str(cache)}}
|
||||
|
||||
def test_a_platform_declaration_reads_the_data_directory_at_its_path(self):
|
||||
"""AmberELEC declares every blueMSX machine's config.ini with no hash.
|
||||
The name step met msx-emu's ColecoVision config.ini first and wrote it
|
||||
into each machine folder, while data/bluemsx held the machine's own
|
||||
at that very path."""
|
||||
self._hold("bios/Other/msx-emu/Machines/COL - ColecoVision/config.ini", b"C" * 64)
|
||||
registry = self._bluemsx_cache("Machines/MSX - Arabic/config.ini", b"A" * 64)
|
||||
entry = {
|
||||
"name": "config.ini",
|
||||
"destination": "bios/Machines/MSX - Arabic/config.ini",
|
||||
}
|
||||
path, status = resolve_local_file(entry, self.db, data_dir_registry=registry)
|
||||
self.assertEqual(status, "path_exact")
|
||||
self.assertEqual(Path(path).read_bytes(), b"A" * 64)
|
||||
|
||||
def test_a_platform_rs232_rom_reads_the_data_directory_at_its_path(self):
|
||||
self._hold("bios/Microsoft/MSX/RS232.ROM", b"L" * 128)
|
||||
registry = self._bluemsx_cache("Machines/Shared Roms/RS232.ROM", b"S" * 64)
|
||||
entry = {
|
||||
"name": "RS232.ROM",
|
||||
"destination": "bios/Machines/Shared Roms/RS232.ROM",
|
||||
}
|
||||
path, _status = resolve_local_file(entry, self.db, data_dir_registry=registry)
|
||||
self.assertEqual(Path(path).read_bytes(), b"S" * 64)
|
||||
|
||||
def test_a_profile_dump_outranks_the_free_copy_of_its_tree(self):
|
||||
"""Dolphin's dsp_coef.bin: the dump in bios/ wins over the free
|
||||
replacement Sys/GC bundles at the same path."""
|
||||
own = self._hold("bios/Nintendo/GameCube/.variants/dsp_coef.bin.c116d867", b"R" * 64)
|
||||
cache = self.root / "data" / "dolphin-sys"
|
||||
(cache / "GC").mkdir(parents=True)
|
||||
(cache / "GC" / "dsp_coef.bin").write_bytes(b"F" * 64)
|
||||
entry = {
|
||||
"name": "dsp_coef.bin", "destination": "GC/dsp_coef.bin",
|
||||
"source_profile": "dolphin",
|
||||
}
|
||||
path, _status = resolve_local_file(
|
||||
entry, self.db, dest_hint="GC/dsp_coef.bin",
|
||||
data_dir_registry={"dolphin-sys": {"local_cache": str(cache)}},
|
||||
)
|
||||
self.assertEqual(path, own)
|
||||
|
||||
def test_another_casing_in_another_tree_is_not_the_file(self):
|
||||
"""reminiscence's music module reunion took skyline's
|
||||
zoneinfo/Indian/Reunion, a time-zone file, on the casefold step."""
|
||||
|
||||
@@ -363,7 +363,7 @@ evidence-compatible match:
|
||||
| 2 | SHA256 | `sha256_exact` | A declared SHA256 identifies a record, again requiring all declarations to agree |
|
||||
| 3 | CRC32 plus size | `crc32_exact` | Used only when no stronger hash is declared. Size confirms the weaker checksum when available |
|
||||
| 4 | MD5 | `md5_exact` | Direct lookup. An explicitly supported truncated MD5 also needs a compatible name |
|
||||
| 5 | Path suffix | `path_exact` or a hash-exact status | Disambiguates regional paths. With any declared hash, the path is accepted only when the content matches it |
|
||||
| 5 | Path suffix | `path_exact` or a hash-exact status | Disambiguates regional paths. With any declared hash, the path is accepted only when the content matches it. A platform declaration with no hash then looks for its destination's tail in the data directories: AmberELEC's `Machines/MSX - Arabic/config.ini` is blueMSX's, never the first `config.ini` the name step meets |
|
||||
| 6 | Name or alias | `name_exact` | Existence/size resolution only when no content hash is declared. Prefers primary files and supports casefold matching |
|
||||
| 7 | Named candidate inspection | `md5_composite_exact`, `md5_exact`, or `hash_mismatch` | Checks composite ZIP MD5 or direct MD5. A matching name with wrong content is surfaced, never treated as exact |
|
||||
| 8 | ZIP contents index | `zip_exact` | `zipped_file` with MD5. Searches the inner-ROM index only after name-based resolution fails |
|
||||
|
||||
Reference in new issue
Block a user