Add an interface to load files with.

This allows loading from other than raw files.
This commit is contained in:
Unknown W. Brackets committed 2014-11-23 13:25:32 -08:00
1 parent a0461f1dcd
commit 102b7b03fa
6 files changed
+190 -57

No files matched your search

+110 -43
View File
@@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "file/file_util.h"
#include <cstdio>
#include "Common/FileUtil.h"
#include "Core/MIPS/MIPS.h"
@@ -30,34 +31,106 @@
#include "Core/ELF/PBPReader.h"
#include "Core/ELF/ParamSFO.h"
// TODO : improve, look in the file more
IdentifiedFileType Identify_File(std::string &filename)
{
if (filename.size() == 0) {
ERROR_LOG(LOADER, "invalid filename %s", filename.c_str());
return FILETYPE_ERROR;
LocalFileLoader::LocalFileLoader(const std::string &filename) {
Reopen(filename);
}
bool LocalFileLoader::Reopen(const std::string &filename) {
fd_ = 0;
f_ = nullptr;
filesize_ = 0;
filename_ = filename;
f_ = File::OpenCFile(filename, "rb");
if (!f_) {
return false;
}
#ifdef ANDROID
fd_ = fileno(f_);
off64_t off = lseek64(fd_, 0, SEEK_END);
filesize_ = off;
lseek64(fd_, 0, SEEK_SET);
#else
fseek(f_, 0, SEEK_END);
filesize_ = ftello(f_);
fseek(f_, 0, SEEK_SET);
#endif
return true;
}
LocalFileLoader::~LocalFileLoader() {
fclose(f_);
}
bool LocalFileLoader::Exists() {
FileInfo info;
if (!getFileInfo(filename.c_str(), &info)) {
return getFileInfo(filename_.c_str(), &info);
}
bool LocalFileLoader::IsDirectory() {
FileInfo info;
if (getFileInfo(filename_.c_str(), &info)) {
return info.isDirectory;
}
return false;
}
s64 LocalFileLoader::FileSize() {
return filesize_;
}
std::string LocalFileLoader::Path() const {
return filename_;
}
void LocalFileLoader::Seek(s64 absolutePos) {
#ifdef ANDROID
lseek64(fd_, absolutePos, SEEK_SET);
#else
fseeko(f_, absolutePos, SEEK_SET);
#endif
}
size_t LocalFileLoader::Read(size_t bytes, size_t count, void *data) {
#ifdef ANDROID
return read(fd_, data, bytes * count) / bytes;
#else
return fread(data, bytes, count, f_);
#endif
}
size_t LocalFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) {
Seek(absolutePos);
return Read(bytes, count, data);
}
// TODO : improve, look in the file more
IdentifiedFileType Identify_File(FileLoader *fileLoader)
{
if (fileLoader == nullptr) {
ERROR_LOG(LOADER, "Invalid fileLoader");
return FILETYPE_ERROR;
}
if (fileLoader->Path().size() == 0) {
ERROR_LOG(LOADER, "Invalid filename %s", fileLoader->Path().c_str());
return FILETYPE_ERROR;
}
std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : "";
if (!fileLoader->Exists()) {
return FILETYPE_ERROR;
}
std::string extension = fileLoader->Extension();
if (!strcasecmp(extension.c_str(),".iso"))
{
// may be a psx iso, they have 2352 byte sectors. You never know what some people try to open
if ((info.size % 2352) == 0)
if ((fileLoader->FileSize() % 2352) == 0)
{
FILE *f = File::OpenCFile(filename.c_str(), "rb");
if (!f) {
// File does not exists
return FILETYPE_ERROR;
}
unsigned char sync[12];
fread(sync,1,12,f);
fclose(f);
fileLoader->ReadAt(0, 12, sync);
// each sector in a mode2 image starts with these 12 bytes
if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00",12) == 0)
@@ -76,7 +149,8 @@ IdentifiedFileType Identify_File(std::string &filename)
// First, check if it's a directory with an EBOOT.PBP in it.
if (info.isDirectory) {
if (fileLoader->IsDirectory()) {
std::string filename = fileLoader->Path();
if (filename.size() > 4) {
FileInfo ebootInfo;
// Check for existence of EBOOT.PBP, as required for "Directory games".
@@ -97,17 +171,10 @@ IdentifiedFileType Identify_File(std::string &filename)
return FILETYPE_NORMAL_DIRECTORY;
}
FILE *f = File::OpenCFile(filename.c_str(), "rb");
if (!f) {
// File does not exists
return FILETYPE_ERROR;
}
u32_le id;
size_t readSize = fread(&id, 4, 1, f);
size_t readSize = fileLoader->ReadAt(0, 4, 1, &id);
if (readSize != 1) {
fclose(f);
return FILETYPE_ERROR;
}
@@ -115,10 +182,8 @@ IdentifiedFileType Identify_File(std::string &filename)
u32 _id = id;
switch (_id) {
case '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);
fileLoader->ReadAt(0x24, 4, 1, &psar_offset);
fileLoader->ReadAt(psar_offset, 4, 1, &psar_id);
break;
case '!raR':
return FILETYPE_ARCHIVE_RAR;
@@ -128,9 +193,8 @@ IdentifiedFileType Identify_File(std::string &filename)
return FILETYPE_ARCHIVE_ZIP;
}
fclose(f);
if (id == 'FLE\x7F') {
std::string filename = fileLoader->Path();
// There are a few elfs misnamed as pbp (like Trig Wars), accept that.
if (!strcasecmp(extension.c_str(), ".plf") || strstr(filename.c_str(),"BOOT.BIN") ||
!strcasecmp(extension.c_str(), ".elf") || !strcasecmp(extension.c_str(), ".prx") ||
@@ -142,6 +206,8 @@ IdentifiedFileType Identify_File(std::string &filename)
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()) {
@@ -199,21 +265,22 @@ IdentifiedFileType Identify_File(std::string &filename)
return FILETYPE_UNKNOWN;
}
bool LoadFile(std::string &filename, std::string *error_string) {
bool LoadFile(FileLoader *fileLoader, std::string *error_string) {
// Note that this can modify filename!
switch (Identify_File(filename)) {
switch (Identify_File(fileLoader)) {
case FILETYPE_PSP_PBP_DIRECTORY:
{
std::string filename = fileLoader->Path();
std::string ebootFilename = filename + "/EBOOT.PBP";
FileInfo fileInfo;
getFileInfo((filename + "/EBOOT.PBP").c_str(), &fileInfo);
if (fileInfo.exists) {
// Switch fileLoader to the EBOOT.
fileLoader->Reopen(ebootFilename);
if (fileLoader->Exists()) {
INFO_LOG(LOADER, "File is a PBP in a directory!");
std::string ebootPath = filename + "/EBOOT.PBP";
IdentifiedFileType ebootType = Identify_File(ebootPath);
IdentifiedFileType ebootType = Identify_File(fileLoader);
if (ebootType == FILETYPE_PSP_ISO_NP) {
InitMemoryForGameISO(ebootPath);
InitMemoryForGameISO(fileLoader);
pspFileSystem.SetStartingDirectory("disc0:/PSP_GAME/USRDIR");
return Load_PSP_ISO(filename.c_str(), error_string);
}
@@ -225,7 +292,7 @@ bool LoadFile(std::string &filename, std::string *error_string) {
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);
return Load_PSP_ELF_PBP(fileLoader->Path().c_str(), error_string);
} else {
*error_string = "No EBOOT.PBP, misidentified game";
return false;
@@ -236,14 +303,14 @@ bool LoadFile(std::string &filename, std::string *error_string) {
case FILETYPE_PSP_ELF:
{
INFO_LOG(LOADER,"File is an ELF or loose PBP!");
return Load_PSP_ELF_PBP(filename.c_str(), error_string);
return Load_PSP_ELF_PBP(fileLoader->Path().c_str(), error_string);
}
case FILETYPE_PSP_ISO:
case FILETYPE_PSP_ISO_NP:
case FILETYPE_PSP_DISC_DIRECTORY: // behaves the same as the mounting is already done by now
pspFileSystem.SetStartingDirectory("disc0:/PSP_GAME/USRDIR");
return Load_PSP_ISO(filename.c_str(), error_string);
return Load_PSP_ISO(fileLoader->Path().c_str(), error_string);
case FILETYPE_PSP_PS1_PBP:
*error_string = "PS1 EBOOTs are not supported by PPSSPP.";
+58 -2
View File
@@ -46,9 +46,65 @@ enum IdentifiedFileType {
FILETYPE_UNKNOWN
};
class FileLoader {
public:
virtual ~FileLoader() {}
// Needed when we switch from a directory to a PBP, etc.
virtual bool Reopen(const std::string &filename) = 0;
virtual bool Exists() = 0;
virtual bool IsDirectory() = 0;
virtual s64 FileSize() = 0;
virtual std::string Path() const = 0;
virtual std::string Extension() {
const std::string filename = Path();
size_t pos = filename.find_last_of('.');
if (pos == filename.npos) {
return "";
} else {
return filename.substr(pos);
}
}
virtual void Seek(s64 absolutePos) = 0;
virtual size_t Read(size_t bytes, size_t count, void *data) = 0;
virtual size_t Read(size_t bytes, void *data) {
return Read(1, bytes, data);
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) = 0;
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) {
return ReadAt(absolutePos, 1, bytes, data);
}
};
class LocalFileLoader : public FileLoader {
public:
LocalFileLoader(const std::string &filename);
virtual ~LocalFileLoader();
virtual bool Reopen(const std::string &filename);
virtual bool Exists() override;
virtual bool IsDirectory() override;
virtual s64 FileSize() override;
virtual std::string Path() const override;
virtual void Seek(s64 absolutePos) override;
virtual size_t Read(size_t bytes, size_t count, void *data) override;
virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override;
private:
// First only used by Android, but we can keep it here for everyone.
int fd_;
FILE *f_;
u64 filesize_;
std::string filename_;
};
// This can modify the string, for example for stripping off the "/EBOOT.PBP"
// for a FILETYPE_PSP_PBP_DIRECTORY.
IdentifiedFileType Identify_File(std::string &str);
IdentifiedFileType Identify_File(FileLoader *fileLoader);
// Can modify the string filename, as it calls IdentifyFile above.
bool LoadFile(std::string &filename, std::string *error_string);
bool LoadFile(FileLoader *fileLoader, std::string *error_string);
+8 -7
View File
@@ -32,6 +32,7 @@
#include "FileSystems/MetaFileSystem.h"
#include "FileSystems/VirtualDiscFileSystem.h"
#include "Core/Loaders.h"
#include "Core/MemMap.h"
#include "Core/HDRemaster.h"
@@ -53,21 +54,21 @@
// 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(std::string fileToStart) {
void InitMemoryForGameISO(FileLoader *fileLoader) {
IFileSystem* umd2;
// check if it's a disc directory
FileInfo info;
if (!getFileInfo(fileToStart.c_str(), &info)) return;
if (!fileLoader->Exists()) {
return;
}
bool actualIso = false;
if (info.isDirectory)
if (fileLoader->IsDirectory())
{
umd2 = new VirtualDiscFileSystem(&pspFileSystem, fileToStart);
umd2 = new VirtualDiscFileSystem(&pspFileSystem, fileLoader->Path());
}
else
{
auto bd = constructBlockDevice(fileToStart.c_str());
auto bd = constructBlockDevice(fileLoader->Path().c_str());
// Can't init anything without a block device...
if (!bd)
return;
+3 -1
View File
@@ -19,6 +19,8 @@
#include <string>
class FileLoader;
bool Load_PSP_ISO(const char *filename, std::string *error_string);
bool Load_PSP_ELF_PBP(const char *filename, std::string *error_string);
void InitMemoryForGameISO(std::string fileToStart);
void InitMemoryForGameISO(FileLoader *fileLoader);
+8 -3
View File
@@ -72,6 +72,7 @@ MetaFileSystem pspFileSystem;
ParamSFOData g_paramSFO;
static GlobalUIState globalUIState;
static CoreParameter coreParameter;
static FileLoader *loadedFile;
static PSPMixer *mixer;
static std::thread *cpuThread = NULL;
static std::thread::id cpuThreadID;
@@ -181,7 +182,8 @@ void CPU_Init() {
Memory::g_PSPModel = g_Config.iPSPModel;
std::string filename = coreParameter.fileToStart;
IdentifiedFileType type = Identify_File(filename);
loadedFile = new LocalFileLoader(filename);
IdentifiedFileType type = Identify_File(loadedFile);
MIPSAnalyst::Reset();
Replacement_Init();
@@ -190,7 +192,7 @@ void CPU_Init() {
case FILETYPE_PSP_ISO:
case FILETYPE_PSP_ISO_NP:
case FILETYPE_PSP_DISC_DIRECTORY:
InitMemoryForGameISO(filename);
InitMemoryForGameISO(loadedFile);
break;
default:
break;
@@ -213,7 +215,7 @@ void CPU_Init() {
// TODO: Check Game INI here for settings, patches and cheats, and modify coreParameter accordingly
// Why did we check for CORE_POWERDOWN here?
if (!LoadFile(filename, &coreParameter.errorString)) {
if (!LoadFile(loadedFile, &coreParameter.errorString)) {
CPU_Shutdown();
coreParameter.fileToStart = "";
CPU_SetState(CPU_THREAD_NOT_RUNNING);
@@ -245,6 +247,9 @@ void CPU_Shutdown() {
pspFileSystem.Shutdown();
mipsr4k.Shutdown();
Memory::Shutdown();
delete loadedFile;
loadedFile = 0;
}
void CPU_RunLoop() {
+3 -1
View File
@@ -17,6 +17,7 @@
#include <string>
#include <map>
#include <memory>
#include <algorithm>
#include "base/logging.h"
@@ -246,8 +247,9 @@ public:
return;
std::string filename = gamePath_;
std::unique_ptr<FileLoader> fileLoader(new LocalFileLoader(filename));
info_->path = gamePath_;
info_->fileType = Identify_File(filename);
info_->fileType = Identify_File(fileLoader.get());
// Fallback title
info_->title = getFilename(info_->path);