Add basic support for directory read functions in IOMAN.

This commit is contained in:
Jean-Philip Desjardins 2018-09-20 19:05:24 -04:00
parent 2dcc319b2b
commit c7eca744bd
10 changed files with 152 additions and 2 deletions

View File

@ -62,3 +62,14 @@ Framework::CStream* CDirectoryDevice::GetFile(uint32 accessType, const char* dev
return nullptr;
}
}
Directory CDirectoryDevice::GetDirectory(const char* devicePath)
{
auto basePath = CAppConfig::GetInstance().GetPreferencePath(m_basePathPreferenceName.c_str());
auto path = basePath / devicePath;
if(!boost::filesystem::is_directory(path))
{
throw std::runtime_error("Not a directory.");
}
return boost::filesystem::directory_iterator(path);
}

View File

@ -12,7 +12,9 @@ namespace Iop
public:
CDirectoryDevice(const char*);
virtual ~CDirectoryDevice() = default;
Framework::CStream* GetFile(uint32, const char*) override;
Directory GetDirectory(const char*) override;
private:
std::string m_basePathPreferenceName;

View File

@ -1,11 +1,14 @@
#pragma once
#include "Stream.h"
#include <boost/filesystem.hpp>
namespace Iop
{
namespace Ioman
{
typedef boost::filesystem::directory_iterator Directory;
class CDevice
{
public:
@ -22,6 +25,7 @@ namespace Iop
virtual ~CDevice() = default;
virtual Framework::CStream* GetFile(uint32, const char*) = 0;
virtual Directory GetDirectory(const char*) = 0;
};
}
}

View File

@ -35,6 +35,18 @@ void CFileIoHandler1000::Invoke(uint32 method, uint32* args, uint32 argsSize, ui
assert(retSize == 4);
*ret = m_ioman->Seek(args[0], args[1], args[2]);
break;
case 9:
assert(retSize == 4);
*ret = m_ioman->Dopen(reinterpret_cast<const char*>(&args[0]));
break;
case 10:
assert(retSize == 4);
*ret = m_ioman->Dclose(args[0]);
break;
case 11:
assert(retSize == 4);
*ret = m_ioman->Dread(args[0], reinterpret_cast<Iop::CIoman::DIRENTRY*>(ram + args[1]));
break;
case 12:
assert(retSize == 4);
*ret = m_ioman->GetStat(reinterpret_cast<const char*>(&args[1]), reinterpret_cast<Iop::CIoman::STAT*>(ram + args[0]));

View File

@ -249,6 +249,96 @@ uint32 CIoman::Seek(uint32 handle, uint32 position, uint32 whence)
return result;
}
int32 CIoman::Dopen(const char* path)
{
CLog::GetInstance().Print(LOG_NAME, "Dopen(path = '%s');\r\n",
path);
int32 handle = -1;
try
{
std::string fullPath(path);
auto position = fullPath.find(":");
if(position == std::string::npos)
{
throw std::runtime_error("Invalid path.");
}
auto deviceName = std::string(fullPath.begin(), fullPath.begin() + position);
auto devicePath = std::string(fullPath.begin() + position + 1, fullPath.end());
auto deviceIterator = m_devices.find(deviceName);
if(deviceIterator == m_devices.end())
{
throw std::runtime_error("Device not found.");
}
//Some games (Street Fighter EX3) provide paths with trailing spaces
devicePath = RightTrim(devicePath);
auto directory = deviceIterator->second->GetDirectory(devicePath.c_str());
handle = m_nextFileHandle++;
m_directories[handle] = directory;
}
catch(const std::exception& except)
{
CLog::GetInstance().Warn(LOG_NAME, "%s: Error occured while trying to open directory : %s\r\n", __FUNCTION__, except.what());
}
return handle;
}
int32 CIoman::Dclose(uint32 handle)
{
CLog::GetInstance().Print(LOG_NAME, "Dclose(handle = %d);\r\n",
handle);
auto directoryIterator = m_directories.find(handle);
if(directoryIterator == std::end(m_directories))
{
return -1;
}
m_directories.erase(directoryIterator);
return 0;
}
int32 CIoman::Dread(uint32 handle, DIRENTRY* dirEntry)
{
CLog::GetInstance().Print(LOG_NAME, "Dread(handle = %d, entry = ptr);\r\n",
handle);
auto directoryIterator = m_directories.find(handle);
if(directoryIterator == std::end(m_directories))
{
return -1;
}
auto& directory = directoryIterator->second;
if(directory == Ioman::Directory())
{
return 0;
}
auto itemPath = directory->path();
auto name = itemPath.leaf().string();
strncpy(dirEntry->name, name.c_str(), DIRENTRY::NAME_SIZE);
dirEntry->name[DIRENTRY::NAME_SIZE - 1] = 0;
auto& stat = dirEntry->stat;
memset(&stat, 0, sizeof(STAT));
if(boost::filesystem::is_directory(itemPath))
{
//Directories have "group read" only permissions? This is required by PS2PSXe.
stat.mode = 0747 | (1 << 12); //File mode + Dir type (1)
stat.attr = 0x8427;
}
else
{
stat.mode = 0777 | (2 << 12); //File mode + File type (2)
stat.loSize = boost::filesystem::file_size(itemPath);
stat.attr = 0x8497;
}
directory++;
return strlen(dirEntry->name);
}
uint32 CIoman::GetStat(const char* path, STAT* stat)
{
CLog::GetInstance().Print(LOG_NAME, "GetStat(path = '%s', stat = ptr);\r\n", path);

View File

@ -33,9 +33,23 @@ namespace Iop
uint8 lastAccessTime[8];
uint8 lastModificationTime[8];
uint32 hiSize;
uint32 reserved[6];
//Reserved (private) fields to be used in later versions of IOMAN
//uint32 reserved[6];
};
static_assert(sizeof(STAT) == 64, "STAT structure must be 64 bytes long.");
static_assert(sizeof(STAT) == 40, "STAT structure must be 40 bytes long.");
struct DIRENTRY
{
enum
{
NAME_SIZE = 256,
};
STAT stat;
char name[NAME_SIZE];
uint32 privatePtr;
};
static_assert(sizeof(DIRENTRY) == 0x12C, "DIRENTRY structure must be 300 bytes long");
class CFile
{
@ -68,6 +82,9 @@ namespace Iop
uint32 Read(uint32, uint32, void*);
uint32 Write(uint32, uint32, const void*);
uint32 Seek(uint32, uint32, uint32);
int32 Dopen(const char*);
int32 Dread(uint32, DIRENTRY*);
int32 Dclose(uint32);
uint32 GetStat(const char*, STAT*);
uint32 AddDrv(uint32);
uint32 DelDrv(uint32);
@ -77,9 +94,11 @@ namespace Iop
private:
typedef std::map<uint32, Framework::CStream*> FileMapType;
typedef std::map<uint32, Ioman::Directory> DirectoryMapType;
typedef std::map<std::string, DevicePtr> DeviceMapType;
FileMapType m_files;
DirectoryMapType m_directories;
DeviceMapType m_devices;
uint8* m_ram;
uint32 m_nextFileHandle;

View File

@ -24,3 +24,8 @@ Framework::CStream* COpticalMediaDevice::GetFile(uint32 mode, const char* device
auto fileSystem = m_opticalMedia->GetFileSystem();
return fileSystem->Open(fixedString.c_str());
}
Directory COpticalMediaDevice::GetDirectory(const char* devicePath)
{
throw std::runtime_error("Not supported.");
}

View File

@ -17,6 +17,7 @@ namespace Iop
virtual ~COpticalMediaDevice() = default;
Framework::CStream* GetFile(uint32, const char*) override;
Directory GetDirectory(const char*) override;
private:
static char FixSlashes(char);

View File

@ -20,3 +20,8 @@ Framework::CStream* CPsfDevice::GetFile(uint32 mode, const char* path)
Framework::CStream* result = m_fileSystem.GetFile(path);
return result;
}
Iop::Ioman::Directory CPsfDevice::GetDirectory(const char* path)
{
throw std::runtime_error("Not supported.");
}

View File

@ -16,6 +16,7 @@ namespace PS2
void AppendArchive(const CPsfBase&);
Framework::CStream* GetFile(uint32, const char*) override;
Iop::Ioman::Directory GetDirectory(const char*) override;
private:
CPsfFs m_fileSystem;