mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
Merge pull request #21463 from hrydgard/misc
Add a new file dumping setting to dump the raw ISO file from NPDRM-packed demos
This commit is contained in:
15 files changed
+101
-37
No files matched your search
@@ -224,6 +224,7 @@ enum class DumpFileType {
|
||||
EBOOT = (1 << 0),
|
||||
PRX = (1 << 1),
|
||||
Atrac3 = (1 << 2),
|
||||
PBP_ISO = (1 << 3),
|
||||
};
|
||||
ENUM_CLASS_BITOPS(DumpFileType);
|
||||
|
||||
|
||||
@@ -78,7 +78,6 @@ LocalFileLoader::LocalFileLoader(const Path &filename)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(HAVE_LIBRETRO_VFS)
|
||||
file_ = File::OpenCFile(filename, "rb");
|
||||
if (!file_) {
|
||||
|
||||
@@ -66,8 +66,9 @@ BlockDevice *ConstructBlockDevice(FileLoader *fileLoader, std::string *errorStri
|
||||
} else if (!memcmp(buffer, "\x00PBP", 4)) {
|
||||
uint32_t psarOffset = 0;
|
||||
size = fileLoader->ReadAt(0x24, 1, 4, &psarOffset);
|
||||
if (size == 4 && psarOffset < fileLoader->FileSize())
|
||||
if (size == 4 && psarOffset < fileLoader->FileSize()) {
|
||||
device = new NPDRMDemoBlockDevice(fileLoader);
|
||||
}
|
||||
} else if (!memcmp(buffer, "MComprHD", 8)) {
|
||||
device = new CHDFileBlockDevice(fileLoader);
|
||||
}
|
||||
|
||||
@@ -26,12 +26,15 @@
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
#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<BlockDevice> GetBlockDevice() { return std::shared_ptr<BlockDevice>(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ struct VolDescriptor {
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
ISOFileSystem::ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice) {
|
||||
ISOFileSystem::ISOFileSystem(IHandleAllocator *_hAlloc, std::shared_ptr<BlockDevice> _blockDevice) {
|
||||
blockDevice = _blockDevice;
|
||||
hAlloc = _hAlloc;
|
||||
|
||||
@@ -173,7 +173,6 @@ ISOFileSystem::ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevic
|
||||
}
|
||||
|
||||
ISOFileSystem::~ISOFileSystem() {
|
||||
delete blockDevice;
|
||||
delete treeroot;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ bool parseLBN(const std::string &filename, u32 *sectorStart, u32 *readSize);
|
||||
|
||||
class ISOFileSystem : public IFileSystem {
|
||||
public:
|
||||
ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice);
|
||||
ISOFileSystem(IHandleAllocator *_hAlloc, std::shared_ptr<BlockDevice> _blockDevice);
|
||||
~ISOFileSystem();
|
||||
|
||||
void DoState(PointerWrap &p) override;
|
||||
@@ -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<BlockDevice> GetBlockDevice() override { return blockDevice; }
|
||||
private:
|
||||
struct TreeEntry {
|
||||
~TreeEntry();
|
||||
@@ -92,7 +93,7 @@ private:
|
||||
EntryMap entries;
|
||||
IHandleAllocator *hAlloc;
|
||||
TreeEntry *treeroot;
|
||||
BlockDevice *blockDevice;
|
||||
std::shared_ptr<BlockDevice> blockDevice;
|
||||
mutable u32 lastReadBlock_;
|
||||
|
||||
TreeEntry entireISO;
|
||||
@@ -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<BlockDevice> GetBlockDevice() { return isoFileSystem_->GetBlockDevice(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<IFileSystem> isoFileSystem_;
|
||||
|
||||
+21
-21
@@ -82,22 +82,8 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin
|
||||
|
||||
std::string extension = fileLoader->GetFileExtension();
|
||||
|
||||
bool isDiscImage = false;
|
||||
|
||||
if (extension == ".iso" || extension == ".cso" || extension == ".chd") {
|
||||
isDiscImage = true;
|
||||
} else if (extension == ".ppst") {
|
||||
return IdentifiedFileType::PPSSPP_SAVESTATE;
|
||||
} else if (extension == ".ppdmp") {
|
||||
char data[8]{};
|
||||
fileLoader->ReadAt(0, 8, data);
|
||||
if (memcmp(data, "PPSSPPGE", 8) == 0) {
|
||||
return IdentifiedFileType::PPSSPP_GE_DUMP;
|
||||
}
|
||||
}
|
||||
|
||||
// First, check if it's a directory with an EBOOT.PBP in it.
|
||||
if (!isDiscImage && fileLoader->IsDirectory()) {
|
||||
if (fileLoader->IsDirectory()) {
|
||||
Path filename = fileLoader->GetPath();
|
||||
if (filename.size() > 4) {
|
||||
// Check for existence of EBOOT.PBP, as required for "Directory games".
|
||||
@@ -119,13 +105,26 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin
|
||||
return IdentifiedFileType::NORMAL_DIRECTORY;
|
||||
}
|
||||
|
||||
bool isDiscImage = false;
|
||||
if (extension == ".iso" || extension == ".cso" || extension == ".chd") {
|
||||
isDiscImage = true;
|
||||
} else if (extension == ".ppst") {
|
||||
return IdentifiedFileType::PPSSPP_SAVESTATE;
|
||||
} else if (extension == ".ppdmp") {
|
||||
char data[8]{};
|
||||
fileLoader->ReadAt(0, 8, data);
|
||||
if (memcmp(data, "PPSSPPGE", 8) == 0) {
|
||||
return IdentifiedFileType::PPSSPP_GE_DUMP;
|
||||
}
|
||||
}
|
||||
|
||||
// OK, quick methods of identification for common types failed. Moving on to more expensive methods,
|
||||
// starting by reading the first few bytes.
|
||||
// This can be necessary for weird Android content storage path types, see issue #17462
|
||||
if (isDiscImage || fileLoader->FileSize() >= 0x8800) {
|
||||
// Do the quick check for PSP ISOs here.
|
||||
std::string bdError;
|
||||
std::unique_ptr<BlockDevice> bd(ConstructBlockDevice(fileLoader, &bdError));
|
||||
std::shared_ptr<BlockDevice> bd(ConstructBlockDevice(fileLoader, &bdError));
|
||||
if (bd) {
|
||||
u8 block16[2048]{};
|
||||
bd->ReadBlock(16, (u8 *)block16);
|
||||
@@ -135,12 +134,12 @@ 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.
|
||||
SequentialHandleAllocator hAlloc;
|
||||
ISOFileSystem umd(&hAlloc, bd.release());
|
||||
ISOFileSystem umd(&hAlloc, bd);
|
||||
if (umd.GetFileInfo("/PSP_GAME").exists) {
|
||||
INFO_LOG(Log::Loader, "Found an UMD VIDEO disc with game data. Treating as game.");
|
||||
*errorString = "UMD Video with PSP GAME data";
|
||||
@@ -163,10 +162,10 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader, std::string *errorStrin
|
||||
} else {
|
||||
// Let's go check for PSP game data.
|
||||
SequentialHandleAllocator hAlloc;
|
||||
ISOFileSystem umd(&hAlloc, bd.release());
|
||||
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());
|
||||
@@ -240,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+43
-3
@@ -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 <thread>
|
||||
|
||||
#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<BlockDevice> bd, Path destPath, std::string title) {
|
||||
NPDRMDemoBlockDevice *npdrmDemoBD = dynamic_cast<NPDRMDemoBlockDevice *>(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<u8> 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<IFileSystem> fileSystem;
|
||||
std::shared_ptr<IFileSystem> blockSystem;
|
||||
@@ -68,7 +108,7 @@ bool MountGameISO(FileLoader *fileLoader, std::string *errorString) {
|
||||
fileSystem = std::make_shared<VirtualDiscFileSystem>(&pspFileSystem, fileLoader->GetPath());
|
||||
blockSystem = fileSystem;
|
||||
} else {
|
||||
auto bd = ConstructBlockDevice(fileLoader, errorString);
|
||||
std::shared_ptr<BlockDevice> bd(ConstructBlockDevice(fileLoader, errorString));
|
||||
if (!bd) {
|
||||
// Can only fail if the ISO is bad.
|
||||
return false;
|
||||
@@ -302,7 +342,7 @@ static Path NormalizePath(const Path &path) {
|
||||
bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string_view discId, 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, error_string);
|
||||
std::shared_ptr<BlockDevice> bd(ConstructBlockDevice(PSP_CoreParameter().mountIsoLoader, error_string));
|
||||
if (bd) {
|
||||
auto umd2 = std::make_shared<ISOFileSystem>(&pspFileSystem, bd);
|
||||
auto blockSystem = std::make_shared<ISOBlockSystem>(umd2);
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
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<BlockDevice> bd, Path destPath, std::string title);
|
||||
@@ -96,7 +96,7 @@ static std::string FormatRCheevosMD5(uint8_t digest[16]) {
|
||||
|
||||
// Consumes the blockDevice.
|
||||
// If failed, returns an empty string, otherwise a 32-character string with the hash in hex format.
|
||||
static std::string ComputePSPISOHash(BlockDevice *blockDevice) {
|
||||
static std::string ComputePSPISOHash(std::shared_ptr<BlockDevice> blockDevice) {
|
||||
md5_context md5;
|
||||
ppsspp_md5_starts(&md5);
|
||||
|
||||
@@ -1068,7 +1068,7 @@ 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.
|
||||
std::string errorString;
|
||||
BlockDevice *blockDevice(ConstructBlockDevice(fileLoader, &errorString));
|
||||
std::shared_ptr<BlockDevice> blockDevice(ConstructBlockDevice(fileLoader, &errorString));
|
||||
if (!blockDevice) {
|
||||
ERROR_LOG(Log::Achievements, "Failed to construct block device for '%s' - can't identify: %s", path.c_str(), errorString.c_str());
|
||||
g_isIdentifying = false;
|
||||
@@ -1132,7 +1132,7 @@ void ChangeUMD(const Path &path, FileLoader *fileLoader) {
|
||||
}
|
||||
|
||||
std::string errorString;
|
||||
BlockDevice *blockDevice = ConstructBlockDevice(fileLoader, &errorString);
|
||||
std::shared_ptr<BlockDevice> blockDevice(ConstructBlockDevice(fileLoader, &errorString));
|
||||
if (!blockDevice) {
|
||||
ERROR_LOG(Log::Achievements, "Failed to construct block device for '%s' - can't identify: %s", path.c_str(), errorString.c_str());
|
||||
return;
|
||||
|
||||
+15
-1
@@ -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<BlockDevice> 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)) {
|
||||
|
||||
@@ -448,7 +448,7 @@ std::string GameManager::GetPBPGameID(FileLoader *loader) const {
|
||||
std::string GameManager::GetISOGameID(FileLoader *loader) const {
|
||||
SequentialHandleAllocator handles;
|
||||
std::string errorString;
|
||||
BlockDevice *bd = ConstructBlockDevice(loader, &errorString);
|
||||
std::shared_ptr<BlockDevice> bd(ConstructBlockDevice(loader, &errorString));
|
||||
if (!bd) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
private:
|
||||
std::string editValue_;
|
||||
std::string *outEditValue_;
|
||||
bool hasRelay_ = true;
|
||||
bool hasRelay_ = false;
|
||||
};
|
||||
|
||||
static UI::View *CreateLinkButton(std::string url) {
|
||||
|
||||
@@ -268,6 +268,7 @@ void DeveloperToolsScreen::CreateDumpFileTab(UI::LinearLayout *list) {
|
||||
list->Add(new BitCheckBox(&g_Config.iDumpFileTypes, (int)DumpFileType::EBOOT, dev->T("Dump Decrypted Eboot", "Dump Decrypted EBOOT.BIN (If Encrypted) When Booting Game")));
|
||||
list->Add(new BitCheckBox(&g_Config.iDumpFileTypes, (int)DumpFileType::PRX, dev->T("PRX")));
|
||||
list->Add(new BitCheckBox(&g_Config.iDumpFileTypes, (int)DumpFileType::Atrac3, dev->T("Atrac3/3+")));
|
||||
list->Add(new BitCheckBox(&g_Config.iDumpFileTypes, (int)DumpFileType::PBP_ISO, dev->T("ISO from PBP")));
|
||||
}
|
||||
|
||||
void DeveloperToolsScreen::CreateHLETab(UI::LinearLayout *list) {
|
||||
|
||||
@@ -813,7 +813,7 @@ handleELF:
|
||||
info_->MarkReadyNoLock(flags_);
|
||||
return;
|
||||
}
|
||||
BlockDevice *bd = ConstructBlockDevice(info_->GetFileLoader().get(), &errorString);
|
||||
std::shared_ptr<BlockDevice> bd(ConstructBlockDevice(info_->GetFileLoader().get(), &errorString));
|
||||
if (!bd) {
|
||||
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);
|
||||
|
||||
Reference in new issue
Block a user