Filesystem: Replace file info's full path with name
Some callers (i.e. ISOProperties) don't want the full path, so giving them it is unnecessary. Those that do want it can use GetPathFromFSTOffset. Not storing full paths everywhere also saves a small bit of RAM and is necessary for a later commit. The code isn't especially pretty right now (callers need to use FST offsets...) but it'll become better later.
This commit is contained in:
parent
5021b4a567
commit
07d3a39aeb
|
@ -88,28 +88,27 @@ void Log(u64 offset, const DiscIO::Partition& partition)
|
|||
if (!s_filesystem)
|
||||
return;
|
||||
|
||||
const std::string filename = s_filesystem->GetFileName(offset);
|
||||
const std::string path = s_filesystem->GetPath(offset);
|
||||
|
||||
// Do nothing if no file was found at that offset
|
||||
if (filename.empty())
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
// Do nothing if we found the same file again
|
||||
if (s_previous_file == filename)
|
||||
if (s_previous_file == path)
|
||||
return;
|
||||
|
||||
const u64 size = s_filesystem->GetFileSize(filename);
|
||||
const u64 size = s_filesystem->GetFileSize(path);
|
||||
const std::string size_string = ThousandSeparate(size / 1000, 7);
|
||||
|
||||
const std::string log_string =
|
||||
StringFromFormat("%s kB %s", size_string.c_str(), filename.c_str());
|
||||
if (IsSoundFile(filename))
|
||||
const std::string log_string = StringFromFormat("%s kB %s", size_string.c_str(), path.c_str());
|
||||
if (IsSoundFile(path))
|
||||
INFO_LOG(FILEMON, "%s", log_string.c_str());
|
||||
else
|
||||
WARN_LOG(FILEMON, "%s", log_string.c_str());
|
||||
|
||||
// Update the last accessed file
|
||||
s_previous_file = filename;
|
||||
s_previous_file = path;
|
||||
}
|
||||
|
||||
} // namespace FileMonitor
|
||||
|
|
|
@ -221,9 +221,12 @@ bool DiscScrubber::ParsePartitionData(const Partition& partition, PartitionHeade
|
|||
MarkAsUsedE(partition_data_offset, header->fst_offset, header->fst_size);
|
||||
|
||||
// Go through the filesystem and mark entries as used
|
||||
for (const FileInfoGCWii& file : filesystem->GetFileList())
|
||||
auto& file_list = filesystem->GetFileList();
|
||||
for (size_t i = 0; i < file_list.size(); ++i)
|
||||
{
|
||||
DEBUG_LOG(DISCIO, "%s", file.m_FullPath.empty() ? "/" : file.m_FullPath.c_str());
|
||||
const std::string path = filesystem->GetPathFromFSTOffset(i);
|
||||
DEBUG_LOG(DISCIO, "%s", path.empty() ? "/" : path.c_str());
|
||||
auto& file = file_list[i];
|
||||
if (!file.IsDirectory())
|
||||
MarkAsUsedE(partition_data_offset, file.GetOffset(), file.GetSize());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -20,14 +20,15 @@ struct Partition;
|
|||
class FileInfoGCWii : public FileInfo
|
||||
{
|
||||
public:
|
||||
FileInfoGCWii(u64 name_offset, u64 offset, u64 file_size);
|
||||
FileInfoGCWii(u64 name_offset, u64 offset, u64 file_size, std::string name);
|
||||
~FileInfoGCWii() override;
|
||||
|
||||
u64 GetOffset() const override { return m_Offset; }
|
||||
u64 GetSize() const override { return m_FileSize; }
|
||||
bool IsDirectory() const override { return (m_NameOffset & 0xFF000000) != 0; }
|
||||
const std::string& GetName() const override { return m_Name; }
|
||||
// TODO: These shouldn't be public
|
||||
std::string m_FullPath;
|
||||
std::string m_Name;
|
||||
const u64 m_NameOffset = 0u;
|
||||
|
||||
private:
|
||||
|
@ -43,7 +44,8 @@ public:
|
|||
bool IsValid() const override { return m_Valid; }
|
||||
u64 GetFileSize(const std::string& _rFullPath) override;
|
||||
const std::vector<FileInfoGCWii>& GetFileList() override;
|
||||
std::string GetFileName(u64 _Address) override;
|
||||
std::string GetPath(u64 _Address) override;
|
||||
std::string GetPathFromFSTOffset(size_t file_info_offset) override;
|
||||
u64 ReadFile(const std::string& _rFullPath, u8* _pBuffer, u64 _MaxBufferSize,
|
||||
u64 _OffsetInFile) override;
|
||||
bool ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) override;
|
||||
|
@ -62,8 +64,6 @@ private:
|
|||
const FileInfoGCWii* FindFileInfo(const std::string& _rFullPath);
|
||||
bool DetectFileSystem();
|
||||
void InitFileSystem();
|
||||
size_t BuildFilenames(const size_t _FirstIndex, const size_t _LastIndex,
|
||||
const std::string& _szDirectory, u64 _NameTableOffset);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
// Not guaranteed to return a meaningful value for directories
|
||||
virtual u64 GetSize() const = 0;
|
||||
virtual bool IsDirectory() const = 0;
|
||||
virtual const std::string& GetName() const = 0;
|
||||
};
|
||||
|
||||
class FileSystem
|
||||
|
@ -45,7 +46,8 @@ public:
|
|||
virtual bool ExportFile(const std::string& _rFullPath, const std::string& _rExportFilename) = 0;
|
||||
virtual bool ExportApploader(const std::string& _rExportFolder) const = 0;
|
||||
virtual bool ExportDOL(const std::string& _rExportFolder) const = 0;
|
||||
virtual std::string GetFileName(u64 _Address) = 0;
|
||||
virtual std::string GetPath(u64 _Address) = 0;
|
||||
virtual std::string GetPathFromFSTOffset(size_t file_info_offset) = 0;
|
||||
virtual std::optional<u64> GetBootDOLOffset() const = 0;
|
||||
virtual std::optional<u32> GetBootDOLSize(u64 dol_offset) const = 0;
|
||||
|
||||
|
|
|
@ -94,32 +94,18 @@ size_t CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
|
|||
while (current_index < last_index)
|
||||
{
|
||||
const DiscIO::FileInfoGCWii& file_info = file_infos[current_index];
|
||||
std::string file_path = file_info.m_FullPath;
|
||||
|
||||
// Trim the trailing '/' if it exists.
|
||||
if (file_path.back() == DIR_SEP_CHR)
|
||||
{
|
||||
file_path.pop_back();
|
||||
}
|
||||
|
||||
// Cut off the path up to the actual filename or folder.
|
||||
// Say we have "/music/stream/stream1.strm", the result will be "stream1.strm".
|
||||
const size_t dir_sep_index = file_path.rfind(DIR_SEP_CHR);
|
||||
if (dir_sep_index != std::string::npos)
|
||||
{
|
||||
file_path = file_path.substr(dir_sep_index + 1);
|
||||
}
|
||||
|
||||
// check next index
|
||||
if (file_info.IsDirectory())
|
||||
{
|
||||
const wxTreeItemId item = tree_ctrl->AppendItem(parent, StrToWxStr(file_path), ICON_FOLDER);
|
||||
const wxTreeItemId item =
|
||||
tree_ctrl->AppendItem(parent, StrToWxStr(file_info.GetName()), ICON_FOLDER);
|
||||
current_index = CreateDirectoryTree(tree_ctrl, item, file_infos, current_index + 1,
|
||||
static_cast<size_t>(file_info.GetSize()));
|
||||
}
|
||||
else
|
||||
{
|
||||
tree_ctrl->AppendItem(parent, StrToWxStr(file_path), ICON_FILE);
|
||||
tree_ctrl->AppendItem(parent, StrToWxStr(file_info.GetName()), ICON_FILE);
|
||||
current_index++;
|
||||
}
|
||||
}
|
||||
|
@ -472,7 +458,7 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path,
|
|||
// Look for the dir we are going to extract
|
||||
for (index = 0; index < fst.size(); ++index)
|
||||
{
|
||||
if (fst[index].m_FullPath == full_path)
|
||||
if (filesystem->GetPathFromFSTOffset(index) == full_path)
|
||||
{
|
||||
INFO_LOG(DISCIO, "Found the directory at %u", index);
|
||||
size = static_cast<u32>(fst[index].GetSize());
|
||||
|
@ -492,12 +478,13 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path,
|
|||
// Extraction
|
||||
for (u32 i = index; i < size; i++)
|
||||
{
|
||||
const std::string path = filesystem->GetPathFromFSTOffset(i);
|
||||
dialog.SetTitle(wxString::Format(
|
||||
"%s : %u%%", dialog_title.c_str(),
|
||||
static_cast<u32>((static_cast<float>(i - index) / static_cast<float>(size - index)) *
|
||||
100)));
|
||||
|
||||
dialog.Update(i, wxString::Format(_("Extracting %s"), StrToWxStr(fst[i].m_FullPath)));
|
||||
dialog.Update(i, wxString::Format(_("Extracting %s"), StrToWxStr(path)));
|
||||
|
||||
if (dialog.WasCancelled())
|
||||
break;
|
||||
|
@ -505,7 +492,7 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path,
|
|||
if (fst[i].IsDirectory())
|
||||
{
|
||||
const std::string export_name =
|
||||
StringFromFormat("%s/%s/", output_folder.c_str(), fst[i].m_FullPath.c_str());
|
||||
StringFromFormat("%s/%s/", output_folder.c_str(), path.c_str());
|
||||
INFO_LOG(DISCIO, "%s", export_name.c_str());
|
||||
|
||||
if (!File::Exists(export_name) && !File::CreateFullPath(export_name))
|
||||
|
@ -523,10 +510,10 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path,
|
|||
else
|
||||
{
|
||||
const std::string export_name =
|
||||
StringFromFormat("%s/%s", output_folder.c_str(), fst[i].m_FullPath.c_str());
|
||||
StringFromFormat("%s/%s", output_folder.c_str(), path.c_str());
|
||||
INFO_LOG(DISCIO, "%s", export_name.c_str());
|
||||
|
||||
if (!File::Exists(export_name) && !filesystem->ExportFile(fst[i].m_FullPath, export_name))
|
||||
if (!File::Exists(export_name) && !filesystem->ExportFile(path, export_name))
|
||||
{
|
||||
ERROR_LOG(DISCIO, "Could not export %s", export_name.c_str());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue