diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index 8a6e7dc8abc5..922137ee3082 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -24,6 +24,7 @@ #include "Common/Swap.h" #include "Common/File/FileUtil.h" #include "Common/File/DirListing.h" +#include "Common/StringUtils.h" #include "Core/Loaders.h" #include "Core/FileSystems/BlockDevices.h" #include "libchdr/chd.h" @@ -35,12 +36,15 @@ extern "C" #include "ext/libkirk/kirk_engine.h" }; -BlockDevice *constructBlockDevice(FileLoader *fileLoader) { +BlockDevice *ConstructBlockDevice(FileLoader *fileLoader, std::string *errorString) { if (!fileLoader->Exists()) { + // Shouldn't get here really. + *errorString = "File doesn't exist"; return nullptr; } if (fileLoader->IsDirectory()) { - ERROR_LOG(Log::Loader, "Can't open directory directly as block device: %s", fileLoader->GetPath().c_str()); + *errorString = "Can't open directory directly as block device: "; + *errorString += fileLoader->GetPath().ToString(); return nullptr; } @@ -48,23 +52,36 @@ BlockDevice *constructBlockDevice(FileLoader *fileLoader) { size_t size = fileLoader->ReadAt(0, 1, 8, buffer); if (size != 8) { // Bad or empty file + *errorString = "File is empty"; return nullptr; } + BlockDevice *device = nullptr; + // Check for CISO if (!memcmp(buffer, "CISO", 4)) { - return new CISOFileBlockDevice(fileLoader); + device = new CISOFileBlockDevice(fileLoader); } else if (!memcmp(buffer, "\x00PBP", 4)) { uint32_t psarOffset = 0; size = fileLoader->ReadAt(0x24, 1, 4, &psarOffset); if (size == 4 && psarOffset < fileLoader->FileSize()) - return new NPDRMDemoBlockDevice(fileLoader); + device = new NPDRMDemoBlockDevice(fileLoader); } else if (!memcmp(buffer, "MComprHD", 8)) { - return new CHDFileBlockDevice(fileLoader); + device = new CHDFileBlockDevice(fileLoader); + } + + // No check above passed, should be just a regular ISO file. Let's open it as a plain block device and let the other systems take over. + if (!device) { + device = new FileBlockDevice(fileLoader); + } + + if (!device->IsOK()) { + *errorString = device->ErrorString(); + delete device; + return nullptr; } - // Should be just a regular ISO file. Let's open it as a plain block device and let the other systems take over. - return new FileBlockDevice(fileLoader); + return device; } void BlockDevice::NotifyReadError() { @@ -80,8 +97,7 @@ FileBlockDevice::FileBlockDevice(FileLoader *fileLoader) filesize_ = fileLoader->FileSize(); } -FileBlockDevice::~FileBlockDevice() { -} +FileBlockDevice::~FileBlockDevice() {} bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) { FileLoader::Flags flags = uncached ? FileLoader::Flags::HINT_UNCACHED : FileLoader::Flags::NONE; @@ -90,7 +106,6 @@ bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr, bool uncached) { DEBUG_LOG(Log::FileSystem, "Could not read 2048 byte block, at block offset %d. Only got %d bytes", blockNumber, (int)retval); return false; } - return true; } @@ -141,17 +156,22 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader) CISO_H hdr; size_t readSize = fileLoader->ReadAt(0, sizeof(CISO_H), 1, &hdr); if (readSize != 1 || memcmp(hdr.magic, "CISO", 4) != 0) { - WARN_LOG(Log::Loader, "Invalid CSO!"); + errorString_ = "Invalid CSO!"; + return; } if (hdr.ver > 1) { - WARN_LOG(Log::Loader, "CSO version too high!"); + errorString_ = "CSO version too high!"; + return; } frameSize = hdr.block_size; - if ((frameSize & (frameSize - 1)) != 0) - ERROR_LOG(Log::Loader, "CSO block size %i unsupported, must be a power of two", frameSize); - else if (frameSize < 0x800) - ERROR_LOG(Log::Loader, "CSO block size %i unsupported, must be at least one sector", frameSize); + if ((frameSize & (frameSize - 1)) != 0) { + errorString_ = StringFromFormat("CSO block size %i unsupported, must be a power of two", frameSize); + return; + } else if (frameSize < 0x800) { + errorString_ = StringFromFormat("CSO block size %i unsupported, must be at least one sector", frameSize); + return; + } // Determine the translation from block to frame. blockShift = 0; @@ -203,10 +223,12 @@ CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader) u64 lastIndexPos = index[indexSize - 1] & 0x7FFFFFFF; u64 expectedFileSize = lastIndexPos << indexShift; if (expectedFileSize > fileSize) { - ERROR_LOG(Log::Loader, "Expected CSO to at least be %lld bytes, but file is %lld bytes. File: '%s'", - expectedFileSize, fileSize, fileLoader->GetPath().c_str()); - NotifyReadError(); + errorString_ = StringFromFormat("Expected CSO to at least be %lld bytes, but file is %lld bytes", expectedFileSize, fileSize); + return; } + + // all ok. + _dbg_assert_(errorString_.empty()); } CISOFileBlockDevice::~CISOFileBlockDevice() @@ -389,7 +411,8 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader) fileLoader_->ReadAt(0x24, 1, 4, &psarOffset); size_t readSize = fileLoader_->ReadAt(psarOffset, 1, 256, &np_header); if (readSize != 256){ - ERROR_LOG(Log::Loader, "Invalid NPUMDIMG header!"); + errorString_ = "Invalid NPUMDIMG header!"; + return; } u32 psar_id; @@ -400,6 +423,7 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader) if (psar_id == 'SISP') { lbaSize_ = 0; // Mark invalid ERROR_LOG(Log::Loader, "PSX not supported! Should have been caught earlier."); + errorString_ = "PSX ISOs not supported!"; return; } @@ -432,8 +456,7 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader) // When we remove the above assert, let's just try to survive. if (blockLBAs_ > 4096) { - ERROR_LOG(Log::Loader, "Bad blockLBAs in header: %08x (%s) psar: %s", blockLBAs_, fileLoader->GetPath().ToVisualString().c_str(), psarStr); - // We'll end up displaying an error message since ReadBlock will fail. + errorString_ = StringFromFormat("Bad blockLBAs in header: %08x (%s) psar: %s", blockLBAs_, fileLoader->GetPath().ToVisualString().c_str(), psarStr); return; } @@ -450,7 +473,8 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader) readSize = fileLoader_->ReadAt(psarOffset + tableOffset_, 1, tableSize_, table_); if (readSize != tableSize_){ - ERROR_LOG(Log::Loader, "Invalid NPUMDIMG table!"); + errorString_ = "Invalid NPUMDIMG table!"; + return; } u32 *p = (u32*)table_; @@ -468,6 +492,7 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader) } currentBlock_ = -1; + _dbg_assert_(errorString_.empty()); } NPDRMDemoBlockDevice::~NPDRMDemoBlockDevice() { @@ -654,8 +679,7 @@ CHDFileBlockDevice::CHDFileBlockDevice(FileLoader *fileLoader) chd_file *file = nullptr; chd_error err = chd_open_core_file(&core_file_->core, CHD_OPEN_READ, NULL, &file); if (err != CHDERR_NONE) { - ERROR_LOG(Log::Loader, "Error loading CHD '%s': %s", paths[depth].c_str(), chd_error_string(err)); - NotifyReadError(); + errorString_ = StringFromFormat("CHD error: %s", paths[depth].c_str(), chd_error_string(err)); return; } @@ -666,6 +690,8 @@ CHDFileBlockDevice::CHDFileBlockDevice(FileLoader *fileLoader) currentHunk = -1; blocksPerHunk = impl_->header->hunkbytes / impl_->header->unitbytes; numBlocks = impl_->header->unitcount; + + _dbg_assert_(errorString_.empty()); } CHDFileBlockDevice::~CHDFileBlockDevice() { diff --git a/Core/FileSystems/BlockDevices.h b/Core/FileSystems/BlockDevices.h index aaa985b700f8..a8ca18480c90 100644 --- a/Core/FileSystems/BlockDevices.h +++ b/Core/FileSystems/BlockDevices.h @@ -55,9 +55,14 @@ class BlockDevice { void NotifyReadError(); + bool IsOK() const { return errorString_.empty(); } + const std::string &ErrorString() { return errorString_; } + protected: FileLoader *fileLoader_; bool reportedError_ = false; + + std::string errorString_; }; class CISOFileBlockDevice : public BlockDevice { @@ -163,4 +168,4 @@ class CHDFileBlockDevice : public BlockDevice { u32 numBlocks = 0; }; -BlockDevice *constructBlockDevice(FileLoader *fileLoader); +BlockDevice *ConstructBlockDevice(FileLoader *fileLoader, std::string *errorString); diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index 980d41fff430..a656724b33a1 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -305,8 +305,8 @@ bool UmdReplace(const Path &filepath, FileLoader **fileLoader, std::string &erro case IdentifiedFileType::PSP_ISO: case IdentifiedFileType::PSP_ISO_NP: case IdentifiedFileType::PSP_DISC_DIRECTORY: - if (!MountGameISO(loadedFile)) { - error = "mounting the new ISO failed"; + if (!MountGameISO(loadedFile, &error)) { + error = "mounting the replaced ISO failed: " + error; return false; } break; diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index ff207ebc63d0..8726c3827cde 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -60,7 +60,7 @@ static void UseLargeMem(int memsize) { } } -bool MountGameISO(FileLoader *fileLoader) { +bool MountGameISO(FileLoader *fileLoader, std::string *errorString) { std::shared_ptr fileSystem; std::shared_ptr blockSystem; @@ -68,7 +68,7 @@ bool MountGameISO(FileLoader *fileLoader) { fileSystem = std::make_shared(&pspFileSystem, fileLoader->GetPath()); blockSystem = fileSystem; } else { - auto bd = constructBlockDevice(fileLoader); + auto bd = ConstructBlockDevice(fileLoader, errorString); if (!bd) { // Can only fail if the ISO is bad. return false; @@ -297,14 +297,16 @@ static Path NormalizePath(const Path &path) { bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) { // This is really just for headless, might need tweaking later. if (PSP_CoreParameter().mountIsoLoader != nullptr) { - auto bd = constructBlockDevice(PSP_CoreParameter().mountIsoLoader); - if (bd != NULL) { + auto bd = ConstructBlockDevice(PSP_CoreParameter().mountIsoLoader, error_string); + if (bd) { auto umd2 = std::make_shared(&pspFileSystem, bd); auto blockSystem = std::make_shared(umd2); pspFileSystem.Mount("umd1:", blockSystem); pspFileSystem.Mount("disc0:", umd2); pspFileSystem.Mount("umd:", blockSystem); + } else { + ERROR_LOG(Log::Loader, "mountIso failed: %s", error_string->c_str()); } } diff --git a/Core/PSPLoaders.h b/Core/PSPLoaders.h index d00752c56331..5bed16454cbc 100644 --- a/Core/PSPLoaders.h +++ b/Core/PSPLoaders.h @@ -25,9 +25,7 @@ bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string); bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string); bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string); -bool MountGameISO(FileLoader *fileLoader); +bool MountGameISO(FileLoader *fileLoader, std::string *errorString); bool LoadParamSFOFromDisc(); bool LoadParamSFOFromPBP(FileLoader *fileLoader); void InitMemorySizeForGame(); - -void PSPLoaders_Shutdown(); diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 8a0c5fee24cf..8a20ccd6eda8 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -135,11 +135,15 @@ namespace Reporting AndroidJNIThreadContext jniContext; FileLoader *fileLoader = ResolveFileLoaderTarget(ConstructFileLoader(crcFilename)); - BlockDevice *blockDevice = constructBlockDevice(fileLoader); + + std::string errorString; + BlockDevice *blockDevice = ConstructBlockDevice(fileLoader, &errorString); u32 crc = 0; if (blockDevice) { crc = CalculateCRC(blockDevice, &crcCancel); + } else { + ERROR_LOG(Log::Loader, "Failed to read from block device for CRC: %s", errorString.c_str()); } delete blockDevice; diff --git a/Core/RetroAchievements.cpp b/Core/RetroAchievements.cpp index 42ab83a9a254..4d5017876ea1 100644 --- a/Core/RetroAchievements.cpp +++ b/Core/RetroAchievements.cpp @@ -1037,9 +1037,10 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad // // TODO: Fish the block device out of the loading process somewhere else. Though, probably easier to just do it here, // we need a temporary blockdevice anyway since it gets consumed by ComputePSPISOHash. - BlockDevice *blockDevice(constructBlockDevice(fileLoader)); + std::string errorString; + BlockDevice *blockDevice(ConstructBlockDevice(fileLoader, &errorString)); if (!blockDevice) { - ERROR_LOG(Log::Achievements, "Failed to construct block device for '%s' - can't identify", path.c_str()); + ERROR_LOG(Log::Achievements, "Failed to construct block device for '%s' - can't identify: %s", path.c_str(), errorString.c_str()); g_isIdentifying = false; return; } @@ -1100,9 +1101,10 @@ void ChangeUMD(const Path &path, FileLoader *fileLoader) { return; } - BlockDevice *blockDevice = constructBlockDevice(fileLoader); + std::string errorString; + BlockDevice *blockDevice = ConstructBlockDevice(fileLoader, &errorString); if (!blockDevice) { - ERROR_LOG(Log::Achievements, "Failed to construct block device for '%s' - can't identify", path.c_str()); + ERROR_LOG(Log::Achievements, "Failed to construct block device for '%s' - can't identify: %s", path.c_str(), errorString.c_str()); return; } diff --git a/Core/System.cpp b/Core/System.cpp index 9d6a63b68839..ce6d64fa13f1 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -282,8 +282,8 @@ static bool CPU_Init(FileLoader *fileLoader, IdentifiedFileType type, std::strin case IdentifiedFileType::PSP_ISO_NP: case IdentifiedFileType::PSP_DISC_DIRECTORY: // Doesn't seem to take ownership of fileLoader? - if (!MountGameISO(fileLoader)) { - *errorString = "Failed to mount ISO file - invalid format?"; + if (!MountGameISO(fileLoader, errorString)) { + *errorString = "Failed to mount ISO file: " + *errorString; return false; } if (LoadParamSFOFromDisc()) { diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index e3a74abcc22f..4c6313f6da25 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -421,7 +421,8 @@ std::string GameManager::GetPBPGameID(FileLoader *loader) const { std::string GameManager::GetISOGameID(FileLoader *loader) const { SequentialHandleAllocator handles; - BlockDevice *bd = constructBlockDevice(loader); + std::string errorString; + BlockDevice *bd = ConstructBlockDevice(loader, &errorString); if (!bd) { return ""; } diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 64cf61b2411a..73f1e071a818 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -198,7 +198,8 @@ u64 GameInfo::GetSizeUncompressedInBytes() { return File::ComputeRecursiveDirectorySize(GetFileLoader()->GetPath()); default: { - BlockDevice *blockDevice = constructBlockDevice(GetFileLoader().get()); + std::string errorString; + BlockDevice *blockDevice = ConstructBlockDevice(GetFileLoader().get(), &errorString); if (blockDevice) { u64 size = blockDevice->GetUncompressedSize(); delete blockDevice; @@ -762,9 +763,9 @@ class GameInfoWorkItem : public Task { info_->MarkReadyNoLock(flags_); return; } - BlockDevice *bd = constructBlockDevice(info_->GetFileLoader().get()); + BlockDevice *bd = ConstructBlockDevice(info_->GetFileLoader().get(), &errorString); if (!bd) { - ERROR_LOG(Log::Loader, "Failed constructing block device for ISO %s", info_->GetFilePath().ToVisualString().c_str()); + ERROR_LOG(Log::Loader, "Failed constructing block device for ISO %s: %s", info_->GetFilePath().ToVisualString().c_str(), errorString.c_str()); std::unique_lock lock(info_->lock); info_->MarkReadyNoLock(flags_); return;