From 8f76b191cd0caf4c1115949a6fa18384cb6681e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 28 Jan 2026 23:48:49 +0100 Subject: [PATCH] More improvements to ISO detection --- Core/Loaders.cpp | 32 ++++++++++++++++++-------------- Core/Loaders.h | 4 ++-- Core/Reporting.cpp | 18 ++++++++++++++---- Core/System.cpp | 13 +++++++------ assets/compat.ini | 3 ++- 5 files changed, 43 insertions(+), 27 deletions(-) diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index f5056ea90f..c5a2098226 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -157,17 +157,19 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin // UMD AUDIO exists technically, but in reality, not really? Let's map it to VIDEO since we support neither. return IdentifiedFileType::PSP_UMD_VIDEO_ISO; } else if (!memcmp(pvd->systemId, "PS3", 3)) { + *errorString = "PS3 ISO"; return IdentifiedFileType::PS3_ISO; } else if (!memcmp(pvd->systemId, "PLAYSTATION", 11)) { - *errorString = "PSX or PS2 ISO"; // Just do a size heuristic here to differentiate. There are better ways but slower. if (bd->GetUncompressedSize() > 800LL * 1024LL * 1024LL) { + *errorString = "PS2 ISO"; return IdentifiedFileType::PS2_ISO; } + *errorString = "PSX ISO?"; return IdentifiedFileType::PSX_ISO; } else { WARN_LOG(Log::Loader, "ISO with unknown system ID: %.32s", pvd->systemId); - *errorString = "ISO missing PSP GAME or PSP NPU identifier"; + *errorString = StringFromFormat("ISO with unknown system ID: %.32s", pvd->systemId); return IdentifiedFileType::UNKNOWN_ISO; } } @@ -180,7 +182,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin // each sector in a mode2 image starts with these 12 bytes if (memcmp(sync, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", 12) == 0) { - *errorString = "ISO in Mode 2: Not a PSP game"; + *errorString = "ISO is a CD - likely PSX"; // Mode 2 CDs are used for PSX games return IdentifiedFileType::PSX_ISO; } } @@ -264,17 +266,18 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin return IdentifiedFileType::UNKNOWN; } -FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader) { - std::string errorString; - IdentifiedFileType type = Identify_File(fileLoader, &errorString); - if (type == IdentifiedFileType::PSP_PBP_DIRECTORY) { +FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader, IdentifiedFileType *fileType, std::string *errorString) { + *fileType = Identify_File(fileLoader, errorString); + if (*fileType == IdentifiedFileType::PSP_PBP_DIRECTORY) { const Path ebootFilename = ResolvePBPFile(fileLoader->GetPath()); if (ebootFilename != fileLoader->GetPath()) { // Switch fileLoader to the actual EBOOT. delete fileLoader; fileLoader = ConstructFileLoader(ebootFilename); + // Re-identify the file. + *fileType = Identify_File(fileLoader, errorString); } - } else if (type == IdentifiedFileType::ARCHIVE_ZIP) { + } else if (*fileType == IdentifiedFileType::ARCHIVE_ZIP) { // Handle zip files, take automatic action depending on contents. // Can also return nullptr. ZipFileLoader *zipLoader = new ZipFileLoader(fileLoader); @@ -287,6 +290,8 @@ FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader) { case ZipFileContents::FRAME_DUMP: { zipLoader->Initialize(zipFileInfo.isoFileIndex); + // Re-identify the file. + *fileType = Identify_File(zipLoader, errorString); return zipLoader; } default: @@ -334,14 +339,13 @@ bool UmdReplace(const Path &filepath, FileLoader **fileLoader, std::string &erro } UpdateLoadedFile(loadedFile); - loadedFile = ResolveFileLoaderTarget(loadedFile); + std::string errorString; + IdentifiedFileType fileType; + loadedFile = ResolveFileLoaderTarget(loadedFile, &fileType, &errorString); *fileLoader = loadedFile; - std::string errorString; - IdentifiedFileType type = Identify_File(loadedFile, &errorString); - - switch (type) { + switch (fileType) { case IdentifiedFileType::PSP_ISO: case IdentifiedFileType::PSP_ISO_NP: case IdentifiedFileType::PSP_DISC_DIRECTORY: @@ -351,7 +355,7 @@ bool UmdReplace(const Path &filepath, FileLoader **fileLoader, std::string &erro } break; default: - error = "Unsupported file type: " + std::to_string((int)type) + " " + errorString; + error = "Unsupported file type: " + std::string(IdentifiedFileTypeToString(fileType)) + " " + errorString; return false; break; } diff --git a/Core/Loaders.h b/Core/Loaders.h index bf064a9ddb..930297dd25 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -152,8 +152,8 @@ inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) { } FileLoader *ConstructFileLoader(const Path &filename); -// Resolve to the target binary, ISO, or other file (e.g. from a directory.) -FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader); +// Identifies the file and resolves to the target binary, ISO, or other file (e.g. from a directory.) +FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader, IdentifiedFileType *fileType, std::string *errorString); Path ResolvePBPDirectory(const Path &filename); Path ResolvePBPFile(const Path &filename); diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 8a20ccd6ed..838f052dea 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -134,19 +134,29 @@ namespace Reporting AndroidJNIThreadContext jniContext; - FileLoader *fileLoader = ResolveFileLoaderTarget(ConstructFileLoader(crcFilename)); + IdentifiedFileType type; std::string errorString; - BlockDevice *blockDevice = ConstructBlockDevice(fileLoader, &errorString); + FileLoader *fileLoader = ResolveFileLoaderTarget(ConstructFileLoader(crcFilename), &type, &errorString); + if (!fileLoader) { + ERROR_LOG(Log::Loader, "Failed to construct file loader for CRC: %s", errorString.c_str()); + std::lock_guard guard(crcLock); + crcResults[crcFilename] = 0; + crcPending = false; + crcCond.notify_one(); + return 0; + } + + std::unique_ptr blockDevice(ConstructBlockDevice(fileLoader, &errorString)); u32 crc = 0; if (blockDevice) { - crc = CalculateCRC(blockDevice, &crcCancel); + crc = CalculateCRC(blockDevice.get(), &crcCancel); } else { ERROR_LOG(Log::Loader, "Failed to read from block device for CRC: %s", errorString.c_str()); } - delete blockDevice; + blockDevice.reset(); delete fileLoader; std::lock_guard guard(crcLock); diff --git a/Core/System.cpp b/Core/System.cpp index 4b2d2562f5..fdbfe9981b 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -340,7 +340,7 @@ static bool CPU_Init(FileLoader *fileLoader, IdentifiedFileType type, std::strin // Trying to boot other things lands us here. We need to return a sensible error string. ERROR_LOG(Log::Loader, "CPU_Init didn't recognize file. %s", errorString->c_str()); auto sy = GetI18NCategory(I18NCat::SYSTEM); - *errorString = sy->T("Not a PSP game"); // best string we have. + *errorString = ApplySafeSubstitutions("%1 (%2)", sy->T("Not a PSP game"), *errorString); // best string we have. return false; } } @@ -616,14 +616,13 @@ bool PSP_InitStart(const CoreParameter &coreParam) { NOTICE_LOG(Log::Boot, "PPSSPP %s", PPSSPP_GIT_VERSION); Path filename = g_CoreParameter.fileToStart; - FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename)); - IdentifiedFileType type = Identify_File(loadedFile, &g_CoreParameter.errorString); - g_CoreParameter.fileType = type; + IdentifiedFileType fileType; + FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename), &fileType, error_string); if (System_GetPropertyBool(SYSPROP_ENOUGH_RAM_FOR_FULL_ISO)) { if (g_Config.bCacheFullIsoInRam) { - switch (g_CoreParameter.fileType) { + switch (fileType) { case IdentifiedFileType::PSP_ISO: case IdentifiedFileType::PSP_ISO_NP: loadedFile = new RamCachingFileLoader(loadedFile); @@ -635,9 +634,11 @@ bool PSP_InitStart(const CoreParameter &coreParam) { } } + g_CoreParameter.fileType = fileType; + // TODO: The reason we pass in g_CoreParameter.errorString here is that it's persistent - // it gets written to from the loader thread that gets spawned. - if (!CPU_Init(loadedFile, type, &g_CoreParameter.errorString)) { + if (!CPU_Init(loadedFile, fileType, &g_CoreParameter.errorString)) { CPU_Shutdown(false); g_CoreParameter.fileToStart.clear(); *error_string = g_CoreParameter.errorString; diff --git a/assets/compat.ini b/assets/compat.ini index c95b899fa4..91fc9559c4 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -231,13 +231,14 @@ NPUH90087 = true # demo NPEH90042 = true # demo [Force04154000Download] -# This applies a hack to Dangan Ronpa, its demo, and its sequel. +# This applies a hack to Dangan Ronpa, its demo, and its sequel, Super Dangan Ronpa 2. # The game draws solid colors to a small framebuffer, and then reads this directly in VRAM. # We force this framebuffer to 1x and force download it automatically. NPJH50631 = true NPJH50372 = true NPJH90164 = true NPJH50515 = true + # Let's also apply to Me & My Katamari. ULUS10094 = true ULES00339 = true