642 lines
19 KiB
C++
642 lines
19 KiB
C++
|
// Copyright 2016 Dolphin Emulator Project
|
||
|
// Licensed under GPLv2+
|
||
|
// Refer to the license.txt file included.
|
||
|
|
||
|
#include "DolphinWX/ISOProperties/FilesystemPanel.h"
|
||
|
|
||
|
#include <array>
|
||
|
#include <vector>
|
||
|
|
||
|
#include <wx/bitmap.h>
|
||
|
#include <wx/button.h>
|
||
|
#include <wx/filepicker.h>
|
||
|
#include <wx/imaglist.h>
|
||
|
#include <wx/menu.h>
|
||
|
#include <wx/msgdlg.h>
|
||
|
#include <wx/progdlg.h>
|
||
|
#include <wx/sizer.h>
|
||
|
#include <wx/textctrl.h>
|
||
|
#include <wx/treectrl.h>
|
||
|
|
||
|
#include "Common/CommonPaths.h"
|
||
|
#include "Common/FileUtil.h"
|
||
|
#include "Common/Logging/Log.h"
|
||
|
#include "DiscIO/Enums.h"
|
||
|
#include "DiscIO/Filesystem.h"
|
||
|
#include "DiscIO/Volume.h"
|
||
|
#include "DiscIO/VolumeCreator.h"
|
||
|
#include "DolphinWX/ISOFile.h"
|
||
|
#include "DolphinWX/WxUtils.h"
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
class WiiPartition final : public wxTreeItemData
|
||
|
{
|
||
|
public:
|
||
|
WiiPartition(std::unique_ptr<DiscIO::IVolume> volume_,
|
||
|
std::unique_ptr<DiscIO::IFileSystem> filesystem_)
|
||
|
: volume{std::move(volume_)}, filesystem{std::move(filesystem_)}
|
||
|
{
|
||
|
}
|
||
|
|
||
|
std::unique_ptr<DiscIO::IVolume> volume;
|
||
|
std::unique_ptr<DiscIO::IFileSystem> filesystem;
|
||
|
};
|
||
|
|
||
|
class IntegrityCheckThread final : public wxThread
|
||
|
{
|
||
|
public:
|
||
|
explicit IntegrityCheckThread(const WiiPartition& partition)
|
||
|
: wxThread{wxTHREAD_JOINABLE}, m_partition{partition}
|
||
|
{
|
||
|
Create();
|
||
|
}
|
||
|
|
||
|
ExitCode Entry() override
|
||
|
{
|
||
|
return reinterpret_cast<ExitCode>(m_partition.volume->CheckIntegrity());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
const WiiPartition& m_partition;
|
||
|
};
|
||
|
|
||
|
enum : int
|
||
|
{
|
||
|
ICON_DISC,
|
||
|
ICON_FOLDER,
|
||
|
ICON_FILE
|
||
|
};
|
||
|
|
||
|
wxImageList* LoadIconBitmaps(const wxWindow* context)
|
||
|
{
|
||
|
static constexpr std::array<const char*, 3> icon_names{
|
||
|
{"isoproperties_disc", "isoproperties_folder", "isoproperties_file"}};
|
||
|
|
||
|
const wxSize icon_size = context->FromDIP(wxSize(16, 16));
|
||
|
auto* const icon_list = new wxImageList(icon_size.GetWidth(), icon_size.GetHeight());
|
||
|
|
||
|
for (const auto& name : icon_names)
|
||
|
{
|
||
|
icon_list->Add(
|
||
|
WxUtils::LoadScaledResourceBitmap(name, context, icon_size, wxDefaultSize,
|
||
|
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER));
|
||
|
}
|
||
|
|
||
|
return icon_list;
|
||
|
}
|
||
|
|
||
|
size_t CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
|
||
|
const std::vector<DiscIO::SFileInfo>& file_infos,
|
||
|
const size_t first_index, const size_t last_index)
|
||
|
{
|
||
|
size_t current_index = first_index;
|
||
|
|
||
|
while (current_index < last_index)
|
||
|
{
|
||
|
const DiscIO::SFileInfo& 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);
|
||
|
current_index = CreateDirectoryTree(tree_ctrl, item, file_infos, current_index + 1,
|
||
|
static_cast<size_t>(file_info.m_FileSize));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tree_ctrl->AppendItem(parent, StrToWxStr(file_path), ICON_FILE);
|
||
|
current_index++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return current_index;
|
||
|
}
|
||
|
|
||
|
size_t CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
|
||
|
const std::vector<DiscIO::SFileInfo>& file_infos)
|
||
|
{
|
||
|
if (file_infos.empty())
|
||
|
return 0;
|
||
|
|
||
|
return CreateDirectoryTree(tree_ctrl, parent, file_infos, 1, file_infos.at(0).m_FileSize);
|
||
|
}
|
||
|
|
||
|
WiiPartition* FindWiiPartition(wxTreeCtrl* tree_ctrl, const wxString& label)
|
||
|
{
|
||
|
wxTreeItemIdValue cookie;
|
||
|
auto partition = tree_ctrl->GetFirstChild(tree_ctrl->GetRootItem(), cookie);
|
||
|
|
||
|
while (partition.IsOk())
|
||
|
{
|
||
|
const wxString partition_label = tree_ctrl->GetItemText(partition);
|
||
|
|
||
|
if (partition_label == label)
|
||
|
return static_cast<WiiPartition*>(tree_ctrl->GetItemData(partition));
|
||
|
|
||
|
partition = tree_ctrl->GetNextSibling(partition);
|
||
|
}
|
||
|
|
||
|
return nullptr;
|
||
|
}
|
||
|
} // Anonymous namespace
|
||
|
|
||
|
FilesystemPanel::FilesystemPanel(wxWindow* parent, wxWindowID id, const GameListItem& item,
|
||
|
const std::unique_ptr<DiscIO::IVolume>& opened_iso)
|
||
|
: wxPanel{parent, id}, m_game_list_item{item}, m_opened_iso{opened_iso}
|
||
|
{
|
||
|
CreateGUI();
|
||
|
BindEvents();
|
||
|
PopulateFileSystemTree();
|
||
|
|
||
|
m_tree_ctrl->Expand(m_tree_ctrl->GetRootItem());
|
||
|
}
|
||
|
|
||
|
FilesystemPanel::~FilesystemPanel() = default;
|
||
|
|
||
|
void FilesystemPanel::BindEvents()
|
||
|
{
|
||
|
m_tree_ctrl->Bind(wxEVT_TREE_ITEM_RIGHT_CLICK, &FilesystemPanel::OnRightClickTree, this);
|
||
|
|
||
|
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractFile, this, ID_EXTRACT_FILE);
|
||
|
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractDirectories, this, ID_EXTRACT_ALL);
|
||
|
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractDirectories, this, ID_EXTRACT_DIR);
|
||
|
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractHeaderData, this, ID_EXTRACT_APPLOADER);
|
||
|
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractHeaderData, this, ID_EXTRACT_DOL);
|
||
|
Bind(wxEVT_MENU, &FilesystemPanel::OnCheckPartitionIntegrity, this, ID_CHECK_INTEGRITY);
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::CreateGUI()
|
||
|
{
|
||
|
m_tree_ctrl = new wxTreeCtrl(this);
|
||
|
m_tree_ctrl->AssignImageList(LoadIconBitmaps(this));
|
||
|
m_tree_ctrl->AddRoot(_("Disc"), ICON_DISC);
|
||
|
|
||
|
const auto space_5 = FromDIP(5);
|
||
|
auto* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||
|
main_sizer->AddSpacer(space_5);
|
||
|
main_sizer->Add(m_tree_ctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space_5);
|
||
|
main_sizer->AddSpacer(space_5);
|
||
|
|
||
|
SetSizer(main_sizer);
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::PopulateFileSystemTree()
|
||
|
{
|
||
|
switch (m_opened_iso->GetVolumeType())
|
||
|
{
|
||
|
case DiscIO::Platform::GAMECUBE_DISC:
|
||
|
PopulateFileSystemTreeGC();
|
||
|
break;
|
||
|
|
||
|
case DiscIO::Platform::WII_DISC:
|
||
|
PopulateFileSystemTreeWii();
|
||
|
break;
|
||
|
|
||
|
case DiscIO::Platform::ELF_DOL:
|
||
|
case DiscIO::Platform::NUMBER_OF_PLATFORMS:
|
||
|
case DiscIO::Platform::WII_WAD:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::PopulateFileSystemTreeGC()
|
||
|
{
|
||
|
m_filesystem = DiscIO::CreateFileSystem(m_opened_iso.get());
|
||
|
if (!m_filesystem)
|
||
|
return;
|
||
|
|
||
|
CreateDirectoryTree(m_tree_ctrl, m_tree_ctrl->GetRootItem(), m_filesystem->GetFileList());
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::PopulateFileSystemTreeWii() const
|
||
|
{
|
||
|
u32 partition_count = 0;
|
||
|
|
||
|
for (u32 group = 0; group < 4; group++)
|
||
|
{
|
||
|
// yes, technically there can be OVER NINE THOUSAND partitions...
|
||
|
for (u32 i = 0; i < 0xFFFFFFFF; i++)
|
||
|
{
|
||
|
auto volume = DiscIO::CreateVolumeFromFilename(m_game_list_item.GetFileName(), group, i);
|
||
|
if (volume == nullptr)
|
||
|
break;
|
||
|
|
||
|
auto file_system = DiscIO::CreateFileSystem(volume.get());
|
||
|
if (file_system != nullptr)
|
||
|
{
|
||
|
auto* const partition = new WiiPartition(std::move(volume), std::move(file_system));
|
||
|
|
||
|
const wxTreeItemId partition_root = m_tree_ctrl->AppendItem(
|
||
|
m_tree_ctrl->GetRootItem(), wxString::Format(_("Partition %u"), partition_count),
|
||
|
ICON_DISC);
|
||
|
|
||
|
m_tree_ctrl->SetItemData(partition_root, partition);
|
||
|
CreateDirectoryTree(m_tree_ctrl, partition_root, partition->filesystem->GetFileList());
|
||
|
|
||
|
if (partition_count == 1)
|
||
|
m_tree_ctrl->Expand(partition_root);
|
||
|
|
||
|
partition_count++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::OnRightClickTree(wxTreeEvent& event)
|
||
|
{
|
||
|
m_tree_ctrl->SelectItem(event.GetItem());
|
||
|
|
||
|
wxMenu menu;
|
||
|
|
||
|
const auto selection = m_tree_ctrl->GetSelection();
|
||
|
const auto first_visible_item = m_tree_ctrl->GetFirstVisibleItem();
|
||
|
const int image_type = m_tree_ctrl->GetItemImage(selection);
|
||
|
|
||
|
if (image_type == ICON_DISC && first_visible_item != selection)
|
||
|
{
|
||
|
menu.Append(ID_EXTRACT_DIR, _("Extract Partition..."));
|
||
|
}
|
||
|
else if (image_type == ICON_FOLDER)
|
||
|
{
|
||
|
menu.Append(ID_EXTRACT_DIR, _("Extract Directory..."));
|
||
|
}
|
||
|
else if (image_type == ICON_FILE)
|
||
|
{
|
||
|
menu.Append(ID_EXTRACT_FILE, _("Extract File..."));
|
||
|
}
|
||
|
|
||
|
menu.Append(ID_EXTRACT_ALL, _("Extract All Files..."));
|
||
|
|
||
|
if (m_opened_iso->GetVolumeType() != DiscIO::Platform::WII_DISC ||
|
||
|
(image_type == ICON_DISC && first_visible_item != selection))
|
||
|
{
|
||
|
menu.AppendSeparator();
|
||
|
menu.Append(ID_EXTRACT_APPLOADER, _("Extract Apploader..."));
|
||
|
menu.Append(ID_EXTRACT_DOL, _("Extract DOL..."));
|
||
|
}
|
||
|
|
||
|
if (image_type == ICON_DISC && first_visible_item != selection)
|
||
|
{
|
||
|
menu.AppendSeparator();
|
||
|
menu.Append(ID_CHECK_INTEGRITY, _("Check Partition Integrity"));
|
||
|
}
|
||
|
|
||
|
PopupMenu(&menu);
|
||
|
event.Skip();
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::OnExtractFile(wxCommandEvent& WXUNUSED(event))
|
||
|
{
|
||
|
const wxString selection_label = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection());
|
||
|
|
||
|
const wxString output_file_path =
|
||
|
wxFileSelector(_("Extract File"), wxEmptyString, selection_label, wxEmptyString,
|
||
|
wxGetTranslation(wxALL_FILES), wxFD_SAVE, this);
|
||
|
|
||
|
if (output_file_path.empty() || selection_label.empty())
|
||
|
return;
|
||
|
|
||
|
ExtractSingleFile(output_file_path);
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::OnExtractDirectories(wxCommandEvent& event)
|
||
|
{
|
||
|
const wxString selected_directory_label = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection());
|
||
|
const wxString extract_path = wxDirSelector(_("Choose the folder to extract to"));
|
||
|
|
||
|
if (extract_path.empty() || selected_directory_label.empty())
|
||
|
return;
|
||
|
|
||
|
switch (event.GetId())
|
||
|
{
|
||
|
case ID_EXTRACT_ALL:
|
||
|
ExtractAllFiles(extract_path);
|
||
|
break;
|
||
|
case ID_EXTRACT_DIR:
|
||
|
ExtractSingleDirectory(extract_path);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::OnExtractHeaderData(wxCommandEvent& event)
|
||
|
{
|
||
|
DiscIO::IFileSystem* file_system = nullptr;
|
||
|
const wxString path = wxDirSelector(_("Choose the folder to extract to"));
|
||
|
|
||
|
if (path.empty())
|
||
|
return;
|
||
|
|
||
|
if (m_opened_iso->GetVolumeType() == DiscIO::Platform::WII_DISC)
|
||
|
{
|
||
|
const auto* const selection_data = m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection());
|
||
|
const auto* const partition = static_cast<const WiiPartition*>(selection_data);
|
||
|
|
||
|
file_system = partition->filesystem.get();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
file_system = m_filesystem.get();
|
||
|
}
|
||
|
|
||
|
bool ret = false;
|
||
|
if (event.GetId() == ID_EXTRACT_APPLOADER)
|
||
|
{
|
||
|
ret = file_system->ExportApploader(WxStrToStr(path));
|
||
|
}
|
||
|
else if (event.GetId() == ID_EXTRACT_DOL)
|
||
|
{
|
||
|
ret = file_system->ExportDOL(WxStrToStr(path));
|
||
|
}
|
||
|
|
||
|
if (!ret)
|
||
|
{
|
||
|
WxUtils::ShowErrorDialog(
|
||
|
wxString::Format(_("Failed to extract to %s!"), WxStrToStr(path).c_str()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::OnCheckPartitionIntegrity(wxCommandEvent& WXUNUSED(event))
|
||
|
{
|
||
|
// Normally we can't enter this function if we aren't analyzing a Wii disc
|
||
|
// anyway, but let's still check to be sure.
|
||
|
if (m_opened_iso->GetVolumeType() != DiscIO::Platform::WII_DISC)
|
||
|
return;
|
||
|
|
||
|
wxProgressDialog dialog(_("Checking integrity..."), _("Working..."), 1000, this,
|
||
|
wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH);
|
||
|
|
||
|
const auto selection = m_tree_ctrl->GetSelection();
|
||
|
|
||
|
IntegrityCheckThread thread(*static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(selection)));
|
||
|
thread.Run();
|
||
|
|
||
|
while (thread.IsAlive())
|
||
|
{
|
||
|
dialog.Pulse();
|
||
|
wxThread::Sleep(50);
|
||
|
}
|
||
|
|
||
|
dialog.Destroy();
|
||
|
|
||
|
if (thread.Wait())
|
||
|
{
|
||
|
wxMessageBox(_("Integrity check completed. No errors have been found."),
|
||
|
_("Integrity check completed"), wxOK | wxICON_INFORMATION, this);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wxMessageBox(wxString::Format(_("Integrity check for %s failed. The disc image is most "
|
||
|
"likely corrupted or has been patched incorrectly."),
|
||
|
m_tree_ctrl->GetItemText(selection)),
|
||
|
_("Integrity Check Error"), wxOK | wxICON_ERROR, this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractAllFiles(const wxString& output_folder)
|
||
|
{
|
||
|
switch (m_opened_iso->GetVolumeType())
|
||
|
{
|
||
|
case DiscIO::Platform::GAMECUBE_DISC:
|
||
|
ExtractAllFilesGC(output_folder);
|
||
|
break;
|
||
|
|
||
|
case DiscIO::Platform::WII_DISC:
|
||
|
ExtractAllFilesWii(output_folder);
|
||
|
break;
|
||
|
|
||
|
case DiscIO::Platform::ELF_DOL:
|
||
|
case DiscIO::Platform::NUMBER_OF_PLATFORMS:
|
||
|
case DiscIO::Platform::WII_WAD:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractAllFilesGC(const wxString& output_folder)
|
||
|
{
|
||
|
ExtractDirectories("", WxStrToStr(output_folder), m_filesystem.get());
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractAllFilesWii(const wxString& output_folder)
|
||
|
{
|
||
|
const wxTreeItemId root = m_tree_ctrl->GetRootItem();
|
||
|
|
||
|
wxTreeItemIdValue cookie;
|
||
|
wxTreeItemId item = m_tree_ctrl->GetFirstChild(root, cookie);
|
||
|
|
||
|
while (item.IsOk())
|
||
|
{
|
||
|
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(item));
|
||
|
ExtractDirectories("", WxStrToStr(output_folder), partition->filesystem.get());
|
||
|
item = m_tree_ctrl->GetNextChild(root, cookie);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractSingleFile(const wxString& output_file_path) const
|
||
|
{
|
||
|
const auto selection_file_path = BuildFilePathFromSelection();
|
||
|
|
||
|
switch (m_opened_iso->GetVolumeType())
|
||
|
{
|
||
|
case DiscIO::Platform::GAMECUBE_DISC:
|
||
|
ExtractSingleFileGC(selection_file_path, output_file_path);
|
||
|
break;
|
||
|
|
||
|
case DiscIO::Platform::WII_DISC:
|
||
|
ExtractSingleFileWii(selection_file_path, output_file_path);
|
||
|
break;
|
||
|
|
||
|
case DiscIO::Platform::ELF_DOL:
|
||
|
case DiscIO::Platform::NUMBER_OF_PLATFORMS:
|
||
|
case DiscIO::Platform::WII_WAD:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractSingleFileGC(const wxString& file_path,
|
||
|
const wxString& output_file_path) const
|
||
|
{
|
||
|
m_filesystem->ExportFile(WxStrToStr(file_path), WxStrToStr(output_file_path));
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractSingleFileWii(wxString file_path,
|
||
|
const wxString& output_file_path) const
|
||
|
{
|
||
|
const size_t slash_index = file_path.find('/');
|
||
|
const wxString partition_label = file_path.substr(0, slash_index);
|
||
|
const auto* const partition = FindWiiPartition(m_tree_ctrl, partition_label);
|
||
|
|
||
|
// Remove "Partition x/"
|
||
|
file_path.erase(0, slash_index + 1);
|
||
|
|
||
|
partition->filesystem->ExportFile(WxStrToStr(file_path), WxStrToStr(output_file_path));
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractSingleDirectory(const wxString& output_folder)
|
||
|
{
|
||
|
const wxString directory_path = BuildDirectoryPathFromSelection();
|
||
|
|
||
|
switch (m_opened_iso->GetVolumeType())
|
||
|
{
|
||
|
case DiscIO::Platform::GAMECUBE_DISC:
|
||
|
ExtractSingleDirectoryGC(directory_path, output_folder);
|
||
|
break;
|
||
|
|
||
|
case DiscIO::Platform::WII_DISC:
|
||
|
ExtractSingleDirectoryWii(directory_path, output_folder);
|
||
|
break;
|
||
|
|
||
|
case DiscIO::Platform::ELF_DOL:
|
||
|
case DiscIO::Platform::NUMBER_OF_PLATFORMS:
|
||
|
case DiscIO::Platform::WII_WAD:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractSingleDirectoryGC(const wxString& directory_path,
|
||
|
const wxString& output_folder)
|
||
|
{
|
||
|
ExtractDirectories(WxStrToStr(directory_path), WxStrToStr(output_folder), m_filesystem.get());
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractSingleDirectoryWii(wxString directory_path,
|
||
|
const wxString& output_folder)
|
||
|
{
|
||
|
const size_t slash_index = directory_path.find('/');
|
||
|
const wxString partition_label = directory_path.substr(0, slash_index);
|
||
|
const auto* const partition = FindWiiPartition(m_tree_ctrl, partition_label);
|
||
|
|
||
|
// Remove "Partition x/"
|
||
|
directory_path.erase(0, slash_index + 1);
|
||
|
|
||
|
ExtractDirectories(WxStrToStr(directory_path), WxStrToStr(output_folder),
|
||
|
partition->filesystem.get());
|
||
|
}
|
||
|
|
||
|
void FilesystemPanel::ExtractDirectories(const std::string& full_path,
|
||
|
const std::string& output_folder,
|
||
|
DiscIO::IFileSystem* filesystem)
|
||
|
{
|
||
|
const std::vector<DiscIO::SFileInfo>& fst = filesystem->GetFileList();
|
||
|
|
||
|
u32 index = 0;
|
||
|
u32 size = 0;
|
||
|
|
||
|
// Extract all
|
||
|
if (full_path.empty())
|
||
|
{
|
||
|
size = static_cast<u32>(fst.size());
|
||
|
|
||
|
filesystem->ExportApploader(output_folder);
|
||
|
if (m_opened_iso->GetVolumeType() == DiscIO::Platform::GAMECUBE_DISC)
|
||
|
filesystem->ExportDOL(output_folder);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Look for the dir we are going to extract
|
||
|
for (index = 0; index < fst.size(); ++index)
|
||
|
{
|
||
|
if (fst[index].m_FullPath == full_path)
|
||
|
{
|
||
|
INFO_LOG(DISCIO, "Found the directory at %u", index);
|
||
|
size = static_cast<u32>(fst[index].m_FileSize);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
INFO_LOG(DISCIO, "Directory found from %u to %u\nextracting to: %s", index, size,
|
||
|
output_folder.c_str());
|
||
|
}
|
||
|
|
||
|
const auto dialog_title = (index != 0) ? _("Extracting Directory") : _("Extracting All Files");
|
||
|
wxProgressDialog dialog(dialog_title, _("Extracting..."), static_cast<int>(size - 1), this,
|
||
|
wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME |
|
||
|
wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);
|
||
|
|
||
|
// Extraction
|
||
|
for (u32 i = index; i < size; 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)));
|
||
|
|
||
|
if (dialog.WasCancelled())
|
||
|
break;
|
||
|
|
||
|
if (fst[i].IsDirectory())
|
||
|
{
|
||
|
const std::string export_name =
|
||
|
StringFromFormat("%s/%s/", output_folder.c_str(), fst[i].m_FullPath.c_str());
|
||
|
INFO_LOG(DISCIO, "%s", export_name.c_str());
|
||
|
|
||
|
if (!File::Exists(export_name) && !File::CreateFullPath(export_name))
|
||
|
{
|
||
|
ERROR_LOG(DISCIO, "Could not create the path %s", export_name.c_str());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!File::IsDirectory(export_name))
|
||
|
ERROR_LOG(DISCIO, "%s already exists and is not a directory", export_name.c_str());
|
||
|
|
||
|
ERROR_LOG(DISCIO, "Folder %s already exists", export_name.c_str());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const std::string export_name =
|
||
|
StringFromFormat("%s/%s", output_folder.c_str(), fst[i].m_FullPath.c_str());
|
||
|
INFO_LOG(DISCIO, "%s", export_name.c_str());
|
||
|
|
||
|
if (!File::Exists(export_name) && !filesystem->ExportFile(fst[i].m_FullPath, export_name))
|
||
|
{
|
||
|
ERROR_LOG(DISCIO, "Could not export %s", export_name.c_str());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ERROR_LOG(DISCIO, "%s already exists", export_name.c_str());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
wxString FilesystemPanel::BuildFilePathFromSelection() const
|
||
|
{
|
||
|
wxString file_path = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection());
|
||
|
|
||
|
const auto root_node = m_tree_ctrl->GetRootItem();
|
||
|
auto node = m_tree_ctrl->GetItemParent(m_tree_ctrl->GetSelection());
|
||
|
|
||
|
while (node != root_node)
|
||
|
{
|
||
|
file_path = m_tree_ctrl->GetItemText(node) + DIR_SEP_CHR + file_path;
|
||
|
node = m_tree_ctrl->GetItemParent(node);
|
||
|
}
|
||
|
|
||
|
return file_path;
|
||
|
}
|
||
|
|
||
|
wxString FilesystemPanel::BuildDirectoryPathFromSelection() const
|
||
|
{
|
||
|
wxString directory_path = BuildFilePathFromSelection();
|
||
|
directory_path += DIR_SEP_CHR;
|
||
|
return directory_path;
|
||
|
}
|