Open directory as disc image

This commit is contained in:
Kingcom 2013-07-23 17:24:33 +02:00
parent c9279a951b
commit 8955fedf44
14 changed files with 214 additions and 15 deletions

View File

@ -18,6 +18,7 @@
#include "ChunkFile.h"
#include "FileUtil.h"
#include "DirectoryFileSystem.h"
#include "ISOFileSystem.h"
#include "Core/HLE/sceKernel.h"
#include "file/zip_read.h"
@ -133,7 +134,17 @@ bool DirectoryFileSystem::FixPathCase(std::string &path, FixPathCaseBehavior beh
#endif
DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath) : basePath(_basePath) {
DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath, bool _virtualDisc)
: basePath(_basePath),virtualDisc(_virtualDisc),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
File::CreateFullPath(basePath);
hAlloc = _hAlloc;
}
@ -288,6 +299,80 @@ bool DirectoryFileSystem::RemoveFile(const std::string &filename) {
}
u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) {
if (filename.compare(0,8,"/sce_lbn") == 0)
{
u32 sectorStart = 0xFFFFFFFF, readSize = 0xFFFFFFFF;
parseLBN(filename, &sectorStart, &readSize);
OpenFileEntry entry;
entry.lbnFile = true;
entry.size = readSize;
entry.curOffset = 0;
std::string actualFileName = "";
for (int i = 0; i < fileBlocks.size(); i++)
{
if (fileBlocks[i].firstBlock <= sectorStart)
{
u32 sectorOffset = (sectorStart-fileBlocks[i].firstBlock)*2048;
u32 endOffset = sectorOffset+readSize;
if (endOffset <= fileBlocks[i].totalSize)
{
entry.startOffset = sectorOffset;
actualFileName = fileBlocks[i].fileName;
break;
}
}
}
// no file info has been gathered? shouldn't happen
if (actualFileName == "")
{
ERROR_LOG(FILESYS, "sce_lbn used without calling fileinfo.");
return 0;
}
#if HOST_IS_CASE_SENSITIVE
if (access & (FILEACCESS_APPEND|FILEACCESS_CREATE|FILEACCESS_WRITE))
{
DEBUG_LOG(HLE, "Checking case for path %s", filename.c_str());
if ( ! FixPathCase(actualFileName, FPC_PATH_MUST_EXIST) )
return 0; // or go on and attempt (for a better error code than just 0?)
}
// else we try fopen first (in case we're lucky) before simulating case insensitivity
#endif
// now we just need an actual file handle
std::string fullName = GetLocalPath(actualFileName);
#ifdef _WIN32
entry.hFile = CreateFile(fullName.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
bool success = entry.hFile != INVALID_HANDLE_VALUE;
#else
entry.hFile = fopen(fullName.c_str(), "rb");
bool success = entry.hFile != 0;
#endif
if (!success)
{
ERROR_LOG(HLE, "DiscDirectoryFileSystem::OpenFile: FAILED, %i", GetLastError());
return 0;
}
// seek to start
#ifdef _WIN32
DWORD newPos = SetFilePointer(entry.hFile, (LONG)entry.startOffset, 0, FILE_BEGIN);
#else
fseek(entry.hFile, entry.startOffset, SEEK_SET);
#endif
u32 newHandle = hAlloc->GetNewHandle();
entries[newHandle] = entry;
return newHandle;
}
#if HOST_IS_CASE_SENSITIVE
if (access & (FILEACCESS_APPEND|FILEACCESS_CREATE|FILEACCESS_WRITE))
{
@ -303,6 +388,7 @@ u32 DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const
INFO_LOG(HLE,"Actually opening %s (%s)", fullNameC, filename.c_str());
OpenFileEntry entry;
entry.lbnFile = false;
//TODO: tests, should append seek to end of file? seeking in a file opened for append?
#ifdef _WIN32
@ -430,6 +516,11 @@ size_t DirectoryFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
#else
bytesRead = fread(pointer, 1, size, iter->second.hFile);
#endif
if (iter->second.lbnFile)
{
iter->second.curOffset += bytesRead;
}
return bytesRead;
} else {
//This shouldn't happen...
@ -459,6 +550,23 @@ size_t DirectoryFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
size_t DirectoryFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
EntryMap::iterator iter = entries.find(handle);
if (iter != entries.end()) {
if (iter->second.lbnFile)
{
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;
}
#ifdef _WIN32
u32 off = iter->second.startOffset+iter->second.curOffset;
DWORD newPos = SetFilePointer((*iter).second.hFile, (LONG)off, 0, FILE_BEGIN);
#else
fseek(iter->second.hFile, iter->second.curOffset+iter->second.startOffset, SEEK_SET);
#endif
return iter->second.curOffset;
}
#ifdef _WIN32
DWORD moveMethod = 0;
switch (type) {
@ -485,6 +593,19 @@ size_t DirectoryFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
}
}
u32 DirectoryFileSystem::GetFileLbn(std::string& fileName)
{
if (!virtualDisc) return -1;
for (int i = 0; i < fileBlocks.size(); i++)
{
if (fileBlocks[i].fileName == fileName)
return fileBlocks[i].firstBlock;
}
return -1;
}
PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) {
PSPFileInfo x;
x.name = filename;
@ -517,6 +638,22 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) {
#else
x.size = s.st_size;
#endif
if (virtualDisc)
{
x.startSector = GetFileLbn(filename);
x.numSectors = (x.size+2047)/2048;
if (x.startSector == -1)
{
x.startSector = currentBlockIndex;
currentBlockIndex += x.numSectors;
LbnMapEntry entry;
entry.fileName = filename;
entry.firstBlock = x.startSector;
entry.totalSize = x.size;
fileBlocks.push_back(entry);
}
}
x.access = s.st_mode & 0x1FF;
localtime_r((time_t*)&s.st_atime,&x.atime);
localtime_r((time_t*)&s.st_ctime,&x.ctime);

View File

@ -49,7 +49,7 @@ typedef void * HANDLE;
class DirectoryFileSystem : public IFileSystem {
public:
DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath);
DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string _basePath, bool _virtualDisc = false);
~DirectoryFileSystem();
void DoState(PointerWrap &p);
@ -69,18 +69,34 @@ public:
bool GetHostPath(const std::string &inpath, std::string &outpath);
private:
u32 GetFileLbn(std::string& fileName);
struct OpenFileEntry {
#ifdef _WIN32
HANDLE hFile;
#else
FILE *hFile;
#endif
bool lbnFile;
u32 startOffset; // only used by lbn files
u32 curOffset; // only used by lbn files;
u32 size; // only used by lbn files
};
typedef std::map<u32, OpenFileEntry> EntryMap;
EntryMap entries;
std::string basePath;
IHandleAllocator *hAlloc;
bool virtualDisc;
typedef struct {
std::string fileName;
u32 firstBlock;
u32 totalSize;
} LbnMapEntry;
std::vector<LbnMapEntry> fileBlocks;
u32 currentBlockIndex;
// In case of Windows: Translate slashes, etc.
std::string GetLocalPath(std::string localpath);

View File

@ -26,7 +26,7 @@
const int sectorSize = 2048;
static bool parseLBN(std::string filename, u32 *sectorStart, u32 *readSize)
bool parseLBN(std::string filename, u32 *sectorStart, u32 *readSize)
{
// The format of this is: "/sce_lbn" "0x"? HEX* ANY* "_size" "0x"? HEX* ANY*
// That means that "/sce_lbn/_size1/" is perfectly valid.

View File

@ -24,6 +24,7 @@
#include "BlockDevices.h"
bool parseLBN(std::string filename, u32 *sectorStart, u32 *readSize);
class ISOFileSystem : public IFileSystem
{

View File

@ -57,7 +57,14 @@ EmuFileType Identify_File(std::string &filename)
if (ebootInfo.exists) {
return FILETYPE_PSP_PBP_DIRECTORY;
}
}
}
// check if it's a disc directory
if (getFileInfo((filename + "/PSP_GAME").c_str(), &ebootInfo)) {
if (ebootInfo.exists) {
return FILETYPE_PSP_DISC_DIRECTORY;
}
}
}
FILE *f = fopen(filename.c_str(), "rb");
@ -157,6 +164,7 @@ bool LoadFile(std::string &filename, std::string *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);

View File

@ -28,6 +28,8 @@ enum EmuFileType
FILETYPE_PSP_ISO,
FILETYPE_PSP_ISO_NP,
FILETYPE_PSP_DISC_DIRECTORY,
FILETYPE_UNKNOWN_BIN,
FILETYPE_UNKNOWN_ELF,

View File

@ -27,6 +27,7 @@
#include "MIPS/MIPSAnalyst.h"
#include "MIPS/MIPSCodeUtils.h"
#include "file/file_util.h"
#include "StringUtils.h"
#include "Host.h"
@ -44,11 +45,24 @@
// to determine if the emulator should enable extra memory and
// double-sized texture coordinates.
void InitMemoryForGameISO(std::string fileToStart) {
auto bd = constructBlockDevice(fileToStart.c_str());
// Can't init anything without a block device...
if (!bd)
return;
ISOFileSystem *umd2 = new ISOFileSystem(&pspFileSystem, bd);
IFileSystem* umd2;
// check if it's a disc directory
FileInfo info;
if (!getFileInfo(fileToStart.c_str(), &info)) return;
if (info.isDirectory)
{
umd2 = new DirectoryFileSystem(&pspFileSystem, fileToStart,true);
}
else
{
auto bd = constructBlockDevice(fileToStart.c_str());
// Can't init anything without a block device...
if (!bd)
return;
umd2 = new ISOFileSystem(&pspFileSystem, bd);
}
// Parse PARAM.SFO

View File

@ -83,7 +83,7 @@ bool PSP_Init(const CoreParameter &coreParam, std::string *error_string)
std::string filename = coreParam.fileToStart;
EmuFileType type = Identify_File(filename);
if(type == FILETYPE_PSP_ISO || type == FILETYPE_PSP_ISO_NP)
if(type == FILETYPE_PSP_ISO || type == FILETYPE_PSP_ISO_NP || type == FILETYPE_PSP_DISC_DIRECTORY)
InitMemoryForGameISO(filename);
Memory::Init();

View File

@ -38,7 +38,7 @@
#ifdef _WIN32
namespace MainWindow {
void BrowseAndBoot(std::string defaultPath);
void BrowseAndBoot(std::string defaultPath, bool browseDirectory = false);
}
#endif

View File

@ -74,7 +74,7 @@
#ifdef _WIN32
namespace MainWindow {
extern HWND hwndMain;
void BrowseAndBoot(std::string defaultPath);
void BrowseAndBoot(std::string defaultPath, bool browseDirectory = false);
}
#endif

View File

@ -303,7 +303,7 @@ namespace MainWindow
return TRUE;
}
void BrowseAndBoot(std::string defaultPath)
void BrowseAndBoot(std::string defaultPath, bool browseDirectory)
{
std::string fn;
std::string filter = "PSP ROMs (*.iso *.cso *.pbp *.elf)|*.pbp;*.elf;*.iso;*.cso;*.prx|All files (*.*)|*.*||";
@ -323,7 +323,24 @@ namespace MainWindow
Core_EnableStepping(true);
}
if (W32Util::BrowseForFileName(true, GetHWND(), "Load File", defaultPath.size() ? defaultPath.c_str() : 0, filter.c_str(),"*.pbp;*.elf;*.iso;*.cso;",fn))
if (browseDirectory)
{
std::string dir = W32Util::BrowseForFolder(GetHWND(),"Choose directory");
if (dir == "" && !isPaused)
{
Core_EnableStepping(false);
}
else
{
if (globalUIState == UISTATE_INGAME || globalUIState == UISTATE_PAUSEMENU)
{
Core_EnableStepping(false);
}
NativeMessageReceived("boot", dir.c_str());
}
}
else if (W32Util::BrowseForFileName(true, GetHWND(), "Load File", defaultPath.size() ? defaultPath.c_str() : 0, filter.c_str(),"*.pbp;*.elf;*.iso;*.cso;",fn))
{
if (globalUIState == UISTATE_INGAME || globalUIState == UISTATE_PAUSEMENU)
{
@ -572,6 +589,10 @@ namespace MainWindow
BrowseAndBoot("");
break;
case ID_FILE_LOAD_DIR:
BrowseAndBoot("",true);
break;
case ID_FILE_LOAD_MEMSTICK:
{
std::string memStickDir, flash0dir;

View File

@ -18,7 +18,7 @@ namespace MainWindow
HINSTANCE GetHInstance();
HWND GetDisplayHWND();
void SetPlaying(const char*text);
void BrowseAndBoot(std::string defaultPath);
void BrowseAndBoot(std::string defaultPath, bool browseDirectory = false);
void SaveStateActionFinished(bool result, void *userdata);
void _ViewFullScreen(HWND hWnd);
void _ViewNormal(HWND hWnd);

Binary file not shown.

Binary file not shown.