Allow iterating in mod directories.

This commit is contained in:
Skyth 2024-12-27 20:24:54 +03:00
parent 1b9d40ac66
commit 3fe31c3570
4 changed files with 77 additions and 61 deletions

View file

@ -16,21 +16,50 @@ struct FileHandle : KernelObject
struct FindHandle : KernelObject struct FindHandle : KernelObject
{ {
std::error_code ec; std::error_code ec;
std::filesystem::path searchPath; ankerl::unordered_dense::map<std::u8string, std::pair<size_t, bool>> searchResult; // Relative path, file size, is directory
std::filesystem::directory_iterator iterator; decltype(searchResult)::iterator iterator;
FindHandle(const std::string_view& path)
{
auto addDirectory = [&](const std::filesystem::path& directory)
{
for (auto& entry : std::filesystem::directory_iterator(directory, ec))
{
std::u8string relativePath = entry.path().lexically_relative(directory).u8string();
searchResult.emplace(relativePath, std::make_pair(entry.is_directory(ec) ? 0 : entry.file_size(ec), entry.is_directory(ec)));
}
};
std::string_view pathNoPrefix = path;
size_t index = pathNoPrefix.find(":\\");
if (index != std::string_view::npos)
pathNoPrefix.remove_prefix(index + 2);
for (size_t i = 0; ; i++)
{
auto* includeDirs = ModLoader::GetIncludeDirectories(i);
if (includeDirs == nullptr)
break;
for (auto& includeDir : *includeDirs)
addDirectory(includeDir / pathNoPrefix);
}
addDirectory(std::u8string_view((const char8_t*)FileSystem::TransformPath(path)));
iterator = searchResult.begin();
}
void fillFindData(WIN32_FIND_DATAA* lpFindFileData) void fillFindData(WIN32_FIND_DATAA* lpFindFileData)
{ {
if (iterator->is_directory()) if (iterator->second.second)
lpFindFileData->dwFileAttributes = ByteSwap(FILE_ATTRIBUTE_DIRECTORY); lpFindFileData->dwFileAttributes = ByteSwap(FILE_ATTRIBUTE_DIRECTORY);
else if (iterator->is_regular_file()) else
lpFindFileData->dwFileAttributes = ByteSwap(FILE_ATTRIBUTE_NORMAL); lpFindFileData->dwFileAttributes = ByteSwap(FILE_ATTRIBUTE_NORMAL);
std::u8string pathU8Str = iterator->path().lexically_relative(searchPath).u8string(); strncpy(lpFindFileData->cFileName, (const char *)(iterator->first.c_str()), sizeof(lpFindFileData->cFileName));
uint64_t fileSize = iterator->file_size(ec); lpFindFileData->nFileSizeLow = ByteSwap(uint32_t(iterator->second.first >> 32U));
strncpy(lpFindFileData->cFileName, (const char *)(pathU8Str.c_str()), sizeof(lpFindFileData->cFileName)); lpFindFileData->nFileSizeHigh = ByteSwap(uint32_t(iterator->second.first));
lpFindFileData->nFileSizeLow = ByteSwap(uint32_t(fileSize >> 32U));
lpFindFileData->nFileSizeHigh = ByteSwap(uint32_t(fileSize));
lpFindFileData->ftCreationTime = {}; lpFindFileData->ftCreationTime = {};
lpFindFileData->ftLastAccessTime = {}; lpFindFileData->ftLastAccessTime = {};
lpFindFileData->ftLastWriteTime = {}; lpFindFileData->ftLastWriteTime = {};
@ -238,45 +267,35 @@ uint32_t XSetFilePointerEx(FileHandle* hFile, int32_t lDistanceToMove, LARGE_INT
FindHandle* XFindFirstFileA(const char* lpFileName, WIN32_FIND_DATAA* lpFindFileData) FindHandle* XFindFirstFileA(const char* lpFileName, WIN32_FIND_DATAA* lpFindFileData)
{ {
const char *transformedPath = FileSystem::TransformPath(lpFileName); std::string_view path = lpFileName;
size_t transformedPathLength = strlen(transformedPath); if (path.find("\\*") == (path.size() - 2) || path.find("/*") == (path.size() - 2))
if (transformedPathLength == 0)
return (FindHandle*)GUEST_INVALID_HANDLE_VALUE;
std::filesystem::path dirPath;
if (strstr(transformedPath, "\\*") == (&transformedPath[transformedPathLength - 2]) || strstr(transformedPath, "/*") == (&transformedPath[transformedPathLength - 2]))
{ {
dirPath = std::u8string_view((const char8_t*)(transformedPath), transformedPathLength - 2); path.remove_suffix(1);
} }
else if (strstr(transformedPath, "\\*.*") == (&transformedPath[transformedPathLength - 4]) || strstr(transformedPath, "/*.*") == (&transformedPath[transformedPathLength - 4])) else if (path.find("\\*.*") == (path.size() - 4) || path.find("/*.*") == (path.size() - 4))
{ {
dirPath = std::u8string_view((const char8_t *)(transformedPath), transformedPathLength - 4); path.remove_suffix(3);
} }
else else
{ {
dirPath = std::u8string_view((const char8_t *)(transformedPath), transformedPathLength); assert(!std::filesystem::path(path).has_extension() && "Unknown search pattern.");
assert(!dirPath.has_extension() && "Unknown search pattern.");
} }
if (!std::filesystem::is_directory(dirPath)) FindHandle findHandle(path);
if (findHandle.searchResult.empty())
return GetInvalidKernelObject<FindHandle>(); return GetInvalidKernelObject<FindHandle>();
std::filesystem::directory_iterator dirIterator(dirPath); findHandle.fillFindData(lpFindFileData);
if (dirIterator == std::filesystem::directory_iterator())
return GetInvalidKernelObject<FindHandle>();
FindHandle *findHandle = CreateKernelObject<FindHandle>(); return CreateKernelObject<FindHandle>(std::move(findHandle));
findHandle->searchPath = std::move(dirPath);
findHandle->iterator = std::move(dirIterator);
findHandle->fillFindData(lpFindFileData);
return findHandle;
} }
uint32_t XFindNextFileA(FindHandle* Handle, WIN32_FIND_DATAA* lpFindFileData) uint32_t XFindNextFileA(FindHandle* Handle, WIN32_FIND_DATAA* lpFindFileData)
{ {
Handle->iterator++; Handle->iterator++;
if (Handle->iterator == std::filesystem::directory_iterator()) if (Handle->iterator == Handle->searchResult.end())
{ {
return FALSE; return FALSE;
} }
@ -338,47 +357,34 @@ uint32_t XWriteFile(FileHandle* hFile, const void* lpBuffer, uint32_t nNumberOfB
return TRUE; return TRUE;
} }
static void fixSlashes(char *path) const char* FileSystem::TransformPath(const std::string_view& path)
{ {
while (*path != 0) thread_local std::string builtPath;
{ builtPath.clear();
if (*path == '\\')
{
*path = '/';
}
path++; size_t index = path.find(":\\");
} if (index != std::string::npos)
}
const char* FileSystem::TransformPath(const char* path)
{
thread_local char builtPath[2048]{};
const char* relativePath = strstr(path, ":\\");
if (relativePath != nullptr)
{ {
// rooted folder, handle direction // rooted folder, handle direction
const std::string_view root = std::string_view{ path, path + (relativePath - path) }; const std::string_view root = path.substr(0, index);
const auto newRoot = XamGetRootPath(root); const auto newRoot = XamGetRootPath(root);
if (!newRoot.empty()) if (!newRoot.empty())
{ {
strncpy(builtPath, newRoot.data(), newRoot.size()); builtPath += newRoot;
builtPath[newRoot.size()] = '\\'; builtPath += '/';
strcpy(builtPath + newRoot.size() + 1, relativePath + 2);
}
else
{
strncpy(builtPath, relativePath + 2, sizeof(builtPath));
}
}
else
{
strncpy(builtPath, path, sizeof(builtPath));
} }
fixSlashes(builtPath); builtPath += path.substr(index + 2);
return builtPath; }
else
{
builtPath += path;
}
std::replace(builtPath.begin(), builtPath.end(), '\\', '/');
return builtPath.c_str();
} }
SWA_API const char* XExpandFilePathA(const char* path) SWA_API const char* XExpandFilePathA(const char* path)

View file

@ -2,5 +2,5 @@
struct FileSystem struct FileSystem
{ {
static const char* TransformPath(const char* path); static const char* TransformPath(const std::string_view& path);
}; };

View file

@ -45,6 +45,11 @@ std::filesystem::path ModLoader::RedirectPath(std::string_view path)
return pathCache.emplace(hash, std::filesystem::path{}).first->second; return pathCache.emplace(hash, std::filesystem::path{}).first->second;
} }
std::vector<std::filesystem::path>* ModLoader::GetIncludeDirectories(size_t modIndex)
{
return modIndex < g_mods.size() ? &g_mods[modIndex].includeDirs : nullptr;
}
void ModLoader::Init() void ModLoader::Init()
{ {
IniFile configIni; IniFile configIni;
@ -78,7 +83,7 @@ void ModLoader::Init()
auto modDirectoryPath = modIniFilePath.parent_path(); auto modDirectoryPath = modIniFilePath.parent_path();
auto& mod = g_mods.emplace_back(); Mod mod;
if (modIni.contains("Details") || modIni.contains("Filesystem")) // UMM if (modIni.contains("Details") || modIni.contains("Filesystem")) // UMM
{ {
@ -97,5 +102,8 @@ void ModLoader::Init()
mod.includeDirs.emplace_back(modDirectoryPath / std::u8string_view((const char8_t*)includeDirU8.c_str())); mod.includeDirs.emplace_back(modDirectoryPath / std::u8string_view((const char8_t*)includeDirU8.c_str()));
} }
} }
if (!mod.includeDirs.empty())
g_mods.emplace_back(std::move(mod));
} }
} }

View file

@ -4,5 +4,7 @@ struct ModLoader
{ {
static std::filesystem::path RedirectPath(std::string_view path); static std::filesystem::path RedirectPath(std::string_view path);
static std::vector<std::filesystem::path>* GetIncludeDirectories(size_t modIndex);
static void Init(); static void Init();
}; };