From 23bb029250ddd3b71310c83ee977ba41bf75314f Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Jun 2017 12:26:32 +0200 Subject: [PATCH 01/15] DiscIO: Add convenience methods IsDisc and IsWii for Platform enum --- Source/Core/DiscIO/Enums.cpp | 10 ++++++++++ Source/Core/DiscIO/Enums.h | 2 ++ Source/Core/DolphinWX/ISOFile.cpp | 8 ++++---- Source/Core/DolphinWX/ISOProperties/ISOProperties.cpp | 2 +- Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp | 4 ++-- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Source/Core/DiscIO/Enums.cpp b/Source/Core/DiscIO/Enums.cpp index eae90b34ab..94af6c75a9 100644 --- a/Source/Core/DiscIO/Enums.cpp +++ b/Source/Core/DiscIO/Enums.cpp @@ -11,6 +11,16 @@ namespace DiscIO { +bool IsDisc(Platform volume_type) +{ + return volume_type == Platform::GAMECUBE_DISC || volume_type == Platform::WII_DISC; +} + +bool IsWii(Platform volume_type) +{ + return volume_type == Platform::WII_DISC || volume_type == Platform::WII_WAD; +} + bool IsNTSC(Region region) { return region == Region::NTSC_J || region == Region::NTSC_U || region == Region::NTSC_K; diff --git a/Source/Core/DiscIO/Enums.h b/Source/Core/DiscIO/Enums.h index fb604fd3be..cce235c38e 100644 --- a/Source/Core/DiscIO/Enums.h +++ b/Source/Core/DiscIO/Enums.h @@ -68,6 +68,8 @@ enum class Language LANGUAGE_UNKNOWN }; +bool IsDisc(Platform volume_type); +bool IsWii(Platform volume_type); bool IsNTSC(Region region); Country TypicalCountryForRegion(Region region); Region RegionSwitchGC(u8 country_code); diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp index 7a35cdb10a..910295b7b2 100644 --- a/Source/Core/DolphinWX/ISOFile.cpp +++ b/Source/Core/DolphinWX/ISOFile.cpp @@ -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 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); diff --git a/Source/Core/DolphinWX/ISOProperties/ISOProperties.cpp b/Source/Core/DolphinWX/ISOProperties/ISOProperties.cpp index b05baa7250..5c81f904a5 100644 --- a/Source/Core/DolphinWX/ISOProperties/ISOProperties.cpp +++ b/Source/Core/DolphinWX/ISOProperties/ISOProperties.cpp @@ -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")); diff --git a/Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp b/Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp index 7ac5b27287..36fba6c543 100644 --- a/Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/InfoPanel.cpp @@ -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); From d06b532150bbf969476f73ea93213c65e203558c Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Jun 2017 12:37:30 +0200 Subject: [PATCH 02/15] DiscIO: Move parts of Filesystem to the new file DiscExtractor --- Source/Core/DiscIO/CMakeLists.txt | 1 + Source/Core/DiscIO/DiscExtractor.cpp | 174 ++++++++++++++++++ Source/Core/DiscIO/DiscExtractor.h | 27 +++ Source/Core/DiscIO/DiscIO.vcxproj | 2 + Source/Core/DiscIO/DiscIO.vcxproj.filters | 9 + Source/Core/DiscIO/DiscScrubber.cpp | 9 +- Source/Core/DiscIO/FileSystemGCWii.cpp | 144 --------------- Source/Core/DiscIO/FileSystemGCWii.h | 8 - Source/Core/DiscIO/Filesystem.h | 8 - Source/Core/DiscIO/VolumeGC.cpp | 6 +- Source/Core/DiscIO/VolumeWii.cpp | 5 +- .../ISOProperties/FilesystemPanel.cpp | 53 +++--- 12 files changed, 255 insertions(+), 191 deletions(-) create mode 100644 Source/Core/DiscIO/DiscExtractor.cpp create mode 100644 Source/Core/DiscIO/DiscExtractor.h diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index f54a048f89..b59435efa0 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -3,6 +3,7 @@ set(SRCS CISOBlob.cpp WbfsBlob.cpp CompressedBlob.cpp + DiscExtractor.cpp DiscScrubber.cpp DriveBlob.cpp Enums.cpp diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp new file mode 100644 index 0000000000..403e6f6d0a --- /dev/null +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -0,0 +1,174 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DiscIO/DiscExtractor.h" + +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "DiscIO/Enums.h" +#include "DiscIO/Filesystem.h" +#include "DiscIO/Volume.h" + +namespace DiscIO +{ +u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, + u8* buffer, u64 max_buffer_size, u64 offset_in_file) +{ + if (!file_info || file_info->IsDirectory()) + return 0; + + if (offset_in_file >= file_info->GetSize()) + return 0; + + 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: %" PRIx32, + read_length, offset_in_file, file_info->GetPath().c_str(), file_info->GetOffset(), + file_info->GetSize()); + + volume.Read(file_info->GetOffset() + offset_in_file, read_length, buffer, partition); + + return read_length; +} + +bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, + const std::string& export_filename) +{ + if (!file_info || file_info->IsDirectory()) + return false; + + u64 remaining_size = file_info->GetSize(); + u64 file_offset = file_info->GetOffset(); + + File::IOFile f(export_filename, "wb"); + if (!f) + return false; + + bool result = true; + + while (remaining_size) + { + // Limit read size to 128 MB + size_t read_size = (size_t)std::min(remaining_size, (u64)0x08000000); + + std::vector buffer(read_size); + + result = volume.Read(file_offset, read_size, &buffer[0], partition); + + if (!result) + break; + + f.WriteBytes(&buffer[0], read_size); + + remaining_size -= read_size; + file_offset += read_size; + } + + return result; +} + +bool ExportApploader(const Volume& volume, const Partition& partition, + const std::string& export_folder) +{ + if (!IsDisc(volume.GetVolumeType())) + return false; + + std::optional apploader_size = volume.ReadSwapped(0x2440 + 0x14, partition); + const std::optional trailer_size = volume.ReadSwapped(0x2440 + 0x18, partition); + constexpr u32 header_size = 0x20; + if (!apploader_size || !trailer_size) + return false; + *apploader_size += *trailer_size + header_size; + DEBUG_LOG(DISCIO, "Apploader size -> %x", *apploader_size); + + std::vector buffer(*apploader_size); + if (volume.Read(0x2440, *apploader_size, buffer.data(), partition)) + { + std::string export_name(export_folder + "/apploader.img"); + + File::IOFile apploader_file(export_name, "wb"); + if (apploader_file) + { + apploader_file.WriteBytes(buffer.data(), *apploader_size); + return true; + } + } + + return false; +} + +std::optional GetBootDOLOffset(const Volume& volume, const Partition& partition) +{ + const Platform volume_type = volume.GetVolumeType(); + if (!IsDisc(volume_type)) + return {}; + + std::optional offset = volume.ReadSwapped(0x420, partition); + const u8 offset_shift = volume_type == Platform::WII_DISC ? 2 : 0; + return offset ? static_cast(*offset) << offset_shift : std::optional(); +} + +std::optional GetBootDOLSize(const Volume& volume, const Partition& partition, u64 dol_offset) +{ + if (!IsDisc(volume.GetVolumeType())) + return {}; + + u32 dol_size = 0; + + // Iterate through the 7 code segments + for (u8 i = 0; i < 7; i++) + { + const std::optional offset = volume.ReadSwapped(dol_offset + 0x00 + i * 4, partition); + const std::optional size = volume.ReadSwapped(dol_offset + 0x90 + i * 4, partition); + if (!offset || !size) + return {}; + dol_size = std::max(*offset + *size, dol_size); + } + + // Iterate through the 11 data segments + for (u8 i = 0; i < 11; i++) + { + const std::optional offset = volume.ReadSwapped(dol_offset + 0x1c + i * 4, partition); + const std::optional size = volume.ReadSwapped(dol_offset + 0xac + i * 4, partition); + if (!offset || !size) + return {}; + dol_size = std::max(*offset + *size, dol_size); + } + + return dol_size; +} + +bool ExportDOL(const Volume& volume, const Partition& partition, const std::string& export_folder) +{ + if (!IsDisc(volume.GetVolumeType())) + return false; + + std::optional dol_offset = GetBootDOLOffset(volume, partition); + if (!dol_offset) + return false; + std::optional dol_size = GetBootDOLSize(volume, partition, *dol_offset); + if (!dol_size) + return false; + + std::vector buffer(*dol_size); + if (volume.Read(*dol_offset, *dol_size, buffer.data(), partition)) + { + std::string export_name(export_folder + "/boot.dol"); + + File::IOFile dol_file(export_name, "wb"); + if (dol_file) + { + dol_file.WriteBytes(&buffer[0], *dol_size); + return true; + } + } + + return false; +} + +} // namespace DiscIO diff --git a/Source/Core/DiscIO/DiscExtractor.h b/Source/Core/DiscIO/DiscExtractor.h new file mode 100644 index 0000000000..e5d80a13ce --- /dev/null +++ b/Source/Core/DiscIO/DiscExtractor.h @@ -0,0 +1,27 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "Common/CommonTypes.h" + +namespace DiscIO +{ +class FileInfo; +struct Partition; +class Volume; + +u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, + u8* buffer, u64 max_buffer_size, u64 offset_in_file = 0); +bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, + const std::string& export_filename); +bool ExportApploader(const Volume& volume, const Partition& partition, + const std::string& export_folder); +std::optional GetBootDOLOffset(const Volume& volume, const Partition& partition); +std::optional GetBootDOLSize(const Volume& volume, const Partition& partition, u64 dol_offset); +bool ExportDOL(const Volume& volume, const Partition& partition, const std::string& export_folder); + +} // namespace DiscIO diff --git a/Source/Core/DiscIO/DiscIO.vcxproj b/Source/Core/DiscIO/DiscIO.vcxproj index 1bc3994345..3a978ad262 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj +++ b/Source/Core/DiscIO/DiscIO.vcxproj @@ -39,6 +39,7 @@ + @@ -60,6 +61,7 @@ + diff --git a/Source/Core/DiscIO/DiscIO.vcxproj.filters b/Source/Core/DiscIO/DiscIO.vcxproj.filters index f5c3f00959..3c1f85ca10 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj.filters +++ b/Source/Core/DiscIO/DiscIO.vcxproj.filters @@ -1,6 +1,9 @@  + + {51cdf366-d3fe-464a-9f89-c9f1592a6f1c} + {3873659a-9a30-4a58-af9e-8dad7d7eb627} @@ -75,6 +78,9 @@ Volume\Blob + + DiscExtractor + @@ -134,6 +140,9 @@ Volume\Blob + + DiscExtractor + diff --git a/Source/Core/DiscIO/DiscScrubber.cpp b/Source/Core/DiscIO/DiscScrubber.cpp index 838df208cf..52d907be69 100644 --- a/Source/Core/DiscIO/DiscScrubber.cpp +++ b/Source/Core/DiscIO/DiscScrubber.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "DiscIO/DiscScrubber.h" + #include #include #include @@ -14,7 +16,8 @@ #include "Common/CommonTypes.h" #include "Common/File.h" #include "Common/Logging/Log.h" -#include "DiscIO/DiscScrubber.h" + +#include "DiscIO/DiscExtractor.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" @@ -200,10 +203,10 @@ bool DiscScrubber::ParsePartitionData(const Partition& partition, PartitionHeade 0x2440 + header->apploader_size + header->apploader_trailer_size); // DOL - const std::optional dol_offset = filesystem->GetBootDOLOffset(); + const std::optional dol_offset = GetBootDOLOffset(*m_disc, partition); if (!dol_offset) return false; - const std::optional dol_size = filesystem->GetBootDOLSize(*dol_offset); + const std::optional dol_size = GetBootDOLSize(*m_disc, partition, *dol_offset); if (!dol_size) return false; header->dol_offset = *dol_offset; diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index 615a33888b..cf70c03052 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -330,148 +330,4 @@ std::unique_ptr FileSystemGCWii::FindFileInfo(u64 disc_offset) const 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 (offset_in_file >= file_info->GetSize()) - return 0; - - 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: %" PRIx32, - read_length, offset_in_file, file_info->GetPath().c_str(), file_info->GetOffset(), - file_info->GetSize()); - - m_volume->Read(file_info->GetOffset() + offset_in_file, read_length, buffer, m_partition); - return read_length; -} - -bool FileSystemGCWii::ExportFile(const FileInfo* file_info, - const std::string& export_filename) const -{ - if (!file_info || file_info->IsDirectory()) - return false; - - u64 remaining_size = file_info->GetSize(); - u64 file_offset = file_info->GetOffset(); - - File::IOFile f(export_filename, "wb"); - if (!f) - return false; - - bool result = true; - - while (remaining_size) - { - // Limit read size to 128 MB - size_t read_size = (size_t)std::min(remaining_size, (u64)0x08000000); - - std::vector buffer(read_size); - - result = m_volume->Read(file_offset, read_size, &buffer[0], m_partition); - - if (!result) - break; - - f.WriteBytes(&buffer[0], read_size); - - remaining_size -= read_size; - file_offset += read_size; - } - - return result; -} - -bool FileSystemGCWii::ExportApploader(const std::string& export_folder) const -{ - std::optional apploader_size = m_volume->ReadSwapped(0x2440 + 0x14, m_partition); - const std::optional trailer_size = m_volume->ReadSwapped(0x2440 + 0x18, m_partition); - constexpr u32 header_size = 0x20; - if (!apploader_size || !trailer_size) - return false; - *apploader_size += *trailer_size + header_size; - DEBUG_LOG(DISCIO, "Apploader size -> %x", *apploader_size); - - std::vector buffer(*apploader_size); - if (m_volume->Read(0x2440, *apploader_size, buffer.data(), m_partition)) - { - std::string export_name(export_folder + "/apploader.img"); - - File::IOFile apploader_file(export_name, "wb"); - if (apploader_file) - { - apploader_file.WriteBytes(buffer.data(), *apploader_size); - return true; - } - } - - return false; -} - -std::optional FileSystemGCWii::GetBootDOLOffset() const -{ - std::optional offset = m_volume->ReadSwapped(0x420, m_partition); - return offset ? static_cast(*offset) << m_offset_shift : std::optional(); -} - -std::optional FileSystemGCWii::GetBootDOLSize(u64 dol_offset) const -{ - u32 dol_size = 0; - - // Iterate through the 7 code segments - for (u8 i = 0; i < 7; i++) - { - const std::optional offset = - m_volume->ReadSwapped(dol_offset + 0x00 + i * 4, m_partition); - const std::optional size = - m_volume->ReadSwapped(dol_offset + 0x90 + i * 4, m_partition); - if (!offset || !size) - return {}; - dol_size = std::max(*offset + *size, dol_size); - } - - // Iterate through the 11 data segments - for (u8 i = 0; i < 11; i++) - { - const std::optional offset = - m_volume->ReadSwapped(dol_offset + 0x1c + i * 4, m_partition); - const std::optional size = - m_volume->ReadSwapped(dol_offset + 0xac + i * 4, m_partition); - if (!offset || !size) - return {}; - dol_size = std::max(*offset + *size, dol_size); - } - - return dol_size; -} - -bool FileSystemGCWii::ExportDOL(const std::string& export_folder) const -{ - std::optional dol_offset = GetBootDOLOffset(); - if (!dol_offset) - return false; - std::optional dol_size = GetBootDOLSize(*dol_offset); - if (!dol_size) - return false; - - std::vector buffer(*dol_size); - if (m_volume->Read(*dol_offset, *dol_size, buffer.data(), m_partition)) - { - std::string export_name(export_folder + "/boot.dol"); - - File::IOFile dol_file(export_name, "wb"); - if (dol_file) - { - dol_file.WriteBytes(&buffer[0], *dol_size); - return true; - } - } - - return false; -} - } // namespace diff --git a/Source/Core/DiscIO/FileSystemGCWii.h b/Source/Core/DiscIO/FileSystemGCWii.h index ee69bfed94..8e393642bf 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.h +++ b/Source/Core/DiscIO/FileSystemGCWii.h @@ -93,14 +93,6 @@ public: std::unique_ptr FindFileInfo(const std::string& path) const override; std::unique_ptr FindFileInfo(u64 disc_offset) const override; - u64 ReadFile(const FileInfo* file_info, u8* buffer, u64 max_buffer_size, - u64 offset_in_file) const override; - bool ExportFile(const FileInfo* file_info, const std::string& export_filename) const override; - bool ExportApploader(const std::string& export_folder) const override; - bool ExportDOL(const std::string& export_folder) const override; - std::optional GetBootDOLOffset() const override; - std::optional GetBootDOLSize(u64 dol_offset) const override; - private: bool m_valid; u32 m_offset_shift; diff --git a/Source/Core/DiscIO/Filesystem.h b/Source/Core/DiscIO/Filesystem.h index 879c6fbbdd..a5695958b7 100644 --- a/Source/Core/DiscIO/Filesystem.h +++ b/Source/Core/DiscIO/Filesystem.h @@ -120,14 +120,6 @@ public: // Returns nullptr if not found virtual std::unique_ptr FindFileInfo(u64 disc_offset) const = 0; - virtual u64 ReadFile(const FileInfo* file_info, u8* buffer, u64 max_buffer_size, - u64 offset_in_file = 0) const = 0; - virtual bool ExportFile(const FileInfo* file_info, const std::string& export_filename) const = 0; - virtual bool ExportApploader(const std::string& export_folder) const = 0; - virtual bool ExportDOL(const std::string& export_folder) const = 0; - virtual std::optional GetBootDOLOffset() const = 0; - virtual std::optional GetBootDOLSize(u64 dol_offset) const = 0; - virtual const Partition GetPartition() const { return m_partition; } protected: const Volume* const m_volume; diff --git a/Source/Core/DiscIO/VolumeGC.cpp b/Source/Core/DiscIO/VolumeGC.cpp index af4178682f..1a89917812 100644 --- a/Source/Core/DiscIO/VolumeGC.cpp +++ b/Source/Core/DiscIO/VolumeGC.cpp @@ -16,7 +16,9 @@ #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" + #include "DiscIO/Blob.h" +#include "DiscIO/DiscExtractor.h" #include "DiscIO/Enums.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" @@ -190,8 +192,8 @@ void VolumeGC::LoadBannerFile() const return; } - if (file_size != - file_system->ReadFile(file_info.get(), reinterpret_cast(&banner_file), file_size)) + if (file_size != ReadFile(*this, PARTITION_NONE, file_info.get(), + reinterpret_cast(&banner_file), file_size)) { WARN_LOG(DISCIO, "Could not read opening.bnr."); return; diff --git a/Source/Core/DiscIO/VolumeWii.cpp b/Source/Core/DiscIO/VolumeWii.cpp index 8ccca04409..0379a0c3cd 100644 --- a/Source/Core/DiscIO/VolumeWii.cpp +++ b/Source/Core/DiscIO/VolumeWii.cpp @@ -24,6 +24,7 @@ #include "Common/Swap.h" #include "DiscIO/Blob.h" +#include "DiscIO/DiscExtractor.h" #include "DiscIO/Enums.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" @@ -274,8 +275,8 @@ std::map VolumeWii::GetLongNames() const std::vector opening_bnr(NAMES_TOTAL_BYTES); std::unique_ptr file_info = file_system->FindFileInfo("opening.bnr"); - opening_bnr.resize( - file_system->ReadFile(file_info.get(), opening_bnr.data(), opening_bnr.size(), 0x5C)); + opening_bnr.resize(ReadFile(*this, GetGamePartition(), file_info.get(), opening_bnr.data(), + opening_bnr.size(), 0x5C)); return ReadWiiNames(opening_bnr); } diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index 93ee3bdb9d..c375931aae 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -25,6 +25,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" @@ -261,32 +262,32 @@ void FilesystemPanel::OnExtractDirectories(wxCommandEvent& event) void FilesystemPanel::OnExtractHeaderData(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(selection_data); + const auto* const wii_partition = static_cast(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)); + ret = DiscIO::ExportApploader(*m_opened_iso, partition, WxStrToStr(path)); } else if (event.GetId() == ID_EXTRACT_DOL) { - ret = file_system->ExportDOL(WxStrToStr(path)); + ret = DiscIO::ExportDOL(*m_opened_iso, partition, WxStrToStr(path)); } if (!ret) @@ -366,14 +367,15 @@ void FilesystemPanel::ExtractSingleFile(const wxString& output_file_path) const // 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)); + DiscIO::ExportFile(*m_opened_iso, partition->filesystem->GetPartition(), + 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)); + DiscIO::ExportFile(*m_opened_iso, DiscIO::PARTITION_NONE, + m_filesystem->FindFileInfo(WxStrToStr(selection_file_path)).get(), + WxStrToStr(output_file_path)); } } @@ -400,7 +402,8 @@ void FilesystemPanel::ExtractSingleDirectory(const wxString& output_folder) } static void ExtractDir(const std::string& full_path, const std::string& output_folder, - const DiscIO::FileSystem& file_system, const DiscIO::FileInfo& directory, + const DiscIO::Volume& volume, const DiscIO::Partition partition, + const DiscIO::FileInfo& directory, const std::function& update_progress) { for (const DiscIO::FileInfo& file_info : directory) @@ -416,13 +419,13 @@ static void ExtractDir(const std::string& full_path, const std::string& output_f if (file_info.IsDirectory()) { File::CreateFullPath(output_path); - ExtractDir(path, output_folder, file_system, file_info, update_progress); + ExtractDir(path, output_folder, volume, partition, 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)) + else if (!DiscIO::ExportFile(volume, partition, &file_info, output_path)) ERROR_LOG(DISCIO, "Could not export %s", output_path.c_str()); } } @@ -434,8 +437,8 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, { if (full_path.empty()) // Root { - filesystem.ExportApploader(output_folder); - filesystem.ExportDOL(output_folder); + DiscIO::ExportApploader(*m_opened_iso, filesystem.GetPartition(), output_folder); + DiscIO::ExportDOL(*m_opened_iso, filesystem.GetPartition(), output_folder); } std::unique_ptr file_info = filesystem.FindFileInfo(full_path); @@ -448,14 +451,16 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, 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((static_cast(progress) / static_cast(size)) * 100))); - dialog.Update(progress, wxString::Format(_("Extracting %s"), StrToWxStr(path))); - ++progress; - return dialog.WasCancelled(); - }); + ExtractDir( + full_path, output_folder, *m_opened_iso, filesystem.GetPartition(), *file_info, + [&](const std::string& path) { + dialog.SetTitle(wxString::Format( + "%s : %d%%", dialog_title.c_str(), + static_cast((static_cast(progress) / static_cast(size)) * 100))); + dialog.Update(progress, wxString::Format(_("Extracting %s"), StrToWxStr(path))); + ++progress; + return dialog.WasCancelled(); + }); } wxString FilesystemPanel::BuildFilePathFromSelection() const From a17272c1467a5e655c309a619e839c00e1538acd Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Jun 2017 13:26:04 +0200 Subject: [PATCH 03/15] DiscExtractor: Minor cleanup --- Source/Core/DiscIO/DiscExtractor.cpp | 33 +++++++++++----------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index 403e6f6d0a..e8ef494f4d 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -18,13 +18,10 @@ namespace DiscIO u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, u8* buffer, u64 max_buffer_size, u64 offset_in_file) { - if (!file_info || file_info->IsDirectory()) + if (!file_info || file_info->IsDirectory() || offset_in_file >= file_info->GetSize()) return 0; - if (offset_in_file >= file_info->GetSize()) - return 0; - - u64 read_length = std::min(max_buffer_size, file_info->GetSize() - offset_in_file); + const 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: %" PRIx32, @@ -49,27 +46,23 @@ bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo if (!f) return false; - bool result = true; - while (remaining_size) { // Limit read size to 128 MB - size_t read_size = (size_t)std::min(remaining_size, (u64)0x08000000); + const size_t read_size = static_cast(std::min(remaining_size, 0x08000000)); std::vector buffer(read_size); - result = volume.Read(file_offset, read_size, &buffer[0], partition); + if (!volume.Read(file_offset, read_size, buffer.data(), partition)) + return false; - if (!result) - break; - - f.WriteBytes(&buffer[0], read_size); + f.WriteBytes(buffer.data(), read_size); remaining_size -= read_size; file_offset += read_size; } - return result; + return true; } bool ExportApploader(const Volume& volume, const Partition& partition, @@ -89,7 +82,7 @@ bool ExportApploader(const Volume& volume, const Partition& partition, std::vector buffer(*apploader_size); if (volume.Read(0x2440, *apploader_size, buffer.data(), partition)) { - std::string export_name(export_folder + "/apploader.img"); + const std::string export_name(export_folder + "/apploader.img"); File::IOFile apploader_file(export_name, "wb"); if (apploader_file) @@ -108,7 +101,7 @@ std::optional GetBootDOLOffset(const Volume& volume, const Partition& parti if (!IsDisc(volume_type)) return {}; - std::optional offset = volume.ReadSwapped(0x420, partition); + const std::optional offset = volume.ReadSwapped(0x420, partition); const u8 offset_shift = volume_type == Platform::WII_DISC ? 2 : 0; return offset ? static_cast(*offset) << offset_shift : std::optional(); } @@ -148,22 +141,22 @@ bool ExportDOL(const Volume& volume, const Partition& partition, const std::stri if (!IsDisc(volume.GetVolumeType())) return false; - std::optional dol_offset = GetBootDOLOffset(volume, partition); + const std::optional dol_offset = GetBootDOLOffset(volume, partition); if (!dol_offset) return false; - std::optional dol_size = GetBootDOLSize(volume, partition, *dol_offset); + const std::optional dol_size = GetBootDOLSize(volume, partition, *dol_offset); if (!dol_size) return false; std::vector buffer(*dol_size); if (volume.Read(*dol_offset, *dol_size, buffer.data(), partition)) { - std::string export_name(export_folder + "/boot.dol"); + const std::string export_name(export_folder + "/boot.dol"); File::IOFile dol_file(export_name, "wb"); if (dol_file) { - dol_file.WriteBytes(&buffer[0], *dol_size); + dol_file.WriteBytes(buffer.data(), *dol_size); return true; } } From 1f31390b54f17f7dd5bd8f17f1842d76b9a4697d Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Jun 2017 13:28:14 +0200 Subject: [PATCH 04/15] DiscExtractor: Improve error handling --- Source/Core/DiscIO/DiscExtractor.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index e8ef494f4d..430ab7f55f 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -28,7 +28,8 @@ u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* f read_length, offset_in_file, file_info->GetPath().c_str(), file_info->GetOffset(), file_info->GetSize()); - volume.Read(file_info->GetOffset() + offset_in_file, read_length, buffer, partition); + if (!volume.Read(file_info->GetOffset() + offset_in_file, read_length, buffer, partition)) + return 0; return read_length; } @@ -56,7 +57,8 @@ bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo if (!volume.Read(file_offset, read_size, buffer.data(), partition)) return false; - f.WriteBytes(buffer.data(), read_size); + if (!f.WriteBytes(buffer.data(), read_size)) + return false; remaining_size -= read_size; file_offset += read_size; @@ -85,11 +87,8 @@ bool ExportApploader(const Volume& volume, const Partition& partition, const std::string export_name(export_folder + "/apploader.img"); File::IOFile apploader_file(export_name, "wb"); - if (apploader_file) - { - apploader_file.WriteBytes(buffer.data(), *apploader_size); + if (apploader_file.WriteBytes(buffer.data(), *apploader_size)) return true; - } } return false; @@ -154,11 +153,8 @@ bool ExportDOL(const Volume& volume, const Partition& partition, const std::stri const std::string export_name(export_folder + "/boot.dol"); File::IOFile dol_file(export_name, "wb"); - if (dol_file) - { - dol_file.WriteBytes(buffer.data(), *dol_size); + if (dol_file.WriteBytes(buffer.data(), *dol_size)) return true; - } } return false; From 89c901780edb286df7cfbdce8cb1b38a6cb529e2 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Jun 2017 13:37:33 +0200 Subject: [PATCH 05/15] DiscScrubber: Deduplicate code for writing to file --- Source/Core/DiscIO/DiscExtractor.cpp | 78 +++++++++++----------------- Source/Core/DiscIO/DiscExtractor.h | 2 + 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index 430ab7f55f..8adbcf02fe 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -34,37 +34,41 @@ u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* f return read_length; } +bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size, + const std::string& export_filename) +{ + File::IOFile f(export_filename, "wb"); + if (!f) + return false; + + while (size) + { + // Limit read size to 128 MB + const size_t read_size = static_cast(std::min(size, 0x08000000)); + + std::vector buffer(read_size); + + if (!volume.Read(offset, read_size, buffer.data(), partition)) + return false; + + if (!f.WriteBytes(buffer.data(), read_size)) + return false; + + size -= read_size; + offset += read_size; + } + + return true; +} + bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, const std::string& export_filename) { if (!file_info || file_info->IsDirectory()) return false; - u64 remaining_size = file_info->GetSize(); - u64 file_offset = file_info->GetOffset(); - - File::IOFile f(export_filename, "wb"); - if (!f) - return false; - - while (remaining_size) - { - // Limit read size to 128 MB - const size_t read_size = static_cast(std::min(remaining_size, 0x08000000)); - - std::vector buffer(read_size); - - if (!volume.Read(file_offset, read_size, buffer.data(), partition)) - return false; - - if (!f.WriteBytes(buffer.data(), read_size)) - return false; - - remaining_size -= read_size; - file_offset += read_size; - } - - return true; + return ExportData(volume, partition, file_info->GetOffset(), file_info->GetSize(), + export_filename); } bool ExportApploader(const Volume& volume, const Partition& partition, @@ -81,17 +85,7 @@ bool ExportApploader(const Volume& volume, const Partition& partition, *apploader_size += *trailer_size + header_size; DEBUG_LOG(DISCIO, "Apploader size -> %x", *apploader_size); - std::vector buffer(*apploader_size); - if (volume.Read(0x2440, *apploader_size, buffer.data(), partition)) - { - const std::string export_name(export_folder + "/apploader.img"); - - File::IOFile apploader_file(export_name, "wb"); - if (apploader_file.WriteBytes(buffer.data(), *apploader_size)) - return true; - } - - return false; + return ExportData(volume, partition, 0x2440, *apploader_size, export_folder + "/apploader.img"); } std::optional GetBootDOLOffset(const Volume& volume, const Partition& partition) @@ -147,17 +141,7 @@ bool ExportDOL(const Volume& volume, const Partition& partition, const std::stri if (!dol_size) return false; - std::vector buffer(*dol_size); - if (volume.Read(*dol_offset, *dol_size, buffer.data(), partition)) - { - const std::string export_name(export_folder + "/boot.dol"); - - File::IOFile dol_file(export_name, "wb"); - if (dol_file.WriteBytes(buffer.data(), *dol_size)) - return true; - } - - return false; + return ExportData(volume, partition, *dol_offset, *dol_size, export_folder + "/boot.dol"); } } // namespace DiscIO diff --git a/Source/Core/DiscIO/DiscExtractor.h b/Source/Core/DiscIO/DiscExtractor.h index e5d80a13ce..2d5299e970 100644 --- a/Source/Core/DiscIO/DiscExtractor.h +++ b/Source/Core/DiscIO/DiscExtractor.h @@ -16,6 +16,8 @@ class Volume; u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, u8* buffer, u64 max_buffer_size, u64 offset_in_file = 0); +bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size, + const std::string& export_filename); bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, const std::string& export_filename); bool ExportApploader(const Volume& volume, const Partition& partition, From baf3a3b188cb996a9994c18960e914f292b43841 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 17 Jun 2017 16:53:55 +0200 Subject: [PATCH 06/15] DiscExtractor: Don't hardcode names in ExportApploader and ExportDOL --- Source/Core/DiscIO/DiscExtractor.cpp | 8 ++++---- Source/Core/DiscIO/DiscExtractor.h | 5 +++-- Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp | 9 +++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index 8adbcf02fe..323fe706f2 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -72,7 +72,7 @@ bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo } bool ExportApploader(const Volume& volume, const Partition& partition, - const std::string& export_folder) + const std::string& export_filename) { if (!IsDisc(volume.GetVolumeType())) return false; @@ -85,7 +85,7 @@ bool ExportApploader(const Volume& volume, const Partition& partition, *apploader_size += *trailer_size + header_size; DEBUG_LOG(DISCIO, "Apploader size -> %x", *apploader_size); - return ExportData(volume, partition, 0x2440, *apploader_size, export_folder + "/apploader.img"); + return ExportData(volume, partition, 0x2440, *apploader_size, export_filename); } std::optional GetBootDOLOffset(const Volume& volume, const Partition& partition) @@ -129,7 +129,7 @@ std::optional GetBootDOLSize(const Volume& volume, const Partition& partiti return dol_size; } -bool ExportDOL(const Volume& volume, const Partition& partition, const std::string& export_folder) +bool ExportDOL(const Volume& volume, const Partition& partition, const std::string& export_filename) { if (!IsDisc(volume.GetVolumeType())) return false; @@ -141,7 +141,7 @@ bool ExportDOL(const Volume& volume, const Partition& partition, const std::stri if (!dol_size) return false; - return ExportData(volume, partition, *dol_offset, *dol_size, export_folder + "/boot.dol"); + return ExportData(volume, partition, *dol_offset, *dol_size, export_filename); } } // namespace DiscIO diff --git a/Source/Core/DiscIO/DiscExtractor.h b/Source/Core/DiscIO/DiscExtractor.h index 2d5299e970..6061075b9f 100644 --- a/Source/Core/DiscIO/DiscExtractor.h +++ b/Source/Core/DiscIO/DiscExtractor.h @@ -21,9 +21,10 @@ bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u6 bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, const std::string& export_filename); bool ExportApploader(const Volume& volume, const Partition& partition, - const std::string& export_folder); + const std::string& export_filename); std::optional GetBootDOLOffset(const Volume& volume, const Partition& partition); std::optional GetBootDOLSize(const Volume& volume, const Partition& partition, u64 dol_offset); -bool ExportDOL(const Volume& volume, const Partition& partition, const std::string& export_folder); +bool ExportDOL(const Volume& volume, const Partition& partition, + const std::string& export_filename); } // namespace DiscIO diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index c375931aae..b77cde850e 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -283,11 +283,11 @@ void FilesystemPanel::OnExtractHeaderData(wxCommandEvent& event) bool ret = false; if (event.GetId() == ID_EXTRACT_APPLOADER) { - ret = DiscIO::ExportApploader(*m_opened_iso, partition, WxStrToStr(path)); + ret = DiscIO::ExportApploader(*m_opened_iso, partition, WxStrToStr(path) + "/apploader.img"); } else if (event.GetId() == ID_EXTRACT_DOL) { - ret = DiscIO::ExportDOL(*m_opened_iso, partition, WxStrToStr(path)); + ret = DiscIO::ExportDOL(*m_opened_iso, partition, WxStrToStr(path) + "/boot.dol"); } if (!ret) @@ -437,8 +437,9 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, { if (full_path.empty()) // Root { - DiscIO::ExportApploader(*m_opened_iso, filesystem.GetPartition(), output_folder); - DiscIO::ExportDOL(*m_opened_iso, filesystem.GetPartition(), output_folder); + DiscIO::ExportApploader(*m_opened_iso, filesystem.GetPartition(), + output_folder + "/apploader.img"); + DiscIO::ExportDOL(*m_opened_iso, filesystem.GetPartition(), output_folder + "/boot.dol"); } std::unique_ptr file_info = filesystem.FindFileInfo(full_path); From 5778e8bdba204a1c571eeaf958250f5afcfd8610 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 18 Jun 2017 12:44:32 +0200 Subject: [PATCH 07/15] FilesystemPanel: Refactor partition name stripping --- .../ISOProperties/FilesystemPanel.cpp | 71 +++++++------------ .../DolphinWX/ISOProperties/FilesystemPanel.h | 5 +- 2 files changed, 29 insertions(+), 47 deletions(-) diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index b77cde850e..226540857d 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -356,49 +356,16 @@ void FilesystemPanel::ExtractAllFiles(const wxString& output_folder) 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); - - DiscIO::ExportFile(*m_opened_iso, partition->filesystem->GetPartition(), - partition->filesystem->FindFileInfo(WxStrToStr(selection_file_path)).get(), - WxStrToStr(output_file_path)); - } - else - { - DiscIO::ExportFile(*m_opened_iso, DiscIO::PARTITION_NONE, - m_filesystem->FindFileInfo(WxStrToStr(selection_file_path)).get(), - WxStrToStr(output_file_path)); - } + const std::pair 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); - } + const std::pair path = BuildDirectoryPathFromSelection(); + ExtractDirectories(WxStrToStr(path.first), WxStrToStr(output_folder), path.second); } static void ExtractDir(const std::string& full_path, const std::string& output_folder, @@ -464,7 +431,7 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, }); } -wxString FilesystemPanel::BuildFilePathFromSelection() const +std::pair FilesystemPanel::BuildFilePathFromSelection() const { wxString file_path = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection()); @@ -477,12 +444,26 @@ wxString FilesystemPanel::BuildFilePathFromSelection() const 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 +FilesystemPanel::BuildDirectoryPathFromSelection() const { - wxString directory_path = BuildFilePathFromSelection(); - directory_path += DIR_SEP_CHR; - return directory_path; + const std::pair result = BuildFilePathFromSelection(); + return {result.first + DIR_SEP_CHR, result.second}; } diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h index ae898b8fd5..9aef184262 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h @@ -6,6 +6,7 @@ #include #include +#include #include class GameListItem; @@ -53,8 +54,8 @@ private: void ExtractDirectories(const std::string& full_path, const std::string& output_folder, const DiscIO::FileSystem& filesystem); - wxString BuildFilePathFromSelection() const; - wxString BuildDirectoryPathFromSelection() const; + std::pair BuildFilePathFromSelection() const; + std::pair BuildDirectoryPathFromSelection() const; wxTreeCtrl* m_tree_ctrl; From 6d5199264895f007b9714d448519f5fafec00fa6 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 18 Jun 2017 13:20:54 +0200 Subject: [PATCH 08/15] Move ExtractDir from FilesystemPanel to DiscExtractor --- Source/Core/DiscIO/DiscExtractor.cpp | 32 +++++++++++++++++ Source/Core/DiscIO/DiscExtractor.h | 10 ++++++ .../ISOProperties/FilesystemPanel.cpp | 35 ++----------------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index 323fe706f2..dbd5a7a821 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -71,6 +71,38 @@ bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo export_filename); } +void ExportDirectory(const Volume& volume, const Partition partition, const FileInfo& directory, + bool recursive, const std::string& filesystem_path, + const std::string& export_folder, + const std::function& update_progress) +{ + for (const FileInfo& file_info : directory) + { + const std::string path = + filesystem_path + file_info.GetName() + (file_info.IsDirectory() ? "/" : ""); + const std::string export_path = export_folder + '/' + path; + + if (update_progress(path)) + return; + + DEBUG_LOG(DISCIO, "%s", export_path.c_str()); + + if (!file_info.IsDirectory()) + { + if (File::Exists(export_path)) + NOTICE_LOG(DISCIO, "%s already exists", export_path.c_str()); + else if (!ExportFile(volume, partition, &file_info, export_path)) + ERROR_LOG(DISCIO, "Could not export %s", export_path.c_str()); + } + else if (recursive) + { + File::CreateFullPath(export_path); + ExportDirectory(volume, partition, file_info, recursive, path, export_folder, + update_progress); + } + } +} + bool ExportApploader(const Volume& volume, const Partition& partition, const std::string& export_filename) { diff --git a/Source/Core/DiscIO/DiscExtractor.h b/Source/Core/DiscIO/DiscExtractor.h index 6061075b9f..1372f2a8cd 100644 --- a/Source/Core/DiscIO/DiscExtractor.h +++ b/Source/Core/DiscIO/DiscExtractor.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "Common/CommonTypes.h" @@ -20,6 +21,15 @@ bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u6 const std::string& export_filename); bool ExportFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, const std::string& export_filename); + +// update_progress is called once for each child (file or directory). +// If update_progress returns true, the extraction gets cancelled. +// filesystem_path is supposed to be the path corresponding to the directory argument. +void ExportDirectory(const Volume& volume, const Partition partition, const FileInfo& directory, + bool recursive, const std::string& filesystem_path, + const std::string& export_folder, + const std::function& update_progress); + bool ExportApploader(const Volume& volume, const Partition& partition, const std::string& export_filename); std::optional GetBootDOLOffset(const Volume& volume, const Partition& partition); diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index 226540857d..f0f7cd429a 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -368,36 +367,6 @@ void FilesystemPanel::ExtractSingleDirectory(const wxString& output_folder) ExtractDirectories(WxStrToStr(path.first), WxStrToStr(output_folder), path.second); } -static void ExtractDir(const std::string& full_path, const std::string& output_folder, - const DiscIO::Volume& volume, const DiscIO::Partition partition, - const DiscIO::FileInfo& directory, - const std::function& 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, volume, partition, file_info, update_progress); - } - else - { - if (File::Exists(output_path)) - NOTICE_LOG(DISCIO, "%s already exists", output_path.c_str()); - else if (!DiscIO::ExportFile(volume, partition, &file_info, output_path)) - ERROR_LOG(DISCIO, "Could not export %s", output_path.c_str()); - } - } -} - void FilesystemPanel::ExtractDirectories(const std::string& full_path, const std::string& output_folder, const DiscIO::FileSystem& filesystem) @@ -419,8 +388,8 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH); File::CreateFullPath(output_folder + "/" + full_path); - ExtractDir( - full_path, output_folder, *m_opened_iso, filesystem.GetPartition(), *file_info, + 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(), From 39ff203c1e60cae0f31fc881cd88fa68a203b79f Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 18 Jun 2017 14:17:33 +0200 Subject: [PATCH 09/15] DiscExtractor: Don't create extra folders when extracting a folder Before, if you extracted a directory like /map/Final/Release/, Dolphin would create the nested folders map, Final and Release in the output directory and put the files in Release instead of just putting the files directly in the output directory. --- Source/Core/DiscIO/DiscExtractor.cpp | 12 ++++++------ .../Core/DolphinWX/ISOProperties/FilesystemPanel.cpp | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index dbd5a7a821..9a2dd16487 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -76,11 +76,13 @@ void ExportDirectory(const Volume& volume, const Partition partition, const File const std::string& export_folder, const std::function& update_progress) { + File::CreateFullPath(export_folder + '/'); + for (const FileInfo& file_info : directory) { - const std::string path = - filesystem_path + file_info.GetName() + (file_info.IsDirectory() ? "/" : ""); - const std::string export_path = export_folder + '/' + path; + const std::string name = file_info.GetName() + (file_info.IsDirectory() ? "/" : ""); + const std::string path = filesystem_path + name; + const std::string export_path = export_folder + '/' + name; if (update_progress(path)) return; @@ -96,9 +98,7 @@ void ExportDirectory(const Volume& volume, const Partition partition, const File } else if (recursive) { - File::CreateFullPath(export_path); - ExportDirectory(volume, partition, file_info, recursive, path, export_folder, - update_progress); + ExportDirectory(volume, partition, file_info, recursive, path, export_path, update_progress); } } } diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index f0f7cd429a..3d7f594aec 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -387,7 +387,6 @@ 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); DiscIO::ExportDirectory( *m_opened_iso, filesystem.GetPartition(), *file_info, true, full_path, output_folder, [&](const std::string& path) { From 2ca5f1dec8e4d00159ff3b3b4be90e225f0621d2 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 20 Jun 2017 20:58:18 +0200 Subject: [PATCH 10/15] FilesystemPanel: Handle root correctly in BuildFilePathFromSelection This was unnecessary in the past but is necessary for the next commit. --- .../DolphinWX/ISOProperties/FilesystemPanel.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index 3d7f594aec..1ecadba87e 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -401,15 +401,21 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, std::pair FilesystemPanel::BuildFilePathFromSelection() const { - wxString file_path = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection()); + const wxTreeItemId root_node = m_tree_ctrl->GetRootItem(); + wxTreeItemId node = m_tree_ctrl->GetSelection(); - const auto root_node = m_tree_ctrl->GetRootItem(); - auto node = m_tree_ctrl->GetItemParent(m_tree_ctrl->GetSelection()); + wxString file_path; - while (node != root_node) + 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); + } } if (m_has_partitions) From 0b068d84d58e4e6584672c5e1a632df8ad67df5c Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 20 Jun 2017 15:41:17 +0200 Subject: [PATCH 11/15] FilesystemPanel: Overhaul the right-click menu --- Source/Core/DiscIO/DiscExtractor.cpp | 9 ++ Source/Core/DiscIO/DiscExtractor.h | 3 + .../ISOProperties/FilesystemPanel.cpp | 131 +++++++++--------- .../DolphinWX/ISOProperties/FilesystemPanel.h | 3 +- 4 files changed, 80 insertions(+), 66 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index 9a2dd16487..d0d7500897 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -176,4 +176,13 @@ bool ExportDOL(const Volume& volume, const Partition& partition, const std::stri return ExportData(volume, partition, *dol_offset, *dol_size, export_filename); } +bool ExportSystemData(const Volume& volume, const Partition& partition, + const std::string& export_folder) +{ + bool success = true; + success &= ExportApploader(volume, partition, export_folder + "/apploader.img"); + success &= ExportDOL(volume, partition, export_folder + "/boot.dol"); + return success; +} + } // namespace DiscIO diff --git a/Source/Core/DiscIO/DiscExtractor.h b/Source/Core/DiscIO/DiscExtractor.h index 1372f2a8cd..c2db7f7a46 100644 --- a/Source/Core/DiscIO/DiscExtractor.h +++ b/Source/Core/DiscIO/DiscExtractor.h @@ -37,4 +37,7 @@ std::optional GetBootDOLSize(const Volume& volume, const Partition& partiti bool ExportDOL(const Volume& volume, const Partition& partition, const std::string& export_filename); +bool ExportSystemData(const Volume& volume, const Partition& partition, + const std::string& export_folder); + } // namespace DiscIO diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index 1ecadba87e..24d0d8a3ee 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -124,7 +124,7 @@ 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); @@ -190,36 +190,34 @@ 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_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")); + 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,18 +243,8 @@ 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) @@ -296,6 +284,41 @@ void FilesystemPanel::OnExtractHeaderData(wxCommandEvent& event) } } +void FilesystemPanel::OnExtractAll(wxCommandEvent& event) +{ + const wxString extract_path = wxDirSelector(_("Choose the folder to extract to")); + + if (extract_path.empty()) + return; + + 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(m_tree_ctrl->GetItemData(item)); + ExtractPartition(WxStrToStr(extract_path), *partition->filesystem); + item = m_tree_ctrl->GetNextChild(root, cookie); + } + } + else if (m_has_partitions && !first_item_selected) + { + const auto* const partition = static_cast(m_tree_ctrl->GetItemData(selection)); + ExtractPartition(WxStrToStr(extract_path), *partition->filesystem); + } + else + { + ExtractPartition(WxStrToStr(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,28 +354,6 @@ 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(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 { const std::pair path = BuildFilePathFromSelection(); @@ -371,13 +372,6 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, const std::string& output_folder, const DiscIO::FileSystem& filesystem) { - if (full_path.empty()) // Root - { - DiscIO::ExportApploader(*m_opened_iso, filesystem.GetPartition(), - output_folder + "/apploader.img"); - DiscIO::ExportDOL(*m_opened_iso, filesystem.GetPartition(), output_folder + "/boot.dol"); - } - std::unique_ptr file_info = filesystem.FindFileInfo(full_path); u32 size = file_info->GetTotalChildren(); u32 progress = 0; @@ -399,6 +393,13 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, }); } +void FilesystemPanel::ExtractPartition(const std::string& output_folder, + const DiscIO::FileSystem& filesystem) +{ + ExtractDirectories("", output_folder, filesystem); + DiscIO::ExportSystemData(*m_opened_iso, filesystem.GetPartition(), output_folder); +} + std::pair FilesystemPanel::BuildFilePathFromSelection() const { const wxTreeItemId root_node = m_tree_ctrl->GetRootItem(); diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h index 9aef184262..040c2b79ad 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h @@ -46,13 +46,14 @@ private: void OnExtractFile(wxCommandEvent&); void OnExtractDirectories(wxCommandEvent&); void OnExtractHeaderData(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); std::pair BuildFilePathFromSelection() const; std::pair BuildDirectoryPathFromSelection() const; From 94b18bfb0781e36e074d2d02c8180cc447256cc3 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 20 Jun 2017 15:48:55 +0200 Subject: [PATCH 12/15] FilesystemPanel: Replace Extract Apploader/DOL with Extract System Data Because having one option for each thing to extract is going to be way too many options once I add support for more things to extract. --- .../ISOProperties/FilesystemPanel.cpp | 22 ++++--------------- .../DolphinWX/ISOProperties/FilesystemPanel.h | 5 ++--- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index 24d0d8a3ee..d0da889c47 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -126,8 +126,7 @@ void FilesystemPanel::BindEvents() Bind(wxEVT_MENU, &FilesystemPanel::OnExtractFile, this, ID_EXTRACT_FILE); 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); } @@ -203,10 +202,7 @@ void FilesystemPanel::OnRightClickTree(wxTreeEvent& event) if (image_type == ICON_DISC) { if (!is_parent_of_partitions) - { - menu.Append(ID_EXTRACT_APPLOADER, _("Extract Apploader...")); - menu.Append(ID_EXTRACT_DOL, _("Extract DOL...")); - } + menu.Append(ID_EXTRACT_SYSTEM_DATA, _("Extract System Data...")); if (first_visible_item == selection) menu.Append(ID_EXTRACT_ALL, _("Extract Entire Disc...")); @@ -247,7 +243,7 @@ void FilesystemPanel::OnExtractDirectories(wxCommandEvent& event) ExtractSingleDirectory(extract_path); } -void FilesystemPanel::OnExtractHeaderData(wxCommandEvent& event) +void FilesystemPanel::OnExtractSystemData(wxCommandEvent& event) { const wxString path = wxDirSelector(_("Choose the folder to extract to")); @@ -267,17 +263,7 @@ void FilesystemPanel::OnExtractHeaderData(wxCommandEvent& event) partition = DiscIO::PARTITION_NONE; } - bool ret = false; - if (event.GetId() == ID_EXTRACT_APPLOADER) - { - ret = DiscIO::ExportApploader(*m_opened_iso, partition, WxStrToStr(path) + "/apploader.img"); - } - else if (event.GetId() == ID_EXTRACT_DOL) - { - ret = DiscIO::ExportDOL(*m_opened_iso, partition, WxStrToStr(path) + "/boot.dol"); - } - - if (!ret) + if (!DiscIO::ExportSystemData(*m_opened_iso, partition, WxStrToStr(path))) { WxUtils::ShowErrorDialog( wxString::Format(_("Failed to extract to %s!"), WxStrToStr(path).c_str())); diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h index 040c2b79ad..59da51ce95 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.h @@ -32,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, }; @@ -45,7 +44,7 @@ private: void OnRightClickTree(wxTreeEvent&); void OnExtractFile(wxCommandEvent&); void OnExtractDirectories(wxCommandEvent&); - void OnExtractHeaderData(wxCommandEvent&); + void OnExtractSystemData(wxCommandEvent&); void OnExtractAll(wxCommandEvent&); void OnCheckPartitionIntegrity(wxCommandEvent&); From 1b6506f4e8efb75ad075903a1f28581091a5806b Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 20 Jun 2017 17:31:50 +0200 Subject: [PATCH 13/15] DiscExtractor: Add support for more things to extract --- Source/Core/DiscIO/DiscExtractor.cpp | 143 +++++++++++++++++- Source/Core/DiscIO/DiscExtractor.h | 22 +++ .../ISOProperties/FilesystemPanel.cpp | 2 +- 3 files changed, 164 insertions(+), 3 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index d0d7500897..f5dd28d9a5 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -103,6 +103,92 @@ void ExportDirectory(const Volume& volume, const Partition partition, const File } } +bool ExportWiiUnencryptedHeader(const Volume& volume, const std::string& export_filename) +{ + if (volume.GetVolumeType() != Platform::WII_DISC) + return false; + + return ExportData(volume, PARTITION_NONE, 0, 0x100, export_filename); +} + +bool ExportWiiRegionData(const Volume& volume, const std::string& export_filename) +{ + if (volume.GetVolumeType() != Platform::WII_DISC) + return false; + + return ExportData(volume, PARTITION_NONE, 0x4E000, 0x20, export_filename); +} + +bool ExportTicket(const Volume& volume, const Partition& partition, + const std::string& export_filename) +{ + if (volume.GetVolumeType() != Platform::WII_DISC) + return false; + + return ExportData(volume, PARTITION_NONE, partition.offset, 0x2a4, export_filename); +} + +bool ExportTMD(const Volume& volume, const Partition& partition, const std::string& export_filename) +{ + if (volume.GetVolumeType() != Platform::WII_DISC) + return false; + + std::optional size = volume.ReadSwapped(partition.offset + 0x2a4, PARTITION_NONE); + std::optional offset = volume.ReadSwapped(partition.offset + 0x2a8, PARTITION_NONE); + if (!size || !offset) + return false; + + const u64 actual_offset = partition.offset + (static_cast(*offset) << 2); + return ExportData(volume, PARTITION_NONE, actual_offset, *size, export_filename); +} + +bool ExportCertificateChain(const Volume& volume, const Partition& partition, + const std::string& export_filename) +{ + if (volume.GetVolumeType() != Platform::WII_DISC) + return false; + + std::optional size = volume.ReadSwapped(partition.offset + 0x2ac, PARTITION_NONE); + std::optional offset = volume.ReadSwapped(partition.offset + 0x2b0, PARTITION_NONE); + if (!size || !offset) + return false; + + const u64 actual_offset = partition.offset + (static_cast(*offset) << 2); + return ExportData(volume, PARTITION_NONE, actual_offset, *size, export_filename); +} + +bool ExportH3Hashes(const Volume& volume, const Partition& partition, + const std::string& export_filename) +{ + if (volume.GetVolumeType() != Platform::WII_DISC) + return false; + + std::optional offset = volume.ReadSwapped(partition.offset + 0x2b4, PARTITION_NONE); + if (!offset) + return false; + + const u64 actual_offset = partition.offset + (static_cast(*offset) << 2); + return ExportData(volume, PARTITION_NONE, actual_offset, 0x18000, export_filename); +} + +bool ExportHeader(const Volume& volume, const Partition& partition, + const std::string& export_filename) +{ + if (!IsDisc(volume.GetVolumeType())) + return false; + + return ExportData(volume, partition, 0, 0x440, export_filename); +} + +bool ExportBI2Data(const Volume& volume, const Partition& partition, + const std::string& export_filename) +{ + if (!IsDisc(volume.GetVolumeType())) + return false; + + return ExportData(volume, partition, 0x440, 0x2000, export_filename); +} + bool ExportApploader(const Volume& volume, const Partition& partition, const std::string& export_filename) { @@ -176,12 +262,65 @@ bool ExportDOL(const Volume& volume, const Partition& partition, const std::stri return ExportData(volume, partition, *dol_offset, *dol_size, export_filename); } +std::optional GetFSTOffset(const Volume& volume, const Partition& partition) +{ + const Platform volume_type = volume.GetVolumeType(); + if (!IsDisc(volume_type)) + return {}; + + const std::optional offset = volume.ReadSwapped(0x424, partition); + const u8 offset_shift = volume_type == Platform::WII_DISC ? 2 : 0; + return offset ? static_cast(*offset) << offset_shift : std::optional(); +} + +std::optional GetFSTSize(const Volume& volume, const Partition& partition) +{ + const Platform volume_type = volume.GetVolumeType(); + if (!IsDisc(volume_type)) + return {}; + + const std::optional size = volume.ReadSwapped(0x428, partition); + const u8 offset_shift = volume_type == Platform::WII_DISC ? 2 : 0; + return size ? static_cast(*size) << offset_shift : std::optional(); +} + +bool ExportFST(const Volume& volume, const Partition& partition, const std::string& export_filename) +{ + if (!IsDisc(volume.GetVolumeType())) + return false; + + const std::optional fst_offset = GetFSTOffset(volume, partition); + const std::optional fst_size = GetFSTSize(volume, partition); + if (!fst_offset || !fst_size) + return false; + + return ExportData(volume, partition, *fst_offset, *fst_size, export_filename); +} + bool ExportSystemData(const Volume& volume, const Partition& partition, const std::string& export_folder) { bool success = true; - success &= ExportApploader(volume, partition, export_folder + "/apploader.img"); - success &= ExportDOL(volume, partition, export_folder + "/boot.dol"); + + File::CreateFullPath(export_folder + "/sys/"); + success &= ExportHeader(volume, partition, export_folder + "/sys/boot.bin"); + success &= ExportBI2Data(volume, partition, export_folder + "/sys/bi2.bin"); + success &= ExportApploader(volume, partition, export_folder + "/sys/apploader.img"); + success &= ExportDOL(volume, partition, export_folder + "/sys/main.dol"); + success &= ExportFST(volume, partition, export_folder + "/sys/fst.bin"); + + if (volume.GetVolumeType() == Platform::WII_DISC) + { + File::CreateFullPath(export_folder + "/disc/"); + success &= ExportWiiUnencryptedHeader(volume, export_folder + "/disc/header.bin"); + success &= ExportWiiRegionData(volume, export_folder + "/disc/region.bin"); + + success &= ExportTicket(volume, partition, export_folder + "/ticket.bin"); + success &= ExportTMD(volume, partition, export_folder + "/tmd.bin"); + success &= ExportCertificateChain(volume, partition, export_folder + "/cert.bin"); + success &= ExportH3Hashes(volume, partition, export_folder + "/h3.bin"); + } + return success; } diff --git a/Source/Core/DiscIO/DiscExtractor.h b/Source/Core/DiscIO/DiscExtractor.h index c2db7f7a46..aa4d2ea3c5 100644 --- a/Source/Core/DiscIO/DiscExtractor.h +++ b/Source/Core/DiscIO/DiscExtractor.h @@ -30,12 +30,34 @@ void ExportDirectory(const Volume& volume, const Partition partition, const File const std::string& export_folder, const std::function& update_progress); +// To export everything listed below, you can use ExportSystemData + +bool ExportWiiUnencryptedHeader(const Volume& volume, const std::string& export_filename); +bool ExportWiiRegionData(const Volume& volume, const std::string& export_filename); + +bool ExportTicket(const Volume& volume, const Partition& partition, + const std::string& export_filename); +bool ExportTMD(const Volume& volume, const Partition& partition, + const std::string& export_filename); +bool ExportCertificateChain(const Volume& volume, const Partition& partition, + const std::string& export_filename); +bool ExportH3Hashes(const Volume& volume, const Partition& partition, + const std::string& export_filename); + +bool ExportHeader(const Volume& volume, const Partition& partition, + const std::string& export_filename); +bool ExportBI2Data(const Volume& volume, const Partition& partition, + const std::string& export_filename); bool ExportApploader(const Volume& volume, const Partition& partition, const std::string& export_filename); std::optional GetBootDOLOffset(const Volume& volume, const Partition& partition); std::optional GetBootDOLSize(const Volume& volume, const Partition& partition, u64 dol_offset); bool ExportDOL(const Volume& volume, const Partition& partition, const std::string& export_filename); +std::optional GetFSTOffset(const Volume& volume, const Partition& partition); +std::optional GetFSTSize(const Volume& volume, const Partition& partition); +bool ExportFST(const Volume& volume, const Partition& partition, + const std::string& export_filename); bool ExportSystemData(const Volume& volume, const Partition& partition, const std::string& export_folder); diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index d0da889c47..4369d2ee3f 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -382,7 +382,7 @@ void FilesystemPanel::ExtractDirectories(const std::string& full_path, void FilesystemPanel::ExtractPartition(const std::string& output_folder, const DiscIO::FileSystem& filesystem) { - ExtractDirectories("", output_folder, filesystem); + ExtractDirectories("", output_folder + "/files", filesystem); DiscIO::ExportSystemData(*m_opened_iso, filesystem.GetPartition(), output_folder); } From 478c4fd1f344e747ddda6cd2f4066c2c2af099d5 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 20 Jun 2017 17:44:37 +0200 Subject: [PATCH 14/15] FileSystemGCWii: Use DiscExtractor's FST offset/size functions --- Source/Core/DiscIO/FileSystemGCWii.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Source/Core/DiscIO/FileSystemGCWii.cpp b/Source/Core/DiscIO/FileSystemGCWii.cpp index cf70c03052..bbc89cfc15 100644 --- a/Source/Core/DiscIO/FileSystemGCWii.cpp +++ b/Source/Core/DiscIO/FileSystemGCWii.cpp @@ -18,6 +18,7 @@ #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" +#include "DiscIO/DiscExtractor.h" #include "DiscIO/FileSystemGCWii.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" @@ -194,13 +195,11 @@ FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partitio else return; - const std::optional fst_offset_unshifted = m_volume->ReadSwapped(0x424, m_partition); - const std::optional fst_size_unshifted = m_volume->ReadSwapped(0x428, m_partition); - if (!fst_offset_unshifted || !fst_size_unshifted) + const std::optional fst_offset = GetFSTOffset(*m_volume, m_partition); + const std::optional fst_size = GetFSTSize(*m_volume, m_partition); + if (!fst_offset || !fst_size) return; - const u64 fst_offset = static_cast(*fst_offset_unshifted) << m_offset_shift; - const u64 fst_size = static_cast(*fst_size_unshifted) << m_offset_shift; - if (fst_size < FST_ENTRY_SIZE) + if (*fst_size < FST_ENTRY_SIZE) { ERROR_LOG(DISCIO, "File system is too small"); return; @@ -209,7 +208,7 @@ FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partitio // 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) + 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. @@ -219,8 +218,8 @@ FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partitio } // 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)) + 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; @@ -234,20 +233,20 @@ FileSystemGCWii::FileSystemGCWii(const Volume* volume, const Partition& partitio return; } - if (FST_ENTRY_SIZE * m_root.GetSize() > fst_size) + 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) + // If the FST's final byte isn't 0, FileInfoGCWii::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); + m_valid = m_root.IsValid(*fst_size, m_root); } FileSystemGCWii::~FileSystemGCWii() = default; From a59edfe8cf4c3dd9275058ca1acd88019a3f6abf Mon Sep 17 00:00:00 2001 From: JosJuice Date: Tue, 20 Jun 2017 21:51:40 +0200 Subject: [PATCH 15/15] FilesystemPanel: Put partitions in separate folders when extracting all partitions --- Source/Core/DiscIO/DiscExtractor.cpp | 27 +++++++++++++++++++ Source/Core/DiscIO/DiscExtractor.h | 2 ++ Source/Core/DiscIO/Volume.h | 1 + Source/Core/DiscIO/VolumeWii.cpp | 18 +++++++++---- Source/Core/DiscIO/VolumeWii.h | 2 ++ .../ISOProperties/FilesystemPanel.cpp | 14 +++++++--- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/Source/Core/DiscIO/DiscExtractor.cpp b/Source/Core/DiscIO/DiscExtractor.cpp index f5dd28d9a5..b56f120a67 100644 --- a/Source/Core/DiscIO/DiscExtractor.cpp +++ b/Source/Core/DiscIO/DiscExtractor.cpp @@ -6,15 +6,42 @@ #include #include +#include #include #include "Common/CommonTypes.h" +#include "Common/StringUtil.h" #include "DiscIO/Enums.h" #include "DiscIO/Filesystem.h" #include "DiscIO/Volume.h" namespace DiscIO { +std::string DirectoryNameForPartitionType(u32 partition_type) +{ + switch (partition_type) + { + case 0: + return "DATA"; + case 1: + return "UPDATE"; + case 2: + return "CHANNEL"; + default: + const std::string type_as_game_id{static_cast((partition_type >> 24) & 0xFF), + static_cast((partition_type >> 16) & 0xFF), + static_cast((partition_type >> 8) & 0xFF), + static_cast(partition_type & 0xFF)}; + if (std::all_of(type_as_game_id.cbegin(), type_as_game_id.cend(), + [](char c) { return std::isprint(c, std::locale::classic()); })) + { + return "P-" + type_as_game_id; + } + + return StringFromFormat("P%u", partition_type); + } +} + u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, u8* buffer, u64 max_buffer_size, u64 offset_in_file) { diff --git a/Source/Core/DiscIO/DiscExtractor.h b/Source/Core/DiscIO/DiscExtractor.h index aa4d2ea3c5..b3a1332c4b 100644 --- a/Source/Core/DiscIO/DiscExtractor.h +++ b/Source/Core/DiscIO/DiscExtractor.h @@ -15,6 +15,8 @@ class FileInfo; struct Partition; class Volume; +std::string DirectoryNameForPartitionType(u32 partition_type); + u64 ReadFile(const Volume& volume, const Partition& partition, const FileInfo* file_info, u8* buffer, u64 max_buffer_size, u64 offset_in_file = 0); bool ExportData(const Volume& volume, const Partition& partition, u64 offset, u64 size, diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h index bbdffaa618..e0978048ab 100644 --- a/Source/Core/DiscIO/Volume.h +++ b/Source/Core/DiscIO/Volume.h @@ -53,6 +53,7 @@ public: } virtual std::vector GetPartitions() const { return {}; } virtual Partition GetGamePartition() const { return PARTITION_NONE; } + virtual std::optional GetPartitionType(const Partition& partition) const { return {}; } std::optional GetTitleID() const { return GetTitleID(GetGamePartition()); } virtual std::optional GetTitleID(const Partition& partition) const { return {}; } virtual const IOS::ES::TicketReader& GetTicket(const Partition& partition) const diff --git a/Source/Core/DiscIO/VolumeWii.cpp b/Source/Core/DiscIO/VolumeWii.cpp index 0379a0c3cd..93c7133036 100644 --- a/Source/Core/DiscIO/VolumeWii.cpp +++ b/Source/Core/DiscIO/VolumeWii.cpp @@ -67,10 +67,11 @@ VolumeWii::VolumeWii(std::unique_ptr reader) continue; const u64 partition_offset = static_cast(*read_buffer) << 2; - // Check if this is the game partition - const bool is_game_partition = - m_game_partition == PARTITION_NONE && - m_pReader->ReadSwapped(partition_table_offset + (i * 8) + 4) == u32(0); + // Read the partition type + const std::optional partition_type = + m_pReader->ReadSwapped(partition_table_offset + (i * 8) + 4); + if (!partition_type) + continue; // Read ticket std::vector ticket_buffer(sizeof(IOS::ES::Ticket)); @@ -106,10 +107,11 @@ VolumeWii::VolumeWii(std::unique_ptr reader) // We've read everything. Time to store it! (The reason we don't store anything // earlier is because we want to be able to skip adding the partition if an error occurs.) const Partition partition(partition_offset); + m_partition_types[partition] = *partition_type; m_partition_keys[partition] = std::move(aes_context); m_partition_tickets[partition] = std::move(ticket); m_partition_tmds[partition] = std::move(tmd); - if (is_game_partition) + if (m_game_partition == PARTITION_NONE && *partition_type == 0) m_game_partition = partition; } } @@ -185,6 +187,12 @@ Partition VolumeWii::GetGamePartition() const return m_game_partition; } +std::optional VolumeWii::GetPartitionType(const Partition& partition) const +{ + auto it = m_partition_types.find(partition); + return it != m_partition_types.end() ? it->second : std::optional(); +} + std::optional VolumeWii::GetTitleID(const Partition& partition) const { const IOS::ES::TicketReader& ticket = GetTicket(partition); diff --git a/Source/Core/DiscIO/VolumeWii.h b/Source/Core/DiscIO/VolumeWii.h index 38dc5c4bc2..780bdb6dd4 100644 --- a/Source/Core/DiscIO/VolumeWii.h +++ b/Source/Core/DiscIO/VolumeWii.h @@ -34,6 +34,7 @@ public: bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, const Partition& partition) const override; std::vector GetPartitions() const override; Partition GetGamePartition() const override; + std::optional GetPartitionType(const Partition& partition) const override; std::optional GetTitleID(const Partition& partition) const override; const IOS::ES::TicketReader& GetTicket(const Partition& partition) const override; const IOS::ES::TMDReader& GetTMD(const Partition& partition) const override; @@ -64,6 +65,7 @@ public: private: std::unique_ptr m_pReader; + std::map m_partition_types; std::map> m_partition_keys; std::map m_partition_tickets; std::map m_partition_tmds; diff --git a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp index 4369d2ee3f..9888036d2a 100644 --- a/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp +++ b/Source/Core/DolphinWX/ISOProperties/FilesystemPanel.cpp @@ -277,6 +277,8 @@ void FilesystemPanel::OnExtractAll(wxCommandEvent& event) 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; @@ -290,18 +292,24 @@ void FilesystemPanel::OnExtractAll(wxCommandEvent& event) while (item.IsOk()) { const auto* const partition = static_cast(m_tree_ctrl->GetItemData(item)); - ExtractPartition(WxStrToStr(extract_path), *partition->filesystem); + const std::optional 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(m_tree_ctrl->GetItemData(selection)); - ExtractPartition(WxStrToStr(extract_path), *partition->filesystem); + ExtractPartition(std_extract_path, *partition->filesystem); } else { - ExtractPartition(WxStrToStr(extract_path), *m_filesystem); + ExtractPartition(std_extract_path, *m_filesystem); } }