diff --git a/Core/ELF/PBPReader.cpp b/Core/ELF/PBPReader.cpp index 12debe624d26..1eb4f70556f0 100644 --- a/Core/ELF/PBPReader.cpp +++ b/Core/ELF/PBPReader.cpp @@ -21,64 +21,51 @@ #include "Common/Log.h" #include "Common/FileUtil.h" +#include "Core/Loaders.h" #include "Core/ELF/PBPReader.h" -PBPReader::PBPReader(const char *filename) : header_(), isELF_(false) { - file_ = File::OpenCFile(filename, "rb"); - if (!file_) { - ERROR_LOG(LOADER, "Failed to open PBP file %s", filename); +PBPReader::PBPReader(FileLoader *fileLoader) : file_(nullptr), header_(), isELF_(false) { + if (!fileLoader->Exists()) { + ERROR_LOG(LOADER, "Failed to open PBP file %s", fileLoader->Path().c_str()); return; } - fseek(file_, 0, SEEK_END); - fileSize_ = ftell(file_); - fseek(file_, 0, SEEK_SET); - if (fread((char *)&header_, 1, sizeof(header_), file_) != sizeof(header_)) { - ERROR_LOG(LOADER, "PBP is too small to be valid: %s", filename); - fclose(file_); - file_ = nullptr; + fileSize_ = (size_t)fileLoader->FileSize(); + if (fileLoader->ReadAt(0, sizeof(header_), (u8 *)&header_) != sizeof(header_)) { + ERROR_LOG(LOADER, "PBP is too small to be valid: %s", fileLoader->Path().c_str()); return; } if (memcmp(header_.magic, "\0PBP", 4) != 0) { if (memcmp(header_.magic, "\nFLE", 4) != 0) { - DEBUG_LOG(LOADER, "%s: File actually an ELF, not a PBP", filename); + DEBUG_LOG(LOADER, "%s: File actually an ELF, not a PBP", fileLoader->Path().c_str()); isELF_ = true; } else { - ERROR_LOG(LOADER, "Magic number in %s indicated no PBP: %s", filename, header_.magic); + ERROR_LOG(LOADER, "Magic number in %s indicated no PBP: %s", fileLoader->Path().c_str(), header_.magic); } - fclose(file_); - file_ = nullptr; return; } DEBUG_LOG(LOADER, "Loading PBP, version = %08x", header_.version); + file_ = fileLoader; } -u8 *PBPReader::GetSubFile(PBPSubFile file, size_t *outSize) { +bool PBPReader::GetSubFile(PBPSubFile file, std::vector *out) { if (!file_) { - *outSize = 0; - return new u8[0]; + return false; } const size_t expected = GetSubFileSize(file); const u32 off = header_.offsets[(int)file]; - *outSize = expected; - if (fseek(file_, off, SEEK_SET) != 0) { - ERROR_LOG(LOADER, "PBP file offset invalid: %d", off); - *outSize = 0; - return new u8[0]; - } else { - u8 *buffer = new u8[expected]; - size_t bytes = fread(buffer, 1, expected, file_); - if (bytes != expected) { - ERROR_LOG(LOADER, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes); - if (bytes < expected) { - *outSize = bytes; - } + out->resize(expected); + size_t bytes = file_->ReadAt(off, expected, &(*out)[0]); + if (bytes != expected) { + ERROR_LOG(LOADER, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes); + if (bytes < expected) { + out->resize(bytes); } - return buffer; } + return true; } void PBPReader::GetSubFileAsString(PBPSubFile file, std::string *out) { @@ -91,21 +78,16 @@ void PBPReader::GetSubFileAsString(PBPSubFile file, std::string *out) { const u32 off = header_.offsets[(int)file]; out->resize(expected); - if (fseek(file_, off, SEEK_SET) != 0) { - ERROR_LOG(LOADER, "PBP file offset invalid: %d", off); - out->clear(); - } else { - size_t bytes = fread((void *)out->data(), 1, expected, file_); - if (bytes != expected) { - ERROR_LOG(LOADER, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes); - if (bytes < expected) { - out->resize(bytes); - } + size_t bytes = file_->ReadAt(off, expected, (void *)out->data()); + if (bytes != expected) { + ERROR_LOG(LOADER, "PBP file read truncated: %d -> %d", (int)expected, (int)bytes); + if (bytes < expected) { + out->resize(bytes); } } } PBPReader::~PBPReader() { - if (file_) - fclose(file_); + // Does not take ownership. + file_ = nullptr; } diff --git a/Core/ELF/PBPReader.h b/Core/ELF/PBPReader.h index ab68ea73ba4e..de3d714cc3a8 100644 --- a/Core/ELF/PBPReader.h +++ b/Core/ELF/PBPReader.h @@ -37,16 +37,17 @@ struct PBPHeader { u32_le offsets[8]; }; +class FileLoader; + class PBPReader { public: - PBPReader(const char *filename); + PBPReader(FileLoader *fileLoader); ~PBPReader(); - bool IsValid() const { return file_ != 0; } - bool IsELF() const { return file_ == 0 && isELF_; } + bool IsValid() const { return file_ != nullptr; } + bool IsELF() const { return file_ == nullptr && isELF_; } - // Delete the returned buffer with delete []. - u8 *GetSubFile(PBPSubFile file, size_t *outSize); + bool GetSubFile(PBPSubFile file, std::vector *out); void GetSubFileAsString(PBPSubFile file, std::string *out); size_t GetSubFileSize(PBPSubFile file) { @@ -59,7 +60,7 @@ class PBPReader { } private: - FILE *file_; + FileLoader *file_; size_t fileSize_; const PBPHeader header_; bool isELF_; diff --git a/Core/ELF/ParamSFO.cpp b/Core/ELF/ParamSFO.cpp index 4c2b65fa9b93..7d9387a97d49 100644 --- a/Core/ELF/ParamSFO.cpp +++ b/Core/ELF/ParamSFO.cpp @@ -86,6 +86,14 @@ u8* ParamSFOData::GetValueData(std::string key, unsigned int *size) return it->second.u_value; } +std::vector ParamSFOData::GetKeys() { + std::vector result; + for (const auto &pair : values) { + result.push_back(pair.first); + } + return result; +} + // I'm so sorry Ced but this is highly endian unsafe :( bool ParamSFOData::ReadSFO(const u8 *paramsfo, size_t size) { diff --git a/Core/ELF/ParamSFO.h b/Core/ELF/ParamSFO.h index e58f28d81708..956ebbab14b0 100644 --- a/Core/ELF/ParamSFO.h +++ b/Core/ELF/ParamSFO.h @@ -34,6 +34,8 @@ class ParamSFOData std::string GetValueString(std::string key); u8* GetValueData(std::string key, unsigned int *size); + std::vector GetKeys(); + bool ReadSFO(const u8 *paramsfo, size_t size); bool WriteSFO(u8 **paramsfo, size_t *size); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 2722a86243bc..a5fda0e8d651 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -29,6 +29,7 @@ #include "Core/HLE/ReplaceTables.h" #include "Core/Reporting.h" #include "Core/Host.h" +#include "Core/Loaders.h" #include "Core/MIPS/MIPS.h" #include "Core/MIPS/MIPSAnalyst.h" #include "Core/MIPS/MIPSCodeUtils.h" @@ -1368,26 +1369,26 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT return module; } -static bool __KernelLoadPBP(const char *filename, std::string *error_string) +static bool __KernelLoadPBP(FileLoader *fileLoader, std::string *error_string) { - PBPReader pbp(filename); + PBPReader pbp(fileLoader); if (!pbp.IsValid()) { - ERROR_LOG(LOADER,"%s is not a valid homebrew PSP1.0 PBP",filename); + ERROR_LOG(LOADER, "%s is not a valid homebrew PSP1.0 PBP", fileLoader->Path().c_str()); *error_string = "Not a valid homebrew PBP"; return false; } - size_t elfSize; - u8 *elfData = pbp.GetSubFile(PBP_EXECUTABLE_PSP, &elfSize); + std::vector elfData; + if (!pbp.GetSubFile(PBP_EXECUTABLE_PSP, &elfData)) { + return false; + } u32 magic; u32 error; - Module *module = __KernelLoadELFFromPtr(elfData, PSP_GetDefaultLoadAddress(), false, error_string, &magic, error); + Module *module = __KernelLoadELFFromPtr(&elfData[0], PSP_GetDefaultLoadAddress(), false, error_string, &magic, error); if (!module) { - delete [] elfData; return false; } mipsr4k.pc = module->nm.entry_addr; - delete [] elfData; return true; } diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index 832fa0171efd..8544c92468ba 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -141,24 +141,16 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) { else if (id == 'PBP\x00') { // Do this PS1 eboot check FIRST before checking other eboot types. // It seems like some are malformed and slip through the PSAR check below. - // TODO: Change PBPReader to read FileLoader objects? - std::string filename = fileLoader->Path(); - PBPReader pbp(filename.c_str()); - if (pbp.IsValid()) { - if (!pbp.IsELF()) { - size_t sfoSize; - u8 *sfoData = pbp.GetSubFile(PBP_PARAM_SFO, &sfoSize); - { - recursive_mutex _lock; - lock_guard lock(_lock); - ParamSFOData paramSFO; - paramSFO.ReadSFO(sfoData, sfoSize); - // 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") - return FILETYPE_PSP_PS1_PBP; - } - delete[] sfoData; + PBPReader pbp(fileLoader); + if (pbp.IsValid() && !pbp.IsELF()) { + std::vector sfoData; + if (pbp.GetSubFile(PBP_PARAM_SFO, &sfoData)) { + ParamSFOData paramSFO; + 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") + return FILETYPE_PSP_PS1_PBP; } } @@ -172,11 +164,10 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) { // 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 = File::GetDir(filename); + std::string path = File::GetDir(fileLoader->Path()); // If loading from memstick... size_t pos = path.find("/PSP/GAME/"); if (pos != std::string::npos) { - filename = path; return FILETYPE_PSP_PBP_DIRECTORY; } return FILETYPE_PSP_PBP; diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 9a90c2b8a82d..e07fc65bb832 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -340,7 +340,7 @@ void Init() void DoState(PointerWrap &p) { - auto s = p.Section("Memory", 1, 2); + auto s = p.Section("Memory", 1, 3); if (!s) return; @@ -348,7 +348,8 @@ void DoState(PointerWrap &p) if (!g_RemasterMode) g_MemorySize = RAM_NORMAL_SIZE; g_PSPModel = PSP_MODEL_FAT; - } else { + } else if (s == 2) { + // In version 2, we determine memory size based on PSP model. u32 oldMemorySize = g_MemorySize; p.Do(g_PSPModel); p.DoMarker("PSPModel"); @@ -359,6 +360,17 @@ void DoState(PointerWrap &p) Init(); } } + } else { + // In version 3, we started just saving the memory size directly. + // It's no longer based strictly on the PSP model. + u32 oldMemorySize = g_MemorySize; + p.Do(g_PSPModel); + p.DoMarker("PSPModel"); + p.Do(g_MemorySize); + if (oldMemorySize != g_MemorySize) { + Shutdown(); + Init(); + } } p.DoArray(GetPointer(PSP_GetKernelMemoryBase()), g_MemorySize); diff --git a/Core/PSPLoaders.cpp b/Core/PSPLoaders.cpp index 82a8f3806855..2d2087aaa2ae 100644 --- a/Core/PSPLoaders.cpp +++ b/Core/PSPLoaders.cpp @@ -51,71 +51,95 @@ #include "Core/HLE/sceKernelModule.h" #include "Core/HLE/sceKernelMemory.h" +static void UseLargeMem(int memsize) { + if (memsize != 1) { + // Nothing requested. + return; + } + + if (Memory::g_PSPModel != PSP_MODEL_FAT) { + INFO_LOG(LOADER, "Game requested full PSP-2000 memory access"); + Memory::g_MemorySize = Memory::RAM_DOUBLE_SIZE; + } else { + WARN_LOG(LOADER, "Game requested full PSP-2000 memory access, ignoring in PSP-1000 mode"); + } +} + // We gather the game info before actually loading/booting the ISO // to determine if the emulator should enable extra memory and // double-sized texture coordinates. void InitMemoryForGameISO(FileLoader *fileLoader) { - IFileSystem* umd2; - if (!fileLoader->Exists()) { return; } + IFileSystem *fileSystem = nullptr; + IFileSystem *blockSystem = nullptr; bool actualIso = false; - if (fileLoader->IsDirectory()) - { - umd2 = new VirtualDiscFileSystem(&pspFileSystem, fileLoader->Path()); - } - else - { + if (fileLoader->IsDirectory()) { + fileSystem = new VirtualDiscFileSystem(&pspFileSystem, fileLoader->Path()); + blockSystem = fileSystem; + } else { auto bd = constructBlockDevice(fileLoader); // Can't init anything without a block device... if (!bd) return; - umd2 = new ISOFileSystem(&pspFileSystem, bd); - actualIso = true; - } - - // Parse PARAM.SFO - - //pspFileSystem.Mount("host0:",umd2); - - IFileSystem *entireIso = 0; - if (actualIso) { - entireIso = new ISOBlockSystem(static_cast(umd2)); - } else { - entireIso = umd2; + ISOFileSystem *iso = new ISOFileSystem(&pspFileSystem, bd); + fileSystem = iso; + blockSystem = new ISOBlockSystem(iso); } - pspFileSystem.Mount("umd0:", entireIso); - pspFileSystem.Mount("umd1:", entireIso); - pspFileSystem.Mount("disc0:", umd2); - pspFileSystem.Mount("umd:", entireIso); + pspFileSystem.Mount("umd0:", blockSystem); + pspFileSystem.Mount("umd1:", blockSystem); + pspFileSystem.Mount("disc0:", fileSystem); + pspFileSystem.Mount("umd:", blockSystem); + // TODO: Should we do this? + //pspFileSystem.Mount("host0:", fileSystem); std::string gameID; std::string sfoPath("disc0:/PSP_GAME/PARAM.SFO"); PSPFileInfo fileInfo = pspFileSystem.GetFileInfo(sfoPath.c_str()); - if (fileInfo.exists) - { + if (fileInfo.exists) { std::vector paramsfo; pspFileSystem.ReadEntireFile(sfoPath, paramsfo); - if (g_paramSFO.ReadSFO(paramsfo)) - { + if (g_paramSFO.ReadSFO(paramsfo)) { + UseLargeMem(g_paramSFO.GetValueInt("MEMSIZE")); + // TODO: Check the SFO for other parameters that might be useful for identifying? gameID = g_paramSFO.GetValueString("DISC_ID"); + } + } + + for (size_t i = 0; i < ARRAY_SIZE(g_HDRemasters); i++) { + if (g_HDRemasters[i].gameID == gameID) { + g_RemasterMode = true; + Memory::g_MemorySize = g_HDRemasters[i].MemorySize; + if (g_HDRemasters[i].DoubleTextureCoordinates) + g_DoubleTextureCoordinates = true; + break; + } + } + if (g_RemasterMode) { + INFO_LOG(LOADER, "HDRemaster found, using increased memory"); + } +} + +void InitMemoryForGamePBP(FileLoader *fileLoader) { + if (!fileLoader->Exists()) { + return; + } - for (size_t i = 0; i < ARRAY_SIZE(g_HDRemasters); i++) { - if(g_HDRemasters[i].gameID == gameID) { - g_RemasterMode = true; - Memory::g_MemorySize = g_HDRemasters[i].MemorySize; - if(g_HDRemasters[i].DoubleTextureCoordinates) - g_DoubleTextureCoordinates = true; - break; - } + PBPReader pbp(fileLoader); + if (pbp.IsValid() && !pbp.IsELF()) { + std::vector sfoData; + if (pbp.GetSubFile(PBP_PARAM_SFO, &sfoData)) { + ParamSFOData paramSFO; + if (paramSFO.ReadSFO(sfoData)) { + // This is the parameter CFW uses to determine homebrew wants the full 64MB. + UseLargeMem(paramSFO.GetValueInt("MEMSIZE")); } - DEBUG_LOG(LOADER, "HDRemaster mode is %s", g_RemasterMode? "true": "false"); } } } diff --git a/Core/PSPLoaders.h b/Core/PSPLoaders.h index 3dce913c0815..400df80d6576 100644 --- a/Core/PSPLoaders.h +++ b/Core/PSPLoaders.h @@ -24,3 +24,4 @@ class FileLoader; bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string); bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string); void InitMemoryForGameISO(FileLoader *fileLoader); +void InitMemoryForGamePBP(FileLoader *fileLoader); diff --git a/Core/System.cpp b/Core/System.cpp index 95e3eb6ca101..5d726ba2ad85 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -177,10 +177,7 @@ void CPU_Init() { // Default memory settings // Seems to be the safest place currently.. - if (g_Config.iPSPModel == PSP_MODEL_FAT) - Memory::g_MemorySize = Memory::RAM_NORMAL_SIZE; // 32 MB of ram by default - else - Memory::g_MemorySize = Memory::RAM_DOUBLE_SIZE; + Memory::g_MemorySize = Memory::RAM_NORMAL_SIZE; // 32 MB of ram by default g_RemasterMode = false; g_DoubleTextureCoordinates = false; @@ -209,6 +206,17 @@ void CPU_Init() { case FILETYPE_PSP_DISC_DIRECTORY: InitMemoryForGameISO(loadedFile); break; + case FILETYPE_PSP_PBP_DIRECTORY: { + // TODO: Can we get this lower into LoadFile? + std::string ebootFilename = loadedFile->Path() + "/EBOOT.PBP"; + FileLoader *tempLoader = ConstructFileLoader(ebootFilename); + InitMemoryForGamePBP(tempLoader); + delete tempLoader; + break; + } + case FILETYPE_PSP_PBP: + InitMemoryForGamePBP(loadedFile); + break; default: break; } diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index e7c07e5a3a2a..75f80c79d18b 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -202,11 +202,15 @@ u64 GameInfo::GetInstallDataSizeInBytes() { } bool GameInfo::LoadFromPath(const std::string &gamePath) { + lock_guard guard(lock); // No need to rebuild if we already have it loaded. if (filePath_ != gamePath) { delete fileLoader; fileLoader = ConstructFileLoader(gamePath); filePath_ = gamePath; + + // This is a fallback title, while we're loading / if unable to load. + title = File::GetFilename(filePath_); } return GetFileLoader()->Exists(); @@ -278,6 +282,11 @@ void GameInfo::ParseParamSFO() { paramSFOLoaded = true; } +std::string GameInfo::GetTitle() { + lock_guard guard(lock); + return title; +} + static bool ReadFileToString(IFileSystem *fs, const char *filename, std::string *contents, recursive_mutex *mtx) { PSPFileInfo info = fs->GetFileInfo(filename); if (!info.exists) { @@ -301,6 +310,21 @@ static bool ReadFileToString(IFileSystem *fs, const char *filename, std::string return true; } +static bool ReadVFSToString(const char *filename, std::string *contents, recursive_mutex *mtx) { + size_t sz; + uint8_t *data = VFSReadFile(filename, &sz); + if (data) { + if (mtx) { + lock_guard lock(*mtx); + *contents = std::string((const char *)data, sz); + } else { + *contents = std::string((const char *)data, sz); + } + } + delete [] data; + return data != nullptr; +} + class GameInfoWorkItem : public PrioritizedWorkQueueItem { public: @@ -313,56 +337,49 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { return; std::string filename = gamePath_; - info_->path = gamePath_; - info_->fileType = Identify_File(info_->GetFileLoader()); - // Fallback title - info_->title = File::GetFilename(info_->path); + { + lock_guard lock(info_->lock); + info_->fileType = Identify_File(info_->GetFileLoader()); + } 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"; + FileLoader *pbpLoader = info_->GetFileLoader(); + std::unique_ptr altLoader; + if (info_->fileType == FILETYPE_PSP_PBP_DIRECTORY) { + pbpLoader = ConstructFileLoader(pbpLoader->Path() + "/EBOOT.PBP"); + altLoader.reset(pbpLoader); + } - PBPReader pbp(pbpFile.c_str()); + PBPReader pbp(pbpLoader); if (!pbp.IsValid()) { if (pbp.IsELF()) { goto handleELF; } - ERROR_LOG(LOADER, "invalid pbp %s\n", pbpFile.c_str()); + ERROR_LOG(LOADER, "invalid pbp %s\n", pbpLoader->Path().c_str()); return; } // First, PARAM.SFO. - size_t sfoSize; - u8 *sfoData = pbp.GetSubFile(PBP_PARAM_SFO, &sfoSize); - { + std::vector sfoData; + if (pbp.GetSubFile(PBP_PARAM_SFO, &sfoData)) { lock_guard lock(info_->lock); - info_->paramSFO.ReadSFO(sfoData, sfoSize); + info_->paramSFO.ReadSFO(sfoData); info_->ParseParamSFO(); } - delete [] sfoData; // Then, ICON0.PNG. - { + if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) { lock_guard lock(info_->lock); - if (pbp.GetSubFileSize(PBP_ICON0_PNG) > 0) { - pbp.GetSubFileAsString(PBP_ICON0_PNG, &info_->iconTextureData); - } else { - // Read standard icon - size_t sz; - DEBUG_LOG(LOADER, "Loading unknown.png because a PBP was missing an icon"); - uint8_t *contents = VFSReadFile("unknown.png", &sz); - if (contents) { - lock_guard lock(info_->lock); - info_->iconTextureData = std::string((const char *)contents, sz); - } - delete [] contents; - } - info_->iconDataLoaded = true; + pbp.GetSubFileAsString(PBP_ICON0_PNG, &info_->iconTextureData); + } else { + // Read standard icon + DEBUG_LOG(LOADER, "Loading unknown.png because a PBP was missing an icon"); + ReadVFSToString("unknown.png", &info_->iconTextureData, &info_->lock); } + info_->iconDataLoaded = true; if (info_->wantFlags & GAMEINFO_WANTBG) { if (pbp.GetSubFileSize(PBP_PIC0_PNG) > 0) { @@ -389,22 +406,17 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { case FILETYPE_PSP_ELF: handleELF: // An elf on its own has no usable information, no icons, no nothing. - info_->title = File::GetFilename(filename); - info_->id = "ELF000000"; - info_->id_version = "ELF000000_1.00"; - info_->paramSFOLoaded = true; { - // Read standard icon - size_t sz; - uint8_t *contents = VFSReadFile("unknown.png", &sz); - DEBUG_LOG(LOADER, "Loading unknown.png because there was an ELF"); - if (contents) { - lock_guard lock(info_->lock); - info_->iconTextureData = std::string((const char *)contents, sz); - info_->iconDataLoaded = true; - } - delete [] contents; + lock_guard lock(info_->lock); + info_->id = "ELF000000"; + info_->id_version = "ELF000000_1.00"; + info_->paramSFOLoaded = true; } + + // Read standard icon + DEBUG_LOG(LOADER, "Loading unknown.png because there was an ELF"); + ReadVFSToString("unknown.png", &info_->iconTextureData, &info_->lock); + info_->iconDataLoaded = true; break; case FILETYPE_PSP_SAVEDATA_DIRECTORY: @@ -478,7 +490,7 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { // Alright, let's fetch the PARAM.SFO. std::string paramSFOcontents; - if (ReadFileToString(&umd, "/PSP_GAME/PARAM.SFO", ¶mSFOcontents, 0)) { + if (ReadFileToString(&umd, "/PSP_GAME/PARAM.SFO", ¶mSFOcontents, nullptr)) { lock_guard lock(info_->lock); info_->paramSFO.ReadSFO((const u8 *)paramSFOcontents.data(), paramSFOcontents.size()); info_->ParseParamSFO(); @@ -497,14 +509,8 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { // Fall back to unknown icon if ISO is broken/is a homebrew ISO, override is allowed though if (!ReadFileToString(&umd, "/PSP_GAME/ICON0.PNG", &info_->iconTextureData, &info_->lock)) { - size_t sz; - uint8_t *contents = VFSReadFile("unknown.png", &sz); DEBUG_LOG(LOADER, "Loading unknown.png because no icon was found"); - if (contents) { - lock_guard lock(info_->lock); - info_->iconTextureData = std::string((const char *)contents, sz); - } - delete [] contents; + ReadVFSToString("unknown.png", &info_->iconTextureData, &info_->lock); } info_->iconDataLoaded = true; break; @@ -513,45 +519,24 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { case FILETYPE_ARCHIVE_ZIP: info_->paramSFOLoaded = true; { - // Read standard icon - size_t sz; - uint8_t *contents = VFSReadFile("zip.png", &sz); - if (contents) { - lock_guard lock(info_->lock); - info_->iconTextureData = std::string((const char *)contents, sz); - info_->iconDataLoaded = true; - } - delete [] contents; + ReadVFSToString("zip.png", &info_->iconTextureData, &info_->lock); + info_->iconDataLoaded = true; } break; case FILETYPE_ARCHIVE_RAR: info_->paramSFOLoaded = true; { - // Read standard icon - size_t sz; - uint8_t *contents = VFSReadFile("rargray.png", &sz); - if (contents) { - lock_guard lock(info_->lock); - info_->iconTextureData = std::string((const char *)contents, sz); - info_->iconDataLoaded = true; - } - delete [] contents; + ReadVFSToString("rargray.png", &info_->iconTextureData, &info_->lock); + info_->iconDataLoaded = true; } break; case FILETYPE_ARCHIVE_7Z: info_->paramSFOLoaded = true; { - // Read standard icon - size_t sz; - uint8_t *contents = VFSReadFile("7z.png", &sz); - if (contents) { - lock_guard lock(info_->lock); - info_->iconTextureData = std::string((const char *)contents, sz); - info_->iconDataLoaded = true; - } - delete[] contents; + ReadVFSToString("7z.png", &info_->iconTextureData, &info_->lock); + info_->iconDataLoaded = true; } break; @@ -564,6 +549,7 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { info_->hasConfig = g_Config.hasGameConfig(info_->id); if (info_->wantFlags & GAMEINFO_WANTSIZE) { + lock_guard lock(info_->lock); info_->gameSize = info_->GetGameSizeInBytes(); info_->saveDataSize = info_->GetSaveDataSizeInBytes(); info_->installDataSize = info_->GetInstallDataSizeInBytes(); diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index fa448272e584..74d2823a1a26 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -116,6 +116,7 @@ class GameInfo { std::vector GetSaveDataDirectories(); + std::string GetTitle(); // Hold this when reading or writing from the GameInfo. // Don't need to hold it when just passing around the pointer, @@ -123,8 +124,6 @@ class GameInfo { // to it. recursive_mutex lock; - std::string path; - std::string title; // for easy access, also available in paramSFO. std::string id; std::string id_version; int disc_total; @@ -166,6 +165,9 @@ class GameInfo { bool pending; protected: + // Note: this can change while loading, use GetTitle(). + std::string title; + FileLoader *fileLoader; std::string filePath_; }; diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index 30f7d53e8fe2..9824068c5e63 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -66,7 +66,7 @@ void GameScreen::CreateViews() { leftColumn->Add(new Choice(di->T("Back"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &GameScreen::OnSwitchBack); if (info) { texvGameIcon_ = leftColumn->Add(new Thin3DTextureView(0, IS_DEFAULT, new AnchorLayoutParams(144 * 2, 80 * 2, 10, 10, NONE, NONE))); - tvTitle_ = leftColumn->Add(new TextView(info->title, ALIGN_LEFT, false, new AnchorLayoutParams(10, 200, NONE, NONE))); + tvTitle_ = leftColumn->Add(new TextView(info->GetTitle(), ALIGN_LEFT, false, new AnchorLayoutParams(10, 200, NONE, NONE))); tvTitle_->SetShadow(true); // This one doesn't need to be updated. leftColumn->Add(new TextView(gamePath_, ALIGN_LEFT, true, new AnchorLayoutParams(10, 250, NONE, NONE)))->SetShadow(true); @@ -159,7 +159,7 @@ void GameScreen::update(InputState &input) { GameInfo *info = g_gameInfoCache.GetInfo(thin3d, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE); if (tvTitle_) - tvTitle_->SetText(info->title + " (" + info->id + ")"); + tvTitle_->SetText(info->GetTitle() + " (" + info->id + ")"); if (info->iconTexture && texvGameIcon_) { texvGameIcon_->SetTexture(info->iconTexture); // Fade the icon with the background. @@ -277,7 +277,7 @@ void GameScreen::CallbackDeleteGame(bool yes) { UI::EventReturn GameScreen::OnCreateShortcut(UI::EventParams &e) { GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, 0); if (info) { - host->CreateDesktopShortcut(gamePath_, info->title); + host->CreateDesktopShortcut(gamePath_, info->GetTitle()); } return UI::EVENT_DONE; } diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index e498e8b86344..755d4e8bef06 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -277,8 +277,9 @@ void GameButton::Draw(UIContext &dc) { float tw, th; dc.Draw()->Flush(); dc.PushScissor(bounds_); - if (title_.empty() && !ginfo->title.empty()) { - title_ = ReplaceAll(ginfo->title + discNumInfo, "&", "&&"); + const std::string currentTitle = ginfo->GetTitle(); + if (!currentTitle.empty()) { + title_ = ReplaceAll(currentTitle + discNumInfo, "&", "&&"); title_ = ReplaceAll(title_, "\n", " "); } @@ -310,8 +311,7 @@ void GameButton::Draw(UIContext &dc) { } else { dc.Draw()->Flush(); } - if (!ginfo->id.empty() && ginfo->hasConfig) - { + if (ginfo->hasConfig && !ginfo->id.empty()) { dc.Draw()->DrawImage(I_GEAR, x, y + h - ui_images[I_GEAR].h, 1.0f); } if (overlayColor) { diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index 5e9b1d864494..9f8b47a34d8f 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -226,8 +226,9 @@ void SavedataButton::Draw(UIContext &dc) { dc.Draw()->Flush(); dc.PushScissor(bounds_); - if (title_.empty() && !ginfo->title.empty()) { - title_ = CleanSaveString(ginfo->title); + const std::string currentTitle = ginfo->GetTitle(); + if (!currentTitle.empty()) { + title_ = CleanSaveString(currentTitle); } if (subtitle_.empty() && ginfo->gameSize > 0) { std::string savedata_title = ginfo->paramSFO.GetValueString("SAVEDATA_TITLE"); @@ -360,7 +361,7 @@ void SavedataScreen::CreateViews() { UI::EventReturn SavedataScreen::OnSavedataButtonClick(UI::EventParams &e) { GameInfo *ginfo = g_gameInfoCache.GetInfo(screenManager()->getThin3DContext(), e.s, 0); - screenManager()->push(new SavedataPopupScreen(e.s, ginfo->title)); + screenManager()->push(new SavedataPopupScreen(e.s, ginfo->GetTitle())); // the game path: e.s; return UI::EVENT_DONE; }