Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 51 additions & 25 deletions Core/FileSystems/BlockDevices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -35,36 +36,52 @@ 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;
}

char buffer[8]{};
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() {
Expand All @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand All @@ -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_;
Expand All @@ -468,6 +492,7 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader)
}

currentBlock_ = -1;
_dbg_assert_(errorString_.empty());
}

NPDRMDemoBlockDevice::~NPDRMDemoBlockDevice() {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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() {
Expand Down
7 changes: 6 additions & 1 deletion Core/FileSystems/BlockDevices.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -163,4 +168,4 @@ class CHDFileBlockDevice : public BlockDevice {
u32 numBlocks = 0;
};

BlockDevice *constructBlockDevice(FileLoader *fileLoader);
BlockDevice *ConstructBlockDevice(FileLoader *fileLoader, std::string *errorString);
4 changes: 2 additions & 2 deletions Core/Loaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 6 additions & 4 deletions Core/PSPLoaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ static void UseLargeMem(int memsize) {
}
}

bool MountGameISO(FileLoader *fileLoader) {
bool MountGameISO(FileLoader *fileLoader, std::string *errorString) {
std::shared_ptr<IFileSystem> fileSystem;
std::shared_ptr<IFileSystem> blockSystem;

if (fileLoader->IsDirectory()) {
fileSystem = std::make_shared<VirtualDiscFileSystem>(&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;
Expand Down Expand Up @@ -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<ISOFileSystem>(&pspFileSystem, bd);
auto blockSystem = std::make_shared<ISOBlockSystem>(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());
}
}

Expand Down
4 changes: 1 addition & 3 deletions Core/PSPLoaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
6 changes: 5 additions & 1 deletion Core/Reporting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 6 additions & 4 deletions Core/RetroAchievements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
4 changes: 2 additions & 2 deletions Core/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
3 changes: 2 additions & 1 deletion Core/Util/GameManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 "";
}
Expand Down
7 changes: 4 additions & 3 deletions UI/GameInfoCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<std::mutex> lock(info_->lock);
info_->MarkReadyNoLock(flags_);
return;
Expand Down
Loading