mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-21 03:09:08 -05:00
fix: keep System.dat lines whose values agree
The rom line renderer upper-cased every crc, so Dinothawr.zip's 683ed4ad, the one lower-case crc libretro writes, changed with no correction behind it. A line whose values match ours now keeps its bytes, a corrected crc follows the case of its own line, and an added line keeps the file's upper case. An empty truth hands System.dat back byte for byte for RetroArch and Lakka.
This commit is contained in:
1 parent
546c1ac871
commit
7e0b3a08b9
4 files changed
+84
-4
No files matched your search
@@ -167,7 +167,7 @@ game (
|
||||
rom ( name vice/DRIVES/dos1571cr-318047-01.bin size 32768 crc F24EFCC4 md5 f9158328494b3e269f86ef419792c2e5 sha1 14ee7a0fb7e1c59c51fbf781f944387037daa3ee )
|
||||
|
||||
comment "Dinothawr"
|
||||
rom ( name Dinothawr.zip size 5763199 crc 683ED4AD md5 a2e891e330d146c4046c2b622fc31462 sha1 693d8bb4d992c645e6413a57195acf4eca2f5a2e )
|
||||
rom ( name Dinothawr.zip size 5763199 crc 683ed4ad md5 a2e891e330d146c4046c2b622fc31462 sha1 693d8bb4d992c645e6413a57195acf4eca2f5a2e )
|
||||
|
||||
comment "DOS"
|
||||
rom ( name MT32_CONTROL.ROM size 65536 crc A7C1531B md5 5626206284b22c2734f3e9efefcd2675 sha1 b083518fffb7f66b03c23b7eb4f868e62dc5a987 )
|
||||
|
||||
@@ -168,7 +168,7 @@ game (
|
||||
rom ( name vice/DRIVES/dos1571cr-318047-01.bin size 32768 crc F24EFCC4 md5 f9158328494b3e269f86ef419792c2e5 sha1 14ee7a0fb7e1c59c51fbf781f944387037daa3ee )
|
||||
|
||||
comment "Dinothawr"
|
||||
rom ( name Dinothawr.zip size 5763199 crc 683ED4AD md5 a2e891e330d146c4046c2b622fc31462 sha1 693d8bb4d992c645e6413a57195acf4eca2f5a2e )
|
||||
rom ( name Dinothawr.zip size 5763199 crc 683ed4ad md5 a2e891e330d146c4046c2b622fc31462 sha1 693d8bb4d992c645e6413a57195acf4eca2f5a2e )
|
||||
|
||||
comment "DOS"
|
||||
rom ( name MT32_CONTROL.ROM size 65536 crc A7C1531B md5 5626206284b22c2734f3e9efefcd2675 sha1 b083518fffb7f66b03c23b7eb4f868e62dc5a987 )
|
||||
|
||||
@@ -42,6 +42,26 @@ def _quote(name: str, quoted: frozenset[str] = frozenset()) -> str:
|
||||
_ROM_NAME = re.compile(r'^(\s+)rom \( name ("[^"]+"|\S+)')
|
||||
|
||||
|
||||
_CRC = re.compile(r" crc (\S+)")
|
||||
|
||||
|
||||
def _patch(line: str, indent: str, ours: str) -> str:
|
||||
"""The original line where our values agree with it, else ours in its form.
|
||||
|
||||
libretro writes one crc in lower case (Dinothawr.zip's 683ed4ad) and the
|
||||
others in upper case. A line whose values did not change keeps its bytes,
|
||||
and a corrected crc takes the case of the line it lands on. The
|
||||
indentation stays libretro's.
|
||||
"""
|
||||
ours = indent + ours.lstrip("\t")
|
||||
if line.lower() == ours.lower():
|
||||
return line
|
||||
theirs = _CRC.search(line)
|
||||
if theirs and theirs.group(1) != theirs.group(1).upper():
|
||||
ours = _CRC.sub(lambda m: f" crc {m.group(1).lower()}", ours, count=1)
|
||||
return ours
|
||||
|
||||
|
||||
def _sections(original: str) -> list[tuple[str, list[str]]]:
|
||||
"""The system sections of a System.dat, each comment with its rom lines."""
|
||||
_, sep, body = original.partition("\ngame (")
|
||||
@@ -191,8 +211,7 @@ class Exporter(BaseExporter):
|
||||
for line in roms:
|
||||
match = _ROM_NAME.match(line)
|
||||
if match and match.group(2) in rendered:
|
||||
# The values are ours, the indentation stays libretro's.
|
||||
body.append(match.group(1) + rendered.pop(match.group(2)).lstrip("\t"))
|
||||
body.append(_patch(line, match.group(1), rendered.pop(match.group(2))))
|
||||
else:
|
||||
body.append(line)
|
||||
body.extend(rendered.values())
|
||||
|
||||
@@ -1343,6 +1343,67 @@ class SystemDatKeepsSpaceIndentedLines(unittest.TestCase):
|
||||
self.assertEqual(produced.count("kick33180.A500"), 1)
|
||||
|
||||
|
||||
class SystemDatComesBackAsWritten(unittest.TestCase):
|
||||
"""libretro writes one crc in lower case, Dinothawr.zip's 683ed4ad, and
|
||||
the 513 others in upper case. Rendered upper case without condition,
|
||||
that line changed with no correction behind it."""
|
||||
|
||||
SECTION = "Dinothawr"
|
||||
ORIGINAL = (
|
||||
'clrmamepro (\n\tname "System"\n)\n\ngame (\n\tname "System"\n'
|
||||
'\tcomment "System"\n\n'
|
||||
'\tcomment "Dinothawr"\n'
|
||||
f"\trom ( name lower.zip size 10 crc 683ed4ad md5 {'1' * 32} sha1 {'1' * 40} )\n"
|
||||
f"\trom ( name upper.zip size 10 crc 0BCDEF12 md5 {'2' * 32} sha1 {'2' * 40} )\n"
|
||||
")\n"
|
||||
)
|
||||
|
||||
def _render(self, truth_files: list[dict]) -> str:
|
||||
scraped = {"systems": {"dinothawr": {"native_id": self.SECTION, "files": [
|
||||
{"name": "lower.zip", "destination": "lower.zip", "native_system": self.SECTION,
|
||||
"size": 10, "crc32": "683ed4ad", "md5": "1" * 32, "sha1": "1" * 40},
|
||||
{"name": "upper.zip", "destination": "upper.zip", "native_system": self.SECTION,
|
||||
"size": 10, "crc32": "0BCDEF12", "md5": "2" * 32, "sha1": "2" * 40},
|
||||
]}}}
|
||||
truth = {"systems": {"dinothawr": {"files": truth_files}}} if truth_files else {"systems": {}}
|
||||
systems, report = build_native_model(truth, scraped)
|
||||
return discover_exporters()["retroarch"]().render(
|
||||
systems, report, {"System.dat": self.ORIGINAL}, None
|
||||
)["System.dat"]
|
||||
|
||||
def test_an_empty_truth_hands_back_the_lines(self):
|
||||
self.assertEqual(self._render([]), self.ORIGINAL)
|
||||
|
||||
def test_a_corrected_crc_follows_the_case_of_its_line(self):
|
||||
produced = self._render([
|
||||
{"name": "lower.zip", "size": 10, "crc32": "abcdef01", "md5": "3" * 32, "sha1": "3" * 40},
|
||||
{"name": "upper.zip", "size": 10, "crc32": "fedcba98", "md5": "4" * 32, "sha1": "4" * 40},
|
||||
])
|
||||
self.assertIn(" crc abcdef01 ", produced)
|
||||
self.assertIn(" crc FEDCBA98 ", produced)
|
||||
|
||||
def test_an_added_line_takes_the_case_of_the_file(self):
|
||||
produced = self._render([
|
||||
{"name": "new.zip", "size": 10, "crc32": "abcdef01", "md5": "5" * 32, "sha1": "5" * 40},
|
||||
])
|
||||
self.assertIn("name new.zip size 10 crc ABCDEF01 ", produced)
|
||||
|
||||
def test_an_empty_truth_hands_back_system_dat(self):
|
||||
for platform in ("retroarch", "lakka"):
|
||||
original_path = UPSTREAM_CACHE / platform / "System.dat"
|
||||
if not original_path.exists():
|
||||
self.skipTest("upstream cache not populated")
|
||||
original = original_path.read_bytes()
|
||||
exporter = discover_exporters()[platform]()
|
||||
config = native_layer(load_platform_config(platform, str(REPO_ROOT / "platforms")))
|
||||
systems, report = build_native_model({"systems": {}}, config)
|
||||
produced = exporter.render(
|
||||
systems, report, {"System.dat": original.decode("utf-8")}, config
|
||||
)
|
||||
with self.subTest(platform=platform):
|
||||
self.assertEqual(produced["System.dat"].encode("utf-8"), original)
|
||||
|
||||
|
||||
class RommSizeIsNeverNone(unittest.TestCase):
|
||||
"""size() is None where the truth contradicts RomM's hash without a size
|
||||
or names several sizes. str(None) went out as "None", validate() passed
|
||||
|
||||
Reference in new issue
Block a user