diff --git a/emulators/citron.yml b/emulators/citron.yml index b6ef0be2..12aa6366 100644 --- a/emulators/citron.yml +++ b/emulators/citron.yml @@ -24,25 +24,25 @@ mode: standalone files: - name: "prod.keys" required: true - path: "switch/" + path: "switch/prod.keys" note: "Production keys for NCA decryption (master, key area, header, titlekek)" source_ref: "src/core/crypto/key_manager.cpp:655-656" - name: "title.keys" required: false - path: "switch/" + path: "switch/title.keys" note: "Per-title encryption keys (rights_id to titlekey mappings)" source_ref: "src/core/crypto/key_manager.cpp:659-660" - name: "console.keys" required: false - path: "switch/" + path: "switch/console.keys" note: "Console-specific keys (BIS, SD seed)" source_ref: "src/core/crypto/key_manager.cpp:661-662" - name: "key_retail.bin" required: false - path: "switch/" + path: "switch/key_retail.bin" size: 160 note: "Amiibo decryption keys (two InternalKey structs, 0x50 bytes each)" source_ref: "src/core/hle/service/nfc/common/amiibo_crypto.cpp:274-292" diff --git a/emulators/eden.yml b/emulators/eden.yml index 617a54b9..79ef3607 100644 --- a/emulators/eden.yml +++ b/emulators/eden.yml @@ -27,31 +27,31 @@ mode: standalone files: - name: "prod.keys" required: true - path: "switch/" + path: "switch/prod.keys" note: "Production keys for NCA decryption (master, key area, header, titlekek)" source_ref: "src/core/crypto/key_manager.cpp:574-575, 853" - name: "dev.keys" required: false - path: "switch/" + path: "switch/dev.keys" note: "Development-unit keys, read instead of prod.keys when use_dev_keys is set" source_ref: "src/core/crypto/key_manager.cpp:570-571, 852" - name: "title.keys" required: false - path: "switch/" + path: "switch/title.keys" note: "Per-title encryption keys (rights_id to titlekey mappings)" source_ref: "src/core/crypto/key_manager.cpp:577-578, 850" - name: "console.keys" required: false - path: "switch/" + path: "switch/console.keys" note: "Console-specific keys (BIS, SD seed)" source_ref: "src/core/crypto/key_manager.cpp:579-580" - name: "key_retail.bin" required: false - path: "switch/" + path: "switch/key_retail.bin" size: 160 note: "Amiibo decryption keys (two InternalKey structs, 0x50 bytes each)" source_ref: "src/core/hle/service/nfc/common/amiibo_crypto.cpp:281-302" diff --git a/emulators/kenji-nx.yml b/emulators/kenji-nx.yml index f696ff50..d60fd020 100644 --- a/emulators/kenji-nx.yml +++ b/emulators/kenji-nx.yml @@ -187,7 +187,7 @@ files: - name: ".der" required: false - path: system/ssl/ + path: "system/ssl/.der" unsourceable: "replacement certificate the user picks for one certificate authority, with no canonical artefact behind the name" description: "Override for one built-in root certificate" note: >- @@ -199,7 +199,7 @@ files: - name: ".zip" required: false - path: drivers/ + path: "drivers/.zip" unsourceable: "third-party Vulkan driver built for one GPU family, not an emulator artefact" description: "Replacement Vulkan driver for the Android build" note: >- diff --git a/emulators/lrps2.yml b/emulators/lrps2.yml index 080e1ec9..8d449e27 100644 --- a/emulators/lrps2.yml +++ b/emulators/lrps2.yml @@ -30,7 +30,7 @@ notes: | files: - name: ".bin" - path: "pcsx2/bios/" + path: "pcsx2/bios/.bin" required: true description: "PS2 BIOS binary" min_size: 4194304 @@ -43,7 +43,7 @@ files: pcsx2_bios. Falls back to first valid BIOS found if configured BIOS is missing. - name: ".rom1" - path: "pcsx2/bios/" + path: "pcsx2/bios/.rom1" required: false max_size: 4194304 description: "DVD player ROM" @@ -53,7 +53,7 @@ files: (extension replaced). Silently skipped if not found. - name: ".rom2" - path: "pcsx2/bios/" + path: "pcsx2/bios/.rom2" required: false max_size: 524288 description: "Chinese ROM extension" @@ -63,7 +63,7 @@ files: Only present on Chinese region consoles. - name: ".nvm" - path: "pcsx2/bios/" + path: "pcsx2/bios/.nvm" required: false hle_fallback: true size: 1024 @@ -75,7 +75,7 @@ files: Auto-created with region-appropriate defaults if missing or invalid. - name: ".mec" - path: "pcsx2/bios/" + path: "pcsx2/bios/.mec" required: false hle_fallback: true size: 4 diff --git a/emulators/pcee2.yml b/emulators/pcee2.yml index 727d9ae1..61bbd291 100644 --- a/emulators/pcee2.yml +++ b/emulators/pcee2.yml @@ -83,7 +83,7 @@ notes: | files: - name: ".bin" - path: "pcsx2/bios/" + path: "pcsx2/bios/.bin" description: "PS2 BIOS image" min_size: 4194304 max_size: 8388608 @@ -96,7 +96,7 @@ files: auto selection accept any size that passes the romdir check. - name: ".rom1" - path: "pcsx2/bios/" + path: "pcsx2/bios/.rom1" description: "DVD player ROM" max_size: 4194304 required: false @@ -106,7 +106,7 @@ files: skipped with a console line when absent. - name: ".rom2" - path: "pcsx2/bios/" + path: "pcsx2/bios/.rom2" description: "Chinese ROM extension" max_size: 4194304 required: false @@ -115,7 +115,7 @@ files: Same lookup as rom1. Present on Chinese region consoles only. - name: ".nvm" - path: "pcsx2/bios/" + path: "pcsx2/bios/.nvm" description: "Console NVRAM (region parameters, language, iLink ID, OSD settings)" size: 1024 required: false @@ -127,7 +127,7 @@ files: on save. - name: ".mec" - path: "pcsx2/bios/" + path: "pcsx2/bios/.mec" description: "Mechacon version, one u32" size: 4 required: false diff --git a/emulators/ryujinx.yml b/emulators/ryujinx.yml index db55db2e..d438e74e 100644 --- a/emulators/ryujinx.yml +++ b/emulators/ryujinx.yml @@ -20,19 +20,19 @@ mode: standalone files: - name: "prod.keys" required: true - path: "switch/" + path: "switch/prod.keys" note: "Switch production keys for NCA decryption" source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:239" - name: "title.keys" required: false - path: "switch/" + path: "switch/title.keys" note: "Per-title decryption keys, needed for specific game content" source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:240" - name: "console.keys" required: false - path: "switch/" + path: "switch/console.keys" note: "Console-specific keys for encrypted content" source_ref: "src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs:241" diff --git a/emulators/shadps4.yml b/emulators/shadps4.yml index 860165de..c33a0973 100644 --- a/emulators/shadps4.yml +++ b/emulators/shadps4.yml @@ -48,20 +48,20 @@ files: - name: "libSceLibcInternal.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceLibcInternal.sprx" description: "PS4 C standard library" source_ref: "src/core/linker.cpp:80-91" - name: "libSceNgs2.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceNgs2.sprx" description: "PS4 next-generation audio system" source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:217" - name: "libSceUlt.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceUlt.sprx" description: "PS4 user-level threading library" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:218" @@ -69,13 +69,13 @@ files: - name: "libSceRtc.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceRtc.sprx" description: "PS4 real-time clock library" source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:221" - name: "libSceJpegDec.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceJpegDec.sprx" description: "PS4 JPEG decoder" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:222" @@ -83,83 +83,83 @@ files: - name: "libSceJpegEnc.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceJpegEnc.sprx" description: "PS4 JPEG encoder" source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:223" - name: "libScePngEnc.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libScePngEnc.sprx" description: "PS4 PNG encoder" source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:225" - name: "libSceJson.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceJson.sprx" description: "PS4 JSON parser" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:226" - name: "libSceJson2.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceJson2.sprx" description: "PS4 JSON v2 parser" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:227" - name: "libSceCesCs.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceCesCs.sprx" description: "PS4 character encoding conversion" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:228" - name: "libSceAt9Enc.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceAt9Enc.sprx" description: "PS4 ATRAC9 encoder" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:229" - name: "libSceAudiodec.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceAudiodec.sprx" description: "PS4 audio decoder" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:230" - name: "libSceAudiodecCpu.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceAudiodecCpu.sprx" description: "PS4 CPU audio decoder" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:231" - name: "libSceAudiodecCpuDdp.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceAudiodecCpuDdp.sprx" description: "PS4 CPU Dolby Digital Plus decoder" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:232" - name: "libSceAudiodecCpuM4aac.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceAudiodecCpuM4aac.sprx" description: "PS4 CPU AAC decoder" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:233" - name: "libSceAudiodecCpuDtsHdLbr.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceAudiodecCpuDtsHdLbr.sprx" description: "PS4 CPU DTS-HD LBR decoder" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:234" - name: "libSceAudiodecCpuHevag.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceAudiodecCpuHevag.sprx" description: "PS4 CPU HEVAG decoder" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:235" @@ -167,34 +167,34 @@ files: - name: "libSceFont.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceFont.sprx" description: "PS4 font rendering library" source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:236" - name: "libSceFontFt.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceFontFt.sprx" description: "PS4 FreeType font library" source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:237" - name: "libSceFreeTypeOt.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceFreeTypeOt.sprx" description: "PS4 FreeType OpenType library" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:238" - name: "libSceFreeTypeOl.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceFreeTypeOl.sprx" description: "PS4 FreeType outline library" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:239" - name: "libSceFreeTypeOptOl.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceFreeTypeOptOl.sprx" description: "PS4 FreeType optimised outline library" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:240" @@ -202,13 +202,13 @@ files: - name: "libSceRudp.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceRudp.sprx" description: "PS4 reliable UDP library" source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:243" - name: "libSceWkFontConfig.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceWkFontConfig.sprx" description: "PS4 WebKit font configuration" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:244" @@ -216,13 +216,13 @@ files: - name: "libSceSystemGesture.sprx" required: false hle_fallback: true - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceSystemGesture.sprx" description: "PS4 system gesture recognition" source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:249" - name: "libSceXml.sprx" required: false - path: "shadps4/sys_modules/" + path: "shadps4/sys_modules/libSceXml.sprx" description: "PS4 XML parser" note: "No HLE implementation; the module is stubbed when absent." source_ref: "src/core/libraries/sysmodule/sysmodule_internal.cpp:250" diff --git a/emulators/suyu.yml b/emulators/suyu.yml index 3dfb587e..b5fe2f85 100644 --- a/emulators/suyu.yml +++ b/emulators/suyu.yml @@ -25,25 +25,25 @@ mode: standalone files: - name: "prod.keys" required: true - path: "switch/" + path: "switch/prod.keys" note: "Production keys for NCA decryption (master, key area, header, titlekek)" source_ref: "src/core/crypto/key_manager.cpp:654" - name: "title.keys" required: false - path: "switch/" + path: "switch/title.keys" note: "Per-title encryption keys (rights_id to titlekey mappings)" source_ref: "src/core/crypto/key_manager.cpp:657" - name: "console.keys" required: false - path: "switch/" + path: "switch/console.keys" note: "Console-specific keys (BIS, SD seed)" source_ref: "src/core/crypto/key_manager.cpp:658" - name: "key_retail.bin" required: false - path: "switch/" + path: "switch/key_retail.bin" size: 160 note: "Amiibo decryption keys (two InternalKey structs, 0x50 bytes each)" source_ref: "src/core/hle/service/nfc/common/amiibo_crypto.cpp:273-294" diff --git a/emulators/yuzu.yml b/emulators/yuzu.yml index 4edd3f9d..729c10a2 100644 --- a/emulators/yuzu.yml +++ b/emulators/yuzu.yml @@ -26,25 +26,25 @@ mode: standalone files: - name: "prod.keys" required: true - path: "switch/" + path: "switch/prod.keys" note: "Production keys for NCA decryption (master, key area, header, titlekek)" source_ref: "src/core/crypto/key_manager.cpp:655-656" - name: "title.keys" required: false - path: "switch/" + path: "switch/title.keys" note: "Per-title encryption keys (rights_id to titlekey mappings)" source_ref: "src/core/crypto/key_manager.cpp:659-660" - name: "console.keys" required: false - path: "switch/" + path: "switch/console.keys" note: "Console-specific keys (BIS, SD seed)" source_ref: "src/core/crypto/key_manager.cpp:661-662" - name: "key_retail.bin" required: false - path: "switch/" + path: "switch/key_retail.bin" size: 160 note: "Amiibo decryption keys (two InternalKey structs, 0x50 bytes each)" source_ref: "src/core/hle/service/nfc/common/amiibo_crypto.cpp:273-294" diff --git a/schemas/emulator.schema.json b/schemas/emulator.schema.json index 1812e96f..5f96a65d 100644 --- a/schemas/emulator.schema.json +++ b/schemas/emulator.schema.json @@ -644,6 +644,25 @@ ] } }, + { + "if": { + "anyOf": [ + { + "required": ["path"], + "properties": {"path": {"type": "string", "pattern": "/$"}} + }, + { + "required": ["standalone_path"], + "properties": {"standalone_path": {"type": "string", "pattern": "/$"}} + } + ] + }, + "then": { + "required": [ + "type" + ] + } + }, { "if": { "required": [ diff --git a/tests/test_directory_entries.py b/tests/test_directory_entries.py index afa52ab5..6a4635c8 100644 --- a/tests/test_directory_entries.py +++ b/tests/test_directory_entries.py @@ -270,6 +270,16 @@ class ProfileContract(unittest.TestCase): self.assertTrue(self._errors({"name": "voice/"})) self.assertEqual(self._errors({"name": "voice/", "type": "directory"}), []) + def test_a_file_path_names_its_file(self): + """`path: switch/` on prod.keys and title.keys sent every key to one + destination: the emulator pack shipped a file named `switch` and + verify counted five keys as one.""" + self.assertTrue(self._errors({"name": "prod.keys", "path": "switch/"})) + self.assertTrue( + self._errors({"name": "prod.keys", "standalone_path": "keys/"}) + ) + self.assertEqual(self._errors({"name": "prod.keys", "path": "switch/prod.keys"}), []) + def test_the_marker_takes_no_other_value(self): self.assertTrue(self._errors({"name": "RTP", "path": "rtp/", "type": "folder"})) @@ -297,7 +307,11 @@ class ProfileContract(unittest.TestCase): path = entry.get("path") if entry.get("type") == "directory": return isinstance(path, str) and not path.endswith("/") - return name.endswith("/") or "type" in entry + slashed = any( + isinstance(entry.get(key), str) and entry[key].endswith("/") + for key in ("path", "standalone_path") + ) + return name.endswith("/") or "type" in entry or slashed class CollectionScanAndIgnoreRules(unittest.TestCase):