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

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

View File

@ -3,6 +3,7 @@ set(SRCS
CISOBlob.cpp
WbfsBlob.cpp
CompressedBlob.cpp
DiscExtractor.cpp
DiscScrubber.cpp
DriveBlob.cpp
Enums.cpp

View File

@ -0,0 +1,354 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DiscIO/DiscExtractor.h"
#include <algorithm>
#include <cinttypes>
#include <locale>
#include <optional>
#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<char>((partition_type >> 24) & 0xFF),
static_cast<char>((partition_type >> 16) & 0xFF),
static_cast<char>((partition_type >> 8) & 0xFF),
static_cast<char>(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)
{
if (!file_info || file_info->IsDirectory() || offset_in_file >= file_info->GetSize())
return 0;
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,
read_length, offset_in_file, file_info->GetPath().c_str(), file_info->GetOffset(),
file_info->GetSize());
if (!volume.Read(file_info->GetOffset() + offset_in_file, read_length, buffer, partition))
return 0;
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<size_t>(std::min<u64>(size, 0x08000000));
std::vector<u8> 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;
return ExportData(volume, partition, file_info->GetOffset(), file_info->GetSize(),
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<bool(const std::string& path)>& update_progress)
{
File::CreateFullPath(export_folder + '/');
for (const FileInfo& file_info : directory)
{
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;
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)
{
ExportDirectory(volume, partition, file_info, recursive, path, export_path, update_progress);
}
}
}
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<u32> size = volume.ReadSwapped<u32>(partition.offset + 0x2a4, PARTITION_NONE);
std::optional<u32> offset = volume.ReadSwapped<u32>(partition.offset + 0x2a8, PARTITION_NONE);
if (!size || !offset)
return false;
const u64 actual_offset = partition.offset + (static_cast<u64>(*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<u32> size = volume.ReadSwapped<u32>(partition.offset + 0x2ac, PARTITION_NONE);
std::optional<u32> offset = volume.ReadSwapped<u32>(partition.offset + 0x2b0, PARTITION_NONE);
if (!size || !offset)
return false;
const u64 actual_offset = partition.offset + (static_cast<u64>(*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<u32> offset = volume.ReadSwapped<u32>(partition.offset + 0x2b4, PARTITION_NONE);
if (!offset)
return false;
const u64 actual_offset = partition.offset + (static_cast<u64>(*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)
{
if (!IsDisc(volume.GetVolumeType()))
return false;
std::optional<u32> apploader_size = volume.ReadSwapped<u32>(0x2440 + 0x14, partition);
const std::optional<u32> trailer_size = volume.ReadSwapped<u32>(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);
return ExportData(volume, partition, 0x2440, *apploader_size, export_filename);
}
std::optional<u64> GetBootDOLOffset(const Volume& volume, const Partition& partition)
{
const Platform volume_type = volume.GetVolumeType();
if (!IsDisc(volume_type))
return {};
const std::optional<u32> offset = volume.ReadSwapped<u32>(0x420, partition);
const u8 offset_shift = volume_type == Platform::WII_DISC ? 2 : 0;
return offset ? static_cast<u64>(*offset) << offset_shift : std::optional<u64>();
}
std::optional<u32> 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<u32> offset = volume.ReadSwapped<u32>(dol_offset + 0x00 + i * 4, partition);
const std::optional<u32> size = volume.ReadSwapped<u32>(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<u32> offset = volume.ReadSwapped<u32>(dol_offset + 0x1c + i * 4, partition);
const std::optional<u32> size = volume.ReadSwapped<u32>(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_filename)
{
if (!IsDisc(volume.GetVolumeType()))
return false;
const std::optional<u64> dol_offset = GetBootDOLOffset(volume, partition);
if (!dol_offset)
return false;
const std::optional<u32> dol_size = GetBootDOLSize(volume, partition, *dol_offset);
if (!dol_size)
return false;
return ExportData(volume, partition, *dol_offset, *dol_size, export_filename);
}
std::optional<u64> GetFSTOffset(const Volume& volume, const Partition& partition)
{
const Platform volume_type = volume.GetVolumeType();
if (!IsDisc(volume_type))
return {};
const std::optional<u32> offset = volume.ReadSwapped<u32>(0x424, partition);
const u8 offset_shift = volume_type == Platform::WII_DISC ? 2 : 0;
return offset ? static_cast<u64>(*offset) << offset_shift : std::optional<u64>();
}
std::optional<u64> GetFSTSize(const Volume& volume, const Partition& partition)
{
const Platform volume_type = volume.GetVolumeType();
if (!IsDisc(volume_type))
return {};
const std::optional<u32> size = volume.ReadSwapped<u64>(0x428, partition);
const u8 offset_shift = volume_type == Platform::WII_DISC ? 2 : 0;
return size ? static_cast<u64>(*size) << offset_shift : std::optional<u64>();
}
bool ExportFST(const Volume& volume, const Partition& partition, const std::string& export_filename)
{
if (!IsDisc(volume.GetVolumeType()))
return false;
const std::optional<u64> fst_offset = GetFSTOffset(volume, partition);
const std::optional<u64> 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;
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;
}
} // namespace DiscIO

View File

@ -0,0 +1,67 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <optional>
#include "Common/CommonTypes.h"
namespace DiscIO
{
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,
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<bool(const std::string& path)>& 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<u64> GetBootDOLOffset(const Volume& volume, const Partition& partition);
std::optional<u32> 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<u64> GetFSTOffset(const Volume& volume, const Partition& partition);
std::optional<u64> 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);
} // namespace DiscIO

View File

@ -39,6 +39,7 @@
<ClCompile Include="Blob.cpp" />
<ClCompile Include="CISOBlob.cpp" />
<ClCompile Include="CompressedBlob.cpp" />
<ClCompile Include="DiscExtractor.cpp" />
<ClCompile Include="DiscScrubber.cpp" />
<ClCompile Include="DriveBlob.cpp" />
<ClCompile Include="Enums.cpp" />
@ -60,6 +61,7 @@
<ClInclude Include="Blob.h" />
<ClInclude Include="CISOBlob.h" />
<ClInclude Include="CompressedBlob.h" />
<ClInclude Include="DiscExtractor.h" />
<ClInclude Include="DiscScrubber.h" />
<ClInclude Include="DriveBlob.h" />
<ClInclude Include="Enums.h" />

View File

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="DiscExtractor">
<UniqueIdentifier>{51cdf366-d3fe-464a-9f89-c9f1592a6f1c}</UniqueIdentifier>
</Filter>
<Filter Include="DiscScrubber">
<UniqueIdentifier>{3873659a-9a30-4a58-af9e-8dad7d7eb627}</UniqueIdentifier>
</Filter>
@ -75,6 +78,9 @@
<ClCompile Include="TGCBlob.cpp">
<Filter>Volume\Blob</Filter>
</ClCompile>
<ClCompile Include="DiscExtractor.cpp">
<Filter>DiscExtractor</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="DiscScrubber.h">
@ -134,6 +140,9 @@
<ClInclude Include="TGCBlob.h">
<Filter>Volume\Blob</Filter>
</ClInclude>
<ClInclude Include="DiscExtractor.h">
<Filter>DiscExtractor</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DiscIO/DiscScrubber.h"
#include <algorithm>
#include <cinttypes>
#include <cstddef>
@ -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<u64> dol_offset = filesystem->GetBootDOLOffset();
const std::optional<u64> dol_offset = GetBootDOLOffset(*m_disc, partition);
if (!dol_offset)
return false;
const std::optional<u64> dol_size = filesystem->GetBootDOLSize(*dol_offset);
const std::optional<u64> dol_size = GetBootDOLSize(*m_disc, partition, *dol_offset);
if (!dol_size)
return false;
header->dol_offset = *dol_offset;

View File

@ -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;

View File

@ -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);

View File

@ -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<u32> fst_offset_unshifted = m_volume->ReadSwapped<u32>(0x424, m_partition);
const std::optional<u32> fst_size_unshifted = m_volume->ReadSwapped<u32>(0x428, m_partition);
if (!fst_offset_unshifted || !fst_size_unshifted)
const std::optional<u64> fst_offset = GetFSTOffset(*m_volume, m_partition);
const std::optional<u64> fst_size = GetFSTSize(*m_volume, m_partition);
if (!fst_offset || !fst_size)
return;
const u64 fst_offset = static_cast<u64>(*fst_offset_unshifted) << m_offset_shift;
const u64 fst_size = static_cast<u64>(*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;
@ -330,148 +329,4 @@ std::unique_ptr<FileInfo> 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<u8> 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<u32> apploader_size = m_volume->ReadSwapped<u32>(0x2440 + 0x14, m_partition);
const std::optional<u32> trailer_size = m_volume->ReadSwapped<u32>(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<u8> 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<u64> FileSystemGCWii::GetBootDOLOffset() const
{
std::optional<u32> offset = m_volume->ReadSwapped<u32>(0x420, m_partition);
return offset ? static_cast<u64>(*offset) << m_offset_shift : std::optional<u64>();
}
std::optional<u32> 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<u32> offset =
m_volume->ReadSwapped<u32>(dol_offset + 0x00 + i * 4, m_partition);
const std::optional<u32> size =
m_volume->ReadSwapped<u32>(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<u32> offset =
m_volume->ReadSwapped<u32>(dol_offset + 0x1c + i * 4, m_partition);
const std::optional<u32> size =
m_volume->ReadSwapped<u32>(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<u64> dol_offset = GetBootDOLOffset();
if (!dol_offset)
return false;
std::optional<u32> dol_size = GetBootDOLSize(*dol_offset);
if (!dol_size)
return false;
std::vector<u8> 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

View File

@ -93,14 +93,6 @@ public:
std::unique_ptr<FileInfo> FindFileInfo(const std::string& path) const override;
std::unique_ptr<FileInfo> 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<u64> GetBootDOLOffset() const override;
std::optional<u32> GetBootDOLSize(u64 dol_offset) const override;
private:
bool m_valid;
u32 m_offset_shift;

View File

@ -120,14 +120,6 @@ public:
// Returns nullptr if not found
virtual std::unique_ptr<FileInfo> 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<u64> GetBootDOLOffset() const = 0;
virtual std::optional<u32> GetBootDOLSize(u64 dol_offset) const = 0;
virtual const Partition GetPartition() const { return m_partition; }
protected:
const Volume* const m_volume;

View File

@ -53,6 +53,7 @@ public:
}
virtual std::vector<Partition> GetPartitions() const { return {}; }
virtual Partition GetGamePartition() const { return PARTITION_NONE; }
virtual std::optional<u32> GetPartitionType(const Partition& partition) const { return {}; }
std::optional<u64> GetTitleID() const { return GetTitleID(GetGamePartition()); }
virtual std::optional<u64> GetTitleID(const Partition& partition) const { return {}; }
virtual const IOS::ES::TicketReader& GetTicket(const Partition& partition) const

View File

@ -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<u8*>(&banner_file), file_size))
if (file_size != ReadFile(*this, PARTITION_NONE, file_info.get(),
reinterpret_cast<u8*>(&banner_file), file_size))
{
WARN_LOG(DISCIO, "Could not read opening.bnr.");
return;

View File

@ -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"
@ -66,10 +67,11 @@ VolumeWii::VolumeWii(std::unique_ptr<BlobReader> reader)
continue;
const u64 partition_offset = static_cast<u64>(*read_buffer) << 2;
// Check if this is the game partition
const bool is_game_partition =
m_game_partition == PARTITION_NONE &&
m_pReader->ReadSwapped<u32>(partition_table_offset + (i * 8) + 4) == u32(0);
// Read the partition type
const std::optional<u32> partition_type =
m_pReader->ReadSwapped<u32>(partition_table_offset + (i * 8) + 4);
if (!partition_type)
continue;
// Read ticket
std::vector<u8> ticket_buffer(sizeof(IOS::ES::Ticket));
@ -105,10 +107,11 @@ VolumeWii::VolumeWii(std::unique_ptr<BlobReader> 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;
}
}
@ -184,6 +187,12 @@ Partition VolumeWii::GetGamePartition() const
return m_game_partition;
}
std::optional<u32> VolumeWii::GetPartitionType(const Partition& partition) const
{
auto it = m_partition_types.find(partition);
return it != m_partition_types.end() ? it->second : std::optional<u32>();
}
std::optional<u64> VolumeWii::GetTitleID(const Partition& partition) const
{
const IOS::ES::TicketReader& ticket = GetTicket(partition);
@ -274,8 +283,8 @@ std::map<Language, std::string> VolumeWii::GetLongNames() const
std::vector<u8> opening_bnr(NAMES_TOTAL_BYTES);
std::unique_ptr<FileInfo> 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);
}

View File

@ -34,6 +34,7 @@ public:
bool Read(u64 _Offset, u64 _Length, u8* _pBuffer, const Partition& partition) const override;
std::vector<Partition> GetPartitions() const override;
Partition GetGamePartition() const override;
std::optional<u32> GetPartitionType(const Partition& partition) const override;
std::optional<u64> 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<BlobReader> m_pReader;
std::map<Partition, u32> m_partition_types;
std::map<Partition, std::unique_ptr<mbedtls_aes_context>> m_partition_keys;
std::map<Partition, IOS::ES::TicketReader> m_partition_tickets;
std::map<Partition, IOS::ES::TMDReader> m_partition_tmds;

View File

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

View File

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

View File

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

View File

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

View File

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