forked from dolphin-emu/dolphin
		
	
		
			
				
	
	
		
			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;
 | 
						|
}
 |