Skip to content

Commit e71e1d2

Browse files
authored
Merge pull request #21169 from hrydgard/more-umd-video-detection
Make UMD_VIDEO discs with game data detect as games.
2 parents 8de5b45 + 9b0d205 commit e71e1d2

10 files changed

Lines changed: 106 additions & 62 deletions

File tree

‎Core/ELF/ParamSFO.cpp‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,11 @@ GameRegion DetectGameRegionFromID(std::string_view id_full) {
399399
return GameRegion::TEST;
400400
} else if (id_letters == "UMDT") {
401401
return GameRegion::DIAGNOSTIC;
402+
} else if (id_letters == "STEA") {
403+
// The bizarre Stealth + Wipeout Pure combo.
404+
return GameRegion::INTERNAL;
402405
}
403406
}
404-
405407
return GameRegion::HOMEBREW;
406408
}
407409

‎Core/FileSystems/BlockDevices.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "Common/System/OSD.h"
2323
#include "Common/Log.h"
2424
#include "Common/Swap.h"
25+
#include "Common/Data/Text/Parsers.h"
2526
#include "Common/File/FileUtil.h"
2627
#include "Common/File/DirListing.h"
2728
#include "Common/StringUtils.h"
@@ -223,7 +224,7 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader)
223224
u64 lastIndexPos = index[indexSize - 1] & 0x7FFFFFFF;
224225
u64 expectedFileSize = lastIndexPos << indexShift;
225226
if (expectedFileSize > fileSize) {
226-
errorString_ = StringFromFormat("Expected CSO to at least be %lld bytes, but file is %lld bytes", expectedFileSize, fileSize);
227+
errorString_ = StringFromFormat("CSO file incomplete: expected %s, but is %s", NiceSizeFormat(expectedFileSize).c_str(), NiceSizeFormat(fileSize).c_str());
227228
return;
228229
}
229230

‎Core/Loaders.cpp‎

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -120,43 +120,55 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin
120120
// OK, quick methods of identification for common types failed. Moving on to more expensive methods,
121121
// starting by reading the first few bytes.
122122
// This can be necessary for weird Android content storage path types, see issue #17462
123-
124-
u32_le id;
125-
126-
size_t readSize = fileLoader->ReadAt(0, 4, 1, &id);
127-
if (readSize != 1) {
128-
*errorString = "Failed to read identification bytes";
129-
return IdentifiedFileType::ERROR_IDENTIFYING;
130-
}
131-
132123
if (isDiscImage || fileLoader->FileSize() >= 0x8800) {
133-
// All zeroes. ISO files start like this but their 16th 2048-byte sector contains metadata.
134124
// Do the quick check for PSP ISOs here.
135-
std::string error;
136-
std::unique_ptr<BlockDevice> bd(ConstructBlockDevice(fileLoader, &error));
125+
std::string bdError;
126+
std::unique_ptr<BlockDevice> bd(ConstructBlockDevice(fileLoader, &bdError));
137127
if (bd) {
138128
u8 block16[2048]{};
139129
bd->ReadBlock(16, (u8 *)block16);
140-
PVD *pvd = (PVD *)(block16);
141-
if (!memcmp(pvd->identifier, "CD001", 5)) {
130+
PVD pvd;
131+
memcpy(&pvd, block16, sizeof(PVD));
132+
if (!memcmp(pvd.identifier, "CD001", 5)) {
142133
// It's a valid DVD-style ISO file. Let's see which type.
143-
if (!memcmp(pvd->systemId, "PSP GAME", 8)) {
144-
// Yes, a proper PSP game, let's get it going.
134+
if (!memcmp(pvd.systemId, "PSP GAME", 8) || !memcmp(pvd.systemId, "\"PSP GAME\"", 10)) {
135+
// Yes, a known proper PSP game, let's get it going.
145136
return IdentifiedFileType::PSP_ISO;
146-
} else if (!memcmp(pvd->systemId, "UMD VIDEO", 9) || !memcmp(pvd->systemId, "UMD AUDIO", 9)) {
137+
} else if (!memcmp(pvd.systemId, "UMD VIDEO", 9) || !memcmp(pvd.systemId, "UMD AUDIO", 9)) {
138+
// This is rare so being slightly slow here shouldn't be a problem. Let's go check for the presence of
139+
// actual game data.
140+
SequentialHandleAllocator hAlloc;
141+
ISOFileSystem umd(&hAlloc, bd.release());
142+
if (umd.GetFileInfo("/PSP_GAME").exists) {
143+
INFO_LOG(Log::Loader, "Found an UMD VIDEO disc with game data. Treating as game.");
144+
*errorString = "UMD Video with PSP GAME data";
145+
return IdentifiedFileType::PSP_ISO;
146+
}
147+
147148
// UMD AUDIO exists technically, but in reality, not really? Let's map it to VIDEO since we support neither.
148149
return IdentifiedFileType::PSP_UMD_VIDEO_ISO;
149-
} else if (!memcmp(pvd->systemId, "PS3", 3)) {
150+
} else if (!memcmp(pvd.systemId, "PS3", 3)) {
151+
*errorString = "PS3 ISO";
150152
return IdentifiedFileType::PS3_ISO;
151-
} else if (!memcmp(pvd->systemId, "PLAYSTATION", 11)) {
152-
*errorString = "PSX or PS2 ISO";
153+
} else if (!memcmp(pvd.systemId, "PLAYSTATION", 11)) {
153154
// Just do a size heuristic here to differentiate. There are better ways but slower.
154155
if (bd->GetUncompressedSize() > 800LL * 1024LL * 1024LL) {
156+
*errorString = "PS2 ISO";
155157
return IdentifiedFileType::PS2_ISO;
156158
}
159+
*errorString = "PSX ISO?";
157160
return IdentifiedFileType::PSX_ISO;
158161
} else {
159-
*errorString = "ISO missing PSP GAME or PSP NPU identifier";
162+
// Let's go check for PSP game data.
163+
SequentialHandleAllocator hAlloc;
164+
ISOFileSystem umd(&hAlloc, bd.release());
165+
if (umd.GetFileInfo("/PSP_GAME").exists) {
166+
INFO_LOG(Log::Loader, "PSP ISO with unknown system ID: %.32s: %s", pvd.systemId, fileLoader->GetPath().c_str());
167+
return IdentifiedFileType::PSP_ISO;
168+
}
169+
170+
INFO_LOG(Log::Loader, "Unknown ISO with unknown system ID: %.32s: %s", pvd.systemId, fileLoader->GetPath().c_str());
171+
*errorString = StringFromFormat("ISO with unknown system ID: %.32s", pvd.systemId);
160172
return IdentifiedFileType::UNKNOWN_ISO;
161173
}
162174
}
@@ -169,29 +181,41 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin
169181

170182
// each sector in a mode2 image starts with these 12 bytes
171183
if (memcmp(sync, "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", 12) == 0) {
172-
*errorString = "ISO in Mode 2: Not a PSP game";
184+
*errorString = "ISO is a CD - likely PSX"; // Mode 2 CDs are used for PSX games
173185
return IdentifiedFileType::PSX_ISO;
174186
}
175187
}
176188
}
177189

178190
if (isDiscImage) {
179-
*errorString = "Not a valid PSP ISO image";
191+
if (!bdError.empty()) {
192+
*errorString = bdError;
193+
} else {
194+
auto sy = GetI18NCategory(I18NCat::SYSTEM);
195+
*errorString = sy->T("Not a PSP game");
196+
}
180197
return IdentifiedFileType::UNKNOWN_ISO;
181198
}
182199
}
183200

201+
u32 id;
202+
203+
size_t readSize = fileLoader->ReadAt(0, 4, 1, &id);
204+
if (readSize != 1) {
205+
*errorString = "Failed to read identification bytes";
206+
return IdentifiedFileType::ERROR_IDENTIFYING;
207+
}
208+
184209
u32_le psar_offset = 0, psar_id = 0;
185-
u32 _id = id;
186-
if (!memcmp(&_id, "PK\x03\x04", 4) || !memcmp(&_id, "PK\x05\x06", 4) || !memcmp(&_id, "PK\x07\x08", 4)) {
210+
if (!memcmp(&id, "PK\x03\x04", 4) || !memcmp(&id, "PK\x05\x06", 4) || !memcmp(&id, "PK\x07\x08", 4)) {
187211
return IdentifiedFileType::ARCHIVE_ZIP;
188-
} else if (!memcmp(&_id, "\x00PBP", 4)) {
212+
} else if (!memcmp(&id, "\x00PBP", 4)) {
189213
fileLoader->ReadAt(0x24, 4, 1, &psar_offset);
190214
fileLoader->ReadAt(psar_offset, 4, 1, &psar_id);
191215
// Fall through to the below if chain.
192-
} else if (!memcmp(&_id, "Rar!", 4)) {
216+
} else if (!memcmp(&id, "Rar!", 4)) {
193217
return IdentifiedFileType::ARCHIVE_RAR;
194-
} else if (!memcmp(&_id, "\x37\x7A\xBC\xAF", 4)) {
218+
} else if (!memcmp(&id, "\x37\x7A\xBC\xAF", 4)) {
195219
return IdentifiedFileType::ARCHIVE_7Z;
196220
}
197221

@@ -253,17 +277,18 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin
253277
return IdentifiedFileType::UNKNOWN;
254278
}
255279

256-
FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader) {
257-
std::string errorString;
258-
IdentifiedFileType type = Identify_File(fileLoader, &errorString);
259-
if (type == IdentifiedFileType::PSP_PBP_DIRECTORY) {
280+
FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader, IdentifiedFileType *fileType, std::string *errorString) {
281+
*fileType = Identify_File(fileLoader, errorString);
282+
if (*fileType == IdentifiedFileType::PSP_PBP_DIRECTORY) {
260283
const Path ebootFilename = ResolvePBPFile(fileLoader->GetPath());
261284
if (ebootFilename != fileLoader->GetPath()) {
262285
// Switch fileLoader to the actual EBOOT.
263286
delete fileLoader;
264287
fileLoader = ConstructFileLoader(ebootFilename);
288+
// Re-identify the file.
289+
*fileType = Identify_File(fileLoader, errorString);
265290
}
266-
} else if (type == IdentifiedFileType::ARCHIVE_ZIP) {
291+
} else if (*fileType == IdentifiedFileType::ARCHIVE_ZIP) {
267292
// Handle zip files, take automatic action depending on contents.
268293
// Can also return nullptr.
269294
ZipFileLoader *zipLoader = new ZipFileLoader(fileLoader);
@@ -276,6 +301,8 @@ FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader) {
276301
case ZipFileContents::FRAME_DUMP:
277302
{
278303
zipLoader->Initialize(zipFileInfo.isoFileIndex);
304+
// Re-identify the file.
305+
*fileType = Identify_File(zipLoader, errorString);
279306
return zipLoader;
280307
}
281308
default:
@@ -323,14 +350,13 @@ bool UmdReplace(const Path &filepath, FileLoader **fileLoader, std::string &erro
323350
}
324351
UpdateLoadedFile(loadedFile);
325352

326-
loadedFile = ResolveFileLoaderTarget(loadedFile);
353+
std::string errorString;
354+
IdentifiedFileType fileType;
355+
loadedFile = ResolveFileLoaderTarget(loadedFile, &fileType, &errorString);
327356

328357
*fileLoader = loadedFile;
329358

330-
std::string errorString;
331-
IdentifiedFileType type = Identify_File(loadedFile, &errorString);
332-
333-
switch (type) {
359+
switch (fileType) {
334360
case IdentifiedFileType::PSP_ISO:
335361
case IdentifiedFileType::PSP_ISO_NP:
336362
case IdentifiedFileType::PSP_DISC_DIRECTORY:
@@ -340,7 +366,7 @@ bool UmdReplace(const Path &filepath, FileLoader **fileLoader, std::string &erro
340366
}
341367
break;
342368
default:
343-
error = "Unsupported file type: " + std::to_string((int)type) + " " + errorString;
369+
error = "Unsupported file type: " + std::string(IdentifiedFileTypeToString(fileType)) + " " + errorString;
344370
return false;
345371
break;
346372
}

‎Core/Loaders.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) {
152152
}
153153

154154
FileLoader *ConstructFileLoader(const Path &filename);
155-
// Resolve to the target binary, ISO, or other file (e.g. from a directory.)
156-
FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader);
155+
// Identifies the file and resolves to the target binary, ISO, or other file (e.g. from a directory.)
156+
FileLoader *ResolveFileLoaderTarget(FileLoader *fileLoader, IdentifiedFileType *fileType, std::string *errorString);
157157

158158
Path ResolvePBPDirectory(const Path &filename);
159159
Path ResolvePBPFile(const Path &filename);

‎Core/Reporting.cpp‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,29 @@ namespace Reporting
134134

135135
AndroidJNIThreadContext jniContext;
136136

137-
FileLoader *fileLoader = ResolveFileLoaderTarget(ConstructFileLoader(crcFilename));
137+
IdentifiedFileType type;
138138

139139
std::string errorString;
140-
BlockDevice *blockDevice = ConstructBlockDevice(fileLoader, &errorString);
140+
FileLoader *fileLoader = ResolveFileLoaderTarget(ConstructFileLoader(crcFilename), &type, &errorString);
141+
if (!fileLoader) {
142+
ERROR_LOG(Log::Loader, "Failed to construct file loader for CRC: %s", errorString.c_str());
143+
std::lock_guard<std::mutex> guard(crcLock);
144+
crcResults[crcFilename] = 0;
145+
crcPending = false;
146+
crcCond.notify_one();
147+
return 0;
148+
}
149+
150+
std::unique_ptr<BlockDevice> blockDevice(ConstructBlockDevice(fileLoader, &errorString));
141151

142152
u32 crc = 0;
143153
if (blockDevice) {
144-
crc = CalculateCRC(blockDevice, &crcCancel);
154+
crc = CalculateCRC(blockDevice.get(), &crcCancel);
145155
} else {
146156
ERROR_LOG(Log::Loader, "Failed to read from block device for CRC: %s", errorString.c_str());
147157
}
148158

149-
delete blockDevice;
159+
blockDevice.reset();
150160
delete fileLoader;
151161

152162
std::lock_guard<std::mutex> guard(crcLock);

‎Core/System.cpp‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,6 @@ static bool CPU_Init(FileLoader *fileLoader, IdentifiedFileType type, std::strin
340340
// Trying to boot other things lands us here. We need to return a sensible error string.
341341
ERROR_LOG(Log::Loader, "CPU_Init didn't recognize file. %s", errorString->c_str());
342342
auto sy = GetI18NCategory(I18NCat::SYSTEM);
343-
*errorString = sy->T("Not a PSP game"); // best string we have.
344343
return false;
345344
}
346345
}
@@ -600,30 +599,29 @@ bool PSP_InitStart(const CoreParameter &coreParam) {
600599
}
601600
g_CoreParameter.errorString.clear();
602601

603-
std::string *error_string = &g_CoreParameter.errorString;
602+
std::string *errorString = &g_CoreParameter.errorString;
604603

605604
INFO_LOG(Log::Loader, "Starting loader thread...");
606605

607606
_assert_msg_(!g_loadingThread.joinable(), "%s", coreParam.fileToStart.c_str());
608607

609608
Core_NotifyLifecycle(CoreLifecycle::STARTING);
610609

611-
g_loadingThread = std::thread([error_string]() {
610+
g_loadingThread = std::thread([errorString]() {
612611
SetCurrentThreadName("ExecLoader");
613612

614613
AndroidJNIThreadContext jniContext;
615614

616615
NOTICE_LOG(Log::Boot, "PPSSPP %s", PPSSPP_GIT_VERSION);
617616

618617
Path filename = g_CoreParameter.fileToStart;
619-
FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename));
620618

621-
IdentifiedFileType type = Identify_File(loadedFile, &g_CoreParameter.errorString);
622-
g_CoreParameter.fileType = type;
619+
IdentifiedFileType fileType;
620+
FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename), &fileType, errorString);
623621

624622
if (System_GetPropertyBool(SYSPROP_ENOUGH_RAM_FOR_FULL_ISO)) {
625623
if (g_Config.bCacheFullIsoInRam) {
626-
switch (g_CoreParameter.fileType) {
624+
switch (fileType) {
627625
case IdentifiedFileType::PSP_ISO:
628626
case IdentifiedFileType::PSP_ISO_NP:
629627
loadedFile = new RamCachingFileLoader(loadedFile);
@@ -635,14 +633,16 @@ bool PSP_InitStart(const CoreParameter &coreParam) {
635633
}
636634
}
637635

636+
g_CoreParameter.fileType = fileType;
637+
638638
// TODO: The reason we pass in g_CoreParameter.errorString here is that it's persistent -
639639
// it gets written to from the loader thread that gets spawned.
640-
if (!CPU_Init(loadedFile, type, &g_CoreParameter.errorString)) {
640+
if (!CPU_Init(loadedFile, fileType, &g_CoreParameter.errorString)) {
641641
CPU_Shutdown(false);
642642
g_CoreParameter.fileToStart.clear();
643-
*error_string = g_CoreParameter.errorString;
644-
if (error_string->empty()) {
645-
*error_string = "Failed initializing CPU/Memory";
643+
*errorString = g_CoreParameter.errorString;
644+
if (errorString->empty()) {
645+
*errorString = "Failed initializing CPU/Memory";
646646
}
647647
g_bootState = BootState::Failed;
648648
return;
@@ -651,7 +651,7 @@ bool PSP_InitStart(const CoreParameter &coreParam) {
651651
// Initialize the GPU as far as we can here (do things like load cache files).
652652
_dbg_assert_(!gpu);
653653
#ifndef __LIBRETRO__
654-
InitGPU(error_string);
654+
InitGPU(errorString);
655655
#endif
656656
g_bootState = BootState::Complete;
657657
});

‎UI/EmuScreen.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1457,7 +1457,7 @@ void EmuScreen::update() {
14571457
std::string errLoadingFile = gamePath_.ToVisualString() + "\n\n";
14581458
errLoadingFile.append(err->T("Error loading file", "Could not load game"));
14591459
errLoadingFile.append("\n");
1460-
errLoadingFile.append(err->T(errorMessage_.c_str()));
1460+
errLoadingFile.append(errorMessage_);
14611461

14621462
screenManager()->push(new PromptScreen(gamePath_, errLoadingFile, di->T("OK"), ""));
14631463
errorMessage_.clear();

‎UI/ImDebugger/ImDebugger.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ struct ImConfig {
121121

122122
bool sasShowAllVoices = false;
123123

124+
float fbViewerZoom = 1.0f;
125+
124126

125127
// We use a separate ini file from the main PPSSPP config.
126128
void LoadConfig(const Path &iniFile);

‎UI/ImDebugger/ImGe.cpp‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,12 @@ void DrawFramebuffersWindow(ImConfig &cfg, FramebufferManagerCommon *framebuffer
7979
}
8080

8181
if (cfg.selectedFramebuffer != -1) {
82+
ImGui::SliderFloat("Scale", &cfg.fbViewerZoom, 0.5f, 16.0f, "%.2f", ImGuiSliderFlags_Logarithmic);
83+
8284
// Now, draw the image of the selected framebuffer.
8385
Draw::Framebuffer *fb = vfbs[cfg.selectedFramebuffer]->fbo;
8486
ImTextureID texId = ImGui_ImplThin3d_AddFBAsTextureTemp(fb, Draw::Aspect::COLOR_BIT, ImGuiPipeline::TexturedOpaque);
85-
ImGui::Image(texId, ImVec2(fb->Width(), fb->Height()));
87+
ImGui::Image(texId, ImVec2(fb->Width() * cfg.fbViewerZoom, fb->Height() * cfg.fbViewerZoom));
8688
}
8789

8890
ImGui::End();

‎assets/compat.ini‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,13 +231,14 @@ NPUH90087 = true # demo
231231
NPEH90042 = true # demo
232232

233233
[Force04154000Download]
234-
# This applies a hack to Dangan Ronpa, its demo, and its sequel.
234+
# This applies a hack to Dangan Ronpa, its demo, and its sequel, Super Dangan Ronpa 2.
235235
# The game draws solid colors to a small framebuffer, and then reads this directly in VRAM.
236236
# We force this framebuffer to 1x and force download it automatically.
237237
NPJH50631 = true
238238
NPJH50372 = true
239239
NPJH90164 = true
240240
NPJH50515 = true
241+
241242
# Let's also apply to Me & My Katamari.
242243
ULUS10094 = true
243244
ULES00339 = true

0 commit comments

Comments
 (0)