diff --git a/emulators/2048.yml b/emulators/2048.yml index b97664ae..d2c86e59 100644 --- a/emulators/2048.yml +++ b/emulators/2048.yml @@ -7,7 +7,7 @@ profiled_date: "2026-03-22" source_commit: "e70c3f82d2b861c64943aaff7fcc29a63013997d" core_version: "1.0" display_name: "2048" -cores: [2048] +cores: ["2048"] systems: [] files: [] notes: > diff --git a/emulators/81.yml b/emulators/81.yml index e4fd7bd1..6bac038a 100644 --- a/emulators/81.yml +++ b/emulators/81.yml @@ -7,7 +7,7 @@ profiled_date: "2026-03-22" source_commit: "fa7094910d040baa5fd8b11dbf6a1a618330ecd9" core_version: "1.0a" display_name: "Sinclair - ZX 81 (EightyOne)" -cores: [81] +cores: ["81"] systems: - sinclair-zx81 - sinclair-zx80 diff --git a/emulators/mame.yml b/emulators/mame.yml index 128f3f82..27310155 100644 --- a/emulators/mame.yml +++ b/emulators/mame.yml @@ -3543,11 +3543,11 @@ files: source_ref: "src/mame/vtech/crvision.cpp:955-959" note: "Salora Manager (Finnish variant)" contents: - - name: 01 + - name: "01" description: ROM bank 0-1 size: 8192 crc32: "702f4cf5" - - name: 23 + - name: "23" description: ROM bank 2-3 size: 8192 crc32: "46489d88" diff --git a/install/targets/retrobat.json b/install/targets/retrobat.json index d7d71ae9..ddfc273b 100644 --- a/install/targets/retrobat.json +++ b/install/targets/retrobat.json @@ -1,6 +1,6 @@ { "windows": [ - 81, + "81", "a5200", "abuse", "arduous", diff --git a/platforms/targets/retrobat.yml b/platforms/targets/retrobat.yml index 48d1453f..0b1de6b2 100644 --- a/platforms/targets/retrobat.yml +++ b/platforms/targets/retrobat.yml @@ -4,7 +4,7 @@ scraped_at: "2026-03-26T00:00:00Z" targets: windows: architecture: x86_64 - cores: [81, a5200, abuse, arduous, atari800, azahar, bennugd, bk, bluemsx, bsnes, + cores: ['81', a5200, abuse, arduous, atari800, azahar, bennugd, bk, bluemsx, bsnes, bstone, cannonball, cap32, catacombgl, cdogs, cemu, cgenius, citron, clk, corsixth, demul, devilutionx, dhewm3, dice, dolphin, dosbox_pure, dxx-rebirth, easyrpg, ecwolf, eduke32, eka2l1, emuscv, etlegacy, fake08, fallout1-ce, fallout2-ce, diff --git a/scripts/scraper/_hash_merge.py b/scripts/scraper/_hash_merge.py index a9cac0ad..0a23749e 100644 --- a/scripts/scraper/_hash_merge.py +++ b/scripts/scraper/_hash_merge.py @@ -507,7 +507,7 @@ def _append_new_entries(text: str, files: list[dict], original: str) -> str: lines = [] for fe in new_entries: - lines.append(f"\n - name: {fe['name']}") + lines.append(f"\n - name: {_yaml_scalar(fe['name'])}") lines.append(f" required: {str(fe['required']).lower()}") lines.append(" category: bios_zip") if fe.get("source_ref"): @@ -521,13 +521,22 @@ def _append_new_entries(text: str, files: list[dict], original: str) -> str: return text +def _yaml_scalar(value) -> str: + """Quote a scalar so YAML reads back exactly what the source said. + + A MAME ROM named ``01`` written bare re-parses as the integer 1, and the + set stops naming the file the driver loads. Quoting is not cosmetic here. + """ + return json.dumps(str(value), ensure_ascii=False) + + def _format_contents(contents: list[dict]) -> str: """Format a contents list as YAML text.""" lines = [" contents:"] for rom in contents: - lines.append(f" - name: {rom['name']}") + lines.append(f" - name: {_yaml_scalar(rom['name'])}") if rom.get("description"): - lines.append(f" description: {rom['description']}") + lines.append(f" description: {_yaml_scalar(rom['description'])}") if rom.get("size"): lines.append(f" size: {rom['size']}") if rom.get("crc32"): @@ -569,8 +578,8 @@ def _backup_and_write_fbneo(path: str, data: dict, hashes: dict) -> None: if new_roms: lines = [] for fe in new_roms: - lines.append(f' - name: "{fe["name"]}"') - lines.append(f" archive: {fe['archive']}") + lines.append(f" - name: {_yaml_scalar(fe['name'])}") + lines.append(f" archive: {_yaml_scalar(fe['archive'])}") lines.append(f" required: {str(fe.get('required', True)).lower()}") if fe.get("size"): lines.append(f" size: {fe['size']}") diff --git a/tests/test_hash_merge.py b/tests/test_hash_merge.py index 303c477c..d7ad3623 100644 --- a/tests/test_hash_merge.py +++ b/tests/test_hash_merge.py @@ -196,6 +196,52 @@ class TestMameMerge(unittest.TestCase): self.assertTrue(pgm["required"]) self.assertEqual(pgm["category"], "bios_zip") + def test_numeric_looking_rom_name_survives_the_write(self) -> None: + """MAME ships ROMs named 01 and 23. Bare YAML turns them into numbers. + + The manager set loads "01"; written unquoted it re-parses as the + integer 1 and the profile stops naming the file the driver opens. + """ + from scripts.scraper._hash_merge import ( + _append_new_entries, + _format_contents, + ) + + contents = [ + {"name": "01", "description": "ROM bank 0-1", "size": 8192, + "crc32": "702f4cf5"}, + {"name": "23", "description": "ROM bank 2-3", "size": 8192, + "crc32": "46489d88"}, + ] + document = yaml.safe_load( + "files:\n - name: manager.zip\n" + _format_contents(contents) + ) + names = [rom["name"] for rom in document["files"][0]["contents"]] + self.assertEqual(names, ["01", "23"]) + for name in names: + self.assertIsInstance(name, str) + + original = "emulator: MAME\nfiles:\n - name: neogeo.zip\n" + appended = _append_new_entries( + original, + [{ + "name": "manager.zip", + "required": False, + "category": "bios_zip", + "source_ref": "src/mame/vtech/crvision.cpp:955-959", + "contents": contents, + }], + original, + ) + entry = next( + f + for f in yaml.safe_load(appended)["files"] + if f["name"] == "manager.zip" + ) + self.assertEqual( + [rom["name"] for rom in entry["contents"]], ["01", "23"] + ) + def test_merge_preserves_non_bios_files(self) -> None: profile = _make_mame_profile() profile["files"].append({"name": "hiscore.dat", "required": False})