Merge pull request #7106 from unknownbrackets/file-remote

Use an interface to read iso files, not raw file reading
This commit is contained in:
Henrik Rydgård committed 2014-11-25 19:42:41 +01:00
commit 8222f1ef09
12 files changed
+850 -179

No files matched your search

+5 -1
View File
@@ -31,9 +31,11 @@ enum GPUCore {
GPU_DIRECTX9,
};
class FileLoader;
// PSP_CoreParameter()
struct CoreParameter {
CoreParameter() : collectEmuLog(0), unthrottle(false), fpsLimit(0), updateRecent(true), freezeNext(false), frozen(false) {}
CoreParameter() : collectEmuLog(0), unthrottle(false), fpsLimit(0), updateRecent(true), freezeNext(false), frozen(false), mountIsoLoader(nullptr) {}
CPUCore cpuCore;
GPUCore gpuCore;
bool enableSound; // there aren't multiple sound cores.
@@ -65,4 +67,6 @@ struct CoreParameter {
// Freeze-frame. For nvidia perfhud profiling. Developers only.
bool freezeNext;
bool frozen;
FileLoader *mountIsoLoader;
};
+31 -97
View File
@@ -17,6 +17,7 @@
#include "Common/FileUtil.h"
#include "Core/Loaders.h"
#include "Core/FileSystems/BlockDevices.h"
#include <cstdio>
#include <cstring>
@@ -29,20 +30,19 @@ extern "C"
#include "ext/libkirk/kirk_engine.h"
};
BlockDevice *constructBlockDevice(const char *filename) {
BlockDevice *constructBlockDevice(FileLoader *fileLoader) {
// Check for CISO
FILE *f = File::OpenCFile(filename, "rb");
if (!f)
return 0;
if (!fileLoader->Exists())
return nullptr;
char buffer[4];
auto size = fread(buffer, 1, 4, f); //size_t
fseek(f, 0, SEEK_SET);
size_t size = fileLoader->ReadAt(0, 1, 4, buffer);
fileLoader->Seek(0);
if (!memcmp(buffer, "CISO", 4) && size == 4)
return new CISOFileBlockDevice(f);
return new CISOFileBlockDevice(fileLoader);
else if (!memcmp(buffer, "\x00PBP", 4) && size == 4)
return new NPDRMDemoBlockDevice(f);
return new NPDRMDemoBlockDevice(fileLoader);
else
return new FileBlockDevice(f);
return new FileBlockDevice(fileLoader);
}
RAMBlockDevice::RAMBlockDevice(BlockDevice *device) {
@@ -74,67 +74,16 @@ u32 RAMBlockDevice::GetNumBlocks() {
// Android NDK does not support 64-bit file I/O using C streams
// so we fall back onto syscalls
#ifdef ANDROID
FileBlockDevice::FileBlockDevice(FILE *file)
: f(file)
{
fd = fileno(file);
off64_t off = lseek64(fd, 0, SEEK_END);
filesize = off;
lseek64(fd, 0, SEEK_SET);
FileBlockDevice::FileBlockDevice(FileLoader *fileLoader)
: fileLoader_(fileLoader) {
filesize_ = fileLoader->FileSize();
}
FileBlockDevice::~FileBlockDevice()
{
fclose(f);
FileBlockDevice::~FileBlockDevice() {
}
bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
{
lseek64(fd, (u64)blockNumber * (u64)GetBlockSize(), SEEK_SET);
if (read(fd, outPtr, 2048) != 2048) {
ERROR_LOG(FILESYS, "Could not read() 2048 bytes from block");
return false;
}
return true;
}
bool FileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr)
{
lseek64(fd, (u64)minBlock * (u64)GetBlockSize(), SEEK_SET);
const s32 bytes = GetBlockSize() * count;
if (read(fd, outPtr, bytes) != bytes) {
ERROR_LOG(FILESYS, "Could not read() %d bytes from block", bytes);
return false;
}
return true;
}
#else
FileBlockDevice::FileBlockDevice(FILE *file)
: f(file)
{
fseek(f, 0, SEEK_END);
filesize = ftello(f);
fseek(f, 0, SEEK_SET);
}
FileBlockDevice::~FileBlockDevice()
{
fclose(f);
}
bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
{
fseeko(f, (u64)blockNumber * (u64)GetBlockSize(), SEEK_SET);
if (fread(outPtr, 1, 2048, f) != 2048) {
bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr) {
if (fileLoader_->ReadAt((u64)blockNumber * (u64)GetBlockSize(), 1, 2048, outPtr) != 2048) {
DEBUG_LOG(FILESYS, "Could not read 2048 bytes from block");
return false;
}
@@ -142,18 +91,14 @@ bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
return true;
}
bool FileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr)
{
fseeko(f, (u64)minBlock * (u64)GetBlockSize(), SEEK_SET);
if (fread(outPtr, 2048, count, f) != count) {
bool FileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr) {
if (fileLoader_->ReadAt((u64)minBlock * (u64)GetBlockSize(), 2048, count, outPtr) != count) {
ERROR_LOG(FILESYS, "Could not read %d bytes from block", 2048 * count);
return false;
}
return true;
}
#endif
// .CSO format
// compressed ISO(9660) header format
@@ -184,14 +129,13 @@ typedef struct ciso_header
static const u32 CSO_READ_BUFFER_SIZE = 256 * 1024;
CISOFileBlockDevice::CISOFileBlockDevice(FILE *file)
: f(file)
CISOFileBlockDevice::CISOFileBlockDevice(FileLoader *fileLoader)
: fileLoader_(fileLoader)
{
// CISO format is fairly simple, but most tools do not write the header_size.
f = file;
CISO_H hdr;
size_t readSize = fread(&hdr, sizeof(CISO_H), 1, f);
size_t readSize = fileLoader->ReadAt(0, sizeof(CISO_H), 1, &hdr);
if (readSize != 1 || memcmp(hdr.magic, "CISO", 4) != 0)
{
WARN_LOG(LOADER, "Invalid CSO!");
@@ -235,13 +179,13 @@ CISOFileBlockDevice::CISOFileBlockDevice(FILE *file)
#if COMMON_LITTLE_ENDIAN
index = new u32[indexSize];
if (fread(index, sizeof(u32), indexSize, f) != indexSize)
if (fileLoader->ReadAt(sizeof(hdr), sizeof(u32), indexSize, index) != indexSize)
memset(index, 0, indexSize * sizeof(u32));
#else
index = new u32[indexSize];
u32_le *indexTemp = new u32_le[indexSize];
if (fread(indexTemp, sizeof(u32), indexSize, f) != indexSize)
if (fileLoader->ReadAt(sizeof(hdr), sizeof(u32), indexSize, indexTemp) != indexSize)
{
memset(indexTemp, 0, indexSize * sizeof(u32_le));
}
@@ -257,7 +201,6 @@ CISOFileBlockDevice::CISOFileBlockDevice(FILE *file)
CISOFileBlockDevice::~CISOFileBlockDevice()
{
fclose(f);
delete [] index;
delete [] readBuffer;
delete [] zlibBuffer;
@@ -285,8 +228,7 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
const int plain = idx & 0x80000000;
if (plain)
{
fseeko(f, compressedReadPos + compressedOffset, SEEK_SET);
int readSize = (u32)fread(outPtr, 1, GetBlockSize(), f);
int readSize = (u32)fileLoader_->ReadAt(compressedReadPos + compressedOffset, 1, GetBlockSize(), outPtr);
if (readSize < GetBlockSize())
memset(outPtr + readSize, 0, GetBlockSize() - readSize);
}
@@ -297,8 +239,7 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
}
else
{
fseeko(f, compressedReadPos, SEEK_SET);
const u32 readSize = (u32)fread(readBuffer, 1, compressedReadSize, f);
const u32 readSize = (u32)fileLoader_->ReadAt(compressedReadPos, 1, compressedReadSize, readBuffer);
z.zalloc = Z_NULL;
z.zfree = Z_NULL;
@@ -387,8 +328,7 @@ bool CISOFileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr) {
const s64 maxNeeded = totalReadEnd - frameReadPos;
const size_t chunkSize = (size_t)std::min(maxNeeded, (s64)std::max(frameReadSize, CSO_READ_BUFFER_SIZE));
fseeko(f, frameReadPos, SEEK_SET);
const u32 readSize = (u32)fread(readBuffer, 1, chunkSize, f);
const u32 readSize = (u32)fileLoader_->ReadAt(frameReadPos, 1, chunkSize, readBuffer);
if (readSize < chunkSize) {
memset(readBuffer + readSize, 0, chunkSize - readSize);
}
@@ -432,8 +372,8 @@ bool CISOFileBlockDevice::ReadBlocks(u32 minBlock, int count, u8 *outPtr) {
}
NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FILE *file)
: f(file)
NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FileLoader *fileLoader)
: fileLoader_(fileLoader)
{
MAC_KEY mkey;
CIPHER_KEY ckey;
@@ -441,10 +381,8 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FILE *file)
u32 tableOffset, tableSize;
u32 lbaStart, lbaEnd;
fseek(f, 0x24, SEEK_SET);
fread(&psarOffset, 1, 4, f);
fseek(f, psarOffset, SEEK_SET);
size_t readSize = fread(&np_header, 1, 256, f);
fileLoader_->ReadAt(0x24, 1, 4, &psarOffset);
size_t readSize = fileLoader_->ReadAt(psarOffset, 1, 256, &np_header);
if(readSize!=256){
ERROR_LOG(LOADER, "Invalid NPUMDIMG header!");
}
@@ -473,12 +411,11 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FILE *file)
tempBuf = new u8[blockSize];
tableOffset = *(u32*)(np_header+0x6c); // table offset
fseek(f, psarOffset+tableOffset, SEEK_SET);
tableSize = numBlocks*32;
table = new table_info[numBlocks];
readSize = fread(table, 1, tableSize, f);
readSize = fileLoader_->ReadAt(psarOffset + tableOffset, 1, tableSize, table);
if(readSize!=tableSize){
ERROR_LOG(LOADER, "Invalid NPUMDIMG table!");
}
@@ -503,7 +440,6 @@ NPDRMDemoBlockDevice::NPDRMDemoBlockDevice(FILE *file)
NPDRMDemoBlockDevice::~NPDRMDemoBlockDevice()
{
fclose(f);
delete [] table;
delete [] tempBuf;
delete [] blockBuf;
@@ -535,14 +471,12 @@ bool NPDRMDemoBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
return false;
}
fseek(f, psarOffset+table[block].offset, SEEK_SET);
if(table[block].size<blockSize)
readBuf = tempBuf;
else
readBuf = blockBuf;
readSize = fread(readBuf, 1, table[block].size, f);
readSize = fileLoader_->ReadAt(psarOffset+table[block].offset, 1, table[block].size, readBuf);
if(readSize != (size_t)table[block].size){
if((u32)block==(numBlocks-1))
return true;
+11 -12
View File
@@ -26,6 +26,8 @@
#include "Common/CommonTypes.h"
#include "Core/ELF/PBPReader.h"
class FileLoader;
class BlockDevice
{
public:
@@ -48,14 +50,14 @@ public:
class CISOFileBlockDevice : public BlockDevice
{
public:
CISOFileBlockDevice(FILE *file);
CISOFileBlockDevice(FileLoader *fileLoader);
~CISOFileBlockDevice();
bool ReadBlock(int blockNumber, u8 *outPtr) override;
bool ReadBlocks(u32 minBlock, int count, u8 *outPtr) override;
u32 GetNumBlocks() { return numBlocks;}
private:
FILE *f;
FileLoader *fileLoader_;
u32 *index;
u8 *readBuffer;
u8 *zlibBuffer;
@@ -71,18 +73,15 @@ private:
class FileBlockDevice : public BlockDevice
{
public:
FileBlockDevice(FILE *file);
FileBlockDevice(FileLoader *fileLoader);
~FileBlockDevice();
bool ReadBlock(int blockNumber, u8 *outPtr) override;
bool ReadBlocks(u32 minBlock, int count, u8 *outPtr) override;
u32 GetNumBlocks() override {return (u32)(filesize / GetBlockSize());}
u32 GetNumBlocks() override {return (u32)(filesize_ / GetBlockSize());}
private:
#ifdef ANDROID
int fd;
#endif
FILE *f;
u64 filesize;
FileLoader *fileLoader_;
u64 filesize_;
};
@@ -99,14 +98,14 @@ struct table_info {
class NPDRMDemoBlockDevice : public BlockDevice
{
public:
NPDRMDemoBlockDevice(FILE *file);
NPDRMDemoBlockDevice(FileLoader *fileLoader);
~NPDRMDemoBlockDevice();
bool ReadBlock(int blockNumber, u8 *outPtr) override;
u32 GetNumBlocks() override {return (u32)lbaSize;}
private:
FILE *f;
FileLoader *fileLoader_;
u32 lbaSize;
u32 psarOffset;
@@ -140,4 +139,4 @@ private:
};
BlockDevice *constructBlockDevice(const char *filename);
BlockDevice *constructBlockDevice(FileLoader *fileLoader);
+11 -2
View File
@@ -20,6 +20,7 @@
#include "file/file_util.h"
#include "Common/ChunkFile.h"
#include "Core/Loaders.h"
#include "Core/MemMap.h"
#include "Core/System.h"
#include "Core/CoreTiming.h"
@@ -460,20 +461,28 @@ u32 sceUmdGetErrorStat()
}
void __UmdReplace(std::string filepath) {
// TODO: This should really go through Loaders, no? What if it's an invalid file?
// Only get system from disc0 seems have been enough.
IFileSystem* currentUMD = pspFileSystem.GetSystem("disc0:");
IFileSystem* currentISOBlock = pspFileSystem.GetSystem("umd0:");
if (!currentUMD)
return;
FileLoader *loadedFile = ConstructFileLoader(filepath);
IFileSystem* umd2;
FileInfo info;
if (!getFileInfo(filepath.c_str(), &info)) // This shouldn't happen, but for safety.
if (!loadedFile->Exists()) {
delete loadedFile;
return;
}
UpdateLoadedFile(loadedFile);
if (info.isDirectory) {
umd2 = new VirtualDiscFileSystem(&pspFileSystem, filepath);
} else {
auto bd = constructBlockDevice(filepath.c_str());
auto bd = constructBlockDevice(loadedFile);
if (!bd)
return;
umd2 = new ISOFileSystem(&pspFileSystem, bd);
+712 -44
View File
@@ -15,7 +15,15 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "thread/thread.h"
#include "base/mutex.h"
#include "base/stringutil.h"
#include "base/timeutil.h"
#include "file/file_util.h"
#include "net/http_client.h"
#include "net/resolve.h"
#include "net/url.h"
#include <cstdio>
#include "Common/FileUtil.h"
#include "Core/MIPS/MIPS.h"
@@ -30,34 +38,698 @@
#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;
class LocalFileLoader : public FileLoader {
public:
LocalFileLoader(const std::string &filename);
virtual ~LocalFileLoader();
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_;
};
class HTTPFileLoader : public FileLoader {
public:
HTTPFileLoader(const std::string &filename);
virtual ~HTTPFileLoader() override;
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 {
return ReadAt(filepos_, bytes, count, data);
}
virtual size_t Read(size_t bytes, void *data) override {
return ReadAt(filepos_, bytes, data);
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override {
return ReadAt(absolutePos, bytes * count, data) / bytes;
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override;
private:
s64 filesize_;
s64 filepos_;
Url url_;
net::AutoInit netInit_;
http::Client client_;
std::string filename_;
};
class RetryingFileLoader : public FileLoader {
public:
RetryingFileLoader(FileLoader *backend);
virtual ~RetryingFileLoader() override;
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 {
return ReadAt(filepos_, bytes, count, data);
}
virtual size_t Read(size_t bytes, void *data) override {
return ReadAt(filepos_, bytes, data);
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override {
return ReadAt(absolutePos, bytes * count, data) / bytes;
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override;
private:
enum {
MAX_RETRIES = 3,
};
s64 filepos_;
FileLoader *backend_;
};
class CachingFileLoader : public FileLoader {
public:
CachingFileLoader(FileLoader *backend);
virtual ~CachingFileLoader() override;
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 {
return ReadAt(filepos_, bytes, count, data);
}
virtual size_t Read(size_t bytes, void *data) override {
return ReadAt(filepos_, bytes, data);
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data) override {
return ReadAt(absolutePos, bytes * count, data) / bytes;
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data) override;
private:
void InitCache();
void ShutdownCache();
size_t ReadFromCache(s64 pos, size_t bytes, void *data);
// Guaranteed to read at least one block into the cache.
void SaveIntoCache(s64 pos, size_t bytes, bool readingAhead = false);
bool MakeCacheSpaceFor(size_t blocks, bool readingAhead);
void StartReadAhead(s64 pos);
enum {
BLOCK_SIZE = 65536,
BLOCK_SHIFT = 16,
MAX_BLOCKS_PER_READ = 16,
MAX_BLOCKS_CACHED = 4096, // 256 MB
BLOCK_READAHEAD = 4,
};
s64 filesize_;
s64 filepos_;
FileLoader *backend_;
int exists_;
int isDirectory_;
u64 generation_;
u64 oldestGeneration_;
size_t cacheSize_;
struct BlockInfo {
u8 *ptr;
u64 generation;
BlockInfo() : ptr(nullptr), generation(0) {
}
BlockInfo(u8 *p) : ptr(p), generation(0) {
}
};
std::map<s64, BlockInfo> blocks_;
recursive_mutex blocksMutex_;
mutable recursive_mutex backendMutex_;
bool aheadThread_;
};
FileLoader *ConstructFileLoader(const std::string &filename) {
if (filename.find("http://") == 0 || filename.find("https://") == 0)
return new CachingFileLoader(new RetryingFileLoader(new HTTPFileLoader(filename)));
return new LocalFileLoader(filename);
}
LocalFileLoader::LocalFileLoader(const std::string &filename)
: fd_(0), f_(nullptr), filesize_(0), filename_(filename) {
f_ = File::OpenCFile(filename, "rb");
if (!f_) {
return;
}
#ifdef ANDROID
// Android NDK does not support 64-bit file I/O using C streams
// so we fall back onto syscalls
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
}
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);
}
HTTPFileLoader::HTTPFileLoader(const std::string &filename)
: filesize_(0), filepos_(0), url_(filename), filename_(filename) {
if (!client_.Resolve(url_.Host().c_str(), 80)) {
return;
}
// TODO: Keepalive, etc.
client_.Connect();
int err = client_.SendRequest("HEAD", url_.Resource().c_str());
if (err < 0) {
return;
}
Buffer readbuf;
std::vector<std::string> responseHeaders;
int code = client_.ReadResponseHeaders(&readbuf, responseHeaders);
if (code != 200) {
// Leave size at 0, invalid.
ERROR_LOG(LOADER, "HTTP request failed, got %03d for %s", code, filename.c_str());
return;
}
// TODO: Expire cache via ETag, etc.
bool acceptsRange = false;
for (std::string header : responseHeaders) {
if (startsWithNoCase(header, "Content-Length:")) {
size_t size_pos = header.find_first_of(' ');
if (size_pos != header.npos) {
size_pos = header.find_first_not_of(' ', size_pos);
}
if (size_pos != header.npos) {
filesize_ = atoll(&header[size_pos]);
}
}
if (startsWithNoCase(header, "Accept-Ranges:")) {
std::string lowerHeader = header;
std::transform(lowerHeader.begin(), lowerHeader.end(), lowerHeader.begin(), tolower);
// TODO: Delimited.
if (lowerHeader.find("bytes") != lowerHeader.npos) {
acceptsRange = true;
}
}
}
client_.Disconnect();
if (!acceptsRange) {
WARN_LOG(LOADER, "HTTP server did not advertise support for range requests.");
}
if (filesize_ == 0) {
ERROR_LOG(LOADER, "Could not determine file size for %s", filename.c_str());
}
// If we didn't end up with a filesize_ (e.g. chunked response), give up. File invalid.
}
HTTPFileLoader::~HTTPFileLoader() {
}
bool HTTPFileLoader::Exists() {
// TODO
return url_.Valid() && filesize_ > 0;
}
bool HTTPFileLoader::IsDirectory() {
// Only files.
return false;
}
s64 HTTPFileLoader::FileSize() {
return filesize_;
}
std::string HTTPFileLoader::Path() const {
return filename_;
}
void HTTPFileLoader::Seek(s64 absolutePos) {
filepos_ = absolutePos;
}
size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) {
s64 absoluteEnd = std::min(absolutePos + (s64)bytes, filesize_);
if (absolutePos >= filesize_ || bytes == 0) {
// Read outside of the file or no read at all, just fail immediately.
return 0;
}
// TODO: Keepalive, etc.
client_.Connect();
char requestHeaders[4096];
// Note that the Range header is *inclusive*.
snprintf(requestHeaders, sizeof(requestHeaders),
"Range: bytes=%lld-%lld\r\n", absolutePos, absoluteEnd - 1);
int err = client_.SendRequest("GET", url_.Resource().c_str(), requestHeaders);
if (err < 0) {
return 0;
}
Buffer readbuf;
std::vector<std::string> responseHeaders;
int code = client_.ReadResponseHeaders(&readbuf, responseHeaders);
if (code != 206) {
ERROR_LOG(LOADER, "HTTP server did not respond with range, received code=%03d", code);
return 0;
}
// TODO: Expire cache via ETag, etc.
// We don't support multipart/byteranges responses.
bool supportedResponse = false;
for (std::string header : responseHeaders) {
if (startsWithNoCase(header, "Content-Range:")) {
// TODO: More correctness. Whitespace can be missing or different.
s64 first = -1, last = -1, total = -1;
std::string lowerHeader = header;
std::transform(lowerHeader.begin(), lowerHeader.end(), lowerHeader.begin(), tolower);
if (sscanf(lowerHeader.c_str(), "content-range: bytes %lld-%lld/%lld", &first, &last, &total) >= 2) {
if (first == absolutePos && last == absoluteEnd - 1) {
supportedResponse = true;
} else {
ERROR_LOG(LOADER, "Unexpected HTTP range: got %lld-%lld, wanted %lld-%lld.", first, last, absolutePos, absoluteEnd - 1);
}
} else {
ERROR_LOG(LOADER, "Unexpected HTTP range response: %s", header.c_str());
}
}
}
// TODO: Would be nice to read directly.
Buffer output;
client_.ReadResponseEntity(&readbuf, responseHeaders, &output);
client_.Disconnect();
if (!supportedResponse) {
ERROR_LOG(LOADER, "HTTP server did not respond with the range we wanted.");
return 0;
}
size_t readBytes = output.size();
output.Take(readBytes, (char *)data);
filepos_ = absolutePos + readBytes;
return readBytes;
}
// Takes ownership of backend.
CachingFileLoader::CachingFileLoader(FileLoader *backend)
: filesize_(0), filepos_(0), backend_(backend), exists_(-1), isDirectory_(-1), aheadThread_(false) {
filesize_ = backend->FileSize();
if (filesize_ > 0) {
InitCache();
}
}
CachingFileLoader::~CachingFileLoader() {
if (filesize_ > 0) {
ShutdownCache();
}
// Takes ownership.
delete backend_;
}
bool CachingFileLoader::Exists() {
if (exists_ == -1) {
lock_guard guard(backendMutex_);
exists_ = backend_->Exists() ? 1 : 0;
}
return exists_ == 1;
}
bool CachingFileLoader::IsDirectory() {
if (isDirectory_ == -1) {
lock_guard guard(backendMutex_);
isDirectory_ = backend_->IsDirectory() ? 1 : 0;
}
return isDirectory_ == 1;
}
s64 CachingFileLoader::FileSize() {
return filesize_;
}
std::string CachingFileLoader::Path() const {
lock_guard guard(backendMutex_);
return backend_->Path();
}
void CachingFileLoader::Seek(s64 absolutePos) {
filepos_ = absolutePos;
}
size_t CachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) {
size_t readSize = ReadFromCache(absolutePos, bytes, data);
// While in case the cache size is too small for the entire read.
while (readSize < bytes) {
SaveIntoCache(absolutePos + readSize, bytes - readSize);
readSize += ReadFromCache(absolutePos + readSize, bytes - readSize, (u8 *)data + readSize);
}
StartReadAhead(absolutePos + readSize);
filepos_ = absolutePos + readSize;
return readSize;
}
void CachingFileLoader::InitCache() {
cacheSize_ = 0;
oldestGeneration_ = 0;
generation_ = 0;
}
void CachingFileLoader::ShutdownCache() {
// TODO: Maybe add some hint that deletion is coming soon?
// We can't delete while the thread is running, so have to wait.
// This should only happen from the menu.
while (aheadThread_) {
sleep_ms(1);
}
lock_guard guard(blocksMutex_);
for (auto block : blocks_) {
delete [] block.second.ptr;
}
blocks_.clear();
cacheSize_ = 0;
}
size_t CachingFileLoader::ReadFromCache(s64 pos, size_t bytes, void *data) {
s64 cacheStartPos = pos >> BLOCK_SHIFT;
s64 cacheEndPos = (pos + bytes - 1) >> BLOCK_SHIFT;
// TODO: Smarter.
size_t readSize = 0;
size_t offset = (size_t)(pos - (cacheStartPos << BLOCK_SHIFT));
u8 *p = (u8 *)data;
lock_guard guard(blocksMutex_);
for (s64 i = cacheStartPos; i <= cacheEndPos; ++i) {
auto block = blocks_.find(i);
if (block == blocks_.end()) {
return readSize;
}
block->second.generation = generation_;
size_t toRead = std::min(bytes - readSize, (size_t)BLOCK_SIZE - offset);
memcpy(p + readSize, block->second.ptr + offset, toRead);
readSize += toRead;
// Don't need an offset after the first read.
offset = 0;
}
return readSize;
}
void CachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, bool readingAhead) {
s64 cacheStartPos = pos >> BLOCK_SHIFT;
s64 cacheEndPos = (pos + bytes - 1) >> BLOCK_SHIFT;
lock_guard guard(blocksMutex_);
size_t blocksToRead = 0;
for (s64 i = cacheStartPos; i <= cacheEndPos; ++i) {
auto block = blocks_.find(i);
if (block != blocks_.end()) {
break;
}
++blocksToRead;
if (blocksToRead >= MAX_BLOCKS_PER_READ) {
break;
}
}
if (!MakeCacheSpaceFor(blocksToRead, readingAhead) || blocksToRead == 0) {
return;
}
if (blocksToRead == 1) {
blocksMutex_.unlock();
u8 *buf = new u8[BLOCK_SIZE];
backendMutex_.lock();
backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, BLOCK_SIZE, buf);
backendMutex_.unlock();
blocksMutex_.lock();
// While blocksMutex_ was unlocked, another thread may have read.
// If so, free the one we just read.
if (blocks_.find(cacheStartPos) == blocks_.end()) {
blocks_[cacheStartPos] = BlockInfo(buf);
} else {
delete [] buf;
}
} else {
blocksMutex_.unlock();
u8 *wholeRead = new u8[blocksToRead << BLOCK_SHIFT];
backendMutex_.lock();
backend_->ReadAt(cacheStartPos << BLOCK_SHIFT, blocksToRead << BLOCK_SHIFT, wholeRead);
backendMutex_.unlock();
blocksMutex_.lock();
for (size_t i = 0; i < blocksToRead; ++i) {
if (blocks_.find(cacheStartPos + i) != blocks_.end()) {
// Written while we were busy, just skip it. Keep the existing block.
continue;
}
u8 *buf = new u8[BLOCK_SIZE];
memcpy(buf, wholeRead + (i << BLOCK_SHIFT), BLOCK_SIZE);
blocks_[cacheStartPos + i] = BlockInfo(buf);
}
delete wholeRead;
}
cacheSize_ += blocksToRead;
++generation_;
}
bool CachingFileLoader::MakeCacheSpaceFor(size_t blocks, bool readingAhead) {
size_t goal = MAX_BLOCKS_CACHED - blocks;
if (readingAhead && cacheSize_ > goal) {
return false;
}
lock_guard guard(blocksMutex_);
while (cacheSize_ > goal) {
u64 minGeneration = generation_;
// We increment the iterator inside because we delete things inside.
for (auto it = blocks_.begin(); it != blocks_.end(); ) {
// Check for the minimum seen generation.
// TODO: Do this smarter?
if (it->second.generation != 0 && it->second.generation < minGeneration) {
minGeneration = it->second.generation;
}
// 0 means it was never used yet or was the first read (e.g. block descriptor.)
if (it->second.generation == oldestGeneration_ || it->second.generation == 0) {
s64 pos = it->first;
delete it->second.ptr;
blocks_.erase(it);
--cacheSize_;
// Our iterator is invalid now. Keep going?
if (cacheSize_ > goal) {
// This finds the one at that position.
it = blocks_.lower_bound(pos);
} else {
break;
}
} else {
++it;
}
}
// If we didn't find any, update to the lowest we did find.
oldestGeneration_ = minGeneration;
}
return true;
}
void CachingFileLoader::StartReadAhead(s64 pos) {
lock_guard guard(blocksMutex_);
if (aheadThread_) {
// Already going.
return;
}
if (cacheSize_ + BLOCK_READAHEAD > MAX_BLOCKS_CACHED) {
// Not enough space to readahead.
return;
}
aheadThread_ = true;
std::thread th([this, pos] {
lock_guard guard(blocksMutex_);
s64 cacheStartPos = pos >> BLOCK_SHIFT;
s64 cacheEndPos = cacheStartPos + BLOCK_READAHEAD - 1;
for (s64 i = cacheStartPos; i <= cacheEndPos; ++i) {
auto block = blocks_.find(i);
if (block == blocks_.end()) {
blocksMutex_.unlock();
SaveIntoCache(i << BLOCK_SHIFT, BLOCK_SIZE * BLOCK_READAHEAD, true);
break;
}
}
aheadThread_ = false;
});
th.detach();
}
// Takes ownership of backend.
RetryingFileLoader::RetryingFileLoader(FileLoader *backend)
: filepos_(0), backend_(backend) {
}
RetryingFileLoader::~RetryingFileLoader() {
// Takes ownership.
delete backend_;
}
bool RetryingFileLoader::Exists() {
if (!backend_->Exists()) {
// Retry once, immediately.
return backend_->Exists();
}
return true;
}
bool RetryingFileLoader::IsDirectory() {
// Can't tell if it's an error either way.
return backend_->IsDirectory();
}
s64 RetryingFileLoader::FileSize() {
s64 filesize = backend_->FileSize();
if (filesize == 0) {
return backend_->FileSize();
}
return filesize;
}
std::string RetryingFileLoader::Path() const {
return backend_->Path();
}
void RetryingFileLoader::Seek(s64 absolutePos) {
filepos_ = absolutePos;
}
size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data) {
size_t readSize = backend_->ReadAt(absolutePos, bytes, data);
int retries = 0;
while (readSize < bytes && retries < MAX_RETRIES) {
u8 *p = (u8 *)data;
readSize += backend_->ReadAt(absolutePos + readSize, bytes - readSize, p + readSize);
++retries;
}
filepos_ = absolutePos + readSize;
return readSize;
}
// 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 +748,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 +770,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 +781,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 +792,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 +805,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,23 +864,26 @@ IdentifiedFileType Identify_File(std::string &filename)
return FILETYPE_UNKNOWN;
}
bool LoadFile(std::string &filename, std::string *error_string) {
bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) {
FileLoader *&fileLoader = *fileLoaderPtr;
// 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.
delete fileLoader;
fileLoader = ConstructFileLoader(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);
return Load_PSP_ISO(fileLoader, error_string);
}
else if (ebootType == FILETYPE_PSP_PS1_PBP) {
*error_string = "PS1 EBOOTs are not supported by PPSSPP.";
@@ -225,7 +893,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, error_string);
} else {
*error_string = "No EBOOT.PBP, misidentified game";
return false;
@@ -236,14 +904,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, 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, error_string);
case FILETYPE_PSP_PS1_PBP:
*error_string = "PS1 EBOOTs are not supported by PPSSPP.";
+33 -2
View File
@@ -46,9 +46,40 @@ enum IdentifiedFileType {
FILETYPE_UNKNOWN
};
class FileLoader {
public:
virtual ~FileLoader() {}
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);
}
};
FileLoader *ConstructFileLoader(const 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 **fileLoaderPtr, std::string *error_string);
+13 -12
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);
// Can't init anything without a block device...
if (!bd)
return;
@@ -150,7 +151,7 @@ static const char *altBootNames[] = {
"disc0:/PSP_GAME/SYSDIR/ss.RAW",
};
bool Load_PSP_ISO(const char *filename, std::string *error_string)
bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string)
{
// Mounting stuff relocated to InitMemoryForGameISO due to HD Remaster restructuring of code.
@@ -223,12 +224,12 @@ static std::string NormalizePath(const std::string &path)
return buf;
}
bool Load_PSP_ELF_PBP(const char *filename, std::string *error_string)
bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string)
{
// This is really just for headless, might need tweaking later.
if (!PSP_CoreParameter().mountIso.empty())
if (PSP_CoreParameter().mountIsoLoader != nullptr)
{
auto bd = constructBlockDevice(PSP_CoreParameter().mountIso.c_str());
auto bd = constructBlockDevice(PSP_CoreParameter().mountIsoLoader);
if (bd != NULL) {
ISOFileSystem *umd2 = new ISOFileSystem(&pspFileSystem, bd);
@@ -238,7 +239,7 @@ bool Load_PSP_ELF_PBP(const char *filename, std::string *error_string)
}
}
std::string full_path = filename;
std::string full_path = fileLoader->Path();
std::string path, file, extension;
SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension);
#ifdef _WIN32
+5 -3
View File
@@ -19,6 +19,8 @@
#include <string>
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);
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);
+22 -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,13 @@ void CPU_Init() {
Memory::g_PSPModel = g_Config.iPSPModel;
std::string filename = coreParameter.fileToStart;
IdentifiedFileType type = Identify_File(filename);
loadedFile = ConstructFileLoader(filename);
IdentifiedFileType type = Identify_File(loadedFile);
// TODO: Put this somewhere better?
if (coreParameter.mountIso != "") {
coreParameter.mountIsoLoader = ConstructFileLoader(coreParameter.mountIso);
}
MIPSAnalyst::Reset();
Replacement_Init();
@@ -190,7 +197,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 +220,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 +252,18 @@ void CPU_Shutdown() {
pspFileSystem.Shutdown();
mipsr4k.Shutdown();
Memory::Shutdown();
delete loadedFile;
loadedFile = nullptr;
delete coreParameter.mountIsoLoader;
coreParameter.mountIsoLoader = nullptr;
}
// TODO: Maybe loadedFile doesn't even belong here...
void UpdateLoadedFile(FileLoader *fileLoader) {
delete loadedFile;
loadedFile = fileLoader;
}
void CPU_RunLoop() {
+2
View File
@@ -63,6 +63,8 @@ void Audio_Init();
bool IsOnSeparateCPUThread();
bool IsAudioInitialised();
void UpdateLoadedFile(FileLoader *fileLoader);
std::string GetSysDirectory(PSPDirectories directoryType);
#ifdef _WIN32
void InitSysDirectories();
+4 -2
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(ConstructFileLoader(filename));
info_->path = gamePath_;
info_->fileType = Identify_File(filename);
info_->fileType = Identify_File(fileLoader.get());
// Fallback title
info_->title = getFilename(info_->path);
@@ -376,7 +378,7 @@ handleELF:
// Let's assume it's an ISO.
// TODO: This will currently read in the whole directory tree. Not really necessary for just a
// few files.
BlockDevice *bd = constructBlockDevice(gamePath_.c_str());
BlockDevice *bd = constructBlockDevice(fileLoader.get());
if (!bd)
return; // nothing to do here..
ISOFileSystem umd(&handles, bd, "/PSP_GAME");
+1 -1
Submodule native updated: 92be7b0b1b...1150598ce4.