From 7a03578dd96efa8a55fa3ee6fbb9931fa48e6b4a Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 6 Nov 2026 08:21:47 +0100 Subject: [PATCH] fix: count name holders with case folded A hashless profile entry adopted the only exact holder of its name as the file its aliases designate. dosbox's SC-55 ROM2.BIN found Galaksija's ROM2.BIN, and ROM2_ST.BIN was indexed against a 4 KiB BASIC ROM while SC-55's rom2.bin sat under the same folded name. The name now has to designate one file once case is folded, a primary and its own variants counted as one. --- database.json | 5 +---- scripts/generate_db.py | 27 +++++++++++++++++++++++---- tests/test_db_aliases.py | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/database.json b/database.json index bc7d27139..375671581 100644 --- a/database.json +++ b/database.json @@ -1,6 +1,6 @@ { "schema_version": 1, - "generated_at": "2026-11-05T23:59:37Z", + "generated_at": "2026-11-06T07:21:27Z", "total_files": 19947, "total_size": 16926035621, "bios_dir": "bios", @@ -281813,9 +281813,6 @@ "TRIO64 (Ver. 1.5-07) [VGA] (S3 Incorporated).bin": [ "a308b15f93da34961c0141ec95b98c211557e2d5" ], - "ROM2_ST.BIN": [ - "5d5ab4313a2d0effe7572bb129193b64cab002c1" - ], "mt32_ctrl_1_04.rom": [ "5a5cb5a77d7d55ee69657c2f870416daed52dea7" ], diff --git a/scripts/generate_db.py b/scripts/generate_db.py index ade383713..32c956171 100644 --- a/scripts/generate_db.py +++ b/scripts/generate_db.py @@ -576,12 +576,26 @@ def _collect_all_aliases( # naming its content once 64DD_IPL.bin sorted first, and its aliases # 64dd_ipl_J.bin and 64DD_IPL_JP.n64 went with it. holders: dict[str, set[str]] = {} + # The files a name designates once case is folded, as the resolver's + # name step folds it, a primary and its own .variants/ counted as one + # file. dosbox's SC-55 ROM2.BIN found Galaksija's ROM2.BIN the only + # exact holder, and its alias ROM2_ST.BIN went to a 4 KiB BASIC ROM, + # while SC-55's rom2.bin sat under the same folded name. + families: dict[str, set[str]] = {} + + def _hold(name: str, path: str, sha1: str) -> None: + holders.setdefault(name, set()).add(sha1) + directory = path.rpartition("/")[0].removesuffix("/.variants") + families.setdefault(name.casefold(), set()).add( + f"{directory}/{variant_base_name(name)}".casefold() + ) + for sha1, entry in files.items(): - holders.setdefault(entry["name"], set()).add(sha1) + _hold(entry["name"], entry["path"], sha1) for sha1, copy_list in (copies or {}).items(): if sha1 in files: for copy in copy_list: - holders.setdefault(copy["name"], set()).add(sha1) + _hold(copy["name"], copy["path"], sha1) aliases = {} @@ -691,11 +705,16 @@ def _collect_all_aliases( ] if taken: shadowed.append((entry_name, set(matched), taken)) - if not matched and len(holders.get(entry_name, ())) == 1: + held = holders.get(entry_name, set()) + if ( + not matched + and len(held) == 1 + and len(families[entry_name.casefold()]) == 1 + ): # A name carried by several contents names none of them: # quasi88's disk.rom aliases went to whichever # disk.rom the scan met last, a Tandy CoCo ROM. - matched = set(holders[entry_name]) + matched = set(held) for sha in sorted(matched): for alias_name in entry_aliases: _add_alias(alias_name, sha) diff --git a/tests/test_db_aliases.py b/tests/test_db_aliases.py index 91bfd56fa..eff324b5f 100644 --- a/tests/test_db_aliases.py +++ b/tests/test_db_aliases.py @@ -56,6 +56,25 @@ class AliasesNeedAnUnambiguousName(unittest.TestCase): named = {a["name"] for entries in aliases.values() for a in entries} self.assertNotIn("n88sub.rom", named) + def test_homonyms_differing_in_case_take_no_alias(self): + """dosbox's SC-55 ROM2.BIN: Galaksija's ROM2.BIN was the only exact + holder, and ROM2_ST.BIN went to it beside SC-55's rom2.bin.""" + files = { + "a": self._file("DISK.ROM", "bios/NEC/PC-98/DISK.ROM", "m1"), + "b": self._file("disk.rom", "bios/Tandy/CoCo/disk.rom", "m2"), + } + aliases = self._aliases(files) + named = {a["name"] for entries in aliases.values() for a in entries} + self.assertNotIn("n88sub.rom", named) + + def test_a_primary_and_its_variant_are_one_file(self): + files = { + "a": self._file("disk.rom", "bios/NEC/PC-88/disk.rom", "m1"), + "b": self._file("DISK.ROM", "bios/NEC/PC-88/.variants/DISK.ROM.0123abcd", "m2"), + } + aliases = self._aliases(files) + self.assertEqual([a["name"] for a in aliases.get("a", [])], ["n88sub.rom"]) + def test_a_unique_name_still_carries_its_aliases(self): files = {"a": self._file("disk.rom", "bios/NEC/PC-88/disk.rom", "m1")} aliases = self._aliases(files)