From 3ecb72d275949dc6d330d7373f069821ce9c20dd Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 7 Aug 2026 15:45:48 +0200 Subject: [PATCH] fix: deflate manifest on zip append path --- scripts/generate_pack.py | 6 ++++-- tests/test_e2e.py | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/scripts/generate_pack.py b/scripts/generate_pack.py index 71ef1df4..ffba4b4e 100644 --- a/scripts/generate_pack.py +++ b/scripts/generate_pack.py @@ -3471,8 +3471,10 @@ def inject_manifest(zip_path: str, manifest: dict) -> None: has_manifest = "manifest.json" in zf.namelist() if not has_manifest: - # Fast path: append directly - with zipfile.ZipFile(zip_path, "a") as zf: + # Fast path: append directly. Append mode defaults to ZIP_STORED, + # which would leave the manifest uncompressed and give the same pack + # two different byte layouts depending on the path taken here. + with zipfile.ZipFile(zip_path, "a", zipfile.ZIP_DEFLATED) as zf: zf.writestr("manifest.json", manifest_json) else: # Rebuild to replace existing manifest diff --git a/tests/test_e2e.py b/tests/test_e2e.py index 9c91bea8..acde81af 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -5222,5 +5222,31 @@ struct BurnDriver BurnDrvneogeo = { self.assertEqual(only_alpha["shared-system"], {"a.bin"}) + def test_227_manifest_injected_compressed(self): + """The manifest is deflated whichever injection path runs.""" + import json as _json + + from generate_pack import inject_manifest + + manifest = {"files": [{"path": f"f{i}.bin"} for i in range(200)]} + raw = _json.dumps(manifest, indent=2, ensure_ascii=False) + sizes = [] + with tempfile.TemporaryDirectory() as tmpdir: + for preexisting in (False, True): + path = os.path.join(tmpdir, f"pack{int(preexisting)}.zip") + with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as zf: + zf.writestr("bios.bin", b"x" * 4096) + if preexisting: + zf.writestr("manifest.json", "{}") + inject_manifest(path, manifest) + with zipfile.ZipFile(path) as zf: + info = zf.getinfo("manifest.json") + self.assertEqual(info.compress_type, zipfile.ZIP_DEFLATED) + self.assertEqual(_json.loads(zf.read("manifest.json")), manifest) + sizes.append(info.compress_size) + self.assertLess(sizes[0], len(raw)) + self.assertEqual(sizes[0], sizes[1]) + + if __name__ == "__main__": unittest.main()