diff options
| author | Leo Lam <leolino.lam@gmail.com> | 2017-06-15 21:24:42 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-06-15 21:24:42 +0200 |
| commit | 09c0a3caaff4961dc33df35cbf6baf09b94d56ec (patch) | |
| tree | 24bc5a9610afab5b95dd5930d8266c9288428510 /Source/Core/DiscIO/FileSystemGCWii.cpp | |
| parent | 335f54cac6ed15148fb7f959ccee9d63b583ea32 (diff) | |
| parent | 583406d900bd0ca9111135c6a9e526aed67e8322 (diff) | |
Merge pull request #2820 from JosJuice/filesystem
Filesystem redesign and performance improvements
Diffstat (limited to 'Source/Core/DiscIO/FileSystemGCWii.cpp')
| -rw-r--r-- | Source/Core/DiscIO/FileSystemGCWii.cpp | 527 |
1 files changed, 327 insertions, 200 deletions
diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index b809047679..09a171677d 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -6,6 +6,8 @@ #include <cinttypes> #include <cstddef> #include <cstring> +#include <map> +#include <memory> #include <optional> #include <string> #include <vector> @@ -22,114 +24,372 @@ namespace DiscIO { -FileSystemGCWii::FileSystemGCWii(const Volume* _rVolume, const Partition& partition) - : FileSystem(_rVolume, partition), m_Initialized(false), m_Valid(false), m_offset_shift(0) +constexpr u32 FST_ENTRY_SIZE = 4 * 3; // An FST entry consists of three 32-bit integers + +// Set everything manually. +FileInfoGCWii::FileInfoGCWii(const u8* fst, u8 offset_shift, u32 index, u32 total_file_infos) + : m_fst(fst), m_offset_shift(offset_shift), m_index(index), m_total_file_infos(total_file_infos) { - m_Valid = DetectFileSystem(); } -FileSystemGCWii::~FileSystemGCWii() +// For the root object only. +// m_fst and m_index must be correctly set before GetSize() is called! +FileInfoGCWii::FileInfoGCWii(const u8* fst, u8 offset_shift) + : m_fst(fst), m_offset_shift(offset_shift), m_index(0), m_total_file_infos(GetSize()) { - m_FileInfoVector.clear(); } -u64 FileSystemGCWii::GetFileSize(const std::string& _rFullPath) +// Copy data that is common to the whole file system. +FileInfoGCWii::FileInfoGCWii(const FileInfoGCWii& file_info, u32 index) + : FileInfoGCWii(file_info.m_fst, file_info.m_offset_shift, index, file_info.m_total_file_infos) { - if (!m_Initialized) - InitFileSystem(); +} - const FileInfo* pFileInfo = FindFileInfo(_rFullPath); +FileInfoGCWii::~FileInfoGCWii() = default; - if (pFileInfo != nullptr && !pFileInfo->IsDirectory()) - return pFileInfo->m_FileSize; +uintptr_t FileInfoGCWii::GetAddress() const +{ + return reinterpret_cast<uintptr_t>(m_fst + FST_ENTRY_SIZE * m_index); +} - return 0; +u32 FileInfoGCWii::GetNextIndex() const +{ + return IsDirectory() ? GetSize() : m_index + 1; } -std::string FileSystemGCWii::GetFileName(u64 _Address) +FileInfo& FileInfoGCWii::operator++() { - if (!m_Initialized) - InitFileSystem(); + m_index = GetNextIndex(); + return *this; +} - for (auto& fileInfo : m_FileInfoVector) +std::unique_ptr<FileInfo> FileInfoGCWii::clone() const +{ + return std::make_unique<FileInfoGCWii>(*this); +} + +FileInfo::const_iterator FileInfoGCWii::begin() const +{ + return const_iterator(std::make_unique<FileInfoGCWii>(*this, m_index + 1)); +} + +FileInfo::const_iterator FileInfoGCWii::end() const +{ + return const_iterator(std::make_unique<FileInfoGCWii>(*this, GetNextIndex())); +} + +u32 FileInfoGCWii::Get(EntryProperty entry_property) const +{ + return Common::swap32(m_fst + FST_ENTRY_SIZE * m_index + + sizeof(u32) * static_cast<int>(entry_property)); +} + +u32 FileInfoGCWii::GetSize() const +{ + return Get(EntryProperty::FILE_SIZE); +} + +u64 FileInfoGCWii::GetOffset() const +{ + return static_cast<u64>(Get(EntryProperty::FILE_OFFSET)) << m_offset_shift; +} + +bool FileInfoGCWii::IsDirectory() const +{ + return (Get(EntryProperty::NAME_OFFSET) & 0xFF000000) != 0; +} + +u32 FileInfoGCWii::GetTotalChildren() const +{ + return Get(EntryProperty::FILE_SIZE) - (m_index + 1); +} + +u64 FileInfoGCWii::GetNameOffset() const +{ + return static_cast<u64>(FST_ENTRY_SIZE) * m_total_file_infos + + (Get(EntryProperty::NAME_OFFSET) & 0xFFFFFF); +} + +std::string FileInfoGCWii::GetName() const +{ + // TODO: Should we really always use SHIFT-JIS? + // Some names in Pikmin (NTSC-U) don't make sense without it, but is it correct? + return SHIFTJISToUTF8(reinterpret_cast<const char*>(m_fst + GetNameOffset())); +} + +std::string FileInfoGCWii::GetPath() const +{ + // The root entry doesn't have a name + if (m_index == 0) + return ""; + + if (IsDirectory()) + { + u32 parent_directory_index = Get(EntryProperty::FILE_OFFSET); + return FileInfoGCWii(*this, parent_directory_index).GetPath() + GetName() + "/"; + } + else { - if ((fileInfo.m_Offset <= _Address) && ((fileInfo.m_Offset + fileInfo.m_FileSize) > _Address)) + // The parent directory can be found by searching backwards + // for a directory that contains this file. The search cannot fail, + // because the root directory at index 0 contains all files. + FileInfoGCWii potential_parent(*this, m_index - 1); + while (!(potential_parent.IsDirectory() && + potential_parent.Get(EntryProperty::FILE_SIZE) > m_index)) { - return fileInfo.m_FullPath; + potential_parent = FileInfoGCWii(*this, potential_parent.m_index - 1); } + return potential_parent.GetPath() + GetName(); + } +} + +bool FileInfoGCWii::IsValid(u64 fst_size, const FileInfoGCWii& parent_directory) const +{ + if (GetNameOffset() >= fst_size) + { + ERROR_LOG(DISCIO, "Impossibly large name offset in file system"); + return false; } - return ""; + if (IsDirectory()) + { + if (Get(EntryProperty::FILE_OFFSET) != parent_directory.m_index) + { + ERROR_LOG(DISCIO, "Incorrect parent offset in file system"); + return false; + } + + u32 size = Get(EntryProperty::FILE_SIZE); + + if (size <= m_index) + { + ERROR_LOG(DISCIO, "Impossibly small directory size in file system"); + return false; + } + + if (size > parent_directory.Get(EntryProperty::FILE_SIZE)) + { + ERROR_LOG(DISCIO, "Impossibly large directory size in file system"); + return false; + } + + for (const FileInfo& child : *this) + { + if (!static_cast<const FileInfoGCWii&>(child).IsValid(fst_size, *this)) + return false; + } + } + + return true; } -u64 FileSystemGCWii::ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize, - u64 _OffsetInFile) +FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partition) + : FileSystem(volume, partition), m_valid(false), m_offset_shift(0), m_root(nullptr, 0, 0, 0) { - if (!m_Initialized) - InitFileSystem(); + // Check if this is a GameCube or Wii disc + if (m_volume->ReadSwapped<u32>(0x18, m_partition) == u32(0x5D1C9EA3)) + m_offset_shift = 2; // Wii file system + else if (m_volume->ReadSwapped<u32>(0x1c, m_partition) == u32(0xC2339F3D)) + m_offset_shift = 0; // GameCube file system + else + return; + + const std::optional<u32> fst_offset_unshifted = m_volume->ReadSwapped<u32>(0x424, m_partition); + const std::optional<u32> fst_size_unshifted = m_volume->ReadSwapped<u32>(0x428, m_partition); + if (!fst_offset_unshifted || !fst_size_unshifted) + return; + const u64 fst_offset = static_cast<u64>(*fst_offset_unshifted) << m_offset_shift; + const u64 fst_size = static_cast<u64>(*fst_size_unshifted) << m_offset_shift; + if (fst_size < FST_ENTRY_SIZE) + { + ERROR_LOG(DISCIO, "File system is too small"); + return; + } + + // 128 MiB is more than the total amount of RAM in a Wii. + // No file system should use anywhere near that much. + static const u32 ARBITRARY_FILE_SYSTEM_SIZE_LIMIT = 128 * 1024 * 1024; + if (fst_size > ARBITRARY_FILE_SYSTEM_SIZE_LIMIT) + { + // Without this check, Dolphin can crash by trying to allocate too much + // memory when loading a disc image with an incorrect FST size. - const FileInfo* pFileInfo = FindFileInfo(_rFullPath); - if (pFileInfo == nullptr) + ERROR_LOG(DISCIO, "File system is abnormally large! Aborting loading"); + return; + } + + // Read the whole FST + m_file_system_table.resize(fst_size); + if (!m_volume->Read(fst_offset, fst_size, m_file_system_table.data(), m_partition)) + { + ERROR_LOG(DISCIO, "Couldn't read file system table"); + return; + } + + // Create the root object + m_root = FileInfoGCWii(m_file_system_table.data(), m_offset_shift); + if (!m_root.IsDirectory()) + { + ERROR_LOG(DISCIO, "File system root is not a directory"); + return; + } + + if (FST_ENTRY_SIZE * m_root.GetSize() > fst_size) + { + ERROR_LOG(DISCIO, "File system has too many entries for its size"); + return; + } + + // If the FST's final byte isn't 0, CFileInfoGCWii::GetName() can read past the end + if (m_file_system_table[fst_size - 1] != 0) + { + ERROR_LOG(DISCIO, "File system does not end with a null byte"); + return; + } + + m_valid = m_root.IsValid(fst_size, m_root); +} + +FileSystemGCWii::~FileSystemGCWii() = default; + +const FileInfo& FileSystemGCWii::GetRoot() const +{ + return m_root; +} + +std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(const std::string& path) const +{ + if (!IsValid()) + return nullptr; + + return FindFileInfo(path, m_root); +} + +std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(const std::string& path, + const FileInfo& file_info) const +{ + // Given a path like "directory1/directory2/fileA.bin", this function will + // find directory1 and then call itself to search for "directory2/fileA.bin". + + if (path.empty() || path == "/") + return file_info.clone(); + + // It's only possible to search in directories. Searching in a file is an error + if (!file_info.IsDirectory()) + return nullptr; + + size_t first_dir_separator = path.find('/'); + const std::string searching_for = path.substr(0, first_dir_separator); + const std::string rest_of_path = + (first_dir_separator != std::string::npos) ? path.substr(first_dir_separator + 1) : ""; + + for (const FileInfo& child : file_info) + { + if (child.GetName() == searching_for) + { + // A match is found. The rest of the path is passed on to finish the search. + std::unique_ptr<FileInfo> result = FindFileInfo(rest_of_path, child); + + // If the search wasn't successful, the loop continues, just in case there's a second + // file info that matches searching_for (which probably won't happen in practice) + if (result) + return result; + } + } + + return nullptr; +} + +std::unique_ptr<FileInfo> FileSystemGCWii::FindFileInfo(u64 disc_offset) const +{ + if (!IsValid()) + return nullptr; + + // Build a cache (unless there already is one) + if (m_offset_file_info_cache.empty()) + { + u32 fst_entries = m_root.GetSize(); + for (u32 i = 0; i < fst_entries; i++) + { + FileInfoGCWii file_info(m_root, i); + if (!file_info.IsDirectory()) + m_offset_file_info_cache.emplace(file_info.GetOffset() + file_info.GetSize(), i); + } + } + + // Get the first file that ends after disc_offset + const auto it = m_offset_file_info_cache.upper_bound(disc_offset); + if (it == m_offset_file_info_cache.end()) + return nullptr; + std::unique_ptr<FileInfo> result(std::make_unique<FileInfoGCWii>(m_root, it->second)); + + // If the file's start isn't after disc_offset, success + if (result->GetOffset() <= disc_offset) + return result; + + return nullptr; +} + +u64 FileSystemGCWii::ReadFile(const FileInfo* file_info, u8* buffer, u64 max_buffer_size, + u64 offset_in_file) const +{ + if (!file_info || file_info->IsDirectory()) return 0; - if (_OffsetInFile >= pFileInfo->m_FileSize) + if (offset_in_file >= file_info->GetSize()) return 0; - u64 read_length = std::min(_MaxBufferSize, pFileInfo->m_FileSize - _OffsetInFile); + u64 read_length = std::min(max_buffer_size, file_info->GetSize() - offset_in_file); DEBUG_LOG(DISCIO, "Reading %" PRIx64 " bytes at %" PRIx64 " from file %s. Offset: %" PRIx64 - " Size: %" PRIx64, - read_length, _OffsetInFile, _rFullPath.c_str(), pFileInfo->m_Offset, - pFileInfo->m_FileSize); + " Size: %" PRIx32, + read_length, offset_in_file, file_info->GetPath().c_str(), file_info->GetOffset(), + file_info->GetSize()); - m_rVolume->Read(pFileInfo->m_Offset + _OffsetInFile, read_length, _pBuffer, m_partition); + m_volume->Read(file_info->GetOffset() + offset_in_file, read_length, buffer, m_partition); return read_length; } -bool FileSystemGCWii::ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) +bool FileSystemGCWii::ExportFile(const FileInfo* file_info, + const std::string& export_filename) const { - if (!m_Initialized) - InitFileSystem(); - - const FileInfo* pFileInfo = FindFileInfo(_rFullPath); - - if (!pFileInfo) + if (!file_info || file_info->IsDirectory()) return false; - u64 remainingSize = pFileInfo->m_FileSize; - u64 fileOffset = pFileInfo->m_Offset; + u64 remaining_size = file_info->GetSize(); + u64 file_offset = file_info->GetOffset(); - File::IOFile f(_rExportFilename, "wb"); + File::IOFile f(export_filename, "wb"); if (!f) return false; bool result = true; - while (remainingSize) + while (remaining_size) { // Limit read size to 128 MB - size_t readSize = (size_t)std::min(remainingSize, (u64)0x08000000); + size_t read_size = (size_t)std::min(remaining_size, (u64)0x08000000); - std::vector<u8> buffer(readSize); + std::vector<u8> buffer(read_size); - result = m_rVolume->Read(fileOffset, readSize, &buffer[0], m_partition); + result = m_volume->Read(file_offset, read_size, &buffer[0], m_partition); if (!result) break; - f.WriteBytes(&buffer[0], readSize); + f.WriteBytes(&buffer[0], read_size); - remainingSize -= readSize; - fileOffset += readSize; + remaining_size -= read_size; + file_offset += read_size; } return result; } -bool FileSystemGCWii::ExportApploader(const std::string& _rExportFolder) const +bool FileSystemGCWii::ExportApploader(const std::string& export_folder) const { - std::optional<u32> apploader_size = m_rVolume->ReadSwapped<u32>(0x2440 + 0x14, m_partition); - const std::optional<u32> trailer_size = m_rVolume->ReadSwapped<u32>(0x2440 + 0x18, m_partition); + std::optional<u32> apploader_size = m_volume->ReadSwapped<u32>(0x2440 + 0x14, m_partition); + const std::optional<u32> trailer_size = m_volume->ReadSwapped<u32>(0x2440 + 0x18, m_partition); constexpr u32 header_size = 0x20; if (!apploader_size || !trailer_size) return false; @@ -137,14 +397,14 @@ bool FileSystemGCWii::ExportApploader(const std::string& _rExportFolder) const DEBUG_LOG(DISCIO, "Apploader size -> %x", *apploader_size); std::vector<u8> buffer(*apploader_size); - if (m_rVolume->Read(0x2440, *apploader_size, buffer.data(), m_partition)) + if (m_volume->Read(0x2440, *apploader_size, buffer.data(), m_partition)) { - std::string exportName(_rExportFolder + "/apploader.img"); + std::string export_name(export_folder + "/apploader.img"); - File::IOFile AppFile(exportName, "wb"); - if (AppFile) + File::IOFile apploader_file(export_name, "wb"); + if (apploader_file) { - AppFile.WriteBytes(buffer.data(), *apploader_size); + apploader_file.WriteBytes(buffer.data(), *apploader_size); return true; } } @@ -154,7 +414,7 @@ bool FileSystemGCWii::ExportApploader(const std::string& _rExportFolder) const std::optional<u64> FileSystemGCWii::GetBootDOLOffset() const { - std::optional<u32> offset = m_rVolume->ReadSwapped<u32>(0x420, m_partition); + std::optional<u32> offset = m_volume->ReadSwapped<u32>(0x420, m_partition); return offset ? static_cast<u64>(*offset) << m_offset_shift : std::optional<u64>(); } @@ -166,9 +426,9 @@ std::optional<u32> FileSystemGCWii::GetBootDOLSize(u64 dol_offset) const for (u8 i = 0; i < 7; i++) { const std::optional<u32> offset = - m_rVolume->ReadSwapped<u32>(dol_offset + 0x00 + i * 4, m_partition); + m_volume->ReadSwapped<u32>(dol_offset + 0x00 + i * 4, m_partition); const std::optional<u32> size = - m_rVolume->ReadSwapped<u32>(dol_offset + 0x90 + i * 4, m_partition); + m_volume->ReadSwapped<u32>(dol_offset + 0x90 + i * 4, m_partition); if (!offset || !size) return {}; dol_size = std::max(*offset + *size, dol_size); @@ -178,9 +438,9 @@ std::optional<u32> FileSystemGCWii::GetBootDOLSize(u64 dol_offset) const for (u8 i = 0; i < 11; i++) { const std::optional<u32> offset = - m_rVolume->ReadSwapped<u32>(dol_offset + 0x1c + i * 4, m_partition); + m_volume->ReadSwapped<u32>(dol_offset + 0x1c + i * 4, m_partition); const std::optional<u32> size = - m_rVolume->ReadSwapped<u32>(dol_offset + 0xac + i * 4, m_partition); + m_volume->ReadSwapped<u32>(dol_offset + 0xac + i * 4, m_partition); if (!offset || !size) return {}; dol_size = std::max(*offset + *size, dol_size); @@ -189,7 +449,7 @@ std::optional<u32> FileSystemGCWii::GetBootDOLSize(u64 dol_offset) const return dol_size; } -bool FileSystemGCWii::ExportDOL(const std::string& _rExportFolder) const +bool FileSystemGCWii::ExportDOL(const std::string& export_folder) const { std::optional<u64> dol_offset = GetBootDOLOffset(); if (!dol_offset) @@ -199,14 +459,14 @@ bool FileSystemGCWii::ExportDOL(const std::string& _rExportFolder) const return false; std::vector<u8> buffer(*dol_size); - if (m_rVolume->Read(*dol_offset, *dol_size, &buffer[0], m_partition)) + if (m_volume->Read(*dol_offset, *dol_size, buffer.data(), m_partition)) { - std::string exportName(_rExportFolder + "/boot.dol"); + std::string export_name(export_folder + "/boot.dol"); - File::IOFile DolFile(exportName, "wb"); - if (DolFile) + File::IOFile dol_file(export_name, "wb"); + if (dol_file) { - DolFile.WriteBytes(&buffer[0], *dol_size); + dol_file.WriteBytes(&buffer[0], *dol_size); return true; } } @@ -214,137 +474,4 @@ bool FileSystemGCWii::ExportDOL(const std::string& _rExportFolder) const return false; } -std::string FileSystemGCWii::GetStringFromOffset(u64 _Offset) const -{ - std::string data(255, 0x00); - m_rVolume->Read(_Offset, data.size(), (u8*)&data[0], m_partition); - data.erase(std::find(data.begin(), data.end(), 0x00), data.end()); - - // TODO: Should we really always use SHIFT-JIS? - // It makes some filenames in Pikmin (NTSC-U) sane, but is it correct? - return SHIFTJISToUTF8(data); -} - -const std::vector<FileInfo>& FileSystemGCWii::GetFileList() -{ - if (!m_Initialized) - InitFileSystem(); - - return m_FileInfoVector; -} - -const FileInfo* FileSystemGCWii::FindFileInfo(const std::string& _rFullPath) -{ - if (!m_Initialized) - InitFileSystem(); - - for (auto& fileInfo : m_FileInfoVector) - { - if (!strcasecmp(fileInfo.m_FullPath.c_str(), _rFullPath.c_str())) - return &fileInfo; - } - - return nullptr; -} - -bool FileSystemGCWii::DetectFileSystem() -{ - if (m_rVolume->ReadSwapped<u32>(0x18, m_partition) == u32(0x5D1C9EA3)) - { - m_offset_shift = 2; // Wii file system - return true; - } - else if (m_rVolume->ReadSwapped<u32>(0x1c, m_partition) == u32(0xC2339F3D)) - { - m_offset_shift = 0; // GameCube file system - return true; - } - - return false; -} - -void FileSystemGCWii::InitFileSystem() -{ - m_Initialized = true; - - // read the whole FST - const std::optional<u32> fst_offset_unshifted = m_rVolume->ReadSwapped<u32>(0x424, m_partition); - if (!fst_offset_unshifted) - return; - const u64 FSTOffset = static_cast<u64>(*fst_offset_unshifted) << m_offset_shift; - - // read all fileinfos - const std::optional<u32> root_name_offset = m_rVolume->ReadSwapped<u32>(FSTOffset, m_partition); - const std::optional<u32> root_offset = m_rVolume->ReadSwapped<u32>(FSTOffset + 0x4, m_partition); - const std::optional<u32> root_size = m_rVolume->ReadSwapped<u32>(FSTOffset + 0x8, m_partition); - if (!root_name_offset || !root_offset || !root_size) - return; - FileInfo root = {*root_name_offset, static_cast<u64>(*root_offset) << m_offset_shift, *root_size}; - - if (!root.IsDirectory()) - return; - - // 12 bytes (the size of a file entry) times 10 * 1024 * 1024 is 120 MiB, - // more than total RAM in a Wii. No file system should use anywhere near that much. - static const u32 ARBITRARY_FILE_SYSTEM_SIZE_LIMIT = 10 * 1024 * 1024; - if (root.m_FileSize > ARBITRARY_FILE_SYSTEM_SIZE_LIMIT) - { - // Without this check, Dolphin can crash by trying to allocate too much - // memory when loading the file systems of certain malformed disc images. - - ERROR_LOG(DISCIO, "File system is abnormally large! Aborting loading"); - return; - } - - if (m_FileInfoVector.size()) - PanicAlert("Wtf?"); - u64 NameTableOffset = FSTOffset; - - m_FileInfoVector.reserve((size_t)root.m_FileSize); - for (u32 i = 0; i < root.m_FileSize; 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; - } - - 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) - { - FileInfo& 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.m_FileSize, - rFileInfo.m_FullPath, _NameTableOffset); - } - - return CurrentIndex; -} - } // namespace |
