From 07d47a8cc1319bc80900cd4140df7a8197b4f1a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 28 Jan 2026 23:29:44 +0100 Subject: [PATCH 1/5] Make UMD_VIDEO discs with game data detect as games. Add special case for region for wacky STEALTH + Wipeout Pure disc, see #21166 --- Core/ELF/ParamSFO.cpp | 4 +++- Core/Loaders.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index f5679cd8f0..07f64e185e 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -399,9 +399,11 @@ GameRegion DetectGameRegionFromID(std::string_view id_full) { return GameRegion::TEST; } else if (id_letters == "UMDT") { return GameRegion::DIAGNOSTIC; + } else if (id_letters == "STEA") { + // The bizarre Stealth + Wipeout Pure combo. + return GameRegion::INTERNAL; } } - return GameRegion::HOMEBREW; } diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index ce788947f3..f5056ea90f 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -144,6 +144,16 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin // Yes, a proper PSP game, let's get it going. return IdentifiedFileType::PSP_ISO; } else if (!memcmp(pvd->systemId, "UMD VIDEO", 9) || !memcmp(pvd->systemId, "UMD AUDIO", 9)) { + // This is rare so being slightly slow here shouldn't be a problem. Let's go check for the presence of + // actual game data. + SequentialHandleAllocator hAlloc; + ISOFileSystem umd(&hAlloc, bd.release()); + if (umd.GetFileInfo("/PSP_GAME").exists) { + INFO_LOG(Log::Loader, "Found an UMD VIDEO disc with game data. Treating as game."); + *errorString = "UMD Video with PSP GAME data"; + return IdentifiedFileType::PSP_ISO; + } + // 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)) { @@ -156,6 +166,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin } 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"; return IdentifiedFileType::UNKNOWN_ISO; } 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 2/5] 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 From 8a431e2ec2569848cf6e5f376765a40bd5934b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 28 Jan 2026 23:49:00 +0100 Subject: [PATCH 3/5] Add zoom feature to framebuffer list view in ImDebugger --- UI/ImDebugger/ImDebugger.h | 2 ++ UI/ImDebugger/ImGe.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/UI/ImDebugger/ImDebugger.h b/UI/ImDebugger/ImDebugger.h index 651c59c188..f7c14d5125 100644 --- a/UI/ImDebugger/ImDebugger.h +++ b/UI/ImDebugger/ImDebugger.h @@ -121,6 +121,8 @@ struct ImConfig { bool sasShowAllVoices = false; + float fbViewerZoom = 1.0f; + // We use a separate ini file from the main PPSSPP config. void LoadConfig(const Path &iniFile); diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index 0ed1f2b77c..70cc812eb4 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -79,10 +79,12 @@ void DrawFramebuffersWindow(ImConfig &cfg, FramebufferManagerCommon *framebuffer } if (cfg.selectedFramebuffer != -1) { + ImGui::SliderFloat("Scale", &cfg.fbViewerZoom, 0.5f, 16.0f, "%.2f", ImGuiSliderFlags_Logarithmic); + // Now, draw the image of the selected framebuffer. Draw::Framebuffer *fb = vfbs[cfg.selectedFramebuffer]->fbo; ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(fb, Draw::Aspect::COLOR_BIT, ImGuiPipeline::TexturedOpaque); - ImGui::Image(texId, ImVec2(fb->Width(), fb->Height())); + ImGui::Image(texId, ImVec2(fb->Width() * cfg.fbViewerZoom, fb->Height() * cfg.fbViewerZoom)); } ImGui::End(); From 4fb3a0e3708490d36c99459f45dd594e977903d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 29 Jan 2026 00:25:25 +0100 Subject: [PATCH 4/5] Bubble up more error messages to the user --- Core/FileSystems/BlockDevices.cpp | 3 +- Core/Loaders.cpp | 52 ++++++++++++++++++------------- Core/System.cpp | 15 +++++---- UI/EmuScreen.cpp | 2 +- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index 922137ee30..8bb9911a80 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -22,6 +22,7 @@ #include "Common/System/OSD.h" #include "Common/Log.h" #include "Common/Swap.h" +#include "Common/Data/Text/Parsers.h" #include "Common/File/FileUtil.h" #include "Common/File/DirListing.h" #include "Common/StringUtils.h" @@ -223,7 +224,7 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader) u64 lastIndexPos = index[indexSize - 1] & 0x7FFFFFFF; u64 expectedFileSize = lastIndexPos << indexShift; if (expectedFileSize > fileSize) { - errorString_ = StringFromFormat("Expected CSO to at least be %lld bytes, but file is %lld bytes", expectedFileSize, fileSize); + errorString_ = StringFromFormat("CSO file incomplete: expected %s, but is %s", NiceSizeFormat(expectedFileSize).c_str(), NiceSizeFormat(fileSize).c_str()); return; } diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index c5a2098226..c24de3af83 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -120,28 +120,18 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin // OK, quick methods of identification for common types failed. Moving on to more expensive methods, // starting by reading the first few bytes. // This can be necessary for weird Android content storage path types, see issue #17462 - - u32_le id; - - size_t readSize = fileLoader->ReadAt(0, 4, 1, &id); - if (readSize != 1) { - *errorString = "Failed to read identification bytes"; - return IdentifiedFileType::ERROR_IDENTIFYING; - } - if (isDiscImage || fileLoader->FileSize() >= 0x8800) { - // All zeroes. ISO files start like this but their 16th 2048-byte sector contains metadata. // Do the quick check for PSP ISOs here. - std::string error; - std::unique_ptr bd(ConstructBlockDevice(fileLoader, &error)); + std::string bdError; + std::unique_ptr bd(ConstructBlockDevice(fileLoader, &bdError)); if (bd) { u8 block16[2048]{}; bd->ReadBlock(16, (u8 *)block16); PVD *pvd = (PVD *)(block16); if (!memcmp(pvd->identifier, "CD001", 5)) { // It's a valid DVD-style ISO file. Let's see which type. - if (!memcmp(pvd->systemId, "PSP GAME", 8)) { - // Yes, a proper PSP game, let's get it going. + if (!memcmp(pvd->systemId, "PSP GAME", 8) || !memcmp(pvd->systemId, "\"PSP GAME\"", 10)) { + // Yes, a known proper PSP game, let's get it going. return IdentifiedFileType::PSP_ISO; } else if (!memcmp(pvd->systemId, "UMD VIDEO", 9) || !memcmp(pvd->systemId, "UMD AUDIO", 9)) { // This is rare so being slightly slow here shouldn't be a problem. Let's go check for the presence of @@ -168,7 +158,15 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin *errorString = "PSX ISO?"; return IdentifiedFileType::PSX_ISO; } else { - WARN_LOG(Log::Loader, "ISO with unknown system ID: %.32s", pvd->systemId); + // Let's go check for PSP game data. + SequentialHandleAllocator hAlloc; + ISOFileSystem umd(&hAlloc, bd.release()); + if (umd.GetFileInfo("/PSP_GAME").exists) { + INFO_LOG(Log::Loader, "PSP ISO with unknown system ID: %.32s: %s", pvd->systemId, fileLoader->GetPath().c_str()); + return IdentifiedFileType::PSP_ISO; + } + + INFO_LOG(Log::Loader, "Unknown ISO with unknown system ID: %.32s: %s", pvd->systemId, fileLoader->GetPath().c_str()); *errorString = StringFromFormat("ISO with unknown system ID: %.32s", pvd->systemId); return IdentifiedFileType::UNKNOWN_ISO; } @@ -189,22 +187,34 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin } if (isDiscImage) { - *errorString = "Not a valid PSP ISO image"; + if (!bdError.empty()) { + *errorString = bdError; + } else { + auto sy = GetI18NCategory(I18NCat::SYSTEM); + *errorString = sy->T("Not a PSP game"); + } return IdentifiedFileType::UNKNOWN_ISO; } } + u32 id; + + size_t readSize = fileLoader->ReadAt(0, 4, 1, &id); + if (readSize != 1) { + *errorString = "Failed to read identification bytes"; + return IdentifiedFileType::ERROR_IDENTIFYING; + } + u32_le psar_offset = 0, psar_id = 0; - u32 _id = id; - if (!memcmp(&_id, "PK\x03\x04", 4) || !memcmp(&_id, "PK\x05\x06", 4) || !memcmp(&_id, "PK\x07\x08", 4)) { + if (!memcmp(&id, "PK\x03\x04", 4) || !memcmp(&id, "PK\x05\x06", 4) || !memcmp(&id, "PK\x07\x08", 4)) { return IdentifiedFileType::ARCHIVE_ZIP; - } else if (!memcmp(&_id, "\x00PBP", 4)) { + } else if (!memcmp(&id, "\x00PBP", 4)) { fileLoader->ReadAt(0x24, 4, 1, &psar_offset); fileLoader->ReadAt(psar_offset, 4, 1, &psar_id); // Fall through to the below if chain. - } else if (!memcmp(&_id, "Rar!", 4)) { + } else if (!memcmp(&id, "Rar!", 4)) { return IdentifiedFileType::ARCHIVE_RAR; - } else if (!memcmp(&_id, "\x37\x7A\xBC\xAF", 4)) { + } else if (!memcmp(&id, "\x37\x7A\xBC\xAF", 4)) { return IdentifiedFileType::ARCHIVE_7Z; } diff --git a/Core/System.cpp b/Core/System.cpp index fdbfe9981b..9057ae8343 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -340,7 +340,6 @@ 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 = ApplySafeSubstitutions("%1 (%2)", sy->T("Not a PSP game"), *errorString); // best string we have. return false; } } @@ -600,7 +599,7 @@ bool PSP_InitStart(const CoreParameter &coreParam) { } g_CoreParameter.errorString.clear(); - std::string *error_string = &g_CoreParameter.errorString; + std::string *errorString = &g_CoreParameter.errorString; INFO_LOG(Log::Loader, "Starting loader thread..."); @@ -608,7 +607,7 @@ bool PSP_InitStart(const CoreParameter &coreParam) { Core_NotifyLifecycle(CoreLifecycle::STARTING); - g_loadingThread = std::thread([error_string]() { + g_loadingThread = std::thread([errorString]() { SetCurrentThreadName("ExecLoader"); AndroidJNIThreadContext jniContext; @@ -618,7 +617,7 @@ bool PSP_InitStart(const CoreParameter &coreParam) { Path filename = g_CoreParameter.fileToStart; IdentifiedFileType fileType; - FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename), &fileType, error_string); + FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename), &fileType, errorString); if (System_GetPropertyBool(SYSPROP_ENOUGH_RAM_FOR_FULL_ISO)) { if (g_Config.bCacheFullIsoInRam) { @@ -641,9 +640,9 @@ bool PSP_InitStart(const CoreParameter &coreParam) { if (!CPU_Init(loadedFile, fileType, &g_CoreParameter.errorString)) { CPU_Shutdown(false); g_CoreParameter.fileToStart.clear(); - *error_string = g_CoreParameter.errorString; - if (error_string->empty()) { - *error_string = "Failed initializing CPU/Memory"; + *errorString = g_CoreParameter.errorString; + if (errorString->empty()) { + *errorString = "Failed initializing CPU/Memory"; } g_bootState = BootState::Failed; return; @@ -652,7 +651,7 @@ bool PSP_InitStart(const CoreParameter &coreParam) { // Initialize the GPU as far as we can here (do things like load cache files). _dbg_assert_(!gpu); #ifndef __LIBRETRO__ - InitGPU(error_string); + InitGPU(errorString); #endif g_bootState = BootState::Complete; }); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index a2170c0a34..5a724fc67d 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1457,7 +1457,7 @@ void EmuScreen::update() { std::string errLoadingFile = gamePath_.ToVisualString() + "\n\n"; errLoadingFile.append(err->T("Error loading file", "Could not load game")); errLoadingFile.append("\n"); - errLoadingFile.append(err->T(errorMessage_.c_str())); + errLoadingFile.append(errorMessage_); screenManager()->push(new PromptScreen(gamePath_, errLoadingFile, di->T("OK"), "")); errorMessage_.clear(); From 9b0d205de351109dc20c85979e8c78a8c33018d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 29 Jan 2026 00:33:03 +0100 Subject: [PATCH 5/5] Slightly more UB-safe, in theory. In practice, doubt it. --- Core/Loaders.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index c24de3af83..c26db48052 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -127,13 +127,14 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin if (bd) { u8 block16[2048]{}; bd->ReadBlock(16, (u8 *)block16); - PVD *pvd = (PVD *)(block16); - if (!memcmp(pvd->identifier, "CD001", 5)) { + PVD pvd; + memcpy(&pvd, block16, sizeof(PVD)); + if (!memcmp(pvd.identifier, "CD001", 5)) { // It's a valid DVD-style ISO file. Let's see which type. - if (!memcmp(pvd->systemId, "PSP GAME", 8) || !memcmp(pvd->systemId, "\"PSP GAME\"", 10)) { + if (!memcmp(pvd.systemId, "PSP GAME", 8) || !memcmp(pvd.systemId, "\"PSP GAME\"", 10)) { // Yes, a known proper PSP game, let's get it going. return IdentifiedFileType::PSP_ISO; - } else if (!memcmp(pvd->systemId, "UMD VIDEO", 9) || !memcmp(pvd->systemId, "UMD AUDIO", 9)) { + } else if (!memcmp(pvd.systemId, "UMD VIDEO", 9) || !memcmp(pvd.systemId, "UMD AUDIO", 9)) { // This is rare so being slightly slow here shouldn't be a problem. Let's go check for the presence of // actual game data. SequentialHandleAllocator hAlloc; @@ -146,10 +147,10 @@ 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)) { + } else if (!memcmp(pvd.systemId, "PS3", 3)) { *errorString = "PS3 ISO"; return IdentifiedFileType::PS3_ISO; - } else if (!memcmp(pvd->systemId, "PLAYSTATION", 11)) { + } else if (!memcmp(pvd.systemId, "PLAYSTATION", 11)) { // Just do a size heuristic here to differentiate. There are better ways but slower. if (bd->GetUncompressedSize() > 800LL * 1024LL * 1024LL) { *errorString = "PS2 ISO"; @@ -162,12 +163,12 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin SequentialHandleAllocator hAlloc; ISOFileSystem umd(&hAlloc, bd.release()); if (umd.GetFileInfo("/PSP_GAME").exists) { - INFO_LOG(Log::Loader, "PSP ISO with unknown system ID: %.32s: %s", pvd->systemId, fileLoader->GetPath().c_str()); + INFO_LOG(Log::Loader, "PSP ISO with unknown system ID: %.32s: %s", pvd.systemId, fileLoader->GetPath().c_str()); return IdentifiedFileType::PSP_ISO; } - INFO_LOG(Log::Loader, "Unknown ISO with unknown system ID: %.32s: %s", pvd->systemId, fileLoader->GetPath().c_str()); - *errorString = StringFromFormat("ISO with unknown system ID: %.32s", pvd->systemId); + INFO_LOG(Log::Loader, "Unknown ISO with unknown system ID: %.32s: %s", pvd.systemId, fileLoader->GetPath().c_str()); + *errorString = StringFromFormat("ISO with unknown system ID: %.32s", pvd.systemId); return IdentifiedFileType::UNKNOWN_ISO; } }