diff options
Diffstat (limited to 'Source/Core/DiscIO/FileSystemGCWii.cpp')
| -rw-r--r-- | Source/Core/DiscIO/FileSystemGCWii.cpp | 112 |
1 files changed, 60 insertions, 52 deletions
diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index 32f93f5eb6..fc0e40f055 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -22,8 +22,8 @@ namespace DiscIO { -FileInfoGCWii::FileInfoGCWii(u64 name_offset, u64 offset, u64 file_size) - : m_NameOffset(name_offset), m_Offset(offset), m_FileSize(file_size) +FileInfoGCWii::FileInfoGCWii(u64 name_offset, u64 offset, u64 file_size, std::string name) + : m_NameOffset(name_offset), m_Offset(offset), m_FileSize(file_size), m_Name(name) { } @@ -55,23 +55,64 @@ u64 FileSystemGCWii::GetFileSize(const std::string& _rFullPath) return 0; } -std::string FileSystemGCWii::GetFileName(u64 _Address) +std::string FileSystemGCWii::GetPath(u64 _Address) { if (!m_Initialized) InitFileSystem(); - for (auto& fileInfo : m_FileInfoVector) + for (size_t i = 0; i < m_FileInfoVector.size(); ++i) { - if ((fileInfo.GetOffset() <= _Address) && - ((fileInfo.GetOffset() + fileInfo.GetSize()) > _Address)) + const FileInfoGCWii& file_info = m_FileInfoVector[i]; + if ((file_info.GetOffset() <= _Address) && + ((file_info.GetOffset() + file_info.GetSize()) > _Address)) { - return fileInfo.m_FullPath; + return GetPathFromFSTOffset(i); } } return ""; } +std::string FileSystemGCWii::GetPathFromFSTOffset(size_t file_info_offset) +{ + if (!m_Initialized) + InitFileSystem(); + + // Root entry doesn't have a name + if (file_info_offset == 0) + return ""; + + const FileInfoGCWii& file_info = m_FileInfoVector[file_info_offset]; + if (file_info.IsDirectory()) + { + // The offset of the parent directory is stored in the current directory. + + if (file_info.GetOffset() >= file_info_offset) + { + // The offset of the parent directory is supposed to be smaller than + // the current offset. If an FST is malformed and breaks that rule, + // there's a risk that parent directory pointers form a loop. + // To avoid stack overflows, this method returns. + ERROR_LOG(DISCIO, "Invalid parent offset in file system"); + return ""; + } + return GetPathFromFSTOffset(file_info.GetOffset()) + file_info.GetName() + "/"; + } + else + { + // The parent directory can be found by searching backwards + // for a directory that contains this file. + + size_t parent_offset = file_info_offset - 1; + while (!(m_FileInfoVector[parent_offset].IsDirectory() && + m_FileInfoVector[parent_offset].GetSize() > file_info_offset)) + { + parent_offset--; + } + return GetPathFromFSTOffset(parent_offset) + file_info.GetName(); + } +} + u64 FileSystemGCWii::ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, u64 _OffsetInFile) { @@ -248,10 +289,10 @@ const FileInfoGCWii* FileSystemGCWii::FindFileInfo(const std::string& _rFullPath if (!m_Initialized) InitFileSystem(); - for (auto& fileInfo : m_FileInfoVector) + for (size_t i = 0; i < m_FileInfoVector.size(); ++i) { - if (!strcasecmp(fileInfo.m_FullPath.c_str(), _rFullPath.c_str())) - return &fileInfo; + if (!strcasecmp(GetPathFromFSTOffset(i).c_str(), _rFullPath.c_str())) + return &m_FileInfoVector[i]; } return nullptr; @@ -290,7 +331,7 @@ void FileSystemGCWii::InitFileSystem() if (!root_name_offset || !root_offset || !root_size) return; FileInfoGCWii root(*root_name_offset, static_cast<u64>(*root_offset) << m_offset_shift, - *root_size); + *root_size, ""); if (!root.IsDirectory()) return; @@ -309,53 +350,20 @@ void FileSystemGCWii::InitFileSystem() if (m_FileInfoVector.size()) PanicAlert("Wtf?"); - u64 NameTableOffset = FSTOffset; + u64 NameTableOffset = FSTOffset + (root.GetSize() * 0xC); m_FileInfoVector.reserve((size_t)root.GetSize()); for (u32 i = 0; i < root.GetSize(); i++) { const u64 read_offset = FSTOffset + (i * 0xC); - const std::optional<u32> name_offset = m_rVolume->ReadSwapped<u32>(read_offset, m_partition); - const std::optional<u32> offset = m_rVolume->ReadSwapped<u32>(read_offset + 0x4, m_partition); - const std::optional<u32> size = m_rVolume->ReadSwapped<u32>(read_offset + 0x8, m_partition); - m_FileInfoVector.emplace_back(name_offset.value_or(0), - static_cast<u64>(offset.value_or(0)) << m_offset_shift, - size.value_or(0)); - NameTableOffset += 0xC; + const u32 name_offset = m_rVolume->ReadSwapped<u32>(read_offset, m_partition).value_or(0); + const u32 offset = m_rVolume->ReadSwapped<u32>(read_offset + 0x4, m_partition).value_or(0); + const u32 size = m_rVolume->ReadSwapped<u32>(read_offset + 0x8, m_partition).value_or(0); + const std::string name = GetStringFromOffset(NameTableOffset + (name_offset & 0xFFFFFF)); + m_FileInfoVector.emplace_back( + name_offset, static_cast<u64>(offset) << (m_offset_shift * !(name_offset & 0xFF000000)), + size, name); } - - BuildFilenames(1, m_FileInfoVector.size(), "", NameTableOffset); -} - -size_t FileSystemGCWii::BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex, - const std::string& _szDirectory, u64 _NameTableOffset) -{ - size_t CurrentIndex = _FirstIndex; - - while (CurrentIndex < _LastIndex) - { - FileInfoGCWii& rFileInfo = m_FileInfoVector[CurrentIndex]; - u64 const uOffset = _NameTableOffset + (rFileInfo.m_NameOffset & 0xFFFFFF); - std::string const offset_str{GetStringFromOffset(uOffset)}; - bool const is_dir = rFileInfo.IsDirectory(); - rFileInfo.m_FullPath.reserve(_szDirectory.size() + offset_str.size()); - - rFileInfo.m_FullPath.append(_szDirectory.data(), _szDirectory.size()) - .append(offset_str.data(), offset_str.size()) - .append("/", size_t(is_dir)); - - if (!is_dir) - { - ++CurrentIndex; - continue; - } - - // check next index - CurrentIndex = BuildFilenames(CurrentIndex + 1, (size_t)rFileInfo.GetSize(), - rFileInfo.m_FullPath, _NameTableOffset); - } - - return CurrentIndex; } } // namespace |
