diff --git a/Core/FileSystems/FileSystem.h b/Core/FileSystems/FileSystem.h index 90cae79131..20cc3b0149 100644 --- a/Core/FileSystems/FileSystem.h +++ b/Core/FileSystems/FileSystem.h @@ -26,12 +26,15 @@ #include #include #include +#include #include "Common.h" #include "Common/File/Path.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/ErrorCodes.h" +class BlockDevice; + enum FileAccess { FILEACCESS_NONE = 0, FILEACCESS_READ = 1, @@ -155,6 +158,7 @@ public: virtual u64 FreeDiskSpace(const std::string &path) = 0; virtual bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) = 0; virtual void Describe(char *buf, size_t size) const = 0; + virtual std::shared_ptr GetBlockDevice() { return std::shared_ptr(); } }; diff --git a/Core/FileSystems/ISOFileSystem.h b/Core/FileSystems/ISOFileSystem.h index 6c51b42ddb..f1e68ee361 100644 --- a/Core/FileSystems/ISOFileSystem.h +++ b/Core/FileSystems/ISOFileSystem.h @@ -57,6 +57,7 @@ public: bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } void Describe(char *buf, size_t size) const override { snprintf(buf, size, "ISO"); } // TODO: Ask the fileLoader about the origins + std::shared_ptr GetBlockDevice() override { return blockDevice; } private: struct TreeEntry { ~TreeEntry(); @@ -166,6 +167,7 @@ public: bool ComputeRecursiveDirSizeIfFast(const std::string &path, int64_t *size) override { return false; } void Describe(char *buf, size_t size) const override { snprintf(buf, size, "ISOBlock"); } + std::shared_ptr GetBlockDevice() { return isoFileSystem_->GetBlockDevice(); } private: std::shared_ptr isoFileSystem_; diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index e2372b595c..041070e7b9 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -134,7 +134,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin // 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)) { // Yes, a known proper PSP game, let's get it going. - return IdentifiedFileType::PSP_ISO; + return bd->IsDisc() ? IdentifiedFileType::PSP_ISO : IdentifiedFileType::PSP_ISO_NP; } 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. @@ -165,7 +165,7 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin ISOFileSystem umd(&hAlloc, bd); 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; + return bd->IsDisc() ? IdentifiedFileType::PSP_ISO : IdentifiedFileType::PSP_ISO_NP; } INFO_LOG(Log::Loader, "Unknown ISO with unknown system ID: %.32s: %s", pvd.systemId, fileLoader->GetPath().c_str()); @@ -239,8 +239,9 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin paramSFO.ReadSFO(sfoData); // PS1 Eboots are supposed to use "ME" as their PARAM SFO category. // If they don't, and they're still malformed (e.g. PSISOIMG0000 isn't found), there's nothing we can do. - if (paramSFO.GetValueString("CATEGORY") == "ME") + if (paramSFO.GetValueString("CATEGORY") == "ME") { return IdentifiedFileType::PSP_PS1_PBP; + } } } diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index e290a4133b..d2ac9bdcde 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include + #include "Core/Core.h" #include "Common/System/Request.h" @@ -24,6 +26,7 @@ #ifdef _WIN32 #include "Common/CommonWindows.h" #endif +#include "Common/System/OSD.h" #include "Core/ELF/ParamSFO.h" #include "Core/ELF/PBPReader.h" @@ -38,7 +41,7 @@ #include "Core/Loaders.h" #include "Core/MemMap.h" #include "Core/HDRemaster.h" - +#include "Core/Util/PathUtil.h" #include "Core/Config.h" #include "Core/ConfigValues.h" @@ -60,6 +63,43 @@ static void UseLargeMem(int memsize) { } } +void DumpBlockDeviceAsync(std::shared_ptr bd, Path destPath, std::string title) { + NPDRMDemoBlockDevice *npdrmDemoBD = dynamic_cast(bd.get()); + if (npdrmDemoBD) { + INFO_LOG(Log::System, "Dumping NPDRM demo ISO... (%s)", destPath.c_str()); + std::thread dumpThread([bd, title, destPath]() { + File::CreateFullPath(destPath.NavigateUp()); + if (File::Exists(destPath)) { + INFO_LOG(Log::System, "Dump file already exists, skipping: %s", destPath.c_str()); + return; + } + FILE *dest = File::OpenCFile(destPath, "wb"); + if (!dest) { + ERROR_LOG(Log::System, "Failed to open destination for NPDRM demo ISO dump: %s", destPath.c_str()); + return; + } + g_OSD.SetProgressBar("npdrm_dump", title, 0.0f, 1.0f, 0.0f, 0.0f); + int blocks = bd->GetNumBlocks(); + std::vector blockBuf(bd->GetBlockSize()); + for (int i = 0; i < blocks; i++) { + bd->ReadBlock(i, blockBuf.data()); + fwrite(blockBuf.data(), 1, blockBuf.size(), dest); + g_OSD.SetProgressBar("npdrm_dump", title, 0.0f, 1.0f, (float)(i + 1) / blocks, 0.0f); + } + fclose(dest); + g_OSD.RemoveProgressBar("npdrm_dump", true, 1.0f); + g_OSD.Show(OSDType::MESSAGE_SUCCESS, title, GetFriendlyPath(destPath), 5.0f, "npdrm_finished"); + if (System_GetPropertyBool(SYSPROP_CAN_SHOW_FILE)) { + g_OSD.SetClickCallback("npdrm_finished", [destPath]() { + System_ShowFileInFolder(destPath); + }); + } + INFO_LOG(Log::System, "Finished dumping NPDRM demo ISO... (%s)", title.c_str()); + }); + dumpThread.detach(); + } +} + bool MountGameISO(FileLoader *fileLoader, std::string *errorString) { std::shared_ptr fileSystem; std::shared_ptr blockSystem; diff --git a/Core/PSPLoaders.h b/Core/PSPLoaders.h index ef200ee8ef..17e017e49f 100644 --- a/Core/PSPLoaders.h +++ b/Core/PSPLoaders.h @@ -18,8 +18,10 @@ #pragma once #include +#include class FileLoader; +class BlockDevice; bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string); bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string_view discId, std::string *error_string); @@ -29,3 +31,4 @@ bool MountGameISO(FileLoader *fileLoader, std::string *errorString); bool LoadParamSFOFromDisc(); bool LoadParamSFOFromPBP(FileLoader *fileLoader); void InitMemorySizeForGame(); +void DumpBlockDeviceAsync(std::shared_ptr bd, Path destPath, std::string title); diff --git a/Core/System.cpp b/Core/System.cpp index 886cf1fa10..98818875ba 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -66,6 +66,7 @@ #include "Core/FileSystems/MetaFileSystem.h" #include "Core/Loaders.h" #include "Core/PSPLoaders.h" +#include "Core/FileSystems/ISOFileSystem.h" #include "Core/ELF/ParamSFO.h" #include "Core/SaveState.h" #include "Core/Util/RecentFiles.h" @@ -302,7 +303,20 @@ static bool CPU_Init(FileLoader *fileLoader, IdentifiedFileType type, std::strin if (LoadParamSFOFromDisc()) { InitMemorySizeForGame(); } - if (type == IdentifiedFileType::PSP_DISC_DIRECTORY) { + + if (type == IdentifiedFileType::PSP_ISO_NP && ((DumpFileType)g_Config.iDumpFileTypes & DumpFileType::PBP_ISO)) { + // We have to fetch the block device again, because we want to do this after loading PARAM.SFO. + std::string title = SanitizeString(g_paramSFO.GetValueString("TITLE"), StringRestriction::AlphaNumDashUnderscore, 0, 100); + std::string filename = title + "-" + g_paramSFO.GetDiscID() + ".iso"; + Path path = GetSysDirectory(DIRECTORY_DUMP) / filename; + IFileSystem *fs = pspFileSystem.GetSystem("umd0:"); + if (fs) { + std::shared_ptr bd = fs->GetBlockDevice(); + if (bd) { + DumpBlockDeviceAsync(bd, path, title); + } + } + } else if (type == IdentifiedFileType::PSP_DISC_DIRECTORY) { // Check for existence of ppsspp-index.lst - if it exists, the user likely knows what they're doing. // TODO: Better would be to check that it was loaded successfully. if (!File::Exists(g_CoreParameter.fileToStart / INDEX_FILENAME)) {