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 \