From 7d114eb29bac533d79ce4a361a6942cf1db3d3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 29 Dec 2023 13:21:55 +0100 Subject: [PATCH] Remote ISO: Add working support for streaming CHD files over the network --- Core/FileSystems/BlockDevices.cpp | 72 ++++++++++++++++++++----------- Core/FileSystems/BlockDevices.h | 3 ++ Core/WebServer.cpp | 4 +- UI/RemoteISOScreen.cpp | 2 +- 4 files changed, 53 insertions(+), 28 deletions(-) diff --git a/Core/FileSystems/BlockDevices.cpp b/Core/FileSystems/BlockDevices.cpp index e0f1847979d9..3ada5b861cdd 100644 --- a/Core/FileSystems/BlockDevices.cpp +++ b/Core/FileSystems/BlockDevices.cpp @@ -525,6 +525,11 @@ struct CHDImpl { const chd_header *header = nullptr; }; +struct ExtendedCoreFile { + core_file core; // Must be the first struct member, for some tricky pointer casts. + uint64_t seekPos; +}; + CHDFileBlockDevice::CHDFileBlockDevice(FileLoader *fileLoader) : BlockDevice(fileLoader), impl_(new CHDImpl()) { @@ -532,6 +537,46 @@ CHDFileBlockDevice::CHDFileBlockDevice(FileLoader *fileLoader) paths[0] = fileLoader->GetPath(); int depth = 0; + core_file_ = new ExtendedCoreFile(); + core_file_->core.argp = fileLoader; + core_file_->core.fsize = [](core_file *file) -> uint64_t { + FileLoader *loader = (FileLoader *)file->argp; + return loader->FileSize(); + }; + core_file_->core.fseek = [](core_file *file, int64_t offset, int seekType) -> int { + ExtendedCoreFile *coreFile = (ExtendedCoreFile *)file; + switch (seekType) { + case SEEK_SET: + coreFile->seekPos = offset; + break; + case SEEK_CUR: + coreFile->seekPos += offset; + break; + case SEEK_END: + { + FileLoader *loader = (FileLoader *)file->argp; + coreFile->seekPos = loader->FileSize() + offset; + break; + } + default: + break; + } + return 0; + }; + core_file_->core.fread = [](void *out_data, size_t size, size_t count, core_file *file) { + ExtendedCoreFile *coreFile = (ExtendedCoreFile *)file; + FileLoader *loader = (FileLoader *)file->argp; + uint64_t totalSize = size * count; + loader->ReadAt(coreFile->seekPos, totalSize, out_data); + coreFile->seekPos += totalSize; + return size * count; + }; + core_file_->core.fclose = [](core_file *file) { + ExtendedCoreFile *coreFile = (ExtendedCoreFile *)file; + delete coreFile; + return 0; + }; + /* // TODO: Support parent/child CHD files. @@ -582,36 +627,15 @@ CHDFileBlockDevice::CHDFileBlockDevice(FileLoader *fileLoader) } */ - chd_file *parent = NULL; - chd_file *child = NULL; - - FILE *file = File::OpenCFile(paths[depth], "rb"); - if (!file) { - ERROR_LOG(LOADER, "Error opening CHD file '%s'", paths[depth].c_str()); - NotifyReadError(); - return; - } - chd_error err = chd_open_file(file, CHD_OPEN_READ, NULL, &child); + 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(LOADER, "Error loading CHD '%s': %s", paths[depth].c_str(), chd_error_string(err)); NotifyReadError(); return; } - // We won't enter this loop until we enable the parent/child stuff above. - for (int d = depth - 1; d >= 0; d--) { - parent = child; - child = NULL; - // TODO: Use chd_open_file - err = chd_open(paths[d].c_str(), CHD_OPEN_READ, parent, &child); - if (err != CHDERR_NONE) { - ERROR_LOG(LOADER, "Error loading CHD '%s': %s", paths[d].c_str(), chd_error_string(err)); - NotifyReadError(); - return; - } - } - impl_->chd = child; - + impl_->chd = file; impl_->header = chd_get_header(impl_->chd); readBuffer = new u8[impl_->header->hunkbytes]; currentHunk = -1; diff --git a/Core/FileSystems/BlockDevices.h b/Core/FileSystems/BlockDevices.h index e5f01767c91a..295f29a57601 100644 --- a/Core/FileSystems/BlockDevices.h +++ b/Core/FileSystems/BlockDevices.h @@ -136,6 +136,8 @@ class NPDRMDemoBlockDevice : public BlockDevice { struct CHDImpl; +struct ExtendedCoreFile; + class CHDFileBlockDevice : public BlockDevice { public: CHDFileBlockDevice(FileLoader *fileLoader); @@ -146,6 +148,7 @@ class CHDFileBlockDevice : public BlockDevice { bool IsDisc() const override { return true; } private: + struct ExtendedCoreFile *core_file_ = nullptr; std::unique_ptr impl_; u8 *readBuffer = nullptr; u32 currentHunk = 0; diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp index af465fd1ae28..5960c0f739c6 100644 --- a/Core/WebServer.cpp +++ b/Core/WebServer.cpp @@ -125,9 +125,7 @@ static bool RegisterServer(int port) { bool RemoteISOFileSupported(const std::string &filename) { // Disc-like files. - // NOTE: chd is temporarily disabled until we can make it use the FileLoader instead of - // trying to re-open the file, since otherwise won't work over HTTP. - if (endsWithNoCase(filename, ".cso") || endsWithNoCase(filename, ".iso")) { + if (endsWithNoCase(filename, ".cso") || endsWithNoCase(filename, ".iso") || endsWithNoCase(filename, ".chd")) { return true; } // May work - but won't have supporting files. diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 003119ec1753..1441dd55e0dc 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -252,7 +252,7 @@ static bool LoadGameList(const Path &url, std::vector &games) { std::vector files; browser.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION)); browser.SetRootAlias("ms:", GetSysDirectory(DIRECTORY_MEMSTICK_ROOT).ToVisualString()); - browser.GetListing(files, "iso:cso:pbp:elf:prx:ppdmp:", &scanCancelled); + browser.GetListing(files, "iso:cso:chd:pbp:elf:prx:ppdmp:", &scanCancelled); if (scanCancelled) { return false; }