Merge pull request #5651 from JosJuice/new-disc-extraction

Use new format for disc extraction
This commit is contained in:
Leo Lam
2017-07-04 13:46:18 +02:00
committed by GitHub
20 changed files with 626 additions and 368 deletions

View File

@ -259,7 +259,7 @@ bool GameListItem::BannerChanged()
if (!m_volume_banner.empty())
return false;
if (m_platform != DiscIO::Platform::WII_DISC && m_platform != DiscIO::Platform::WII_WAD)
if (!DiscIO::IsWii(m_platform))
return false;
auto& banner = m_pending.volume_banner;
@ -286,7 +286,7 @@ std::string GameListItem::GetDescription(DiscIO::Language language) const
std::string GameListItem::GetDescription() const
{
bool wii = m_platform != DiscIO::Platform::GAMECUBE_DISC;
const bool wii = DiscIO::IsWii(m_platform);
return GetDescription(SConfig::GetInstance().GetCurrentLanguage(wii));
}
@ -300,7 +300,7 @@ std::string GameListItem::GetName() const
if (!m_custom_name.empty())
return m_custom_name;
bool wii = m_platform != DiscIO::Platform::GAMECUBE_DISC;
const bool wii = DiscIO::IsWii(m_platform);
std::string name = GetName(SConfig::GetInstance().GetCurrentLanguage(wii));
if (!name.empty())
return name;
@ -356,7 +356,7 @@ std::vector<DiscIO::Language> GameListItem::GetLanguages() const
const std::string GameListItem::GetWiiFSPath() const
{
if (m_platform != DiscIO::Platform::WII_DISC && m_platform != DiscIO::Platform::WII_WAD)
if (!DiscIO::IsWii(m_platform))
return "";
const std::string path = Common::GetTitleDataPath(m_title_id, Common::FROM_CONFIGURED_ROOT);

View File

@ -6,7 +6,6 @@
#include <array>
#include <chrono>
#include <functional>
#include <future>
#include <memory>
#include <vector>
@ -25,6 +24,7 @@
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "DiscIO/DiscExtractor.h"
#include "DiscIO/Enums.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h"
@ -124,10 +124,9 @@ 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::OnExtractAll, 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::OnExtractSystemData, this, ID_EXTRACT_SYSTEM_DATA);
Bind(wxEVT_MENU, &FilesystemPanel::OnCheckPartitionIntegrity, this, ID_CHECK_INTEGRITY);
}
@ -190,36 +189,31 @@ void FilesystemPanel::OnRightClickTree(wxTreeEvent& event)
wxMenu menu;
const auto selection = m_tree_ctrl->GetSelection();
const auto first_visible_item = m_tree_ctrl->GetFirstVisibleItem();
const wxTreeItemId selection = m_tree_ctrl->GetSelection();
const wxTreeItemId first_visible_item = m_tree_ctrl->GetFirstVisibleItem();
const int image_type = m_tree_ctrl->GetItemImage(selection);
const bool is_parent_of_partitions = m_has_partitions && first_visible_item == 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)
{
if (image_type == ICON_FILE)
menu.Append(ID_EXTRACT_FILE, _("Extract File..."));
}
else if (!is_parent_of_partitions)
menu.Append(ID_EXTRACT_DIR, _("Extract Files..."));
menu.Append(ID_EXTRACT_ALL, _("Extract All Files..."));
if (!m_has_partitions || (image_type == ICON_DISC && first_visible_item != selection))
if (image_type == ICON_DISC)
{
menu.AppendSeparator();
menu.Append(ID_EXTRACT_APPLOADER, _("Extract Apploader..."));
menu.Append(ID_EXTRACT_DOL, _("Extract DOL..."));
}
if (!is_parent_of_partitions)
menu.Append(ID_EXTRACT_SYSTEM_DATA, _("Extract System Data..."));
if (image_type == ICON_DISC && first_visible_item != selection)
{
menu.AppendSeparator();
menu.Append(ID_CHECK_INTEGRITY, _("Check Partition Integrity"));
if (first_visible_item == selection)
menu.Append(ID_EXTRACT_ALL, _("Extract Entire Disc..."));
else
menu.Append(ID_EXTRACT_ALL, _("Extract Entire Partition..."));
if (first_visible_item != selection)
{
menu.AppendSeparator();
menu.Append(ID_CHECK_INTEGRITY, _("Check Partition Integrity"));
}
}
PopupMenu(&menu);
@ -245,57 +239,80 @@ 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:
if (!extract_path.empty() && !selected_directory_label.empty())
ExtractSingleDirectory(extract_path);
break;
}
}
void FilesystemPanel::OnExtractHeaderData(wxCommandEvent& event)
void FilesystemPanel::OnExtractSystemData(wxCommandEvent& event)
{
DiscIO::FileSystem* file_system = nullptr;
const wxString path = wxDirSelector(_("Choose the folder to extract to"));
if (path.empty())
return;
DiscIO::Partition partition;
if (m_has_partitions)
{
const auto* const selection_data = m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection());
const auto* const partition = static_cast<const WiiPartition*>(selection_data);
const auto* const wii_partition = static_cast<const WiiPartition*>(selection_data);
file_system = partition->filesystem.get();
partition = wii_partition->filesystem->GetPartition();
}
else
{
file_system = m_filesystem.get();
partition = DiscIO::PARTITION_NONE;
}
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)
if (!DiscIO::ExportSystemData(*m_opened_iso, partition, WxStrToStr(path)))
{
WxUtils::ShowErrorDialog(
wxString::Format(_("Failed to extract to %s!"), WxStrToStr(path).c_str()));
}
}
void FilesystemPanel::OnExtractAll(wxCommandEvent& event)
{
const wxString extract_path = wxDirSelector(_("Choose the folder to extract to"));
if (extract_path.empty())
return;
const std::string std_extract_path = WxStrToStr(extract_path);
const wxTreeItemId selection = m_tree_ctrl->GetSelection();
const bool first_item_selected = m_tree_ctrl->GetFirstVisibleItem() == selection;
if (m_has_partitions && first_item_selected)
{
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));
const std::optional<u32> partition_type =
*m_opened_iso->GetPartitionType(partition->filesystem->GetPartition());
if (partition_type)
{
const std::string partition_name = DiscIO::DirectoryNameForPartitionType(*partition_type);
ExtractPartition(std_extract_path + '/' + partition_name, *partition->filesystem);
}
item = m_tree_ctrl->GetNextChild(root, cookie);
}
}
else if (m_has_partitions && !first_item_selected)
{
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(selection));
ExtractPartition(std_extract_path, *partition->filesystem);
}
else
{
ExtractPartition(std_extract_path, *m_filesystem);
}
}
void FilesystemPanel::OnCheckPartitionIntegrity(wxCommandEvent& WXUNUSED(event))
{
// Normally we can't enter this function if we're analyzing a volume that
@ -331,113 +348,24 @@ void FilesystemPanel::OnCheckPartitionIntegrity(wxCommandEvent& WXUNUSED(event))
}
}
void FilesystemPanel::ExtractAllFiles(const wxString& output_folder)
{
if (m_has_partitions)
{
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);
item = m_tree_ctrl->GetNextChild(root, cookie);
}
}
else
{
ExtractDirectories("", WxStrToStr(output_folder), *m_filesystem);
}
}
void FilesystemPanel::ExtractSingleFile(const wxString& output_file_path) const
{
wxString selection_file_path = BuildFilePathFromSelection();
if (m_has_partitions)
{
const size_t slash_index = selection_file_path.find('/');
const wxString partition_label = selection_file_path.substr(0, slash_index);
const auto* const partition = FindWiiPartition(m_tree_ctrl, partition_label);
// Remove "Partition x/"
selection_file_path.erase(0, slash_index + 1);
partition->filesystem->ExportFile(
partition->filesystem->FindFileInfo(WxStrToStr(selection_file_path)).get(),
WxStrToStr(output_file_path));
}
else
{
m_filesystem->ExportFile(m_filesystem->FindFileInfo(WxStrToStr(selection_file_path)).get(),
WxStrToStr(output_file_path));
}
const std::pair<wxString, const DiscIO::FileSystem&> path = BuildFilePathFromSelection();
DiscIO::ExportFile(*m_opened_iso, path.second.GetPartition(),
path.second.FindFileInfo(WxStrToStr(path.first)).get(),
WxStrToStr(output_file_path));
}
void FilesystemPanel::ExtractSingleDirectory(const wxString& output_folder)
{
wxString directory_path = BuildDirectoryPathFromSelection();
if (m_has_partitions)
{
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);
}
else
{
ExtractDirectories(WxStrToStr(directory_path), WxStrToStr(output_folder), *m_filesystem);
}
}
static void ExtractDir(const std::string& full_path, const std::string& output_folder,
const DiscIO::FileSystem& file_system, const DiscIO::FileInfo& directory,
const std::function<bool(const std::string& path)>& update_progress)
{
for (const DiscIO::FileInfo& file_info : directory)
{
const std::string path = full_path + file_info.GetName() + (file_info.IsDirectory() ? "/" : "");
const std::string output_path = output_folder + DIR_SEP_CHR + path;
if (update_progress(path))
return;
DEBUG_LOG(DISCIO, "%s", output_path.c_str());
if (file_info.IsDirectory())
{
File::CreateFullPath(output_path);
ExtractDir(path, output_folder, file_system, file_info, update_progress);
}
else
{
if (File::Exists(output_path))
NOTICE_LOG(DISCIO, "%s already exists", output_path.c_str());
else if (!file_system.ExportFile(&file_info, output_path))
ERROR_LOG(DISCIO, "Could not export %s", output_path.c_str());
}
}
const std::pair<wxString, const DiscIO::FileSystem&> path = BuildDirectoryPathFromSelection();
ExtractDirectories(WxStrToStr(path.first), WxStrToStr(output_folder), path.second);
}
void FilesystemPanel::ExtractDirectories(const std::string& full_path,
const std::string& output_folder,
const DiscIO::FileSystem& filesystem)
{
if (full_path.empty()) // Root
{
filesystem.ExportApploader(output_folder);
filesystem.ExportDOL(output_folder);
}
std::unique_ptr<DiscIO::FileInfo> file_info = filesystem.FindFileInfo(full_path);
u32 size = file_info->GetTotalChildren();
u32 progress = 0;
@ -447,36 +375,64 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path,
wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME |
wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);
File::CreateFullPath(output_folder + "/" + full_path);
ExtractDir(full_path, output_folder, filesystem, *file_info, [&](const std::string& path) {
dialog.SetTitle(wxString::Format(
"%s : %d%%", dialog_title.c_str(),
static_cast<u32>((static_cast<float>(progress) / static_cast<float>(size)) * 100)));
dialog.Update(progress, wxString::Format(_("Extracting %s"), StrToWxStr(path)));
++progress;
return dialog.WasCancelled();
});
DiscIO::ExportDirectory(
*m_opened_iso, filesystem.GetPartition(), *file_info, true, full_path, output_folder,
[&](const std::string& path) {
dialog.SetTitle(wxString::Format(
"%s : %d%%", dialog_title.c_str(),
static_cast<u32>((static_cast<float>(progress) / static_cast<float>(size)) * 100)));
dialog.Update(progress, wxString::Format(_("Extracting %s"), StrToWxStr(path)));
++progress;
return dialog.WasCancelled();
});
}
wxString FilesystemPanel::BuildFilePathFromSelection() const
void FilesystemPanel::ExtractPartition(const std::string& output_folder,
const DiscIO::FileSystem& filesystem)
{
wxString file_path = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection());
ExtractDirectories("", output_folder + "/files", filesystem);
DiscIO::ExportSystemData(*m_opened_iso, filesystem.GetPartition(), output_folder);
}
const auto root_node = m_tree_ctrl->GetRootItem();
auto node = m_tree_ctrl->GetItemParent(m_tree_ctrl->GetSelection());
std::pair<wxString, const DiscIO::FileSystem&> FilesystemPanel::BuildFilePathFromSelection() const
{
const wxTreeItemId root_node = m_tree_ctrl->GetRootItem();
wxTreeItemId node = m_tree_ctrl->GetSelection();
while (node != root_node)
wxString file_path;
if (node != root_node)
{
file_path = m_tree_ctrl->GetItemText(node) + DIR_SEP_CHR + file_path;
file_path = m_tree_ctrl->GetItemText(node);
node = m_tree_ctrl->GetItemParent(node);
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;
if (m_has_partitions)
{
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);
return {file_path, *partition->filesystem};
}
else
{
return {file_path, *m_filesystem};
}
}
wxString FilesystemPanel::BuildDirectoryPathFromSelection() const
std::pair<wxString, const DiscIO::FileSystem&>
FilesystemPanel::BuildDirectoryPathFromSelection() const
{
wxString directory_path = BuildFilePathFromSelection();
directory_path += DIR_SEP_CHR;
return directory_path;
const std::pair<wxString, const DiscIO::FileSystem&> result = BuildFilePathFromSelection();
return {result.first + DIR_SEP_CHR, result.second};
}

View File

@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include <utility>
#include <wx/panel.h>
class GameListItem;
@ -31,8 +32,7 @@ private:
ID_EXTRACT_DIR = 20000,
ID_EXTRACT_ALL,
ID_EXTRACT_FILE,
ID_EXTRACT_APPLOADER,
ID_EXTRACT_DOL,
ID_EXTRACT_SYSTEM_DATA,
ID_CHECK_INTEGRITY,
};
@ -44,17 +44,18 @@ private:
void OnRightClickTree(wxTreeEvent&);
void OnExtractFile(wxCommandEvent&);
void OnExtractDirectories(wxCommandEvent&);
void OnExtractHeaderData(wxCommandEvent&);
void OnExtractSystemData(wxCommandEvent&);
void OnExtractAll(wxCommandEvent&);
void OnCheckPartitionIntegrity(wxCommandEvent&);
void ExtractAllFiles(const wxString& output_folder);
void ExtractSingleFile(const wxString& output_file_path) const;
void ExtractSingleDirectory(const wxString& output_folder);
void ExtractDirectories(const std::string& full_path, const std::string& output_folder,
const DiscIO::FileSystem& filesystem);
void ExtractPartition(const std::string& output_folder, const DiscIO::FileSystem& filesystem);
wxString BuildFilePathFromSelection() const;
wxString BuildDirectoryPathFromSelection() const;
std::pair<wxString, const DiscIO::FileSystem&> BuildFilePathFromSelection() const;
std::pair<wxString, const DiscIO::FileSystem&> BuildDirectoryPathFromSelection() const;
wxTreeCtrl* m_tree_ctrl;

View File

@ -430,7 +430,7 @@ void CISOProperties::CreateGUIControls()
gecko_layout->Add(m_geckocode_panel, 1, wxEXPAND);
gecko_cheat_page->SetSizer(gecko_layout);
if (m_open_iso->GetVolumeType() != DiscIO::Platform::WII_WAD)
if (DiscIO::IsDisc(m_open_iso->GetVolumeType()))
{
m_Notebook->AddPage(new FilesystemPanel(m_Notebook, ID_FILESYSTEM, m_open_iso),
_("Filesystem"));

View File

@ -198,7 +198,7 @@ void InfoPanel::LoadBannerDetails()
{
LoadBannerImage();
const bool is_wii = m_opened_iso->GetVolumeType() != DiscIO::Platform::GAMECUBE_DISC;
const bool is_wii = DiscIO::IsWii(m_opened_iso->GetVolumeType());
ChangeBannerDetails(SConfig::GetInstance().GetCurrentLanguage(is_wii));
}
@ -311,7 +311,7 @@ wxStaticBoxSizer* InfoPanel::CreateBannerDetailsSizer()
wxChoice* InfoPanel::CreateCommentLanguageChoice()
{
const auto languages = m_game_list_item.GetLanguages();
const bool is_wii = m_opened_iso->GetVolumeType() != DiscIO::Platform::GAMECUBE_DISC;
const bool is_wii = DiscIO::IsWii(m_opened_iso->GetVolumeType());
const auto preferred_language = SConfig::GetInstance().GetCurrentLanguage(is_wii);
const int preferred_language_index = FindPreferredLanguageIndex(preferred_language, languages);
const auto choices = GetLanguageChoiceStrings(languages);