mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-09 08:21:29 +12:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
54d6aee028
31 changed files with 723 additions and 251 deletions
|
@ -57,7 +57,7 @@ int fmt::CmpNoCase(const std::string& a, const std::string& b)
|
||||||
return std::equal(a.begin(),
|
return std::equal(a.begin(),
|
||||||
a.end(),
|
a.end(),
|
||||||
b.begin(),
|
b.begin(),
|
||||||
[](const char& a, const char& b){return tolower(a) == tolower(b); })
|
[](const char& a, const char& b){return ::tolower(a) == ::tolower(b); })
|
||||||
? 0 : -1;
|
? 0 : -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,4 +102,66 @@ std::vector<std::string> fmt::rSplit(const std::string& source, const std::strin
|
||||||
}
|
}
|
||||||
} while (true);
|
} while (true);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> fmt::split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty)
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
size_t cursor_begin = 0;
|
||||||
|
|
||||||
|
for (size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end)
|
||||||
|
{
|
||||||
|
for (auto &separator : separators)
|
||||||
|
{
|
||||||
|
if (strncmp(source.c_str() + cursor_end, separator.c_str(), separator.length()) == 0)
|
||||||
|
{
|
||||||
|
std::string candidate = source.substr(cursor_begin, cursor_end - cursor_begin);
|
||||||
|
if (!is_skip_empty || !candidate.empty())
|
||||||
|
result.push_back(candidate);
|
||||||
|
|
||||||
|
cursor_begin = cursor_end + separator.length();
|
||||||
|
cursor_end = cursor_begin - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor_begin != source.length())
|
||||||
|
{
|
||||||
|
result.push_back(source.substr(cursor_begin));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fmt::merge(std::vector<std::string> source, const std::string& separator)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
for (auto &s : source)
|
||||||
|
{
|
||||||
|
result += s + separator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fmt::merge(std::initializer_list<std::vector<std::string>> sources, const std::string& separator)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
for (auto &v : sources)
|
||||||
|
{
|
||||||
|
result += fmt::merge(v, separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fmt::tolower(std::string source)
|
||||||
|
{
|
||||||
|
std::transform(source.begin(), source.end(), source.begin(), ::tolower);
|
||||||
|
|
||||||
|
return source;
|
||||||
}
|
}
|
|
@ -192,4 +192,9 @@ namespace fmt{
|
||||||
void Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm);
|
void Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm);
|
||||||
|
|
||||||
std::vector<std::string> rSplit(const std::string& source, const std::string& delim);
|
std::vector<std::string> rSplit(const std::string& source, const std::string& delim);
|
||||||
|
|
||||||
|
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
|
||||||
|
std::string merge(std::vector<std::string> source, const std::string& separator);
|
||||||
|
std::string merge(std::initializer_list<std::vector<std::string>> sources, const std::string& separator);
|
||||||
|
std::string tolower(std::string source);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,49 @@
|
||||||
#include "Emu/HDD/HDD.h"
|
#include "Emu/HDD/HDD.h"
|
||||||
#include "vfsDeviceLocalFile.h"
|
#include "vfsDeviceLocalFile.h"
|
||||||
#include "Ini.h"
|
#include "Ini.h"
|
||||||
|
#include "Emu/System.h"
|
||||||
|
|
||||||
#undef CreateFile // TODO: what's wrong with it?
|
#undef CreateFile
|
||||||
|
|
||||||
int sort_devices(const void* _a, const void* _b)
|
std::vector<std::string> simplify_path_blocks(const std::string& path)
|
||||||
{
|
{
|
||||||
const vfsDevice& a = **(const vfsDevice**)_a;
|
std::vector<std::string> path_blocks = std::move(fmt::split(fmt::tolower(path), { "/", "\\" }));
|
||||||
const vfsDevice& b = **(const vfsDevice**)_b;
|
|
||||||
|
|
||||||
if(a.GetPs3Path().length() > b.GetPs3Path().length()) return 1;
|
for (size_t i = 0; i < path_blocks.size(); ++i)
|
||||||
if(a.GetPs3Path().length() < b.GetPs3Path().length()) return -1;
|
{
|
||||||
|
if (path_blocks[i] == ".")
|
||||||
|
{
|
||||||
|
path_blocks.erase(path_blocks.begin() + i--);
|
||||||
|
}
|
||||||
|
else if (i && path_blocks[i] == "..")
|
||||||
|
{
|
||||||
|
path_blocks.erase(path_blocks.begin() + (i - 1), path_blocks.begin() + (i + 1));
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return path_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string simplify_path(const std::string& path, bool is_dir)
|
||||||
|
{
|
||||||
|
std::vector<std::string> path_blocks = simplify_path_blocks(path);
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
if (path_blocks.empty())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if (is_dir)
|
||||||
|
{
|
||||||
|
result = fmt::merge(path_blocks, "/");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = fmt::merge(std::vector<std::string>(path_blocks.begin(), path_blocks.end() - 1), "/") + path_blocks[path_blocks.size() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
VFS::~VFS()
|
VFS::~VFS()
|
||||||
|
@ -25,24 +56,62 @@ VFS::~VFS()
|
||||||
|
|
||||||
void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device)
|
void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device)
|
||||||
{
|
{
|
||||||
UnMount(ps3_path);
|
std::string simpl_ps3_path = simplify_path(ps3_path, true);
|
||||||
|
|
||||||
device->SetPath(ps3_path, local_path);
|
UnMount(simpl_ps3_path);
|
||||||
|
|
||||||
|
device->SetPath(simpl_ps3_path, simplify_path(local_path, true));
|
||||||
m_devices.push_back(device);
|
m_devices.push_back(device);
|
||||||
|
|
||||||
if(m_devices.size() > 1)
|
if (m_devices.size() > 1)
|
||||||
{
|
{
|
||||||
//std::qsort(m_devices.GetPtr(), m_devices.GetCount(), sizeof(vfsDevice*), sort_devices);
|
std::sort(m_devices.begin(), m_devices.end(), [](vfsDevice *a, vfsDevice *b) { return b->GetPs3Path().length() < a->GetPs3Path().length(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VFS::Link(const std::string& mount_point, const std::string& ps3_path)
|
||||||
|
{
|
||||||
|
links[simplify_path_blocks(mount_point)] = simplify_path_blocks(ps3_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string VFS::GetLinked(std::string ps3_path) const
|
||||||
|
{
|
||||||
|
ps3_path = fmt::tolower(ps3_path);
|
||||||
|
auto path_blocks = fmt::split(ps3_path, { "/", "\\" });
|
||||||
|
|
||||||
|
for (auto link : links)
|
||||||
|
{
|
||||||
|
if (path_blocks.size() < link.first.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool is_ok = true;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < link.first.size(); ++i)
|
||||||
|
{
|
||||||
|
if (link.first[i] != path_blocks[i])
|
||||||
|
{
|
||||||
|
is_ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ok)
|
||||||
|
return fmt::merge({ link.second, std::vector<std::string>(path_blocks.begin() + link.first.size(), path_blocks.end()) }, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps3_path;
|
||||||
|
}
|
||||||
|
|
||||||
void VFS::UnMount(const std::string& ps3_path)
|
void VFS::UnMount(const std::string& ps3_path)
|
||||||
{
|
{
|
||||||
for(u32 i=0; i<m_devices.size(); ++i)
|
std::string simpl_ps3_path = simplify_path(ps3_path, true);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_devices.size(); ++i)
|
||||||
{
|
{
|
||||||
if(!m_devices[i]->GetPs3Path().compare(ps3_path))
|
if (!strcmp(m_devices[i]->GetPs3Path().c_str(), simpl_ps3_path.c_str()))
|
||||||
{
|
{
|
||||||
delete m_devices[i];
|
delete m_devices[i];
|
||||||
|
|
||||||
m_devices.erase(m_devices.begin() +i);
|
m_devices.erase(m_devices.begin() +i);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -63,9 +132,9 @@ void VFS::UnMountAll()
|
||||||
vfsFileBase* VFS::OpenFile(const std::string& ps3_path, vfsOpenMode mode) const
|
vfsFileBase* VFS::OpenFile(const std::string& ps3_path, vfsOpenMode mode) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path, path))
|
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
||||||
{
|
{
|
||||||
if(vfsFileBase* res = dev->GetNewFileStream())
|
if (vfsFileBase* res = dev->GetNewFileStream())
|
||||||
{
|
{
|
||||||
res->Open(path, mode);
|
res->Open(path, mode);
|
||||||
return res;
|
return res;
|
||||||
|
@ -79,9 +148,9 @@ vfsDirBase* VFS::OpenDir(const std::string& ps3_path) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path, path))
|
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
||||||
{
|
{
|
||||||
if(vfsDirBase* res = dev->GetNewDirStream())
|
if (vfsDirBase* res = dev->GetNewDirStream())
|
||||||
{
|
{
|
||||||
res->Open(path);
|
res->Open(path);
|
||||||
return res;
|
return res;
|
||||||
|
@ -94,11 +163,11 @@ vfsDirBase* VFS::OpenDir(const std::string& ps3_path) const
|
||||||
bool VFS::CreateFile(const std::string& ps3_path) const
|
bool VFS::CreateFile(const std::string& ps3_path) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path, path))
|
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
||||||
{
|
{
|
||||||
std::shared_ptr<vfsFileBase> res(dev->GetNewFileStream());
|
std::shared_ptr<vfsFileBase> res(dev->GetNewFileStream());
|
||||||
|
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res->Create(path);
|
return res->Create(path);
|
||||||
}
|
}
|
||||||
|
@ -110,11 +179,11 @@ bool VFS::CreateFile(const std::string& ps3_path) const
|
||||||
bool VFS::CreateDir(const std::string& ps3_path) const
|
bool VFS::CreateDir(const std::string& ps3_path) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path, path))
|
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
||||||
{
|
{
|
||||||
std::shared_ptr<vfsDirBase> res(dev->GetNewDirStream());
|
std::shared_ptr<vfsDirBase> res(dev->GetNewDirStream());
|
||||||
|
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res->Create(path);
|
return res->Create(path);
|
||||||
}
|
}
|
||||||
|
@ -126,11 +195,11 @@ bool VFS::CreateDir(const std::string& ps3_path) const
|
||||||
bool VFS::RemoveFile(const std::string& ps3_path) const
|
bool VFS::RemoveFile(const std::string& ps3_path) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path, path))
|
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
||||||
{
|
{
|
||||||
std::shared_ptr<vfsFileBase> res(dev->GetNewFileStream());
|
std::shared_ptr<vfsFileBase> res(dev->GetNewFileStream());
|
||||||
|
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res->Remove(path);
|
return res->Remove(path);
|
||||||
}
|
}
|
||||||
|
@ -142,11 +211,11 @@ bool VFS::RemoveFile(const std::string& ps3_path) const
|
||||||
bool VFS::RemoveDir(const std::string& ps3_path) const
|
bool VFS::RemoveDir(const std::string& ps3_path) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path, path))
|
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
||||||
{
|
{
|
||||||
std::shared_ptr<vfsDirBase> res(dev->GetNewDirStream());
|
std::shared_ptr<vfsDirBase> res(dev->GetNewDirStream());
|
||||||
|
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res->Remove(path);
|
return res->Remove(path);
|
||||||
}
|
}
|
||||||
|
@ -158,11 +227,11 @@ bool VFS::RemoveDir(const std::string& ps3_path) const
|
||||||
bool VFS::ExistsFile(const std::string& ps3_path) const
|
bool VFS::ExistsFile(const std::string& ps3_path) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path, path))
|
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
||||||
{
|
{
|
||||||
std::shared_ptr<vfsFileBase> res(dev->GetNewFileStream());
|
std::shared_ptr<vfsFileBase> res(dev->GetNewFileStream());
|
||||||
|
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res->Exists(path);
|
return res->Exists(path);
|
||||||
}
|
}
|
||||||
|
@ -174,11 +243,11 @@ bool VFS::ExistsFile(const std::string& ps3_path) const
|
||||||
bool VFS::ExistsDir(const std::string& ps3_path) const
|
bool VFS::ExistsDir(const std::string& ps3_path) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path, path))
|
if (vfsDevice* dev = GetDevice(ps3_path, path))
|
||||||
{
|
{
|
||||||
std::shared_ptr<vfsDirBase> res(dev->GetNewDirStream());
|
std::shared_ptr<vfsDirBase> res(dev->GetNewDirStream());
|
||||||
|
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res->IsExists(path);
|
return res->IsExists(path);
|
||||||
}
|
}
|
||||||
|
@ -190,11 +259,11 @@ bool VFS::ExistsDir(const std::string& ps3_path) const
|
||||||
bool VFS::RenameFile(const std::string& ps3_path_from, const std::string& ps3_path_to) const
|
bool VFS::RenameFile(const std::string& ps3_path_from, const std::string& ps3_path_to) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path_from, path))
|
if (vfsDevice* dev = GetDevice(ps3_path_from, path))
|
||||||
{
|
{
|
||||||
std::shared_ptr<vfsFileBase> res(dev->GetNewFileStream());
|
std::shared_ptr<vfsFileBase> res(dev->GetNewFileStream());
|
||||||
|
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res->Rename(path, ps3_path_to);
|
return res->Rename(path, ps3_path_to);
|
||||||
}
|
}
|
||||||
|
@ -206,11 +275,11 @@ bool VFS::RenameFile(const std::string& ps3_path_from, const std::string& ps3_pa
|
||||||
bool VFS::RenameDir(const std::string& ps3_path_from, const std::string& ps3_path_to) const
|
bool VFS::RenameDir(const std::string& ps3_path_from, const std::string& ps3_path_to) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
if(vfsDevice* dev = GetDevice(ps3_path_from, path))
|
if (vfsDevice* dev = GetDevice(ps3_path_from, path))
|
||||||
{
|
{
|
||||||
std::shared_ptr<vfsDirBase> res(dev->GetNewDirStream());
|
std::shared_ptr<vfsDirBase> res(dev->GetNewDirStream());
|
||||||
|
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res->Rename(path, ps3_path_to);
|
return res->Rename(path, ps3_path_to);
|
||||||
}
|
}
|
||||||
|
@ -221,53 +290,108 @@ bool VFS::RenameDir(const std::string& ps3_path_from, const std::string& ps3_pat
|
||||||
|
|
||||||
vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const
|
vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const
|
||||||
{
|
{
|
||||||
u32 max_eq;
|
auto try_get_device = [this, &path](const std::string& ps3_path) -> vfsDevice*
|
||||||
s32 max_i=-1;
|
|
||||||
|
|
||||||
for(u32 i=0; i<m_devices.size(); ++i)
|
|
||||||
{
|
{
|
||||||
const u32 eq = m_devices[i]->CmpPs3Path(ps3_path);
|
std::vector<std::string> ps3_path_blocks = simplify_path_blocks(ps3_path);
|
||||||
|
size_t max_eq = 0;
|
||||||
|
int max_i = -1;
|
||||||
|
|
||||||
if(max_i < 0 || eq > max_eq)
|
for (u32 i = 0; i < m_devices.size(); ++i)
|
||||||
{
|
{
|
||||||
max_eq = eq;
|
std::vector<std::string> dev_ps3_path_blocks = simplify_path_blocks(m_devices[i]->GetPs3Path());
|
||||||
max_i = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(max_i < 0) return nullptr;
|
if (ps3_path_blocks.size() < dev_ps3_path_blocks.size())
|
||||||
path = vfsDevice::GetWinPath(m_devices[max_i]->GetLocalPath(), ps3_path.substr(max_eq, ps3_path.length() - max_eq));
|
continue;
|
||||||
return m_devices[max_i];
|
|
||||||
|
size_t eq = 0;
|
||||||
|
for (; eq < dev_ps3_path_blocks.size(); ++eq)
|
||||||
|
{
|
||||||
|
if (strcmp(ps3_path_blocks[eq].c_str(), dev_ps3_path_blocks[eq].c_str()))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eq > max_eq)
|
||||||
|
{
|
||||||
|
max_eq = eq;
|
||||||
|
max_i = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_i < 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
path = m_devices[max_i]->GetLocalPath();
|
||||||
|
|
||||||
|
for (u32 i = max_eq; i < ps3_path_blocks.size(); i++)
|
||||||
|
{
|
||||||
|
path += "/" + ps3_path_blocks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
path = simplify_path(path, false);
|
||||||
|
|
||||||
|
return m_devices[max_i];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto res = try_get_device(GetLinked(ps3_path)))
|
||||||
|
return res;
|
||||||
|
|
||||||
|
if (auto res = try_get_device(GetLinked(cwd + ps3_path)))
|
||||||
|
return res;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfsDevice* VFS::GetDeviceLocal(const std::string& local_path, std::string& path) const
|
vfsDevice* VFS::GetDeviceLocal(const std::string& local_path, std::string& path) const
|
||||||
{
|
{
|
||||||
u32 max_eq;
|
size_t max_eq = 0;
|
||||||
s32 max_i=-1;
|
int max_i = -1;
|
||||||
|
|
||||||
rFileName file_path(local_path);
|
std::vector<std::string> local_path_blocks = simplify_path_blocks(local_path);
|
||||||
file_path.Normalize();
|
|
||||||
std::string mormalized_path = file_path.GetFullPath();
|
|
||||||
|
|
||||||
for(u32 i=0; i<m_devices.size(); ++i)
|
for (u32 i = 0; i < m_devices.size(); ++i)
|
||||||
{
|
{
|
||||||
const u32 eq = m_devices[i]->CmpLocalPath(mormalized_path);
|
std::vector<std::string> dev_local_path_blocks_blocks = simplify_path_blocks(m_devices[i]->GetLocalPath());
|
||||||
|
|
||||||
if(max_i < 0 || eq > max_eq)
|
if (local_path_blocks.size() < dev_local_path_blocks_blocks.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size_t eq = 0;
|
||||||
|
for (; eq < dev_local_path_blocks_blocks.size(); ++eq)
|
||||||
|
{
|
||||||
|
if (strcmp(local_path_blocks[eq].c_str(), dev_local_path_blocks_blocks[eq].c_str()))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eq > max_eq)
|
||||||
{
|
{
|
||||||
max_eq = eq;
|
max_eq = eq;
|
||||||
max_i = i;
|
max_i = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_i < 0) return nullptr;
|
if (max_i < 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
path = m_devices[max_i]->GetPs3Path();
|
||||||
|
|
||||||
|
for (u32 i = max_eq; i < local_path_blocks.size(); i++)
|
||||||
|
{
|
||||||
|
path += "/" + local_path_blocks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
path = simplify_path(path, false);
|
||||||
|
|
||||||
path = vfsDevice::GetPs3Path(m_devices[max_i]->GetPs3Path(), local_path.substr(max_eq, local_path.length() - max_eq));
|
|
||||||
return m_devices[max_i];
|
return m_devices[max_i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFS::Init(const std::string& path)
|
void VFS::Init(const std::string& path)
|
||||||
{
|
{
|
||||||
|
cwd = simplify_path(path, true);
|
||||||
|
|
||||||
UnMountAll();
|
UnMountAll();
|
||||||
|
|
||||||
std::vector<VFSManagerEntry> entries;
|
std::vector<VFSManagerEntry> entries;
|
||||||
|
@ -293,10 +417,12 @@ void VFS::Init(const std::string& path)
|
||||||
|
|
||||||
std::string mpath = entry.path;
|
std::string mpath = entry.path;
|
||||||
// TODO: This shouldn't use current dir
|
// TODO: This shouldn't use current dir
|
||||||
fmt::Replace(mpath,"$(EmulatorDir)", ".");
|
fmt::Replace(mpath, "$(EmulatorDir)", Emu.GetEmulatorPath());
|
||||||
fmt::Replace(mpath,"$(GameDir)", vfsDevice::GetRoot(path));
|
fmt::Replace(mpath, "$(GameDir)", cwd);
|
||||||
Mount(entry.mount, mpath, dev);
|
Mount(entry.mount, mpath, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Link("/app_home/", cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load)
|
void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load)
|
||||||
|
@ -305,21 +431,19 @@ void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load)
|
||||||
entries_count.Init("count", "VFSManager");
|
entries_count.Init("count", "VFSManager");
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
if(is_load)
|
if (is_load)
|
||||||
{
|
{
|
||||||
count = entries_count.LoadValue(count);
|
count = entries_count.LoadValue(count);
|
||||||
|
|
||||||
if(!count)
|
if (!count)
|
||||||
{
|
{
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd0/", "/dev_hdd0/");
|
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd0/", "/dev_hdd0/");
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd1/", "/dev_hdd1/");
|
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd1/", "/dev_hdd1/");
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/");
|
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/");
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/");
|
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/");
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/");
|
res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/");
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(GameDir)", "/app_home/");
|
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(GameDir)/../", "/dev_bdvd/");
|
res.emplace_back(vfsDevice_LocalFile, "$(GameDir)/../", "/dev_bdvd/");
|
||||||
res.emplace_back(vfsDevice_LocalFile, "", "/host_root/");
|
res.emplace_back(vfsDevice_LocalFile, "", "/host_root/");
|
||||||
res.emplace_back(vfsDevice_LocalFile, "$(GameDir)", "/");
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -344,7 +468,7 @@ void VFS::SaveLoadDevices(std::vector<VFSManagerEntry>& res, bool is_load)
|
||||||
entry_mount.Init(fmt::Format("mount[%d]", i), "VFSManager");
|
entry_mount.Init(fmt::Format("mount[%d]", i), "VFSManager");
|
||||||
entry_device.Init(fmt::Format("device[%d]", i), "VFSManager");
|
entry_device.Init(fmt::Format("device[%d]", i), "VFSManager");
|
||||||
|
|
||||||
if(is_load)
|
if (is_load)
|
||||||
{
|
{
|
||||||
res[i] = VFSManagerEntry();
|
res[i] = VFSManagerEntry();
|
||||||
res[i].path = entry_path.LoadValue("");
|
res[i].path = entry_path.LoadValue("");
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include <map>
|
||||||
|
|
||||||
class vfsDevice;
|
class vfsDevice;
|
||||||
struct vfsFileBase;
|
struct vfsFileBase;
|
||||||
|
@ -42,20 +43,39 @@ struct VFSManagerEntry
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> simplify_path_blocks(const std::string& path);
|
||||||
|
std::string simplify_path(const std::string& path, bool is_dir);
|
||||||
|
|
||||||
struct VFS
|
struct VFS
|
||||||
{
|
{
|
||||||
~VFS();
|
~VFS();
|
||||||
|
|
||||||
|
std::string cwd;
|
||||||
|
|
||||||
//TODO: find out where these are supposed to be deleted or just make it shared_ptr
|
//TODO: find out where these are supposed to be deleted or just make it shared_ptr
|
||||||
//and also make GetDevice and GetDeviceLocal return shared_ptr then.
|
//and also make GetDevice and GetDeviceLocal return shared_ptr then.
|
||||||
// A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed.
|
// A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed.
|
||||||
// This will cause problems if other code stores the pointer returned by GetDevice/GetDeviceLocal
|
// This will cause problems if other code stores the pointer returned by GetDevice/GetDeviceLocal
|
||||||
// and tries to use it after the device is unmounted.
|
// and tries to use it after the device is unmounted.
|
||||||
std::vector<vfsDevice *> m_devices;
|
std::vector<vfsDevice *> m_devices;
|
||||||
|
|
||||||
|
struct links_sorter
|
||||||
|
{
|
||||||
|
bool operator()(const std::vector<std::string>& a, const std::vector<std::string>& b)
|
||||||
|
{
|
||||||
|
return b.size() < a.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<std::vector<std::string>, std::vector<std::string>, links_sorter> links;
|
||||||
|
|
||||||
void Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device);
|
void Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device);
|
||||||
|
void Link(const std::string& mount_point, const std::string& ps3_path);
|
||||||
void UnMount(const std::string& ps3_path);
|
void UnMount(const std::string& ps3_path);
|
||||||
void UnMountAll();
|
void UnMountAll();
|
||||||
|
|
||||||
|
std::string GetLinked(std::string ps3_path) const;
|
||||||
|
|
||||||
vfsFileBase* OpenFile(const std::string& ps3_path, vfsOpenMode mode) const;
|
vfsFileBase* OpenFile(const std::string& ps3_path, vfsOpenMode mode) const;
|
||||||
vfsDirBase* OpenDir(const std::string& ps3_path) const;
|
vfsDirBase* OpenDir(const std::string& ps3_path) const;
|
||||||
bool CreateFile(const std::string& ps3_path) const;
|
bool CreateFile(const std::string& ps3_path) const;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
|
|
||||||
|
#include "vfsDevice.h"
|
||||||
#include "VFS.h"
|
#include "VFS.h"
|
||||||
#include "vfsDir.h"
|
#include "vfsDir.h"
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ vfsDir::vfsDir()
|
||||||
{
|
{
|
||||||
// TODO: proper implementation
|
// TODO: proper implementation
|
||||||
// m_stream is nullptr here. So open root until a proper dir is given
|
// m_stream is nullptr here. So open root until a proper dir is given
|
||||||
Open("/");
|
//Open("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
vfsDir::vfsDir(const std::string& path)
|
vfsDir::vfsDir(const std::string& path)
|
||||||
|
@ -26,37 +27,78 @@ bool vfsDir::Open(const std::string& path)
|
||||||
|
|
||||||
m_stream.reset(Emu.GetVFS().OpenDir(path));
|
m_stream.reset(Emu.GetVFS().OpenDir(path));
|
||||||
|
|
||||||
return m_stream && m_stream->IsOpened();
|
DirEntryInfo info;
|
||||||
|
|
||||||
|
m_cwd = simplify_path(Emu.GetVFS().GetLinked(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path), true);
|
||||||
|
|
||||||
|
auto blocks = simplify_path_blocks(GetPath());
|
||||||
|
|
||||||
|
for (auto dev : Emu.GetVFS().m_devices)
|
||||||
|
{
|
||||||
|
auto dev_blocks = simplify_path_blocks(dev->GetPs3Path());
|
||||||
|
|
||||||
|
if (dev_blocks.size() < (blocks.size() + 1))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_ok = true;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < blocks.size(); ++i)
|
||||||
|
{
|
||||||
|
if (strcmp(dev_blocks[i].c_str(), blocks[i].c_str()))
|
||||||
|
{
|
||||||
|
is_ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_ok)
|
||||||
|
{
|
||||||
|
info.name = dev_blocks[blocks.size()];
|
||||||
|
m_entries.push_back(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_stream && m_stream->IsOpened())
|
||||||
|
{
|
||||||
|
m_entries.insert(m_entries.begin(), m_stream->GetEntries().begin(), m_stream->GetEntries().end());
|
||||||
|
}
|
||||||
|
|
||||||
|
return !m_entries.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vfsDir::Create(const std::string& path)
|
bool vfsDir::Create(const std::string& path)
|
||||||
{
|
{
|
||||||
return m_stream->Create(path);
|
return Emu.GetVFS().CreateDir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vfsDir::IsExists(const std::string& path) const
|
bool vfsDir::IsExists(const std::string& path) const
|
||||||
{
|
{
|
||||||
return m_stream->IsExists(path);
|
auto path_blocks = simplify_path_blocks(path);
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<DirEntryInfo>& vfsDir::GetEntries() const
|
if (path_blocks.empty())
|
||||||
{
|
return false;
|
||||||
return m_stream->GetEntries();
|
|
||||||
|
std::string dir_name = path_blocks[path_blocks.size() - 1];
|
||||||
|
|
||||||
|
for (const auto entry : vfsDir(path + "/.."))
|
||||||
|
{
|
||||||
|
if (!strcmp(entry->name.c_str(), dir_name.c_str()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vfsDir::Rename(const std::string& from, const std::string& to)
|
bool vfsDir::Rename(const std::string& from, const std::string& to)
|
||||||
{
|
{
|
||||||
return m_stream->Rename(from, to);
|
return Emu.GetVFS().RenameDir(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vfsDir::Remove(const std::string& path)
|
bool vfsDir::Remove(const std::string& path)
|
||||||
{
|
{
|
||||||
return m_stream->Remove(path);
|
return Emu.GetVFS().RemoveDir(path);
|
||||||
}
|
|
||||||
|
|
||||||
const DirEntryInfo* vfsDir::Read()
|
|
||||||
{
|
|
||||||
return m_stream->Read();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfsDir::Close()
|
void vfsDir::Close()
|
||||||
|
@ -64,12 +106,7 @@ void vfsDir::Close()
|
||||||
m_stream.reset();
|
m_stream.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string vfsDir::GetPath() const
|
|
||||||
{
|
|
||||||
return m_stream->GetPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool vfsDir::IsOpened() const
|
bool vfsDir::IsOpened() const
|
||||||
{
|
{
|
||||||
return m_stream && m_stream->IsOpened();
|
return !m_entries.empty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,11 @@ public:
|
||||||
virtual bool Open(const std::string& path) override;
|
virtual bool Open(const std::string& path) override;
|
||||||
virtual bool IsOpened() const override;
|
virtual bool IsOpened() const override;
|
||||||
virtual bool IsExists(const std::string& path) const override;
|
virtual bool IsExists(const std::string& path) const override;
|
||||||
virtual const std::vector<DirEntryInfo>& GetEntries() const override;
|
|
||||||
virtual void Close() override;
|
virtual void Close() override;
|
||||||
virtual std::string GetPath() const override;
|
//virtual std::string GetPath() const override;
|
||||||
|
|
||||||
virtual bool Create(const std::string& path) override;
|
virtual bool Create(const std::string& path) override;
|
||||||
//virtual bool Create(const DirEntryInfo& info) override;
|
//virtual bool Create(const DirEntryInfo& info) override;
|
||||||
virtual bool Rename(const std::string& from, const std::string& to) override;
|
virtual bool Rename(const std::string& from, const std::string& to) override;
|
||||||
virtual bool Remove(const std::string& path) override;
|
virtual bool Remove(const std::string& path) override;
|
||||||
virtual const DirEntryInfo* Read() override;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,7 @@ bool vfsDirBase::IsOpened() const
|
||||||
|
|
||||||
bool vfsDirBase::IsExists(const std::string& path) const
|
bool vfsDirBase::IsExists(const std::string& path) const
|
||||||
{
|
{
|
||||||
return rExists(path);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<DirEntryInfo>& vfsDirBase::GetEntries() const
|
const std::vector<DirEntryInfo>& vfsDirBase::GetEntries() const
|
||||||
|
@ -58,3 +58,9 @@ const DirEntryInfo* vfsDirBase::Read()
|
||||||
|
|
||||||
return &m_entries[m_pos++];
|
return &m_entries[m_pos++];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DirEntryInfo* vfsDirBase::First()
|
||||||
|
{
|
||||||
|
m_pos = 0;
|
||||||
|
return Read();
|
||||||
|
}
|
|
@ -53,4 +53,57 @@ public:
|
||||||
virtual bool Rename(const std::string& from, const std::string& to) = 0;
|
virtual bool Rename(const std::string& from, const std::string& to) = 0;
|
||||||
virtual bool Remove(const std::string& path) = 0;
|
virtual bool Remove(const std::string& path) = 0;
|
||||||
virtual const DirEntryInfo* Read();
|
virtual const DirEntryInfo* Read();
|
||||||
|
virtual const DirEntryInfo* First();
|
||||||
|
|
||||||
|
class iterator
|
||||||
|
{
|
||||||
|
vfsDirBase *parent;
|
||||||
|
const DirEntryInfo* data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
iterator(vfsDirBase* parent)
|
||||||
|
: parent(parent)
|
||||||
|
, data(parent->First())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator(const DirEntryInfo* data)
|
||||||
|
: parent(parent)
|
||||||
|
, data(data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& operator++()
|
||||||
|
{
|
||||||
|
data = parent->Read();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator++(int)
|
||||||
|
{
|
||||||
|
const DirEntryInfo* olddata = data;
|
||||||
|
data = parent->Read();
|
||||||
|
return iterator(olddata);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DirEntryInfo* operator *()
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(iterator other) const
|
||||||
|
{
|
||||||
|
return data != other.data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return iterator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator((const DirEntryInfo*)nullptr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,7 @@ bool vfsLocalDir::Open(const std::string& path)
|
||||||
std::string name;
|
std::string name;
|
||||||
for(bool is_ok = dir.GetFirst(&name); is_ok; is_ok = dir.GetNext(&name))
|
for(bool is_ok = dir.GetFirst(&name); is_ok; is_ok = dir.GetNext(&name))
|
||||||
{
|
{
|
||||||
std::string dir_path = path + name;
|
std::string dir_path = path + "/" + name;
|
||||||
|
|
||||||
m_entries.emplace_back();
|
m_entries.emplace_back();
|
||||||
// TODO: Use same info structure as fileinfo?
|
// TODO: Use same info structure as fileinfo?
|
||||||
|
@ -46,6 +46,11 @@ bool vfsLocalDir::Create(const std::string& path)
|
||||||
return rMkpath(path);
|
return rMkpath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool vfsLocalDir::IsExists(const std::string& path) const
|
||||||
|
{
|
||||||
|
return rIsDir(path);
|
||||||
|
}
|
||||||
|
|
||||||
bool vfsLocalDir::Rename(const std::string& from, const std::string& to)
|
bool vfsLocalDir::Rename(const std::string& from, const std::string& to)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -18,4 +18,5 @@ public:
|
||||||
virtual bool Rename(const std::string& from, const std::string& to) override;
|
virtual bool Rename(const std::string& from, const std::string& to) override;
|
||||||
virtual bool Remove(const std::string& path) override;
|
virtual bool Remove(const std::string& path) override;
|
||||||
virtual bool IsOpened() const override;
|
virtual bool IsOpened() const override;
|
||||||
|
virtual bool IsExists(const std::string& path) const;
|
||||||
};
|
};
|
|
@ -219,4 +219,37 @@ namespace vm
|
||||||
assert(location < memory_location_count);
|
assert(location < memory_location_count);
|
||||||
return g_locations[location];
|
return g_locations[location];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class stack
|
||||||
|
{
|
||||||
|
u32 m_begin;
|
||||||
|
u32 m_size;
|
||||||
|
int m_page_size;
|
||||||
|
int m_position;
|
||||||
|
u8 m_align;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void init(u32 begin, u32 size, u32 page_size = 180, u8 align = 0x10)
|
||||||
|
{
|
||||||
|
m_begin = begin;
|
||||||
|
m_size = size;
|
||||||
|
m_page_size = page_size;
|
||||||
|
m_position = 0;
|
||||||
|
m_align = align;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 alloc_new_page()
|
||||||
|
{
|
||||||
|
assert(m_position + m_page_size < (int)m_size);
|
||||||
|
m_position += (int)m_page_size;
|
||||||
|
return m_begin + m_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 dealloc_new_page()
|
||||||
|
{
|
||||||
|
assert(m_position - m_page_size > 0);
|
||||||
|
m_position -= (int)m_page_size;
|
||||||
|
return m_begin + m_position;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2270,7 +2270,7 @@ void RSXThread::Task()
|
||||||
if(cmd == 0)
|
if(cmd == 0)
|
||||||
{
|
{
|
||||||
LOG_ERROR(Log::RSX, "null cmd: cmd=0x%x, put=0x%x, get=0x%x (addr=0x%x)", cmd, put, get, (u32)Memory.RSXIOMem.RealAddr(get));
|
LOG_ERROR(Log::RSX, "null cmd: cmd=0x%x, put=0x%x, get=0x%x (addr=0x%x)", cmd, put, get, (u32)Memory.RSXIOMem.RealAddr(get));
|
||||||
Emu.Pause();
|
//Emu.Pause();
|
||||||
//HACK! We shouldn't be here
|
//HACK! We shouldn't be here
|
||||||
m_ctrl->get = get + (count + 1) * 4;
|
m_ctrl->get = get + (count + 1) * 4;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -16,8 +16,8 @@ enum VideoErrorCode
|
||||||
|
|
||||||
enum CellVideoOut
|
enum CellVideoOut
|
||||||
{
|
{
|
||||||
CELL_VIDEO_OUT_PRIMARY,
|
CELL_VIDEO_OUT_PRIMARY = 0,
|
||||||
CELL_VIDEO_OUT_SECONDARY,
|
CELL_VIDEO_OUT_SECONDARY = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CellVideoOutResolutionId
|
enum CellVideoOutResolutionId
|
||||||
|
|
|
@ -10,7 +10,6 @@ class ModuleManager
|
||||||
std::vector<ModuleFunc *> m_modules_funcs_list;
|
std::vector<ModuleFunc *> m_modules_funcs_list;
|
||||||
std::vector<Module> m_mod_init; //owner of Module
|
std::vector<Module> m_mod_init; //owner of Module
|
||||||
bool initialized;
|
bool initialized;
|
||||||
std::unordered_map<u32, u32> m_registered_functions;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModuleManager();
|
ModuleManager();
|
||||||
|
@ -26,20 +25,4 @@ public:
|
||||||
u32 GetFuncNumById(u32 id);
|
u32 GetFuncNumById(u32 id);
|
||||||
Module* GetModuleByName(const std::string& name);
|
Module* GetModuleByName(const std::string& name);
|
||||||
Module* GetModuleById(u16 id);
|
Module* GetModuleById(u16 id);
|
||||||
|
|
||||||
void register_function(u32 fnid, u32 fstub)
|
|
||||||
{
|
|
||||||
m_registered_functions[fnid] = fstub;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_function_stub(u32 fnid, be_t<u32>& res)
|
|
||||||
{
|
|
||||||
auto f = m_registered_functions.find(fnid);
|
|
||||||
|
|
||||||
if (f == m_registered_functions.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
res = f->second;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
|
@ -62,10 +62,12 @@ Module::~Module()
|
||||||
{
|
{
|
||||||
UnLoad();
|
UnLoad();
|
||||||
|
|
||||||
for (int i = 0; i < m_funcs_list.size(); i++)
|
for (auto &i : m_funcs_list)
|
||||||
{
|
{
|
||||||
delete m_funcs_list[i];
|
delete i.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_funcs_list.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Load()
|
void Module::Load()
|
||||||
|
@ -75,12 +77,10 @@ void Module::Load()
|
||||||
|
|
||||||
if(m_load_func) m_load_func();
|
if(m_load_func) m_load_func();
|
||||||
|
|
||||||
for(u32 i=0; i<m_funcs_list.size(); ++i)
|
for (auto &i : m_funcs_list)
|
||||||
{
|
{
|
||||||
Emu.GetModuleManager().AddFunc(m_funcs_list[i]);
|
Emu.GetModuleManager().AddFunc(i.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetLoaded(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::UnLoad()
|
void Module::UnLoad()
|
||||||
|
@ -90,6 +90,11 @@ void Module::UnLoad()
|
||||||
|
|
||||||
if(m_unload_func) m_unload_func();
|
if(m_unload_func) m_unload_func();
|
||||||
|
|
||||||
|
for (auto &i : m_funcs_list)
|
||||||
|
{
|
||||||
|
i.second->lle_func.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Re-enable this when needed
|
// TODO: Re-enable this when needed
|
||||||
// This was disabled because some functions would get unloaded and
|
// This was disabled because some functions would get unloaded and
|
||||||
// some games tried to use them, thus only printing a TODO message
|
// some games tried to use them, thus only printing a TODO message
|
||||||
|
@ -106,16 +111,14 @@ bool Module::Load(u32 id)
|
||||||
if(Emu.GetModuleManager().IsLoadedFunc(id))
|
if(Emu.GetModuleManager().IsLoadedFunc(id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for(u32 i=0; i<m_funcs_list.size(); ++i)
|
auto res = m_funcs_list.find(id);
|
||||||
{
|
|
||||||
if(m_funcs_list[i]->id == id)
|
|
||||||
{
|
|
||||||
Emu.GetModuleManager().AddFunc(m_funcs_list[i]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
if (res == m_funcs_list.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Emu.GetModuleManager().AddFunc(res->second);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Module::UnLoad(u32 id)
|
bool Module::UnLoad(u32 id)
|
||||||
|
@ -177,7 +180,7 @@ void fix_import(Module* module, u32 func, u32 addr)
|
||||||
{
|
{
|
||||||
using namespace PPU_instr;
|
using namespace PPU_instr;
|
||||||
|
|
||||||
vm::ptr<u32>& ptr = (vm::ptr<u32>&)addr;
|
vm::ptr<u32> ptr = vm::ptr<u32>::make(addr);
|
||||||
|
|
||||||
*ptr++ = ADDIS(11, 0, func >> 16);
|
*ptr++ = ADDIS(11, 0, func >> 16);
|
||||||
*ptr++ = ORI(11, 11, func & 0xffff);
|
*ptr++ = ORI(11, 11, func & 0xffff);
|
||||||
|
|
|
@ -9,10 +9,12 @@ struct ModuleFunc
|
||||||
{
|
{
|
||||||
u32 id;
|
u32 id;
|
||||||
func_caller* func;
|
func_caller* func;
|
||||||
|
vm::ptr<void(*)()> lle_func;
|
||||||
|
|
||||||
ModuleFunc(u32 id, func_caller* func)
|
ModuleFunc(u32 id, func_caller* func, vm::ptr<void(*)()> lle_func = vm::ptr<void(*)()>::make(0))
|
||||||
: id(id)
|
: id(id)
|
||||||
, func(func)
|
, func(func)
|
||||||
|
, lle_func(lle_func)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +59,7 @@ class Module : public LogBase
|
||||||
void PushNewFuncSub(SFunc* func);
|
void PushNewFuncSub(SFunc* func);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::vector<ModuleFunc*> m_funcs_list;
|
std::unordered_map<u32, ModuleFunc*> m_funcs_list;
|
||||||
|
|
||||||
Module(u16 id, const char* name, void(*load)() = nullptr, void(*unload)() = nullptr);
|
Module(u16 id, const char* name, void(*load)() = nullptr, void(*unload)() = nullptr);
|
||||||
|
|
||||||
|
@ -66,6 +68,16 @@ public:
|
||||||
|
|
||||||
Module &operator =(Module &other) = delete;
|
Module &operator =(Module &other) = delete;
|
||||||
Module &operator =(Module &&other);
|
Module &operator =(Module &&other);
|
||||||
|
|
||||||
|
ModuleFunc* GetFunc(u32 id)
|
||||||
|
{
|
||||||
|
auto res = m_funcs_list.find(id);
|
||||||
|
|
||||||
|
if (res == m_funcs_list.end())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return res->second;
|
||||||
|
}
|
||||||
|
|
||||||
~Module();
|
~Module();
|
||||||
|
|
||||||
|
@ -114,9 +126,20 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoveId(u32 id);
|
bool RemoveId(u32 id);
|
||||||
|
|
||||||
|
void RegisterLLEFunc(u32 id, vm::ptr<void(*)()> func)
|
||||||
|
{
|
||||||
|
if (auto f = GetFunc(id))
|
||||||
|
{
|
||||||
|
f->lle_func = func;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_funcs_list[id] = new ModuleFunc(id, nullptr, func);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T> __forceinline void AddFunc(u32 id, T func);
|
template<typename T> __forceinline void AddFunc(u32 id, T func);
|
||||||
template<typename T> __forceinline void AddFunc(const char* name, T func);
|
template<typename T> __forceinline void AddFunc(const char* name, T func);
|
||||||
template<typename T> __forceinline void AddFuncSub(const char group[8], const u64 ops[], const char* name, T func);
|
template<typename T> __forceinline void AddFuncSub(const char group[8], const u64 ops[], const char* name, T func);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -125,7 +148,7 @@ u32 getFunctionId(const char* name);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
__forceinline void Module::AddFunc(u32 id, T func)
|
__forceinline void Module::AddFunc(u32 id, T func)
|
||||||
{
|
{
|
||||||
m_funcs_list.emplace_back(new ModuleFunc(id, bind_func(func)));
|
m_funcs_list[id] = new ModuleFunc(id, bind_func(func));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -30,7 +30,7 @@ int cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr<CellGa
|
||||||
size->sysSizeKB = 0;
|
size->sysSizeKB = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfsFile f("/app_home/PARAM.SFO");
|
vfsFile f("/app_home/../PARAM.SFO");
|
||||||
if (!f.IsOpened())
|
if (!f.IsOpened())
|
||||||
{
|
{
|
||||||
cellGame->Error("cellGameBootCheck(): CELL_GAME_ERROR_ACCESS_ERROR (cannot open PARAM.SFO)");
|
cellGame->Error("cellGameBootCheck(): CELL_GAME_ERROR_ACCESS_ERROR (cannot open PARAM.SFO)");
|
||||||
|
@ -100,7 +100,7 @@ int cellGamePatchCheck(vm::ptr<CellGameContentSize> size, u32 reserved_addr)
|
||||||
size->sysSizeKB = 0;
|
size->sysSizeKB = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfsFile f("/app_home/PARAM.SFO");
|
vfsFile f("/app_home/../PARAM.SFO");
|
||||||
if (!f.IsOpened())
|
if (!f.IsOpened())
|
||||||
{
|
{
|
||||||
cellGame->Error("cellGamePatchCheck(): CELL_GAME_ERROR_ACCESS_ERROR (cannot open PARAM.SFO)");
|
cellGame->Error("cellGamePatchCheck(): CELL_GAME_ERROR_ACCESS_ERROR (cannot open PARAM.SFO)");
|
||||||
|
@ -336,7 +336,7 @@ int cellGameGetParamInt(u32 id, vm::ptr<u32> value)
|
||||||
cellGame->Warning("cellGameGetParamInt(id=%d, value_addr=0x%x)", id, value.addr());
|
cellGame->Warning("cellGameGetParamInt(id=%d, value_addr=0x%x)", id, value.addr());
|
||||||
|
|
||||||
// TODO: Access through cellGame***Check functions
|
// TODO: Access through cellGame***Check functions
|
||||||
vfsFile f("/app_home/PARAM.SFO");
|
vfsFile f("/app_home/../PARAM.SFO");
|
||||||
PSFLoader psf(f);
|
PSFLoader psf(f);
|
||||||
if(!psf.Load(false))
|
if(!psf.Load(false))
|
||||||
return CELL_GAME_ERROR_FAILURE;
|
return CELL_GAME_ERROR_FAILURE;
|
||||||
|
@ -359,7 +359,7 @@ int cellGameGetParamString(u32 id, vm::ptr<char> buf, u32 bufsize)
|
||||||
cellGame->Warning("cellGameGetParamString(id=%d, buf_addr=0x%x, bufsize=%d)", id, buf.addr(), bufsize);
|
cellGame->Warning("cellGameGetParamString(id=%d, buf_addr=0x%x, bufsize=%d)", id, buf.addr(), bufsize);
|
||||||
|
|
||||||
// TODO: Access through cellGame***Check functions
|
// TODO: Access through cellGame***Check functions
|
||||||
vfsFile f("/app_home/PARAM.SFO");
|
vfsFile f("/app_home/../PARAM.SFO");
|
||||||
PSFLoader psf(f);
|
PSFLoader psf(f);
|
||||||
if(!psf.Load(false))
|
if(!psf.Load(false))
|
||||||
return CELL_GAME_ERROR_FAILURE;
|
return CELL_GAME_ERROR_FAILURE;
|
||||||
|
|
|
@ -96,7 +96,7 @@ int sceNpTrophyCreateContext(vm::ptr<u32> context, vm::ptr<SceNpCommunicationId>
|
||||||
// TODO: There are other possible errors
|
// TODO: There are other possible errors
|
||||||
|
|
||||||
// TODO: Is the TROPHY.TRP file necessarily located in this path?
|
// TODO: Is the TROPHY.TRP file necessarily located in this path?
|
||||||
vfsDir dir("/app_home/TROPDIR/");
|
vfsDir dir("/app_home/../TROPDIR/");
|
||||||
if(!dir.IsOpened())
|
if(!dir.IsOpened())
|
||||||
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST;
|
return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST;
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ int sceNpTrophyCreateContext(vm::ptr<u32> context, vm::ptr<SceNpCommunicationId>
|
||||||
{
|
{
|
||||||
if (entry->flags & DirEntry_TypeDir)
|
if (entry->flags & DirEntry_TypeDir)
|
||||||
{
|
{
|
||||||
vfsStream* stream = Emu.GetVFS().OpenFile("/app_home/TROPDIR/" + entry->name + "/TROPHY.TRP", vfsRead);
|
vfsStream* stream = Emu.GetVFS().OpenFile("/app_home/../TROPDIR/" + entry->name + "/TROPHY.TRP", vfsRead);
|
||||||
|
|
||||||
if (stream && stream->IsOpened())
|
if (stream && stream->IsOpened())
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,7 +40,7 @@ s32 cellFsOpen(vm::ptr<const char> path, s32 flags, vm::ptr<be_t<u32>> fd, vm::p
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
s32 _oflags = flags;
|
s32 _oflags = flags;
|
||||||
if(flags & CELL_O_CREAT)
|
if (flags & CELL_O_CREAT)
|
||||||
{
|
{
|
||||||
_oflags &= ~CELL_O_CREAT;
|
_oflags &= ~CELL_O_CREAT;
|
||||||
Emu.GetVFS().CreateFile(_path);
|
Emu.GetVFS().CreateFile(_path);
|
||||||
|
@ -48,7 +48,7 @@ s32 cellFsOpen(vm::ptr<const char> path, s32 flags, vm::ptr<be_t<u32>> fd, vm::p
|
||||||
|
|
||||||
vfsOpenMode o_mode;
|
vfsOpenMode o_mode;
|
||||||
|
|
||||||
switch(flags & CELL_O_ACCMODE)
|
switch (flags & CELL_O_ACCMODE)
|
||||||
{
|
{
|
||||||
case CELL_O_RDONLY:
|
case CELL_O_RDONLY:
|
||||||
_oflags &= ~CELL_O_RDONLY;
|
_oflags &= ~CELL_O_RDONLY;
|
||||||
|
@ -88,7 +88,7 @@ s32 cellFsOpen(vm::ptr<const char> path, s32 flags, vm::ptr<be_t<u32>> fd, vm::p
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_oflags != 0)
|
if (_oflags != 0)
|
||||||
{
|
{
|
||||||
sys_fs->Error("\"%s\" has unknown flags! flags: 0x%08x", path.get_ptr(), flags);
|
sys_fs->Error("\"%s\" has unknown flags! flags: 0x%08x", path.get_ptr(), flags);
|
||||||
return CELL_EINVAL;
|
return CELL_EINVAL;
|
||||||
|
@ -102,7 +102,7 @@ s32 cellFsOpen(vm::ptr<const char> path, s32 flags, vm::ptr<be_t<u32>> fd, vm::p
|
||||||
|
|
||||||
vfsFileBase* stream = Emu.GetVFS().OpenFile(_path, o_mode);
|
vfsFileBase* stream = Emu.GetVFS().OpenFile(_path, o_mode);
|
||||||
|
|
||||||
if(!stream || !stream->IsOpened())
|
if (!stream || !stream->IsOpened())
|
||||||
{
|
{
|
||||||
delete stream;
|
delete stream;
|
||||||
sys_fs->Error("\"%s\" not found! flags: 0x%08x", path.get_ptr(), flags);
|
sys_fs->Error("\"%s\" not found! flags: 0x%08x", path.get_ptr(), flags);
|
||||||
|
@ -124,9 +124,11 @@ s32 cellFsRead(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<be_t<u64>> nread)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
if (nbytes != (u32)nbytes) return CELL_ENOMEM;
|
if (nbytes != (u32)nbytes)
|
||||||
|
return CELL_ENOMEM;
|
||||||
|
|
||||||
// TODO: checks
|
// TODO: checks
|
||||||
|
|
||||||
|
@ -145,7 +147,7 @@ s32 cellFsWrite(u32 fd, vm::ptr<const void> buf, u64 nbytes, vm::ptr<u64> nwrite
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
||||||
|
|
||||||
if (nbytes != (u32)nbytes) return CELL_ENOMEM;
|
if (nbytes != (u32)nbytes) return CELL_ENOMEM;
|
||||||
|
|
||||||
|
@ -164,7 +166,7 @@ s32 cellFsClose(u32 fd)
|
||||||
|
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
if(!Emu.GetIdManager().RemoveID(fd))
|
if (!Emu.GetIdManager().RemoveID(fd))
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
|
@ -177,7 +179,7 @@ s32 cellFsOpendir(vm::ptr<const char> path, vm::ptr<u32> fd)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsDirBase* dir = Emu.GetVFS().OpenDir(path.get_ptr());
|
vfsDirBase* dir = Emu.GetVFS().OpenDir(path.get_ptr());
|
||||||
if(!dir || !dir->IsOpened())
|
if (!dir || !dir->IsOpened())
|
||||||
{
|
{
|
||||||
delete dir;
|
delete dir;
|
||||||
return CELL_ENOENT;
|
return CELL_ENOENT;
|
||||||
|
@ -194,11 +196,11 @@ s32 cellFsReaddir(u32 fd, vm::ptr<CellFsDirent> dir, vm::ptr<u64> nread)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsDirBase* directory;
|
vfsDirBase* directory;
|
||||||
if(!sys_fs->CheckId(fd, directory))
|
if (!sys_fs->CheckId(fd, directory))
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
|
|
||||||
const DirEntryInfo* info = directory->Read();
|
const DirEntryInfo* info = directory->Read();
|
||||||
if(info)
|
if (info)
|
||||||
{
|
{
|
||||||
dir->d_type = (info->flags & DirEntry_TypeFile) ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY;
|
dir->d_type = (info->flags & DirEntry_TypeFile) ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY;
|
||||||
dir->d_namlen = u8(std::min((u32)info->name.length(), (u32)CELL_MAX_FS_FILE_NAME_LENGTH));
|
dir->d_namlen = u8(std::min((u32)info->name.length(), (u32)CELL_MAX_FS_FILE_NAME_LENGTH));
|
||||||
|
@ -219,7 +221,7 @@ s32 cellFsClosedir(u32 fd)
|
||||||
|
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
if(!Emu.GetIdManager().RemoveID(fd))
|
if (!Emu.GetIdManager().RemoveID(fd))
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
|
@ -276,9 +278,8 @@ s32 cellFsFstat(u32 fd, vm::ptr<CellFsStat> sb)
|
||||||
|
|
||||||
IDType type;
|
IDType type;
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) {
|
if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE)
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
|
||||||
|
|
||||||
sb->st_mode =
|
sb->st_mode =
|
||||||
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
|
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
|
||||||
|
@ -305,9 +306,10 @@ s32 cellFsMkdir(vm::ptr<const char> path, u32 mode)
|
||||||
|
|
||||||
const std::string _path = path.get_ptr();
|
const std::string _path = path.get_ptr();
|
||||||
|
|
||||||
if(Emu.GetVFS().ExistsDir(_path))
|
if (vfsDir().IsExists(_path))
|
||||||
return CELL_EEXIST;
|
return CELL_EEXIST;
|
||||||
if(!Emu.GetVFS().CreateDir(_path))
|
|
||||||
|
if (!Emu.GetVFS().CreateDir(_path))
|
||||||
return CELL_EBUSY;
|
return CELL_EBUSY;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
|
@ -378,10 +380,10 @@ s32 cellFsRmdir(vm::ptr<const char> path)
|
||||||
std::string _path = path.get_ptr();
|
std::string _path = path.get_ptr();
|
||||||
|
|
||||||
vfsDir d;
|
vfsDir d;
|
||||||
if(!d.IsExists(_path))
|
if (!d.IsExists(_path))
|
||||||
return CELL_ENOENT;
|
return CELL_ENOENT;
|
||||||
|
|
||||||
if(!d.Remove(_path))
|
if (!d.Remove(_path))
|
||||||
return CELL_EBUSY;
|
return CELL_EBUSY;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
|
@ -395,7 +397,7 @@ s32 cellFsUnlink(vm::ptr<const char> path)
|
||||||
|
|
||||||
std::string _path = path.get_ptr();
|
std::string _path = path.get_ptr();
|
||||||
|
|
||||||
if (Emu.GetVFS().ExistsDir(_path))
|
if (vfsDir().IsExists(_path))
|
||||||
return CELL_EISDIR;
|
return CELL_EISDIR;
|
||||||
|
|
||||||
if (!Emu.GetVFS().ExistsFile(_path))
|
if (!Emu.GetVFS().ExistsFile(_path))
|
||||||
|
@ -426,9 +428,9 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr<be_t<u64>> pos)
|
||||||
|
|
||||||
IDType type;
|
IDType type;
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) {
|
if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE)
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
|
||||||
*pos = file->Seek(offset, seek_mode);
|
*pos = file->Seek(offset, seek_mode);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -441,9 +443,9 @@ s32 cellFsFtruncate(u32 fd, u64 size)
|
||||||
|
|
||||||
IDType type;
|
IDType type;
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) {
|
if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE)
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
|
||||||
u64 initialSize = file->GetSize();
|
u64 initialSize = file->GetSize();
|
||||||
|
|
||||||
if (initialSize < size)
|
if (initialSize < size)
|
||||||
|
@ -471,7 +473,7 @@ s32 cellFsTruncate(vm::ptr<const char> path, u64 size)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsFile f(path.get_ptr(), vfsReadWrite);
|
vfsFile f(path.get_ptr(), vfsReadWrite);
|
||||||
if(!f.IsOpened())
|
if (!f.IsOpened())
|
||||||
{
|
{
|
||||||
sys_fs->Warning("cellFsTruncate: \"%s\" not found.", path.get_ptr());
|
sys_fs->Warning("cellFsTruncate: \"%s\" not found.", path.get_ptr());
|
||||||
return CELL_ENOENT;
|
return CELL_ENOENT;
|
||||||
|
@ -504,7 +506,8 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr<u64> sector_size, vm::ptr<u64> block_siz
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
*sector_size = 4096; // ?
|
*sector_size = 4096; // ?
|
||||||
*block_size = 4096; // ?
|
*block_size = 4096; // ?
|
||||||
|
@ -547,11 +550,11 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr<CellFsDirectoryEntry> entries, u32
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsDirBase* directory;
|
vfsDirBase* directory;
|
||||||
if(!sys_fs->CheckId(fd, directory))
|
if (!sys_fs->CheckId(fd, directory))
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
|
|
||||||
const DirEntryInfo* info = directory->Read();
|
const DirEntryInfo* info = directory->Read();
|
||||||
if(info)
|
if (info)
|
||||||
{
|
{
|
||||||
entries->attribute.st_mode =
|
entries->attribute.st_mode =
|
||||||
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
|
CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR |
|
||||||
|
@ -585,17 +588,16 @@ s32 cellFsStReadInit(u32 fd, vm::ptr<CellFsRingBuffer> ringbuf)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
fs_config.m_ring_buffer = *ringbuf;
|
fs_config.m_ring_buffer = *ringbuf;
|
||||||
|
|
||||||
// If the size is less than 1MB
|
// If the size is less than 1MB
|
||||||
if(ringbuf->ringbuf_size < 0x40000000) {
|
if (ringbuf->ringbuf_size < 0x40000000)
|
||||||
fs_config.m_alloc_mem_size = (((u32)ringbuf->ringbuf_size + 64 * 1024 - 1) / (64 * 1024)) * (64 * 1024);
|
fs_config.m_alloc_mem_size = (((u32)ringbuf->ringbuf_size + 64 * 1024 - 1) / (64 * 1024)) * (64 * 1024);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
fs_config.m_alloc_mem_size = (((u32)ringbuf->ringbuf_size + 1024 * 1024 - 1) / (1024 * 1024)) * (1024 * 1024);
|
fs_config.m_alloc_mem_size = (((u32)ringbuf->ringbuf_size + 1024 * 1024 - 1) / (1024 * 1024)) * (1024 * 1024);
|
||||||
}
|
|
||||||
|
|
||||||
// alloc memory
|
// alloc memory
|
||||||
fs_config.m_buffer = (u32)Memory.Alloc(fs_config.m_alloc_mem_size, 1024);
|
fs_config.m_buffer = (u32)Memory.Alloc(fs_config.m_alloc_mem_size, 1024);
|
||||||
|
@ -613,7 +615,8 @@ s32 cellFsStReadFinish(u32 fd)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
Memory.Free(fs_config.m_buffer);
|
Memory.Free(fs_config.m_buffer);
|
||||||
fs_config.m_fs_status = CELL_FS_ST_NOT_INITIALIZED;
|
fs_config.m_fs_status = CELL_FS_ST_NOT_INITIALIZED;
|
||||||
|
@ -628,7 +631,8 @@ s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr<CellFsRingBuffer> ringbuf)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
*ringbuf = fs_config.m_ring_buffer;
|
*ringbuf = fs_config.m_ring_buffer;
|
||||||
|
|
||||||
|
@ -644,7 +648,8 @@ s32 cellFsStReadGetStatus(u32 fd, vm::ptr<u64> status)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
*status = fs_config.m_fs_status;
|
*status = fs_config.m_fs_status;
|
||||||
|
|
||||||
|
@ -658,7 +663,8 @@ s32 cellFsStReadGetRegid(u32 fd, vm::ptr<u64> regid)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
*regid = fs_config.m_regid;
|
*regid = fs_config.m_regid;
|
||||||
|
|
||||||
|
@ -672,7 +678,8 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
fs_config.m_current_addr = fs_config.m_buffer + (u32)offset;
|
fs_config.m_current_addr = fs_config.m_buffer + (u32)offset;
|
||||||
fs_config.m_fs_status = CELL_FS_ST_PROGRESS;
|
fs_config.m_fs_status = CELL_FS_ST_PROGRESS;
|
||||||
|
@ -687,7 +694,8 @@ s32 cellFsStReadStop(u32 fd)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
fs_config.m_fs_status = CELL_FS_ST_STOP;
|
fs_config.m_fs_status = CELL_FS_ST_STOP;
|
||||||
|
|
||||||
|
@ -701,7 +709,8 @@ s32 cellFsStRead(u32 fd, u32 buf_addr, u64 size, vm::ptr<u64> rsize)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
// TODO: use ringbuffer (fs_config)
|
// TODO: use ringbuffer (fs_config)
|
||||||
fs_config.m_regid += size;
|
fs_config.m_regid += size;
|
||||||
|
@ -721,7 +730,8 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr<u32> addr, vm::ptr<u64> size)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -733,7 +743,8 @@ s32 cellFsStReadPutCurrentAddr(u32 fd, u32 addr_addr, u64 size)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -745,7 +756,8 @@ s32 cellFsStReadWait(u32 fd, u64 size)
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
@ -757,7 +769,8 @@ s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr<void (*)(int xfd, u64 xsi
|
||||||
LV2_LOCK(0);
|
LV2_LOCK(0);
|
||||||
|
|
||||||
vfsStream* file;
|
vfsStream* file;
|
||||||
if(!sys_fs->CheckId(fd, file)) return CELL_ESRCH;
|
if (!sys_fs->CheckId(fd, file))
|
||||||
|
return CELL_ESRCH;
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,7 @@ u32 EventFlag::check()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_protocol == SYS_SYNC_PRIORITY)
|
if (m_protocol == SYS_SYNC_PRIORITY)
|
||||||
{
|
|
||||||
target = sq.pop_prio();
|
target = sq.pop_prio();
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -42,13 +40,13 @@ s32 sys_event_flag_create(vm::ptr<u32> eflag_id, vm::ptr<sys_event_flag_attr> at
|
||||||
sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)",
|
sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)",
|
||||||
eflag_id.addr(), attr.addr(), init);
|
eflag_id.addr(), attr.addr(), init);
|
||||||
|
|
||||||
if (eflag_id.addr() == NULL)
|
if (!eflag_id)
|
||||||
{
|
{
|
||||||
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (eflag_id_addr=0x%x)", eflag_id.addr());
|
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (eflag_id_addr=0x%x)", eflag_id.addr());
|
||||||
return CELL_EFAULT;
|
return CELL_EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attr.addr() == NULL)
|
if (!attr)
|
||||||
{
|
{
|
||||||
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (attr_addr=0x%x)", attr.addr());
|
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (attr_addr=0x%x)", attr.addr());
|
||||||
return CELL_EFAULT;
|
return CELL_EFAULT;
|
||||||
|
@ -64,9 +62,7 @@ s32 sys_event_flag_create(vm::ptr<u32> eflag_id, vm::ptr<sys_event_flag_attr> at
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attr->pshared.ToBE() != se32(0x200))
|
if (attr->pshared.ToBE() != se32(0x200))
|
||||||
{
|
|
||||||
return CELL_EINVAL;
|
return CELL_EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
switch (attr->type.ToBE())
|
switch (attr->type.ToBE())
|
||||||
{
|
{
|
||||||
|
@ -370,7 +366,7 @@ s32 sys_event_flag_get(u32 eflag_id, vm::ptr<u64> flags)
|
||||||
{
|
{
|
||||||
sys_event_flag.Log("sys_event_flag_get(eflag_id=%d, flags_addr=0x%x)", eflag_id, flags.addr());
|
sys_event_flag.Log("sys_event_flag_get(eflag_id=%d, flags_addr=0x%x)", eflag_id, flags.addr());
|
||||||
|
|
||||||
if (flags.addr() == NULL)
|
if (!flags)
|
||||||
{
|
{
|
||||||
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (flags_addr=0x%x)", flags.addr());
|
sys_event_flag.Error("sys_event_flag_create(): invalid memory access (flags_addr=0x%x)", flags.addr());
|
||||||
return CELL_EFAULT;
|
return CELL_EFAULT;
|
||||||
|
|
|
@ -28,7 +28,7 @@ s32 sys_memory_allocate(u32 size, u32 flags, u32 alloc_addr_addr)
|
||||||
default: return CELL_EINVAL;
|
default: return CELL_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!addr)
|
if (!addr)
|
||||||
return CELL_ENOMEM;
|
return CELL_ENOMEM;
|
||||||
|
|
||||||
// Write back the start address of the allocated area.
|
// Write back the start address of the allocated area.
|
||||||
|
|
|
@ -73,16 +73,27 @@ void sys_game_process_exitspawn(
|
||||||
envp++;
|
envp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &arg : argv){
|
for (auto &arg : argv) {
|
||||||
sys_process.Log("argument: %s", arg.c_str());
|
sys_process.Log("argument: %s", arg.c_str());
|
||||||
}
|
}
|
||||||
for (auto &en : env){
|
|
||||||
|
for (auto &en : env) {
|
||||||
sys_process.Log("env_argument: %s", en.c_str());
|
sys_process.Log("env_argument: %s", en.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: execute the file in <path> with the args in argv
|
//TODO: execute the file in <path> with the args in argv
|
||||||
//and the environment parameters in envp and copy the data
|
//and the environment parameters in envp and copy the data
|
||||||
//from data_addr into the adress space of the new process
|
//from data_addr into the adress space of the new process
|
||||||
//then kill the current process
|
//then kill the current process
|
||||||
|
|
||||||
|
Emu.Pause();
|
||||||
|
sys_process.Success("Process finished");
|
||||||
|
|
||||||
|
CallAfter([]()
|
||||||
|
{
|
||||||
|
Emu.Stop();
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,16 +132,27 @@ void sys_game_process_exitspawn2(
|
||||||
envp++;
|
envp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &arg : argv){
|
for (auto &arg : argv) {
|
||||||
sys_process.Log("argument: %s", arg.c_str());
|
sys_process.Log("argument: %s", arg.c_str());
|
||||||
}
|
}
|
||||||
for (auto &en : env){
|
|
||||||
|
for (auto &en : env) {
|
||||||
sys_process.Log("env_argument: %s", en.c_str());
|
sys_process.Log("env_argument: %s", en.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: execute the file in <path> with the args in argv
|
//TODO: execute the file in <path> with the args in argv
|
||||||
//and the environment parameters in envp and copy the data
|
//and the environment parameters in envp and copy the data
|
||||||
//from data_addr into the adress space of the new process
|
//from data_addr into the adress space of the new process
|
||||||
//then kill the current process
|
//then kill the current process
|
||||||
|
|
||||||
|
Emu.Pause();
|
||||||
|
sys_process.Success("Process finished");
|
||||||
|
|
||||||
|
CallAfter([]()
|
||||||
|
{
|
||||||
|
Emu.Stop();
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ void Emulator::Load()
|
||||||
|
|
||||||
LOG_NOTICE(LOADER, "Loading '%s'...", m_path.c_str());
|
LOG_NOTICE(LOADER, "Loading '%s'...", m_path.c_str());
|
||||||
GetInfo().Reset();
|
GetInfo().Reset();
|
||||||
GetVFS().Init(m_path);
|
GetVFS().Init(rFileName(m_path).GetPath());
|
||||||
|
|
||||||
LOG_NOTICE(LOADER, " "); //used to be skip_line
|
LOG_NOTICE(LOADER, " "); //used to be skip_line
|
||||||
LOG_NOTICE(LOADER, "Mount info:");
|
LOG_NOTICE(LOADER, "Mount info:");
|
||||||
|
|
|
@ -112,6 +112,7 @@ class Emulator
|
||||||
public:
|
public:
|
||||||
std::string m_path;
|
std::string m_path;
|
||||||
std::string m_elf_path;
|
std::string m_elf_path;
|
||||||
|
std::string m_emu_path;
|
||||||
std::string m_title_id;
|
std::string m_title_id;
|
||||||
u32 m_ppu_thr_stop;
|
u32 m_ppu_thr_stop;
|
||||||
s32 m_sdk_version;
|
s32 m_sdk_version;
|
||||||
|
@ -128,6 +129,16 @@ public:
|
||||||
return m_elf_path;
|
return m_elf_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetEmulatorPath() const
|
||||||
|
{
|
||||||
|
return m_emu_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetEmulatorPath(const std::string& path)
|
||||||
|
{
|
||||||
|
m_emu_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
std::recursive_mutex& GetCoreMutex() { return m_core_mutex; }
|
std::recursive_mutex& GetCoreMutex() { return m_core_mutex; }
|
||||||
|
|
||||||
CPUThreadManager& GetCPU() { return *m_thread_manager; }
|
CPUThreadManager& GetCPU() { return *m_thread_manager; }
|
||||||
|
|
|
@ -112,7 +112,7 @@ void GameViewer::LoadGames()
|
||||||
|
|
||||||
m_games.clear();
|
m_games.clear();
|
||||||
|
|
||||||
for(const DirEntryInfo* info = dir.Read(); info; info = dir.Read())
|
for(const DirEntryInfo* info : dir)
|
||||||
{
|
{
|
||||||
if(info->flags & DirEntry_TypeDir)
|
if(info->flags & DirEntry_TypeDir)
|
||||||
{
|
{
|
||||||
|
@ -182,7 +182,7 @@ void GameViewer::ShowData()
|
||||||
|
|
||||||
void GameViewer::Refresh()
|
void GameViewer::Refresh()
|
||||||
{
|
{
|
||||||
Emu.GetVFS().Init(m_path);
|
Emu.GetVFS().Init("/");
|
||||||
LoadGames();
|
LoadGames();
|
||||||
LoadPSF();
|
LoadPSF();
|
||||||
ShowData();
|
ShowData();
|
||||||
|
@ -210,7 +210,7 @@ void GameViewer::DClick(wxListEvent& event)
|
||||||
|
|
||||||
Debug::AutoPause::getInstance().Reload();
|
Debug::AutoPause::getInstance().Reload();
|
||||||
|
|
||||||
Emu.GetVFS().Init(path);
|
Emu.GetVFS().Init("/");
|
||||||
std::string local_path;
|
std::string local_path;
|
||||||
if (Emu.GetVFS().GetDevice(path, local_path) && !Emu.BootGame(local_path)) {
|
if (Emu.GetVFS().GetDevice(path, local_path) && !Emu.BootGame(local_path)) {
|
||||||
LOG_ERROR(HLE, "Boot error: elf not found! [%s]", path.c_str());
|
LOG_ERROR(HLE, "Boot error: elf not found! [%s]", path.c_str());
|
||||||
|
|
|
@ -147,7 +147,7 @@ void KernelExplorer::Update()
|
||||||
sprintf(name, "Modules (%d)", count);
|
sprintf(name, "Modules (%d)", count);
|
||||||
const auto& node = m_tree->AppendItem(root, name);
|
const auto& node = m_tree->AppendItem(root, name);
|
||||||
const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_PRX);
|
const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_PRX);
|
||||||
sprintf(name, "Segment List (%d)", 2 * objects.size()); // TODO: Assuming 2 segments per PRX file is not good
|
sprintf(name, "Segment List (%l)", 2 * objects.size()); // TODO: Assuming 2 segments per PRX file is not good
|
||||||
m_tree->AppendItem(node, name);
|
m_tree->AppendItem(node, name);
|
||||||
for (const auto& id : objects)
|
for (const auto& id : objects)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,19 +13,20 @@ LLEModulesManagerFrame::LLEModulesManagerFrame(wxWindow* parent) : FrameBase(par
|
||||||
wxBoxSizer *s_p_panel = new wxBoxSizer(wxVERTICAL);
|
wxBoxSizer *s_p_panel = new wxBoxSizer(wxVERTICAL);
|
||||||
wxPanel *p_main = new wxPanel(this);
|
wxPanel *p_main = new wxPanel(this);
|
||||||
m_check_list = new wxCheckListBox(p_main, wxID_ANY);
|
m_check_list = new wxCheckListBox(p_main, wxID_ANY);
|
||||||
s_p_panel->Add(m_check_list, 0, wxEXPAND | wxALL, 5);
|
s_p_panel->Add(m_check_list, 1, wxEXPAND | wxALL, 5);
|
||||||
p_main->SetSizerAndFit(s_p_panel);
|
p_main->SetSizerAndFit(s_p_panel);
|
||||||
s_panel->Add(p_main, 0, wxEXPAND | wxALL, 5);
|
s_panel->Add(p_main, 1, wxEXPAND | wxALL, 5);
|
||||||
SetSizerAndFit(s_panel);
|
SetSizerAndFit(s_panel);
|
||||||
|
|
||||||
Refresh();
|
Refresh();
|
||||||
//Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent& event) { UpdateSelection(); });
|
Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent& event) { UpdateSelection(event.GetInt()); event.Skip(); });
|
||||||
Bind(wxEVT_SIZE, [p_main, this](wxSizeEvent& event) { p_main->SetSize(GetClientSize()); m_check_list->SetSize(p_main->GetClientSize() - wxSize(10, 10)); });
|
Bind(wxEVT_SIZE, [p_main, this](wxSizeEvent& event) { p_main->SetSize(GetClientSize()); m_check_list->SetSize(p_main->GetClientSize() - wxSize(10, 10)); event.Skip(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLEModulesManagerFrame::Refresh()
|
void LLEModulesManagerFrame::Refresh()
|
||||||
{
|
{
|
||||||
m_check_list->Clear();
|
m_check_list->Clear();
|
||||||
|
m_funcs.clear();
|
||||||
|
|
||||||
std::string path = "/dev_flash/sys/external/";
|
std::string path = "/dev_flash/sys/external/";
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ void LLEModulesManagerFrame::Refresh()
|
||||||
vfsDir dir(path);
|
vfsDir dir(path);
|
||||||
|
|
||||||
loader::handlers::elf64 sprx_loader;
|
loader::handlers::elf64 sprx_loader;
|
||||||
for (const DirEntryInfo* info = dir.Read(); info; info = dir.Read())
|
for (const auto info : dir)
|
||||||
{
|
{
|
||||||
if (info->flags & DirEntry_TypeFile)
|
if (info->flags & DirEntry_TypeFile)
|
||||||
{
|
{
|
||||||
|
@ -49,17 +50,45 @@ void LLEModulesManagerFrame::Refresh()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprx_loader.load();
|
//loader::handlers::elf64::sprx_info info;
|
||||||
|
//sprx_loader.load_sprx(info);
|
||||||
|
|
||||||
m_check_list->Check(m_check_list->Append(sprx_loader.sprx_get_module_name() +
|
std::string name = sprx_loader.sprx_get_module_name();
|
||||||
" v" + std::to_string((int)sprx_loader.m_sprx_module_info.version[0]) + "." + std::to_string((int)sprx_loader.m_sprx_module_info.version[1])));
|
|
||||||
|
bool is_skip = false;
|
||||||
|
for (auto &i : m_funcs)
|
||||||
|
{
|
||||||
|
if (i == name)
|
||||||
|
{
|
||||||
|
is_skip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_skip)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_funcs.push_back(name);
|
||||||
|
|
||||||
|
IniEntry<bool> load_lib;
|
||||||
|
load_lib.Init(name, "LLE");
|
||||||
|
|
||||||
|
m_check_list->Check(m_check_list->Append(name +
|
||||||
|
" v" + std::to_string((int)sprx_loader.m_sprx_module_info.version[0]) +
|
||||||
|
"." + std::to_string((int)sprx_loader.m_sprx_module_info.version[1])),
|
||||||
|
load_lib.LoadValue(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Emu.GetVFS().UnMountAll();
|
Emu.GetVFS().UnMountAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLEModulesManagerFrame::UpdateSelection()
|
void LLEModulesManagerFrame::UpdateSelection(int index)
|
||||||
{
|
{
|
||||||
|
if (index < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IniEntry<bool> load_lib;
|
||||||
|
load_lib.Init(m_funcs[index], "LLE");
|
||||||
|
load_lib.SaveValue(m_check_list->IsChecked(index));
|
||||||
}
|
}
|
|
@ -5,9 +5,10 @@
|
||||||
class LLEModulesManagerFrame : public FrameBase
|
class LLEModulesManagerFrame : public FrameBase
|
||||||
{
|
{
|
||||||
wxCheckListBox *m_check_list;
|
wxCheckListBox *m_check_list;
|
||||||
|
std::vector<std::string> m_funcs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LLEModulesManagerFrame(wxWindow *parent);
|
LLEModulesManagerFrame(wxWindow *parent);
|
||||||
void Refresh();
|
void Refresh();
|
||||||
void UpdateSelection();
|
void UpdateSelection(int index);
|
||||||
};
|
};
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Utilities/rFile.h"
|
#include "Utilities/rFile.h"
|
||||||
#include "Emu/FS/vfsStream.h"
|
#include "Emu/FS/vfsStream.h"
|
||||||
#include "Emu/FS/vfsFile.h"
|
#include "Emu/FS/vfsFile.h"
|
||||||
|
#include "Emu/FS/vfsDir.h"
|
||||||
#include "Emu/Memory/Memory.h"
|
#include "Emu/Memory/Memory.h"
|
||||||
#include "Emu/System.h"
|
#include "Emu/System.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
#include "Emu/Cell/PPUInstrTable.h"
|
#include "Emu/Cell/PPUInstrTable.h"
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "ELF64.h"
|
#include "ELF64.h"
|
||||||
|
#include "Ini.h"
|
||||||
|
|
||||||
using namespace PPU_instr;
|
using namespace PPU_instr;
|
||||||
|
|
||||||
|
@ -43,8 +45,6 @@ namespace loader
|
||||||
return broken_file;
|
return broken_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_WARNING(LOADER, "m_ehdr.e_type = 0x%x", m_ehdr.e_type.ToLE());
|
|
||||||
|
|
||||||
if (m_ehdr.e_machine != MACHINE_PPC64 && m_ehdr.e_machine != MACHINE_SPU)
|
if (m_ehdr.e_machine != MACHINE_PPC64 && m_ehdr.e_machine != MACHINE_SPU)
|
||||||
{
|
{
|
||||||
LOG_ERROR(LOADER, "Unknown elf64 machine type: 0x%x", m_ehdr.e_machine.ToLE());
|
LOG_ERROR(LOADER, "Unknown elf64 machine type: 0x%x", m_ehdr.e_machine.ToLE());
|
||||||
|
@ -73,8 +73,6 @@ namespace loader
|
||||||
|
|
||||||
if (is_sprx())
|
if (is_sprx())
|
||||||
{
|
{
|
||||||
LOG_NOTICE(LOADER, "SPRX loading...");
|
|
||||||
|
|
||||||
m_stream->Seek(handler::get_stream_offset() + m_phdrs[0].p_paddr.addr());
|
m_stream->Seek(handler::get_stream_offset() + m_phdrs[0].p_paddr.addr());
|
||||||
m_stream->Read(&m_sprx_module_info, sizeof(sprx_module_info));
|
m_stream->Read(&m_sprx_module_info, sizeof(sprx_module_info));
|
||||||
|
|
||||||
|
@ -94,7 +92,7 @@ namespace loader
|
||||||
{
|
{
|
||||||
for (auto &phdr : m_phdrs)
|
for (auto &phdr : m_phdrs)
|
||||||
{
|
{
|
||||||
switch (phdr.p_type.ToLE())
|
switch ((u32)phdr.p_type)
|
||||||
{
|
{
|
||||||
case 0x1: //load
|
case 0x1: //load
|
||||||
if (phdr.p_memsz)
|
if (phdr.p_memsz)
|
||||||
|
@ -127,6 +125,8 @@ namespace loader
|
||||||
m_stream->Seek(handler::get_stream_offset() + phdr.p_paddr.addr());
|
m_stream->Seek(handler::get_stream_offset() + phdr.p_paddr.addr());
|
||||||
m_stream->Read(&module_info, sizeof(module_info));
|
m_stream->Read(&module_info, sizeof(module_info));
|
||||||
LOG_ERROR(LOADER, "%s (%x):", module_info.name, (u32)module_info.toc);
|
LOG_ERROR(LOADER, "%s (%x):", module_info.name, (u32)module_info.toc);
|
||||||
|
info.name = std::string((const char*)module_info.name, 28);
|
||||||
|
info.rtoc = module_info.toc;
|
||||||
|
|
||||||
int import_count = (module_info.imports_end - module_info.imports_start) / sizeof(sys_prx_library_info_t);
|
int import_count = (module_info.imports_end - module_info.imports_start) / sizeof(sys_prx_library_info_t);
|
||||||
|
|
||||||
|
@ -149,12 +149,12 @@ namespace loader
|
||||||
{
|
{
|
||||||
char name[27];
|
char name[27];
|
||||||
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr);
|
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr);
|
||||||
modulename = std::string(name, m_stream->Read(name, sizeof(name)));
|
m_stream->Read(name, sizeof(name));
|
||||||
|
modulename = std::string(name);
|
||||||
LOG_ERROR(LOADER, "**** %s", name);
|
LOG_ERROR(LOADER, "**** %s", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
//ModuleManager& manager = Emu.GetModuleManager();
|
auto &module = info.modules[modulename];
|
||||||
//Module* module = manager.GetModuleByName(modulename);
|
|
||||||
|
|
||||||
LOG_ERROR(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6);
|
LOG_ERROR(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6);
|
||||||
|
|
||||||
|
@ -167,7 +167,7 @@ namespace loader
|
||||||
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub));
|
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub));
|
||||||
m_stream->Read(&fstub, sizeof(fstub));
|
m_stream->Read(&fstub, sizeof(fstub));
|
||||||
|
|
||||||
info.exports[fnid] = fstub;
|
module.exports[fnid] = fstub;
|
||||||
|
|
||||||
//LOG_NOTICE(LOADER, "Exported function '%s' in '%s' module (LLE)", SysCalls::GetHLEFuncName(fnid).c_str(), module_name.c_str());
|
//LOG_NOTICE(LOADER, "Exported function '%s' in '%s' module (LLE)", SysCalls::GetHLEFuncName(fnid).c_str(), module_name.c_str());
|
||||||
LOG_ERROR(LOADER, "**** %s: [%s] -> 0x%x", modulename.c_str(), SysCalls::GetHLEFuncName(fnid).c_str(), (u32)fstub);
|
LOG_ERROR(LOADER, "**** %s: [%s] -> 0x%x", modulename.c_str(), SysCalls::GetHLEFuncName(fnid).c_str(), (u32)fstub);
|
||||||
|
@ -201,17 +201,17 @@ namespace loader
|
||||||
switch ((u32)rel.type)
|
switch ((u32)rel.type)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
LOG_ERROR(LOADER, "**** RELOCATION(1): 0x%x <- 0x%x", ADDR, (u32)(info.segments[rel.index_value].begin.addr() + rel.ptr.addr()));
|
LOG_WARNING(LOADER, "**** RELOCATION(1): 0x%x <- 0x%x", ADDR, (u32)(info.segments[rel.index_value].begin.addr() + rel.ptr.addr()));
|
||||||
*vm::ptr<u32>::make(ADDR) = info.segments[rel.index_value].begin.addr() + rel.ptr.addr();
|
*vm::ptr<u32>::make(ADDR) = info.segments[rel.index_value].begin.addr() + rel.ptr.addr();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
LOG_ERROR(LOADER, "**** RELOCATION(4): 0x%x <- 0x%x", ADDR, (u16)(rel.ptr.addr()));
|
LOG_WARNING(LOADER, "**** RELOCATION(4): 0x%x <- 0x%x", ADDR, (u16)(rel.ptr.addr()));
|
||||||
*vm::ptr<u16>::make(ADDR) = (u16)(u64)rel.ptr.addr();
|
*vm::ptr<u16>::make(ADDR) = (u16)(u64)rel.ptr.addr();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
LOG_ERROR(LOADER, "**** RELOCATION(5): 0x%x <- 0x%x", ADDR, (u16)(info.segments[rel.index_value].begin.addr() >> 16));
|
LOG_WARNING(LOADER, "**** RELOCATION(5): 0x%x <- 0x%x", ADDR, (u16)(info.segments[rel.index_value].begin.addr() >> 16));
|
||||||
*vm::ptr<u16>::make(ADDR) = info.segments[rel.index_value].begin.addr() >> 16;
|
*vm::ptr<u16>::make(ADDR) = info.segments[rel.index_value].begin.addr() >> 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -230,20 +230,23 @@ namespace loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &e : info.exports)
|
for (auto &m : info.modules)
|
||||||
{
|
{
|
||||||
u32 stub = e.second;
|
for (auto &e : m.second.exports)
|
||||||
|
|
||||||
for (auto &s : info.segments)
|
|
||||||
{
|
{
|
||||||
if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file)
|
u32 stub = e.second;
|
||||||
{
|
|
||||||
stub += s.begin.addr() - s.initial_addr.addr();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.second = stub;
|
for (auto &s : info.segments)
|
||||||
|
{
|
||||||
|
if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file)
|
||||||
|
{
|
||||||
|
stub += s.begin.addr() - s.initial_addr.addr();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.second = stub;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -266,12 +269,12 @@ namespace loader
|
||||||
std::vector<u32> stop_funcs;
|
std::vector<u32> stop_funcs;
|
||||||
|
|
||||||
//load modules
|
//load modules
|
||||||
static const char* lle_modules[] = { "lv2", "sre", "l10n", "gcm_sys", "fs" };
|
vfsDir lle_dir("/dev_flash/sys/external");
|
||||||
//TODO: for (auto &module : lle_modules)
|
|
||||||
char* module; if (0)
|
for (const auto module : lle_dir)
|
||||||
{
|
{
|
||||||
elf64 sprx_handler;
|
elf64 sprx_handler;
|
||||||
vfsFile fsprx(std::string("/dev_flash/sys/external/lib") + module + ".sprx");
|
vfsFile fsprx(lle_dir.GetPath() + "/" + module->name);
|
||||||
|
|
||||||
if (fsprx.IsOpened())
|
if (fsprx.IsOpened())
|
||||||
{
|
{
|
||||||
|
@ -279,21 +282,52 @@ namespace loader
|
||||||
|
|
||||||
if (sprx_handler.is_sprx())
|
if (sprx_handler.is_sprx())
|
||||||
{
|
{
|
||||||
|
IniEntry<bool> load_lib;
|
||||||
|
load_lib.Init(sprx_handler.sprx_get_module_name(), "LLE");
|
||||||
|
|
||||||
|
if (!load_lib.LoadValue(false))
|
||||||
|
{
|
||||||
|
LOG_ERROR(LOADER, "skipped lle library '%s'", sprx_handler.sprx_get_module_name().c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_WARNING(LOADER, "loading lle library '%s'", sprx_handler.sprx_get_module_name().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
sprx_info info;
|
sprx_info info;
|
||||||
sprx_handler.load_sprx(info);
|
sprx_handler.load_sprx(info);
|
||||||
|
|
||||||
std::unordered_map<u32, u32>::iterator f;
|
for (auto &m : info.modules)
|
||||||
|
|
||||||
if ((f = info.exports.find(0xbc9a0086)) != info.exports.end())
|
|
||||||
start_funcs.push_back(f->second);
|
|
||||||
|
|
||||||
if ((f = info.exports.find(0xab779874)) != info.exports.end())
|
|
||||||
stop_funcs.push_back(f->second);
|
|
||||||
|
|
||||||
for (auto &e : info.exports)
|
|
||||||
{
|
{
|
||||||
if (e.first != 0xbc9a0086 && e.first != 0xab779874)
|
if (m.first == "")
|
||||||
Emu.GetModuleManager().register_function(e.first, e.second);
|
{
|
||||||
|
for (auto &e : m.second.exports)
|
||||||
|
{
|
||||||
|
switch (e.first)
|
||||||
|
{
|
||||||
|
case 0xbc9a0086: start_funcs.push_back(e.second); break;
|
||||||
|
case 0xab779874: stop_funcs.push_back(e.second); break;
|
||||||
|
|
||||||
|
default: LOG_ERROR(LOADER, "unknown special func 0x%08x in '%s' library", e.first, info.name.c_str()); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Module* module = Emu.GetModuleManager().GetModuleByName(m.first);
|
||||||
|
|
||||||
|
if (!module)
|
||||||
|
{
|
||||||
|
LOG_ERROR(LOADER, "unknown module '%s' in '%s' library", m.first.c_str(), info.name.c_str());
|
||||||
|
module = new Module(-1, m.first.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &e : m.second.exports)
|
||||||
|
{
|
||||||
|
module->RegisterLLEFunc(e.first, vm::ptr<void(*)()>::make(e.second));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,8 +503,9 @@ namespace loader
|
||||||
for (u32 i = 0; i < stub->s_imports; ++i)
|
for (u32 i = 0; i < stub->s_imports; ++i)
|
||||||
{
|
{
|
||||||
const u32 nid = stub->s_nid[i];
|
const u32 nid = stub->s_nid[i];
|
||||||
|
auto func = module ? module->GetFunc(nid) : nullptr;
|
||||||
|
|
||||||
if (!Emu.GetModuleManager().get_function_stub(nid, stub->s_text[i]))
|
if (!func || !func->lle_func)
|
||||||
{
|
{
|
||||||
dst[i] = stub_data;
|
dst[i] = stub_data;
|
||||||
|
|
||||||
|
@ -490,6 +525,7 @@ namespace loader
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
stub->s_text[i] = func->lle_func.addr();
|
||||||
//Is function auto exported, than we can use it
|
//Is function auto exported, than we can use it
|
||||||
LOG_NOTICE(LOADER, "Imported function '%s' in '%s' module (LLE: 0x%x)", SysCalls::GetHLEFuncName(nid).c_str(), module_name.c_str(), (u32)stub->s_text[i]);
|
LOG_NOTICE(LOADER, "Imported function '%s' in '%s' module (LLE: 0x%x)", SysCalls::GetHLEFuncName(nid).c_str(), module_name.c_str(), (u32)stub->s_text[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,8 +131,16 @@ namespace loader
|
||||||
|
|
||||||
struct sprx_info
|
struct sprx_info
|
||||||
{
|
{
|
||||||
std::unordered_map<u32, u32> exports;
|
std::string name;
|
||||||
std::unordered_map<u32, u32> imports;
|
u32 rtoc;
|
||||||
|
|
||||||
|
struct module_info
|
||||||
|
{
|
||||||
|
std::unordered_map<u32, u32> exports;
|
||||||
|
std::unordered_map<u32, u32> imports;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, module_info> modules;
|
||||||
std::vector<sprx_segment_info> segments;
|
std::vector<sprx_segment_info> segments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ wxDEFINE_EVENT(wxEVT_DBG_COMMAND, wxCommandEvent);
|
||||||
IMPLEMENT_APP(Rpcs3App)
|
IMPLEMENT_APP(Rpcs3App)
|
||||||
Rpcs3App* TheApp;
|
Rpcs3App* TheApp;
|
||||||
|
|
||||||
|
std::string simplify_path(const std::string& path, bool is_dir);
|
||||||
|
|
||||||
bool Rpcs3App::OnInit()
|
bool Rpcs3App::OnInit()
|
||||||
{
|
{
|
||||||
SetSendDbgCommandCallback([](DbgCommand id, CPUThread* t)
|
SetSendDbgCommandCallback([](DbgCommand id, CPUThread* t)
|
||||||
|
@ -128,16 +130,17 @@ bool Rpcs3App::OnInit()
|
||||||
wxInitAllImageHandlers();
|
wxInitAllImageHandlers();
|
||||||
|
|
||||||
// RPCS3 assumes the current working directory is the folder where it is contained, so we make sure this is true
|
// RPCS3 assumes the current working directory is the folder where it is contained, so we make sure this is true
|
||||||
const wxString executablePath = wxStandardPaths::Get().GetExecutablePath();
|
const wxString executablePath = wxPathOnly(wxStandardPaths::Get().GetExecutablePath());
|
||||||
wxSetWorkingDirectory(wxPathOnly(executablePath));
|
wxSetWorkingDirectory(executablePath);
|
||||||
|
|
||||||
main_thread = std::this_thread::get_id();
|
main_thread = std::this_thread::get_id();
|
||||||
|
|
||||||
Ini.Load();
|
Ini.Load();
|
||||||
|
Emu.Init();
|
||||||
|
Emu.SetEmulatorPath(executablePath.ToStdString());
|
||||||
|
|
||||||
m_MainFrame = new MainFrame();
|
m_MainFrame = new MainFrame();
|
||||||
SetTopWindow(m_MainFrame);
|
SetTopWindow(m_MainFrame);
|
||||||
Emu.Init();
|
|
||||||
|
|
||||||
m_MainFrame->Show();
|
m_MainFrame->Show();
|
||||||
m_MainFrame->DoSettings(true);
|
m_MainFrame->DoSettings(true);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue