diff --git a/CMakeLists.txt b/CMakeLists.txt index 42bc6e0828..2bba36f1b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -695,6 +695,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/ELF/ElfReader.cpp Core/ELF/ElfReader.h Core/ELF/ElfTypes.h + Core/ELF/PBPReader.cpp + Core/ELF/PBPReader.h Core/ELF/PrxDecrypter.cpp Core/ELF/PrxDecrypter.h Core/ELF/ParamSFO.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 24c48abe92..398ed92033 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -158,6 +158,7 @@ + @@ -331,6 +332,7 @@ + @@ -469,4 +471,4 @@ - + \ No newline at end of file diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 25d658f2ed..77296a5538 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -400,6 +400,9 @@ HLE\Libraries + + ELF + @@ -738,6 +741,9 @@ HLE\Libraries + + ELF + diff --git a/Core/ELF/PBPReader.cpp b/Core/ELF/PBPReader.cpp new file mode 100644 index 0000000000..d574d097d2 --- /dev/null +++ b/Core/ELF/PBPReader.cpp @@ -0,0 +1,60 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include + +#include "Common/Log.h" +#include "Core/ELF/PBPReader.h" + +PBPReader::PBPReader(const char *filename) { + file_ = fopen(filename, "rb"); + if (!file_) { + return; + } + + fseek(file_, 0, SEEK_END); + fileSize_ = ftell(file_); + fseek(file_, 0, SEEK_SET); + fread((char *)&header_, 1, sizeof(header_), file_); + if (memcmp(header_.magic, "\0PBP", 4) != 0) { + fclose(file_); + file_ = 0; + return; + } + + INFO_LOG(LOADER, "Loading PBP, version = %08x", header_.version); +} + +u8 *PBPReader::GetSubFile(PBPSubFile file, size_t *outSize) { + *outSize = GetSubFileSize(file); + u8 *buffer = new u8[*outSize]; + fseek(file_, header_.offsets[(int)file], SEEK_SET); + fread(buffer, 1, *outSize, file_); + return buffer; +} + +void PBPReader::GetSubFileAsString(PBPSubFile file, std::string *out) { + out->resize(GetSubFileSize(file)); + fseek(file_, header_.offsets[(int)file], SEEK_SET); + fread((void *)out->data(), 1, out->size(), file_); +} + +PBPReader::~PBPReader() { + if (file_) + fclose(file_); +} diff --git a/Core/ELF/PBPReader.h b/Core/ELF/PBPReader.h new file mode 100644 index 0000000000..de43e1b68a --- /dev/null +++ b/Core/ELF/PBPReader.h @@ -0,0 +1,64 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + + +#pragma once + +#include "Common/CommonTypes.h" + +enum PBPSubFile { + PBP_PARAM_SFO, + PBP_ICON0_PNG, + PBP_ICON1_PMF, + PBP_UNKNOWN_PNG, // PIC0? + PBP_PIC1_PNG, + PBP_SND0_AT3, + PBP_EXECUTABLE_PSP, + PBP_UNKNOWN_PSAR, +}; + +struct PBPHeader { + char magic[4]; + u32 version; + u32 offsets[8]; +}; + +class PBPReader { +public: + PBPReader(const char *filename); + ~PBPReader(); + + bool IsValid() const { return file_ != 0; } + + // Delete the returned buffer with delete []. + u8 *GetSubFile(PBPSubFile file, size_t *outSize); + void GetSubFileAsString(PBPSubFile file, std::string *out); + + size_t GetSubFileSize(PBPSubFile file) { + int num = (int)file; + if (num < 7) { + return header_.offsets[file + 1] - header_.offsets[file]; + } else { + return fileSize_ - header_.offsets[file]; + } + } + +private: + FILE *file_; + size_t fileSize_; + const PBPHeader header_; +}; \ No newline at end of file diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index e127ca36e9..48af444eef 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -22,19 +22,20 @@ #include "Core/Reporting.h" #include "Common/FileUtil.h" #include "../Host.h" -#include "../MIPS/MIPS.h" -#include "../MIPS/MIPSAnalyst.h" -#include "../ELF/ElfReader.h" -#include "../ELF/PrxDecrypter.h" +#include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSAnalyst.h" +#include "Core/ELF/ElfReader.h" +#include "Core/ELF/PBPReader.h" +#include "Core/ELF/PrxDecrypter.h" #include "../Debugger/SymbolMap.h" #include "../FileSystems/FileSystem.h" #include "../FileSystems/MetaFileSystem.h" #include "../Util/BlockAllocator.h" -#include "../CoreTiming.h" -#include "../PSPLoaders.h" -#include "../System.h" -#include "../MemMap.h" -#include "../Debugger/SymbolMap.h" +#include "Core/CoreTiming.h" +#include "Core/PSPLoaders.h" +#include "Core/System.h" +#include "Core/MemMap.h" +#include "Core/Debugger/SymbolMap.h" #include "sceKernel.h" #include "sceKernelModule.h" @@ -598,43 +599,22 @@ bool __KernelLoadPBP(const char *filename, std::string *error_string) "PIC1.PNG", "SND0.AT3", "UNKNOWN.PSP", "UNKNOWN.PSAR" }; - std::ifstream in(filename, std::ios::binary); - - char temp[4]; - in.read(temp,4); - - if (memcmp(temp,"\0PBP",4) != 0) - { - //This is not a valid file! + PBPReader pbp(filename); + if (!pbp.IsValid()) { ERROR_LOG(LOADER,"%s is not a valid homebrew PSP1.0 PBP",filename); *error_string = "Not a valid homebrew PBP"; return false; } - u32 version, offset0, offsets[16]; - int numfiles; - - in.read((char*)&version,4); - - in.read((char*)&offset0,4); - numfiles = (offset0 - 8) / 4; - offsets[0] = offset0; - for (int i = 1; i < numfiles; i++) - in.read((char*)&offsets[i], 4); - - // The 6th is always the executable? - in.seekg(offsets[5]); - //in.read((char*)&id,4); - { - u8 *elftemp = new u8[1024*1024*8]; - in.read((char*)elftemp, 1024*1024*8); - Module *module = __KernelLoadELFFromPtr(elftemp, PSP_GetDefaultLoadAddress(), error_string); - if (!module) - return false; - mipsr4k.pc = module->nm.entry_addr; - delete [] elftemp; + size_t elfSize; + u8 *elfData = pbp.GetSubFile(PBP_EXECUTABLE_PSP, &elfSize); + Module *module = __KernelLoadELFFromPtr(elfData, PSP_GetDefaultLoadAddress(), error_string); + if (!module) { + delete [] elfData; + return false; } - in.close(); + mipsr4k.pc = module->nm.entry_addr; + delete [] elfData; return true; } diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index da2ff2b449..9b3437d43d 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -24,6 +24,7 @@ #include "GameInfoCache.h" #include "Core/FileSystems/ISOFileSystem.h" #include "Core/FileSystems/DirectoryFileSystem.h" +#include "Core/ELF/PBPReader.h" GameInfoCache g_gameInfoCache; @@ -137,7 +138,44 @@ again: if (startsWith(gamePath, "ms0:/PSP/GAME")) { return 0; // TODO: The case of these extensions is not perfect. - } else if (endsWith(gamePath, ".PBP") || endsWith(gamePath, ".elf") || endsWith(gamePath, ".prx")) { + } else if (endsWith(gamePath, ".PBP")) { + PBPReader pbp(gamePath.c_str()); + if (!pbp.IsValid()) + return 0; + GameInfo *info = new GameInfo(); + info->wantBG = wantBG; + + // 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. + } + } + + if (info->wantBG) { + { + lock_guard lock(info->lock); + if (pbp.GetSubFileSize(PBP_PIC1_PNG) > 0) + pbp.GetSubFileAsString(PBP_PIC1_PNG, &info->pic1TextureData); + } + } + info_[gamePath] = info; + return info; + + } else if (endsWith(gamePath, ".elf") || endsWith(gamePath, ".prx")) { return 0; } else { SequentialHandleAllocator handles; diff --git a/android/jni/Android.mk b/android/jni/Android.mk index e86cb001f0..10ec4197ba 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -158,6 +158,7 @@ LOCAL_SRC_FILES := \ $(SRC)/GPU/GLES/FragmentShaderGenerator.cpp \ $(SRC)/GPU/Null/NullGpu.cpp \ $(SRC)/Core/ELF/ElfReader.cpp \ + $(SRC)/Core/ELF/PBPReader.cpp \ $(SRC)/Core/ELF/PrxDecrypter.cpp \ $(SRC)/Core/ELF/ParamSFO.cpp \ $(SRC)/Core/HW/MemoryStick.cpp \