diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h index edbc68a1f1..e832c33a4b 100644 --- a/Core/CoreParameter.h +++ b/Core/CoreParameter.h @@ -33,7 +33,7 @@ enum GPUCore { struct CoreParameter { - CoreParameter() : collectEmuLog(0), unthrottle(false), updateRecent(true), fpsLimit(0) {} + CoreParameter() : collectEmuLog(0), unthrottle(false), fpsLimit(0), updateRecent(true) {} // 0 = Interpreter // 1 = Jit // 2 = JitIL diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index 91ecbbe0a2..6279f24802 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -164,7 +164,7 @@ inline std::vector makeCodeParts() { std::vector CWCheatEngine::GetCodesList() { std::string line; - char* skip = "//"; + std::string skip = "//"; std::vector codesList; // Read from INI here std::ifstream list(activeCheatFile.c_str()); for (int i = 0; !list.eof(); i ++) { diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index 47b13499d7..0ea66d30a2 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -27,42 +27,60 @@ #include "System.h" // TODO : improve, look in the file more -EmuFileType Identify_File(const char *filename) +EmuFileType Identify_File(std::string &filename) { - //then: easy bulletproof IDs. - FILE *f = fopen(filename, "rb"); - if (!f) - { - //File does not exists + if (filename.size() < 5) { + ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); return FILETYPE_ERROR; } - u32 id; - u32 psar_offset, psar_id; - size_t readSize = fread(&id,4,1,f); - if(readSize != 1) - { + // First, check if it's a directory with an EBOOT.PBP in it. + FileInfo info; + if (!getFileInfo(filename.c_str(), &info)) { + return FILETYPE_ERROR; + } + + if (info.isDirectory) { + FileInfo ebootInfo; + // Check for existence of EBOOT.PBP, as required for "Directory games". + if (getFileInfo((filename + "/EBOOT.PBP").c_str(), &ebootInfo)) { + if (ebootInfo.exists) { + return FILETYPE_PSP_PBP_DIRECTORY; + } + } + } + + FILE *f = fopen(filename.c_str(), "rb"); + if (!f) { + // File does not exists + return FILETYPE_ERROR; + } + + + u32 id; + + size_t readSize = fread(&id, 4, 1, f); + if (readSize != 1) { fclose(f); return FILETYPE_ERROR; } - psar_id = 0; - fseek(f, 0x24, SEEK_SET); - fread(&psar_offset, 4, 1, f); - fseek(f, psar_offset, SEEK_SET); - fread(&psar_id, 4, 1, f); + u32 psar_offset = 0, psar_id = 0; + if (id == 'PBP\x00') { + fseek(f, 0x24, SEEK_SET); + fread(&psar_offset, 4, 1, f); + fseek(f, psar_offset, SEEK_SET); + fread(&psar_id, 4, 1, f); + } fclose(f); - if (strlen(filename) < 5) { - ERROR_LOG(LOADER, "invalid filename %s", filename); - } - const char *extension = filename + strlen(filename) - 4; + std::string extension = filename.substr(filename.size() - 4); if (id == 'FLE\x7F') { - if (!strcasecmp(extension, ".plf") || strstr(filename,"BOOT.BIN") || - !strcasecmp(extension, ".elf") || !strcasecmp(extension,".prx") ) + if (!strcasecmp(extension.c_str(), ".plf") || strstr(filename.c_str(),"BOOT.BIN") || + !strcasecmp(extension.c_str(), ".elf") || !strcasecmp(extension.c_str(), ".prx") ) { return FILETYPE_PSP_ELF; } @@ -71,26 +89,36 @@ EmuFileType Identify_File(const char *filename) } else if (id == 'PBP\x00') { - if(psar_id == 'MUPN') + if (psar_id == 'MUPN') { return FILETYPE_PSP_ISO_NP; - else - return FILETYPE_PSP_PBP; + } else { + // Let's check if we got pointed to a PBP within such a directory. + // If so we just move up and return the directory itself as the game. + std::string path = getDir(filename); + // If loading from memstick... + size_t pos = path.find("/PSP/GAME/"); + if (pos != std::string::npos) { + filename = path; + return FILETYPE_PSP_PBP_DIRECTORY; + } + } } else { - if (!strcasecmp(extension,".pbp")) + if (!strcasecmp(extension.c_str(),".pbp")) { + ERROR_LOG(LOADER, "A PBP with the wrong magic number?"); return FILETYPE_PSP_PBP; } - else if (!strcasecmp(extension,".iso")) + else if (!strcasecmp(extension.c_str(),".iso")) { return FILETYPE_PSP_ISO; } - else if (!strcasecmp(extension,".cso")) + else if (!strcasecmp(extension.c_str(),".cso")) { return FILETYPE_PSP_ISO; } - else if (!strcasecmp(extension,".bin")) + else if (!strcasecmp(extension.c_str(),".bin")) { return FILETYPE_UNKNOWN_BIN; } @@ -98,30 +126,46 @@ EmuFileType Identify_File(const char *filename) return FILETYPE_UNKNOWN; } -bool LoadFile(const char *filename, std::string *error_string) -{ +bool LoadFile(std::string &filename, std::string *error_string) { INFO_LOG(LOADER,"Identifying file..."); - switch (Identify_File(filename)) - { + // Note that this can modify filename! + switch (Identify_File(filename)) { + case FILETYPE_PSP_PBP_DIRECTORY: + { + std::string ebootFilename = filename + "/EBOOT.PBP"; + FileInfo fileInfo; + getFileInfo((filename + "/EBOOT.PBP").c_str(), &fileInfo); + + if (fileInfo.exists) { + INFO_LOG(LOADER, "File is a PBP in a directory!"); + std::string path = filename; + size_t pos = path.find("/PSP/GAME/"); + if (pos != std::string::npos) + pspFileSystem.SetStartingDirectory("ms0:" + path.substr(pos)); + return Load_PSP_ELF_PBP(ebootFilename.c_str(), error_string); + } else { + *error_string = "No EBOOT.PBP, misidentified game"; + return false; + } + } + case FILETYPE_PSP_PBP: case FILETYPE_PSP_ELF: { - INFO_LOG(LOADER,"File is an ELF!"); - std::string path = getDir(filename); - // If loading from memstick... - size_t pos = path.find("/PSP/GAME/"); - if (pos != std::string::npos) - pspFileSystem.SetStartingDirectory("ms0:" + path.substr(pos)); - return Load_PSP_ELF_PBP(filename, error_string); + INFO_LOG(LOADER,"File is an ELF or loose PBP!"); + return Load_PSP_ELF_PBP(filename.c_str(), error_string); } + case FILETYPE_PSP_ISO: case FILETYPE_PSP_ISO_NP: pspFileSystem.SetStartingDirectory("disc0:/PSP_GAME/USRDIR"); - return Load_PSP_ISO(filename, error_string); + return Load_PSP_ISO(filename.c_str(), error_string); + case FILETYPE_ERROR: ERROR_LOG(LOADER, "Could not read file"); *error_string = "Error reading file"; break; + case FILETYPE_UNKNOWN_BIN: case FILETYPE_UNKNOWN_ELF: case FILETYPE_UNKNOWN: diff --git a/Core/Loaders.h b/Core/Loaders.h index c295596314..8693f88eb2 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -21,6 +21,8 @@ enum EmuFileType { FILETYPE_ERROR, + FILETYPE_PSP_PBP_DIRECTORY, + FILETYPE_PSP_PBP, FILETYPE_PSP_ELF, FILETYPE_PSP_ISO, @@ -32,6 +34,9 @@ enum EmuFileType FILETYPE_UNKNOWN }; -EmuFileType Identify_File(const char *filename); +// This can modify the string, for example for stripping off the "/EBOOT.PBP" +// for a FILETYPE_PSP_PBP_DIRECTORY. +EmuFileType Identify_File(std::string &str); -bool LoadFile(const char *filename, std::string *error_string); +// Can modify the string filename, as it calls IdentifyFile above. +bool LoadFile(std::string &filename, std::string *error_string); diff --git a/Core/System.cpp b/Core/System.cpp index 53aeeec3ea..dbafe42f57 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -96,8 +96,8 @@ bool PSP_Init(const CoreParameter &coreParam, std::string *error_string) // TODO: Check Game INI here for settings, patches and cheats, and modify coreParameter accordingly - if (!LoadFile(coreParameter.fileToStart.c_str(), error_string)) - { + std::string filename = coreParameter.fileToStart; + if (!LoadFile(filename, error_string)) { pspFileSystem.Shutdown(); CoreTiming::Shutdown(); __KernelShutdown(); @@ -109,7 +109,7 @@ bool PSP_Init(const CoreParameter &coreParam, std::string *error_string) } if (coreParam.updateRecent) - g_Config.AddRecent(coreParameter.fileToStart); + g_Config.AddRecent(filename); // Setup JIT here. if (coreParameter.startPaused) diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 628c9bc9cc..56a7a90e83 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -20,6 +20,7 @@ #include "base/timeutil.h" #include "base/stringutil.h" +#include "file/file_util.h" #include "image/png_load.h" #include "thread/prioritizedworkqueue.h" #include "GameInfoCache.h" @@ -27,8 +28,69 @@ #include "Core/FileSystems/DirectoryFileSystem.h" #include "Core/ELF/PBPReader.h" +#include "Core/Config.h" + GameInfoCache g_gameInfoCache; +bool GameInfo::DeleteGame() { + switch (fileType) { + case FILETYPE_PSP_ISO: + case FILETYPE_PSP_ISO_NP: + // Just delete the one file (TODO: handle two-disk games as well somehow). + deleteFile(fileInfo.fullName.c_str()); + return true; + + case FILETYPE_PSP_PBP_DIRECTORY: + // Recursively deleting directories not yet supported + return false; + + default: + return false; + } +} + +u64 GameInfo::GetGameSizeInBytes() { + switch (fileType) { + case FILETYPE_PSP_PBP_DIRECTORY: + // TODO: Need to recurse here. + return 0; + default: + return fileInfo.size; + } +} + +std::string GameInfo::GetSaveDataDirectory() { + std::string id = paramSFO.GetValueString("ID"); + return g_Config.memCardDirectory + "/PSP/GAME/" + id; +} + +u64 GameInfo::GetSaveDataSizeInBytes() { + std::string saveDataDir = GetSaveDataDirectory(); + + std::vector fileInfo; + getFilesInDir(saveDataDir.c_str(), &fileInfo); + + u64 totalSize = 0; + for (size_t i = 0; i < fileInfo.size(); i++) { + totalSize += fileInfo[i].size; + } + return totalSize; +} + +bool GameInfo::DeleteAllSaveData() { + std::string saveDataDir = GetSaveDataDirectory(); + + std::vector fileInfo; + getFilesInDir(saveDataDir.c_str(), &fileInfo); + + u64 totalSize = 0; + for (size_t i = 0; i < fileInfo.size(); i++) { + deleteFile(fileInfo[i].fullName.c_str()); + } + + deleteDir(saveDataDir.c_str()); + return true; +} static bool ReadFileToString(IFileSystem *fs, const char *filename, std::string *contents, recursive_mutex *mtx) { PSPFileInfo info = fs->GetFileInfo(filename); @@ -61,46 +123,59 @@ public: } virtual void run() { - // A game can be either an UMD or a directory under ms0:/PSP/GAME . - if (startsWith(gamePath_, "ms0:/PSP/GAME")) { + getFileInfo(gamePath_.c_str(), &info_->fileInfo); + if (!info_->fileInfo.exists) return; - // TODO: The case of these extensions is not perfect. - } else if (endsWith(gamePath_, ".PBP")) { - PBPReader pbp(gamePath_.c_str()); - if (!pbp.IsValid()) - return; - info_->fileType = FILETYPE_PSP_PBP; - // First, PARAM.SFO. - size_t sfoSize; - u8 *sfoData = pbp.GetSubFile(PBP_PARAM_SFO, &sfoSize); - { - lock_guard lock(info_->lock); - info_->paramSFO.ReadSFO(sfoData, sfoSize); - info_->title = info_->paramSFO.GetValueString("TITLE"); - } - delete [] sfoData; - // Then, ICON0.PNG. - { - lock_guard lock(info_->lock); - if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) { - pbp.GetSubFileAsString(PBP_ICON0_PNG, &info_->iconTextureData); - } else { - // We should load a default image here. - } - } + std::string filename = gamePath_; + info_->fileType = Identify_File(filename); - if (info_->wantBG) { + switch (info_->fileType) { + case FILETYPE_PSP_PBP: + case FILETYPE_PSP_PBP_DIRECTORY: + { + std::string pbpFile = filename; + if (info_->fileType == FILETYPE_PSP_PBP_DIRECTORY) + pbpFile += "/EBOOT.PBP"; + + PBPReader pbp(pbpFile.c_str()); + if (!pbp.IsValid()) + return; + + // First, PARAM.SFO. + size_t sfoSize; + u8 *sfoData = pbp.GetSubFile(PBP_PARAM_SFO, &sfoSize); { lock_guard lock(info_->lock); - if (pbp.GetSubFileSize(PBP_PIC1_PNG) > 0) - pbp.GetSubFileAsString(PBP_PIC1_PNG, &info_->pic1TextureData); + info_->paramSFO.ReadSFO(sfoData, sfoSize); + info_->title = info_->paramSFO.GetValueString("TITLE"); + } + delete [] sfoData; + + // Then, ICON0.PNG. + { + lock_guard lock(info_->lock); + if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) { + pbp.GetSubFileAsString(PBP_ICON0_PNG, &info_->iconTextureData); + } else { + // We should load a default image here. + } + } + + if (info_->wantBG) { + { + lock_guard lock(info_->lock); + if (pbp.GetSubFileSize(PBP_PIC1_PNG) > 0) + pbp.GetSubFileAsString(PBP_PIC1_PNG, &info_->pic1TextureData); + } } } - } else if (endsWith(gamePath_, ".elf") || endsWith(gamePath_, ".prx")) { - info_->fileType = FILETYPE_PSP_ELF; + case FILETYPE_PSP_ELF: + // An elf on its own has no usable information, no icons, no nothing. return; - } else { + + case FILETYPE_PSP_ISO: + case FILETYPE_PSP_ISO_NP: info_->fileType = FILETYPE_PSP_ISO; SequentialHandleAllocator handles; // Let's assume it's an ISO. diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 75d0dd72c6..cf2745350a 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -21,21 +21,38 @@ #include #include "base/mutex.h" +#include "file/file_util.h" #include "thread/prioritizedworkqueue.h" #include "gfx/texture.h" #include "Core/ELF/ParamSFO.h" #include "Core/Loaders.h" +// A GameInfo holds information about a game, and also lets you do things that the VSH +// does on the PSP, namely checking for and deleting savedata, and similar things. + class GameInfo { public: GameInfo() : fileType(FILETYPE_UNKNOWN), iconTexture(NULL), pic0Texture(NULL), pic1Texture(NULL) {} + + bool DeleteGame(); // Better be sure what you're doing when calling this. + bool DeleteAllSaveData(); + + u64 GetGameSizeInBytes(); + u64 GetSaveDataSizeInBytes(); + + void LoadParamSFO(); + + std::string GetSaveDataDirectory(); + + // Hold this when reading or writing from the GameInfo. // Don't need to hold it when just passing around the pointer, // and obviously also not when creating it and holding the only pointer // to it. recursive_mutex lock; + FileInfo fileInfo; std::string title; // for easy access, also available in paramSFO. EmuFileType fileType; ParamSFOData paramSFO; diff --git a/native b/native index c94767905a..8e5890a7e2 160000 --- a/native +++ b/native @@ -1 +1 @@ -Subproject commit c94767905aa6fc1f0853e052948d2ebc27eb1b9b +Subproject commit 8e5890a7e28af03f237eafaaa25e7a10d16899da diff --git a/pspautotests b/pspautotests index 636e0ff840..d1038e00bd 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 636e0ff8403d4086b9753b3c057d09ba33b70ceb +Subproject commit d1038e00bdcf48e2ab057616bb2ec973980a7b3f