diff --git a/CMakeLists.txt b/CMakeLists.txt
index d98728371f..e257316aab 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -784,6 +784,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/FileSystems/ISOFileSystem.h
Core/FileSystems/MetaFileSystem.cpp
Core/FileSystems/MetaFileSystem.h
+ Core/FileSystems/VirtualDiscFileSystem.cpp
+ Core/FileSystems/VirtualDiscFileSystem.h
Core/Font/PGF.cpp
Core/Font/PGF.h
Core/HLE/FunctionWrappers.h
diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt
index bb185990cf..9d1b4bf89c 100644
--- a/Core/CMakeLists.txt
+++ b/Core/CMakeLists.txt
@@ -81,6 +81,7 @@ set(SRCS
FileSystems/ISOFileSystem.cpp
FileSystems/DirectoryFileSystem.cpp
FileSystems/MetaFileSystem.cpp
+ FileSystems/VirtualDiscFileSystem.cpp
Util/BlockAllocator.cpp
Util/ppge_atlas.cpp
Util/PPGeDraw.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index cdc76a6070..2ac6129b66 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -187,6 +187,7 @@
+
@@ -371,6 +372,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 49008c0860..ae1395a957 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -448,6 +448,9 @@
MIPS
+
+ FileSystems
+
@@ -831,6 +834,9 @@
MIPS
+
+ FileSystems
+
diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp
index a9aed142d3..e8a0ce222c 100644
--- a/Core/FileSystems/DirectoryFileSystem.cpp
+++ b/Core/FileSystems/DirectoryFileSystem.cpp
@@ -33,12 +33,6 @@
#endif
#if HOST_IS_CASE_SENSITIVE
-typedef enum {
- FPC_FILE_MUST_EXIST, // all path components must exist (rmdir, move from)
- FPC_PATH_MUST_EXIST, // all except the last one must exist - still tries to fix last one (fopen, move to)
- FPC_PARTIAL_ALLOWED, // don't care how many exist (mkdir recursive)
-} FixPathCaseBehavior;
-
static bool FixFilenameCase(const std::string &path, std::string &filename)
{
// Are we lucky?
@@ -303,20 +297,6 @@ void DirectoryFileHandle::Close()
#endif
}
-u64 getFileSize(std::string& fileName)
-{
-#ifdef _WIN32
- WIN32_FILE_ATTRIBUTE_DATA data;
- GetFileAttributesEx(fileName.c_str(), GetFileExInfoStandard, &data);
-
- return data.nFileSizeLow | ((u64)data.nFileSizeHigh<<32);
-#else
- struct stat s;
- stat(fileName.c_str(), &s);
- return s.st_size;
-#endif
-}
-
DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) {
File::CreateFullPath(basePath);
hAlloc = _hAlloc;
@@ -570,7 +550,7 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) {
struct stat s;
stat(fullName.c_str(), &s);
- x.size = getFileSize(fullName);
+ x.size = File::GetSize(fullName);
x.access = s.st_mode & 0x1FF;
localtime_r((time_t*)&s.st_atime,&x.atime);
localtime_r((time_t*)&s.st_ctime,&x.ctime);
@@ -686,446 +666,6 @@ void DirectoryFileSystem::DoState(PointerWrap &p) {
-VirtualDiscFileSystem::VirtualDiscFileSystem(IHandleAllocator *_hAlloc, std::string _basePath)
- : basePath(_basePath),currentBlockIndex(0) {
-
-#ifdef _WIN32
- if (basePath.size() > 0 && basePath[basePath.size()-1] != '\\')
- basePath = basePath + "\\";
-#else
- if (basePath.size() > 0 && basePath[basePath.size()-1] != '/')
- basePath = basePath + "/";
-#endif
-
- hAlloc = _hAlloc;
-}
-
-VirtualDiscFileSystem::~VirtualDiscFileSystem() {
- for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
- if (iter->second.type != VFILETYPE_ISO)
- iter->second.hFile.Close();
- }
-}
-
-void VirtualDiscFileSystem::DoState(PointerWrap &p)
-{
- int fileListSize = fileList.size();
- int entryCount = entries.size();
-
- p.Do(fileListSize);
- p.Do(entryCount);
- p.Do(currentBlockIndex);
-
- if (p.mode == p.MODE_READ)
- {
- fileList.clear();
- entries.clear();
-
- for (int i = 0; i < fileListSize; i++)
- {
- FileListEntry entry;
- p.Do(entry.fileName);
- p.Do(entry.firstBlock);
- p.Do(entry.totalSize);
- fileList.push_back(entry);
- }
-
- for (int i = 0; i < entryCount; i++)
- {
- u32 fd;
- OpenFileEntry of;
-
- p.Do(fd);
- p.Do(of.fileIndex);
- p.Do(of.type);
- p.Do(of.curOffset);
- p.Do(of.startOffset);
- p.Do(of.size);
-
- // open file
- if (of.type != VFILETYPE_ISO)
- {
- bool success = of.hFile.Open(basePath,fileList[of.fileIndex].fileName,FILEACCESS_READ);
- if (!success)
- {
- ERROR_LOG(FILESYS, "Failed to create file handle for %s.",fileList[of.fileIndex].fileName.c_str());
- } else {
- if (of.type == VFILETYPE_LBN)
- {
- of.hFile.Seek(of.curOffset+of.startOffset,FILEMOVE_BEGIN);
- } else {
- of.hFile.Seek(of.curOffset,FILEMOVE_BEGIN);
- }
- }
- }
-
- entries[fd] = of;
- }
- } else {
- for (int i = 0; i < fileListSize; i++)
- {
- p.Do(fileList[i].fileName);
- p.Do(fileList[i].firstBlock);
- p.Do(fileList[i].totalSize);
- }
-
- for (EntryMap::iterator it = entries.begin(), end = entries.end(); it != end; ++it)
- {
- OpenFileEntry &of = it->second;
-
- p.Do(it->first);
- p.Do(of.fileIndex);
- p.Do(of.type);
- p.Do(of.curOffset);
- p.Do(of.startOffset);
- p.Do(of.size);
- }
- }
-
- p.DoMarker("VirtualDiscFileSystem");
-}
-
-std::string VirtualDiscFileSystem::GetLocalPath(std::string localpath) {
- if (localpath.empty())
- return basePath;
-
- if (localpath[0] == '/')
- localpath.erase(0,1);
- //Convert slashes
-#ifdef _WIN32
- for (size_t i = 0; i < localpath.size(); i++) {
- if (localpath[i] == '/')
- localpath[i] = '\\';
- }
-#endif
- return basePath + localpath;
-}
-
-int VirtualDiscFileSystem::getFileListIndex(std::string& fileName)
-{
- for (size_t i = 0; i < fileList.size(); i++)
- {
- if (fileList[i].fileName == fileName)
- return (int)i;
- }
-
- // unknown file - add it
- std::string fullName = GetLocalPath(fileName);
- if (! File::Exists(fullName)) {
-#if HOST_IS_CASE_SENSITIVE
- if (! FixPathCase(basePath,fileName, FPC_FILE_MUST_EXIST))
- return -1;
- fullName = GetLocalPath(fileName);
-
- if (! File::Exists(fullName))
- return -1;
-#else
- return -1;
-#endif
- }
-
- FileType type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
- if (type == FILETYPE_DIRECTORY)
- return -1;
-
- FileListEntry entry;
- entry.fileName = fileName;
- entry.totalSize = getFileSize(fullName);
- entry.firstBlock = currentBlockIndex;
- currentBlockIndex += (entry.totalSize+2047)/2048;
-
- fileList.push_back(entry);
-
- return fileList.size()-1;
-}
-
-int VirtualDiscFileSystem::getFileListIndex(u32 accessBlock, u32 accessSize)
-{
- for (size_t i = 0; i < fileList.size(); i++)
- {
- if (fileList[i].firstBlock <= accessBlock)
- {
- u32 sectorOffset = (accessBlock-fileList[i].firstBlock)*2048;
- u32 endOffset = sectorOffset+accessSize;
- if (endOffset <= fileList[i].totalSize)
- {
- return (int)i;
- }
- }
- }
-
- return -1;
-}
-
-u32 VirtualDiscFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename)
-{
- OpenFileEntry entry;
- entry.curOffset = 0;
- entry.size = 0;
- entry.startOffset = 0;
-
- if (filename == "")
- {
- entry.type = VFILETYPE_ISO;
- entry.fileIndex = -1;
-
- u32 newHandle = hAlloc->GetNewHandle();
- entries[newHandle] = entry;
-
- return newHandle;
- }
-
- if (filename.compare(0,8,"/sce_lbn") == 0)
- {
- u32 sectorStart = 0xFFFFFFFF, readSize = 0xFFFFFFFF;
- parseLBN(filename, §orStart, &readSize);
-
- entry.type = VFILETYPE_LBN;
- entry.size = readSize;
-
- int fileIndex = getFileListIndex(sectorStart,readSize);
- if (fileIndex == -1)
- {
- ERROR_LOG(FILESYS, "VirtualDiscFileSystem: sce_lbn used without calling fileinfo.");
- return 0;
- }
- entry.fileIndex = (u32)fileIndex;
-
- entry.startOffset = (sectorStart-fileList[entry.fileIndex].firstBlock)*2048;
-
- // now we just need an actual file handle
- bool success = entry.hFile.Open(basePath,fileList[entry.fileIndex].fileName,FILEACCESS_READ);
-
- if (!success)
- {
-#ifdef _WIN32
- ERROR_LOG(HLE, "VirtualDiscFileSystem::OpenFile: FAILED, %i", GetLastError());
-#else
- ERROR_LOG(HLE, "VirtualDiscFileSystem::OpenFile: FAILED");
-#endif
- return 0;
- }
-
- // seek to start
- entry.hFile.Seek(entry.startOffset,FILEMOVE_BEGIN);
-
- u32 newHandle = hAlloc->GetNewHandle();
- entries[newHandle] = entry;
-
- return newHandle;
- }
-
- entry.type = VFILETYPE_NORMAL;
- bool success = entry.hFile.Open(basePath,filename,access);
-
- if (!success) {
-#ifdef _WIN32
- ERROR_LOG(HLE, "VirtualDiscFileSystem::OpenFile: FAILED, %i - access = %i", GetLastError(), (int)access);
-#else
- ERROR_LOG(HLE, "VirtualDiscFileSystem::OpenFile: FAILED, access = %i", (int)access);
-#endif
- //wwwwaaaaahh!!
- return 0;
- } else {
- entry.fileIndex = getFileListIndex(filename);
-
- u32 newHandle = hAlloc->GetNewHandle();
- entries[newHandle] = entry;
-
- return newHandle;
- }
-}
-
-size_t VirtualDiscFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
- EntryMap::iterator iter = entries.find(handle);
- if (iter != entries.end()) {
- switch (iter->second.type)
- {
- case VFILETYPE_NORMAL:
- {
- return iter->second.hFile.Seek(position,type);
- }
- case VFILETYPE_LBN:
- {
- switch (type)
- {
- case FILEMOVE_BEGIN: iter->second.curOffset = position; break;
- case FILEMOVE_CURRENT: iter->second.curOffset += position; break;
- case FILEMOVE_END: iter->second.curOffset = iter->second.size-position; break;
- }
-
- u32 off = iter->second.startOffset+iter->second.curOffset;
- iter->second.hFile.Seek(off,FILEMOVE_BEGIN);
- return iter->second.curOffset;
- }
- case VFILETYPE_ISO:
- {
- switch (type)
- {
- case FILEMOVE_BEGIN: iter->second.curOffset = position; break;
- case FILEMOVE_CURRENT: iter->second.curOffset += position; break;
- case FILEMOVE_END: return -1; // unsupported
- }
-
- return iter->second.curOffset;
- }
- }
- return 0;
- } else {
- //This shouldn't happen...
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot seek in file that hasn't been opened: %08x", handle);
- return 0;
- }
-}
-
-size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
- EntryMap::iterator iter = entries.find(handle);
- if (iter != entries.end())
- {
- // it's the whole iso... it could reference any of the files on the disc.
- // For now let's just open and close the files on demand. Can certainly be done
- // better though
- if (iter->second.type == VFILETYPE_ISO)
- {
- int fileIndex = getFileListIndex(iter->second.curOffset,size*2048);
- if (fileIndex == -1)
- {
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Reading from unknown address %08x", handle);
- return 0;
- }
-
- DirectoryFileHandle hFile;
- bool success = hFile.Open(basePath,fileList[fileIndex].fileName,FILEACCESS_READ);
-
- if (!success)
- {
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Error opening file %s", fileList[fileIndex].fileName.c_str());
- return 0;
- }
-
- u32 startOffset = (iter->second.curOffset-fileList[fileIndex].firstBlock)*2048;
- size_t bytesRead;
-
- hFile.Seek(startOffset,FILEMOVE_BEGIN);
- bytesRead = hFile.Read(pointer,size*2048);
- hFile.Close();
-
- return bytesRead;
- }
-
- size_t bytesRead = iter->second.hFile.Read(pointer,size);
- iter->second.curOffset += bytesRead;
- return bytesRead;
- } else {
- //This shouldn't happen...
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot read file that hasn't been opened: %08x", handle);
- return 0;
- }
-}
-
-void VirtualDiscFileSystem::CloseFile(u32 handle) {
- EntryMap::iterator iter = entries.find(handle);
- if (iter != entries.end()) {
- hAlloc->FreeHandle(handle);
- iter->second.hFile.Close();
- entries.erase(iter);
- } else {
- //This shouldn't happen...
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot close file that hasn't been opened: %08x", handle);
- }
-}
-
-bool VirtualDiscFileSystem::OwnsHandle(u32 handle) {
- EntryMap::iterator iter = entries.find(handle);
- return (iter != entries.end());
-}
-
-PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) {
- PSPFileInfo x;
- x.name = filename;
-
- std::string fullName = GetLocalPath(filename);
- if (! File::Exists(fullName)) {
-#if HOST_IS_CASE_SENSITIVE
- if (! FixPathCase(basePath,filename, FPC_FILE_MUST_EXIST))
- return x;
- fullName = GetLocalPath(filename);
-
- if (! File::Exists(fullName))
- return x;
-#else
- return x;
-#endif
- }
-
- x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
- x.exists = true;
-
- if (x.type != FILETYPE_DIRECTORY)
- {
- struct stat s;
- stat(fullName.c_str(), &s);
-
- x.size = getFileSize(fullName);
-
- int fileIndex = getFileListIndex(filename);
- x.startSector = fileList[fileIndex].firstBlock;
- x.numSectors = (x.size+2047)/2048;
-
- x.access = s.st_mode & 0x1FF;
- localtime_r((time_t*)&s.st_atime,&x.atime);
- localtime_r((time_t*)&s.st_ctime,&x.ctime);
- localtime_r((time_t*)&s.st_mtime,&x.mtime);
- }
-
- return x;
-}
-
-bool VirtualDiscFileSystem::GetHostPath(const std::string &inpath, std::string &outpath)
-{
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Retrieving host path");
- return false;
-}
-
-std::vector VirtualDiscFileSystem::GetDirListing(std::string path)
-{
- // todo
- std::vector result;
- return result;
-}
-
-size_t VirtualDiscFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)
-{
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot write to file on virtual disc");
- return 0;
-}
-
-bool VirtualDiscFileSystem::MkDir(const std::string &dirname)
-{
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot create directory on virtual disc");
- return false;
-}
-
-bool VirtualDiscFileSystem::RmDir(const std::string &dirname)
-{
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot remove directory on virtual disc");
- return false;
-}
-
-int VirtualDiscFileSystem::RenameFile(const std::string &from, const std::string &to)
-{
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot rename file on virtual disc");
- return -1;
-}
-
-bool VirtualDiscFileSystem::RemoveFile(const std::string &filename)
-{
- ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot remove file on virtual disc");
- return false;
-}
-
-
-
VFSFileSystem::VFSFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) {
INFO_LOG(HLE, "Creating VFS file system");
hAlloc = _hAlloc;
diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h
index 2419b90727..6027640636 100644
--- a/Core/FileSystems/DirectoryFileSystem.h
+++ b/Core/FileSystems/DirectoryFileSystem.h
@@ -47,14 +47,24 @@ typedef void * HANDLE;
#endif
-typedef struct sDirectoryFileHandle
+#if HOST_IS_CASE_SENSITIVE
+enum FixPathCaseBehavior {
+ FPC_FILE_MUST_EXIST, // all path components must exist (rmdir, move from)
+ FPC_PATH_MUST_EXIST, // all except the last one must exist - still tries to fix last one (fopen, move to)
+ FPC_PARTIAL_ALLOWED, // don't care how many exist (mkdir recursive)
+};
+
+bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior);
+#endif
+
+struct DirectoryFileHandle
{
#ifdef _WIN32
HANDLE hFile;
#else
FILE* hFile;
#endif
- sDirectoryFileHandle()
+ DirectoryFileHandle()
{
#ifdef _WIN32
hFile = (HANDLE)-1;
@@ -69,7 +79,7 @@ typedef struct sDirectoryFileHandle
size_t Write(const u8* pointer, s64 size);
size_t Seek(s32 position, FileMove type);
void Close();
-} DirectoryFileHandle;
+};
class DirectoryFileSystem : public IFileSystem {
public:
@@ -106,60 +116,6 @@ private:
std::string GetLocalPath(std::string localpath);
};
-class VirtualDiscFileSystem: public IFileSystem
-{
-public:
- VirtualDiscFileSystem(IHandleAllocator *_hAlloc, std::string _basePath);
- ~VirtualDiscFileSystem();
-
- void DoState(PointerWrap &p);
- u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL);
- size_t SeekFile(u32 handle, s32 position, FileMove type);
- size_t ReadFile(u32 handle, u8 *pointer, s64 size);
- void CloseFile(u32 handle);
- PSPFileInfo GetFileInfo(std::string filename);
- bool OwnsHandle(u32 handle);
- bool GetHostPath(const std::string &inpath, std::string &outpath);
- std::vector GetDirListing(std::string path);
-
- // unsupported operations
- size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
- bool MkDir(const std::string &dirname);
- bool RmDir(const std::string &dirname);
- int RenameFile(const std::string &from, const std::string &to);
- bool RemoveFile(const std::string &filename);
-
-private:
- int getFileListIndex(std::string& fileName);
- int getFileListIndex(u32 accessBlock, u32 accessSize);
- std::string GetLocalPath(std::string localpath);
-
- typedef enum { VFILETYPE_NORMAL, VFILETYPE_LBN, VFILETYPE_ISO } VirtualFileType;
-
- struct OpenFileEntry {
- DirectoryFileHandle hFile;
- VirtualFileType type;
- u32 fileIndex;
- u32 curOffset;
- u32 startOffset; // only used by lbn files
- u32 size; // only used by lbn files
- };
-
- typedef std::map EntryMap;
- EntryMap entries;
- IHandleAllocator *hAlloc;
- std::string basePath;
-
- typedef struct {
- std::string fileName;
- u32 firstBlock;
- u32 totalSize;
- } FileListEntry;
-
- std::vector fileList;
- u32 currentBlockIndex;
-};
-
// VFSFileSystem: Ability to map in Android APK paths as well! Does not support all features, only meant for fonts.
// Very inefficient - always load the whole file on open.
class VFSFileSystem : public IFileSystem {
diff --git a/Core/FileSystems/VirtualDiscFileSystem.cpp b/Core/FileSystems/VirtualDiscFileSystem.cpp
new file mode 100644
index 0000000000..7d5358bb2a
--- /dev/null
+++ b/Core/FileSystems/VirtualDiscFileSystem.cpp
@@ -0,0 +1,471 @@
+// Copyright (c) 2012- 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 "Common/FileUtil.h"
+#include "Common/ChunkFile.h"
+#include "Core/FileSystems/VirtualDiscFileSystem.h"
+#include "Core/FileSystems/ISOFileSystem.h"
+#include "Core/HLE/sceKernel.h"
+#include "file/zip_read.h"
+
+#ifdef _WIN32
+#include
+#include
+#else
+#include
+#include
+#include
+#include
+#endif
+
+VirtualDiscFileSystem::VirtualDiscFileSystem(IHandleAllocator *_hAlloc, std::string _basePath)
+ : basePath(_basePath),currentBlockIndex(0) {
+
+#ifdef _WIN32
+ if (basePath.size() > 0 && basePath[basePath.size()-1] != '\\')
+ basePath = basePath + "\\";
+#else
+ if (basePath.size() > 0 && basePath[basePath.size()-1] != '/')
+ basePath = basePath + "/";
+#endif
+
+ hAlloc = _hAlloc;
+}
+
+VirtualDiscFileSystem::~VirtualDiscFileSystem() {
+ for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
+ if (iter->second.type != VFILETYPE_ISO)
+ iter->second.hFile.Close();
+ }
+}
+
+void VirtualDiscFileSystem::DoState(PointerWrap &p)
+{
+ int fileListSize = fileList.size();
+ int entryCount = entries.size();
+
+ p.Do(fileListSize);
+ p.Do(entryCount);
+ p.Do(currentBlockIndex);
+
+ if (p.mode == p.MODE_READ)
+ {
+ fileList.clear();
+ entries.clear();
+
+ for (int i = 0; i < fileListSize; i++)
+ {
+ FileListEntry entry;
+ p.Do(entry.fileName);
+ p.Do(entry.firstBlock);
+ p.Do(entry.totalSize);
+ fileList.push_back(entry);
+ }
+
+ for (int i = 0; i < entryCount; i++)
+ {
+ u32 fd;
+ OpenFileEntry of;
+
+ p.Do(fd);
+ p.Do(of.fileIndex);
+ p.Do(of.type);
+ p.Do(of.curOffset);
+ p.Do(of.startOffset);
+ p.Do(of.size);
+
+ // open file
+ if (of.type != VFILETYPE_ISO)
+ {
+ bool success = of.hFile.Open(basePath,fileList[of.fileIndex].fileName,FILEACCESS_READ);
+ if (!success)
+ {
+ ERROR_LOG(FILESYS, "Failed to create file handle for %s.",fileList[of.fileIndex].fileName.c_str());
+ } else {
+ if (of.type == VFILETYPE_LBN)
+ {
+ of.hFile.Seek(of.curOffset+of.startOffset,FILEMOVE_BEGIN);
+ } else {
+ of.hFile.Seek(of.curOffset,FILEMOVE_BEGIN);
+ }
+ }
+ }
+
+ entries[fd] = of;
+ }
+ } else {
+ for (int i = 0; i < fileListSize; i++)
+ {
+ p.Do(fileList[i].fileName);
+ p.Do(fileList[i].firstBlock);
+ p.Do(fileList[i].totalSize);
+ }
+
+ for (EntryMap::iterator it = entries.begin(), end = entries.end(); it != end; ++it)
+ {
+ OpenFileEntry &of = it->second;
+
+ p.Do(it->first);
+ p.Do(of.fileIndex);
+ p.Do(of.type);
+ p.Do(of.curOffset);
+ p.Do(of.startOffset);
+ p.Do(of.size);
+ }
+ }
+
+ p.DoMarker("VirtualDiscFileSystem");
+}
+
+std::string VirtualDiscFileSystem::GetLocalPath(std::string localpath) {
+ if (localpath.empty())
+ return basePath;
+
+ if (localpath[0] == '/')
+ localpath.erase(0,1);
+ //Convert slashes
+#ifdef _WIN32
+ for (size_t i = 0; i < localpath.size(); i++) {
+ if (localpath[i] == '/')
+ localpath[i] = '\\';
+ }
+#endif
+ return basePath + localpath;
+}
+
+int VirtualDiscFileSystem::getFileListIndex(std::string& fileName)
+{
+ for (size_t i = 0; i < fileList.size(); i++)
+ {
+ if (fileList[i].fileName == fileName)
+ return (int)i;
+ }
+
+ // unknown file - add it
+ std::string fullName = GetLocalPath(fileName);
+ if (! File::Exists(fullName)) {
+#if HOST_IS_CASE_SENSITIVE
+ if (! FixPathCase(basePath,fileName, FPC_FILE_MUST_EXIST))
+ return -1;
+ fullName = GetLocalPath(fileName);
+
+ if (! File::Exists(fullName))
+ return -1;
+#else
+ return -1;
+#endif
+ }
+
+ FileType type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
+ if (type == FILETYPE_DIRECTORY)
+ return -1;
+
+ FileListEntry entry;
+ entry.fileName = fileName;
+ entry.totalSize = File::GetSize(fullName);
+ entry.firstBlock = currentBlockIndex;
+ currentBlockIndex += (entry.totalSize+2047)/2048;
+
+ fileList.push_back(entry);
+
+ return fileList.size()-1;
+}
+
+int VirtualDiscFileSystem::getFileListIndex(u32 accessBlock, u32 accessSize)
+{
+ for (size_t i = 0; i < fileList.size(); i++)
+ {
+ if (fileList[i].firstBlock <= accessBlock)
+ {
+ u32 sectorOffset = (accessBlock-fileList[i].firstBlock)*2048;
+ u32 endOffset = sectorOffset+accessSize;
+ if (endOffset <= fileList[i].totalSize)
+ {
+ return (int)i;
+ }
+ }
+ }
+
+ return -1;
+}
+
+u32 VirtualDiscFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename)
+{
+ OpenFileEntry entry;
+ entry.curOffset = 0;
+ entry.size = 0;
+ entry.startOffset = 0;
+
+ if (filename == "")
+ {
+ entry.type = VFILETYPE_ISO;
+ entry.fileIndex = -1;
+
+ u32 newHandle = hAlloc->GetNewHandle();
+ entries[newHandle] = entry;
+
+ return newHandle;
+ }
+
+ if (filename.compare(0,8,"/sce_lbn") == 0)
+ {
+ u32 sectorStart = 0xFFFFFFFF, readSize = 0xFFFFFFFF;
+ parseLBN(filename, §orStart, &readSize);
+
+ entry.type = VFILETYPE_LBN;
+ entry.size = readSize;
+
+ int fileIndex = getFileListIndex(sectorStart,readSize);
+ if (fileIndex == -1)
+ {
+ ERROR_LOG(FILESYS, "VirtualDiscFileSystem: sce_lbn used without calling fileinfo.");
+ return 0;
+ }
+ entry.fileIndex = (u32)fileIndex;
+
+ entry.startOffset = (sectorStart-fileList[entry.fileIndex].firstBlock)*2048;
+
+ // now we just need an actual file handle
+ bool success = entry.hFile.Open(basePath,fileList[entry.fileIndex].fileName,FILEACCESS_READ);
+
+ if (!success)
+ {
+#ifdef _WIN32
+ ERROR_LOG(HLE, "VirtualDiscFileSystem::OpenFile: FAILED, %i", GetLastError());
+#else
+ ERROR_LOG(HLE, "VirtualDiscFileSystem::OpenFile: FAILED");
+#endif
+ return 0;
+ }
+
+ // seek to start
+ entry.hFile.Seek(entry.startOffset,FILEMOVE_BEGIN);
+
+ u32 newHandle = hAlloc->GetNewHandle();
+ entries[newHandle] = entry;
+
+ return newHandle;
+ }
+
+ entry.type = VFILETYPE_NORMAL;
+ bool success = entry.hFile.Open(basePath,filename,access);
+
+ if (!success) {
+#ifdef _WIN32
+ ERROR_LOG(HLE, "VirtualDiscFileSystem::OpenFile: FAILED, %i - access = %i", GetLastError(), (int)access);
+#else
+ ERROR_LOG(HLE, "VirtualDiscFileSystem::OpenFile: FAILED, access = %i", (int)access);
+#endif
+ //wwwwaaaaahh!!
+ return 0;
+ } else {
+ entry.fileIndex = getFileListIndex(filename);
+
+ u32 newHandle = hAlloc->GetNewHandle();
+ entries[newHandle] = entry;
+
+ return newHandle;
+ }
+}
+
+size_t VirtualDiscFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
+ EntryMap::iterator iter = entries.find(handle);
+ if (iter != entries.end()) {
+ switch (iter->second.type)
+ {
+ case VFILETYPE_NORMAL:
+ {
+ return iter->second.hFile.Seek(position,type);
+ }
+ case VFILETYPE_LBN:
+ {
+ switch (type)
+ {
+ case FILEMOVE_BEGIN: iter->second.curOffset = position; break;
+ case FILEMOVE_CURRENT: iter->second.curOffset += position; break;
+ case FILEMOVE_END: iter->second.curOffset = iter->second.size-position; break;
+ }
+
+ u32 off = iter->second.startOffset+iter->second.curOffset;
+ iter->second.hFile.Seek(off,FILEMOVE_BEGIN);
+ return iter->second.curOffset;
+ }
+ case VFILETYPE_ISO:
+ {
+ switch (type)
+ {
+ case FILEMOVE_BEGIN: iter->second.curOffset = position; break;
+ case FILEMOVE_CURRENT: iter->second.curOffset += position; break;
+ case FILEMOVE_END: return -1; // unsupported
+ }
+
+ return iter->second.curOffset;
+ }
+ }
+ return 0;
+ } else {
+ //This shouldn't happen...
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot seek in file that hasn't been opened: %08x", handle);
+ return 0;
+ }
+}
+
+size_t VirtualDiscFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
+ EntryMap::iterator iter = entries.find(handle);
+ if (iter != entries.end())
+ {
+ // it's the whole iso... it could reference any of the files on the disc.
+ // For now let's just open and close the files on demand. Can certainly be done
+ // better though
+ if (iter->second.type == VFILETYPE_ISO)
+ {
+ int fileIndex = getFileListIndex(iter->second.curOffset,size*2048);
+ if (fileIndex == -1)
+ {
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Reading from unknown address %08x", handle);
+ return 0;
+ }
+
+ DirectoryFileHandle hFile;
+ bool success = hFile.Open(basePath,fileList[fileIndex].fileName,FILEACCESS_READ);
+
+ if (!success)
+ {
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Error opening file %s", fileList[fileIndex].fileName.c_str());
+ return 0;
+ }
+
+ u32 startOffset = (iter->second.curOffset-fileList[fileIndex].firstBlock)*2048;
+ size_t bytesRead;
+
+ hFile.Seek(startOffset,FILEMOVE_BEGIN);
+ bytesRead = hFile.Read(pointer,size*2048);
+ hFile.Close();
+
+ return bytesRead;
+ }
+
+ size_t bytesRead = iter->second.hFile.Read(pointer,size);
+ iter->second.curOffset += bytesRead;
+ return bytesRead;
+ } else {
+ //This shouldn't happen...
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot read file that hasn't been opened: %08x", handle);
+ return 0;
+ }
+}
+
+void VirtualDiscFileSystem::CloseFile(u32 handle) {
+ EntryMap::iterator iter = entries.find(handle);
+ if (iter != entries.end()) {
+ hAlloc->FreeHandle(handle);
+ iter->second.hFile.Close();
+ entries.erase(iter);
+ } else {
+ //This shouldn't happen...
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot close file that hasn't been opened: %08x", handle);
+ }
+}
+
+bool VirtualDiscFileSystem::OwnsHandle(u32 handle) {
+ EntryMap::iterator iter = entries.find(handle);
+ return (iter != entries.end());
+}
+
+PSPFileInfo VirtualDiscFileSystem::GetFileInfo(std::string filename) {
+ PSPFileInfo x;
+ x.name = filename;
+
+ std::string fullName = GetLocalPath(filename);
+ if (! File::Exists(fullName)) {
+#if HOST_IS_CASE_SENSITIVE
+ if (! FixPathCase(basePath,filename, FPC_FILE_MUST_EXIST))
+ return x;
+ fullName = GetLocalPath(filename);
+
+ if (! File::Exists(fullName))
+ return x;
+#else
+ return x;
+#endif
+ }
+
+ x.type = File::IsDirectory(fullName) ? FILETYPE_DIRECTORY : FILETYPE_NORMAL;
+ x.exists = true;
+
+ if (x.type != FILETYPE_DIRECTORY)
+ {
+ struct stat s;
+ stat(fullName.c_str(), &s);
+
+ x.size = File::GetSize(fullName);
+
+ int fileIndex = getFileListIndex(filename);
+ x.startSector = fileList[fileIndex].firstBlock;
+ x.numSectors = (x.size+2047)/2048;
+
+ x.access = s.st_mode & 0x1FF;
+ localtime_r((time_t*)&s.st_atime,&x.atime);
+ localtime_r((time_t*)&s.st_ctime,&x.ctime);
+ localtime_r((time_t*)&s.st_mtime,&x.mtime);
+ }
+
+ return x;
+}
+
+bool VirtualDiscFileSystem::GetHostPath(const std::string &inpath, std::string &outpath)
+{
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Retrieving host path");
+ return false;
+}
+
+std::vector VirtualDiscFileSystem::GetDirListing(std::string path)
+{
+ // todo
+ std::vector result;
+ return result;
+}
+
+size_t VirtualDiscFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size)
+{
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot write to file on virtual disc");
+ return 0;
+}
+
+bool VirtualDiscFileSystem::MkDir(const std::string &dirname)
+{
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot create directory on virtual disc");
+ return false;
+}
+
+bool VirtualDiscFileSystem::RmDir(const std::string &dirname)
+{
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot remove directory on virtual disc");
+ return false;
+}
+
+int VirtualDiscFileSystem::RenameFile(const std::string &from, const std::string &to)
+{
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot rename file on virtual disc");
+ return -1;
+}
+
+bool VirtualDiscFileSystem::RemoveFile(const std::string &filename)
+{
+ ERROR_LOG(HLE,"VirtualDiscFileSystem: Cannot remove file on virtual disc");
+ return false;
+}
diff --git a/Core/FileSystems/VirtualDiscFileSystem.h b/Core/FileSystems/VirtualDiscFileSystem.h
new file mode 100644
index 0000000000..83fc0ed829
--- /dev/null
+++ b/Core/FileSystems/VirtualDiscFileSystem.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012- 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
+
+// TODO: Remove the Windows-specific code, FILE is fine there too.
+
+#include