diff --git a/src/xenia/base/filesystem.h b/src/xenia/base/filesystem.h index b4b0b23bf..91304d273 100644 --- a/src/xenia/base/filesystem.h +++ b/src/xenia/base/filesystem.h @@ -22,8 +22,8 @@ namespace filesystem { bool PathExists(const std::wstring& path); bool CreateFolder(const std::wstring& path); - bool DeleteFolder(const std::wstring& path); +bool IsFolder(const std::wstring& path); struct FileInfo { enum class Type { diff --git a/src/xenia/base/filesystem_win.cc b/src/xenia/base/filesystem_win.cc index 05e99fe8d..ecf694144 100644 --- a/src/xenia/base/filesystem_win.cc +++ b/src/xenia/base/filesystem_win.cc @@ -43,6 +43,12 @@ bool DeleteFolder(const std::wstring& path) { return SHFileOperation(&op) == 0; } +bool IsFolder(const std::wstring& path) { + DWORD attrib = GetFileAttributes(path.c_str()); + return attrib != INVALID_FILE_ATTRIBUTES && + (attrib & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY; +} + #define COMBINE_TIME(t) (((uint64_t)t.dwHighDateTime << 32) | t.dwLowDateTime) std::vector ListFiles(const std::wstring& path) { diff --git a/src/xenia/vfs/devices/stfs_container_device.cc b/src/xenia/vfs/devices/stfs_container_device.cc index 3c6cd3f8b..5bfdb1ac0 100644 --- a/src/xenia/vfs/devices/stfs_container_device.cc +++ b/src/xenia/vfs/devices/stfs_container_device.cc @@ -32,6 +32,50 @@ STFSContainerDevice::STFSContainerDevice(const std::string& mount_path, STFSContainerDevice::~STFSContainerDevice() = default; bool STFSContainerDevice::Initialize() { + if (filesystem::IsFolder(local_path_)) { + // Was given a folder. Try to find the file in + // local_path\TITLE_ID\000D0000\HASH_OF_42_CHARS + // We take care to not die if there are additional files around. + bool found_alternative = false; + auto files = filesystem::ListFiles(local_path_); + for (auto& file : files) { + if (file.type != filesystem::FileInfo::Type::kDirectory || + file.name.size() != 8) { + continue; + } + auto child_path = xe::join_paths(local_path_, file.name); + auto child_files = filesystem::ListFiles(child_path); + for (auto& child_file : child_files) { + if (child_file.type != filesystem::FileInfo::Type::kDirectory || + child_file.name != L"000D0000") { + continue; + } + auto stfs_path = xe::join_paths(child_path, child_file.name); + auto stfs_files = filesystem::ListFiles(stfs_path); + for (auto& stfs_file : stfs_files) { + if (stfs_file.type != filesystem::FileInfo::Type::kFile || + stfs_file.name.size() != 42) { + continue; + } + // Probably it! + local_path_ = xe::join_paths(stfs_path, stfs_file.name); + found_alternative = true; + break; + } + if (found_alternative) { + break; + } + } + if (found_alternative) { + break; + } + } + } + if (!filesystem::PathExists(local_path_)) { + XELOGE("STFS container does not exist"); + return false; + } + mmap_ = MappedMemory::Open(local_path_, MappedMemory::Mode::kRead); if (!mmap_) { XELOGE("STFS container could not be mapped");