Merge pull request #4521 from JosJuice/tgc

Add TGC disc image compatibility
This commit is contained in:
Anthony 2016-12-20 17:45:39 -06:00 committed by GitHub
commit ca91b6df52
19 changed files with 246 additions and 18 deletions

View File

@ -41,7 +41,8 @@ public class FileListItem implements Comparable<FileListItem>
String fileExtension = mPath.substring(extensionStart); String fileExtension = mPath.substring(extensionStart);
// The extensions we care about. // The extensions we care about.
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(".ciso", ".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs")); Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(
".ciso", ".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".tgc", ".wad", ".wbfs"));
// Check that the file has an extension we care about before trying to read out of it. // Check that the file has an extension we care about before trying to read out of it.
if (allowedExtensions.contains(fileExtension.toLowerCase())) if (allowedExtensions.contains(fileExtension.toLowerCase()))

View File

@ -150,7 +150,8 @@ public final class GameDatabase extends SQLiteOpenHelper
null, null,
null); // Order of folders is irrelevant. null); // Order of folders is irrelevant.
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".wad", ".wbfs")); Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(
".ciso", ".dff", ".dol", ".elf", ".gcm", ".gcz", ".iso", ".tgc", ".wad", ".wbfs"));
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. // Possibly overly defensive, but ensures that moveToNext() does not skip a row.
folderCursor.moveToPosition(-1); folderCursor.moveToPosition(-1);

View File

@ -844,8 +844,9 @@ bool SConfig::AutoSetup(EBootBS2 _BootBS2)
std::string Extension; std::string Extension;
SplitPath(m_strFilename, nullptr, nullptr, &Extension); SplitPath(m_strFilename, nullptr, nullptr, &Extension);
if (!strcasecmp(Extension.c_str(), ".gcm") || !strcasecmp(Extension.c_str(), ".iso") || if (!strcasecmp(Extension.c_str(), ".gcm") || !strcasecmp(Extension.c_str(), ".iso") ||
!strcasecmp(Extension.c_str(), ".wbfs") || !strcasecmp(Extension.c_str(), ".ciso") || !strcasecmp(Extension.c_str(), ".tgc") || !strcasecmp(Extension.c_str(), ".wbfs") ||
!strcasecmp(Extension.c_str(), ".gcz") || bootDrive) !strcasecmp(Extension.c_str(), ".ciso") || !strcasecmp(Extension.c_str(), ".gcz") ||
bootDrive)
{ {
m_BootType = BOOT_ISO; m_BootType = BOOT_ISO;
std::unique_ptr<DiscIO::IVolume> pVolume(DiscIO::CreateVolumeFromFilename(m_strFilename)); std::unique_ptr<DiscIO::IVolume> pVolume(DiscIO::CreateVolumeFromFilename(m_strFilename));

View File

@ -17,6 +17,7 @@
#include "DiscIO/CompressedBlob.h" #include "DiscIO/CompressedBlob.h"
#include "DiscIO/DriveBlob.h" #include "DiscIO/DriveBlob.h"
#include "DiscIO/FileBlob.h" #include "DiscIO/FileBlob.h"
#include "DiscIO/TGCBlob.h"
#include "DiscIO/WbfsBlob.h" #include "DiscIO/WbfsBlob.h"
namespace DiscIO namespace DiscIO
@ -188,6 +189,9 @@ std::unique_ptr<IBlobReader> CreateBlobReader(const std::string& filename)
if (IsCISOBlob(filename)) if (IsCISOBlob(filename))
return CISOFileReader::Create(filename); return CISOFileReader::Create(filename);
if (IsTGCBlob(filename))
return TGCFileReader::Create(filename);
// Still here? Assume plain file - since we know it exists due to the File::Exists check above. // Still here? Assume plain file - since we know it exists due to the File::Exists check above.
return PlainFileReader::Create(filename); return PlainFileReader::Create(filename);
} }

View File

@ -30,7 +30,8 @@ enum class BlobType
DIRECTORY, DIRECTORY,
GCZ, GCZ,
CISO, CISO,
WBFS WBFS,
TGC
}; };
class IBlobReader class IBlobReader

View File

@ -10,6 +10,7 @@ set(SRCS Blob.cpp
FileSystemGCWii.cpp FileSystemGCWii.cpp
Filesystem.cpp Filesystem.cpp
NANDContentLoader.cpp NANDContentLoader.cpp
TGCBlob.cpp
Volume.cpp Volume.cpp
VolumeCreator.cpp VolumeCreator.cpp
VolumeDirectory.cpp VolumeDirectory.cpp

View File

@ -46,6 +46,7 @@
<ClCompile Include="Filesystem.cpp" /> <ClCompile Include="Filesystem.cpp" />
<ClCompile Include="FileSystemGCWii.cpp" /> <ClCompile Include="FileSystemGCWii.cpp" />
<ClCompile Include="NANDContentLoader.cpp" /> <ClCompile Include="NANDContentLoader.cpp" />
<ClCompile Include="TGCBlob.cpp" />
<ClCompile Include="Volume.cpp" /> <ClCompile Include="Volume.cpp" />
<ClCompile Include="VolumeCreator.cpp" /> <ClCompile Include="VolumeCreator.cpp" />
<ClCompile Include="VolumeDirectory.cpp" /> <ClCompile Include="VolumeDirectory.cpp" />
@ -67,6 +68,7 @@
<ClInclude Include="Filesystem.h" /> <ClInclude Include="Filesystem.h" />
<ClInclude Include="FileSystemGCWii.h" /> <ClInclude Include="FileSystemGCWii.h" />
<ClInclude Include="NANDContentLoader.h" /> <ClInclude Include="NANDContentLoader.h" />
<ClInclude Include="TGCBlob.h" />
<ClInclude Include="Volume.h" /> <ClInclude Include="Volume.h" />
<ClInclude Include="VolumeCreator.h" /> <ClInclude Include="VolumeCreator.h" />
<ClInclude Include="VolumeDirectory.h" /> <ClInclude Include="VolumeDirectory.h" />

View File

@ -75,6 +75,9 @@
<ClCompile Include="Volume.cpp"> <ClCompile Include="Volume.cpp">
<Filter>Volume</Filter> <Filter>Volume</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="TGCBlob.cpp">
<Filter>Volume\Blob</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="DiscScrubber.h"> <ClInclude Include="DiscScrubber.h">
@ -134,6 +137,9 @@
<ClInclude Include="Enums.h"> <ClInclude Include="Enums.h">
<Filter>Volume</Filter> <Filter>Volume</Filter>
</ClInclude> </ClInclude>
<ClCompile Include="TGCBlob.h">
<Filter>Volume\Blob</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Text Include="CMakeLists.txt" /> <Text Include="CMakeLists.txt" />

View File

@ -0,0 +1,141 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <memory>
#include <string>
#include "Common/CommonFuncs.h"
#include "Common/FileUtil.h"
#include "DiscIO/TGCBlob.h"
namespace
{
template <typename T>
struct Interval
{
T start;
T length;
T End() const { return start + length; }
bool IsEmpty() const { return length == 0; }
};
template <typename T>
void SplitInterval(T split_point, Interval<T> interval, Interval<T>* out_1, Interval<T>* out_2)
{
if (interval.start < split_point)
*out_1 = {interval.start, std::min(interval.length, split_point - interval.start)};
else
*out_1 = {0, 0};
if (interval.End() > split_point)
*out_2 = {std::max(interval.start, split_point),
std::min(interval.length, interval.End() - split_point)};
else
*out_2 = {0, 0};
}
u32 SubtractBE32(u32 minuend_be, u32 subtrahend_le)
{
return Common::swap32(Common::swap32(minuend_be) - subtrahend_le);
}
void Replace8(u64 offset, u64 nbytes, u8* out_ptr, u64 replace_offset, u8 replace_value)
{
if (offset <= replace_offset && offset + nbytes > replace_offset)
out_ptr[replace_offset - offset] = replace_value;
}
void Replace32(u64 offset, u64 nbytes, u8* out_ptr, u64 replace_offset, u32 replace_value)
{
for (size_t i = 0; i < sizeof(u32); ++i)
Replace8(offset, nbytes, out_ptr, replace_offset + i, reinterpret_cast<u8*>(&replace_value)[i]);
}
}
namespace DiscIO
{
bool IsTGCBlob(const std::string& path)
{
File::IOFile file(path, "rb");
TGCHeader header;
return (file.ReadArray(&header, 1) && header.magic == Common::swap32(0xAE0F38A2));
}
std::unique_ptr<TGCFileReader> TGCFileReader::Create(const std::string& path)
{
if (IsTGCBlob(path))
{
File::IOFile file(path, "rb");
return std::unique_ptr<TGCFileReader>(new TGCFileReader(std::move(file)));
}
return nullptr;
}
TGCFileReader::TGCFileReader(File::IOFile&& file) : m_file(std::move(file))
{
m_file.ReadArray(&m_header, 1);
u32 header_size = Common::swap32(m_header.header_size);
m_size = m_file.GetSize();
m_file_offset = Common::swap32(m_header.unknown_important_2) -
Common::swap32(m_header.unknown_important_1) + header_size;
}
u64 TGCFileReader::GetDataSize() const
{
return m_size + Common::swap32(m_header.unknown_important_2) -
Common::swap32(m_header.unknown_important_1);
}
bool TGCFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
{
Interval<u64> first_part;
Interval<u64> empty_part;
Interval<u64> last_part;
u32 header_size = Common::swap32(m_header.header_size);
SplitInterval(m_file_offset, Interval<u64>{offset, nbytes}, &first_part, &last_part);
SplitInterval(m_size - header_size, first_part, &first_part, &empty_part);
// Offsets before m_file_offset are read as usual
if (!first_part.IsEmpty())
{
if (!InternalRead(first_part.start, first_part.length, out_ptr + (first_part.start - offset)))
return false;
}
// If any offset before m_file_offset isn't actually in the file,
// treat it as 0x00 bytes (so e.g. MD5 calculation of the whole disc won't fail)
if (!empty_part.IsEmpty())
std::fill_n(out_ptr + (empty_part.start - offset), empty_part.length, 0);
// Offsets after m_file_offset are read as if they are (offset - m_file_offset)
if (!last_part.IsEmpty())
{
if (!InternalRead(last_part.start - m_file_offset, last_part.length,
out_ptr + (last_part.start - offset)))
return false;
}
return true;
}
bool TGCFileReader::InternalRead(u64 offset, u64 nbytes, u8* out_ptr)
{
u32 header_size = Common::swap32(m_header.header_size);
if (m_file.Seek(offset + header_size, SEEK_SET) && m_file.ReadBytes(out_ptr, nbytes))
{
Replace32(offset, nbytes, out_ptr, 0x420, SubtractBE32(m_header.dol_offset, header_size));
Replace32(offset, nbytes, out_ptr, 0x424, SubtractBE32(m_header.fst_offset, header_size));
return true;
}
m_file.Clear();
return false;
}
} // namespace DiscIO

View File

@ -0,0 +1,64 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <memory>
#include <utility>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "DiscIO/Blob.h"
namespace DiscIO
{
bool IsTGCBlob(const std::string& path);
struct TGCHeader
{
u32 magic;
u32 unknown_1;
u32 header_size;
u32 unknown_2;
u32 fst_offset;
u32 fst_size;
u32 fst_max_size;
u32 dol_offset;
u32 dol_size;
u32 unknown_important_1;
u32 unknown_3;
u32 unknown_4;
u32 unknown_5;
u32 unknown_important_2;
};
class TGCFileReader final : public IBlobReader
{
public:
static std::unique_ptr<TGCFileReader> Create(const std::string& filename);
BlobType GetBlobType() const override { return BlobType::TGC; }
u64 GetDataSize() const override;
u64 GetRawSize() const override { return m_size; }
bool Read(u64 offset, u64 nbytes, u8* out_ptr) override;
private:
TGCFileReader(File::IOFile&& file);
bool InternalRead(u64 offset, u64 nbytes, u8* out_ptr);
File::IOFile m_file;
u64 m_size;
u64 m_file_offset;
// Stored as big endian in memory, regardless of the host endianness
TGCHeader m_header = {};
};
} // namespace DiscIO

View File

@ -54,7 +54,7 @@ void PathDialog::BrowseDefaultGame()
{ {
QString file = QFileDialog::getOpenFileName( QString file = QFileDialog::getOpenFileName(
this, tr("Select a Game"), QDir::currentPath(), this, tr("Select a Game"), QDir::currentPath(),
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.wbfs *.ciso *.gcz *.wad);;" tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad);;"
"All Files (*)")); "All Files (*)"));
if (!file.isEmpty()) if (!file.isEmpty())
{ {

View File

@ -9,10 +9,10 @@
#include "DolphinQt2/GameList/GameTracker.h" #include "DolphinQt2/GameList/GameTracker.h"
#include "DolphinQt2/Settings.h" #include "DolphinQt2/Settings.h"
static const QStringList game_filters{QStringLiteral("*.gcm"), QStringLiteral("*.iso"), static const QStringList game_filters{
QStringLiteral("*.ciso"), QStringLiteral("*.gcz"), QStringLiteral("*.gcm"), QStringLiteral("*.iso"), QStringLiteral("*.tgc"),
QStringLiteral("*.wbfs"), QStringLiteral("*.wad"), QStringLiteral("*.ciso"), QStringLiteral("*.gcz"), QStringLiteral("*.wbfs"),
QStringLiteral("*.elf"), QStringLiteral("*.dol")}; QStringLiteral("*.wad"), QStringLiteral("*.elf"), QStringLiteral("*.dol")};
GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent) GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent)
{ {

View File

@ -13,6 +13,7 @@
<string>gcm</string> <string>gcm</string>
<string>gcz</string> <string>gcz</string>
<string>iso</string> <string>iso</string>
<string>tgc</string>
<string>wad</string> <string>wad</string>
<string>wbfs</string> <string>wbfs</string>
</array> </array>

View File

@ -137,7 +137,7 @@ void MainWindow::Open()
{ {
QString file = QFileDialog::getOpenFileName( QString file = QFileDialog::getOpenFileName(
this, tr("Select a File"), QDir::currentPath(), this, tr("Select a File"), QDir::currentPath(),
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.wbfs *.ciso *.gcz *.wad);;" tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wad);;"
"All Files (*)")); "All Files (*)"));
if (!file.isEmpty()) if (!file.isEmpty())
StartGame(file); StartGame(file);

View File

@ -41,8 +41,8 @@ void PathConfigPane::InitializeGUI()
m_default_iso_filepicker = new wxFilePickerCtrl( m_default_iso_filepicker = new wxFilePickerCtrl(
this, wxID_ANY, wxEmptyString, _("Choose a default ISO:"), this, wxID_ANY, wxEmptyString, _("Choose a default ISO:"),
_("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") + _("All GC/Wii files (elf, dol, gcm, iso, tgc, wbfs, ciso, gcz, wad)") +
wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad|%s", wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.tgc;*.wbfs;*.ciso;*.gcz;*.wad|%s",
wxGetTranslation(wxALL_FILES)), wxGetTranslation(wxALL_FILES)),
wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL); wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL);
m_dvd_root_dirpicker = m_dvd_root_dirpicker =

View File

@ -332,8 +332,9 @@ void CFrame::DoOpen(bool Boot)
wxString path = wxFileSelector( wxString path = wxFileSelector(
_("Select the file to load"), wxEmptyString, wxEmptyString, wxEmptyString, _("Select the file to load"), wxEmptyString, wxEmptyString, wxEmptyString,
_("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") + _("All GC/Wii files (elf, dol, gcm, iso, tgc, wbfs, ciso, gcz, wad)") +
wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad;*.dff;*.tmd|%s", wxString::Format(
"|*.elf;*.dol;*.gcm;*.iso;*.tgc;*.wbfs;*.ciso;*.gcz;*.wad;*.dff;*.tmd|%s",
wxGetTranslation(wxALL_FILES)), wxGetTranslation(wxALL_FILES)),
wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);

View File

@ -566,7 +566,10 @@ void CGameListCtrl::ScanForISOs()
std::vector<std::string> Extensions; std::vector<std::string> Extensions;
if (SConfig::GetInstance().m_ListGC) if (SConfig::GetInstance().m_ListGC)
{
Extensions.push_back(".gcm"); Extensions.push_back(".gcm");
Extensions.push_back(".tgc");
}
if (SConfig::GetInstance().m_ListWii || SConfig::GetInstance().m_ListGC) if (SConfig::GetInstance().m_ListWii || SConfig::GetInstance().m_ListGC)
{ {
Extensions.push_back(".iso"); Extensions.push_back(".iso");

View File

@ -13,6 +13,7 @@
<string>gcm</string> <string>gcm</string>
<string>gcz</string> <string>gcz</string>
<string>iso</string> <string>iso</string>
<string>tgc</string>
<string>wad</string> <string>wad</string>
<string>wbfs</string> <string>wbfs</string>
</array> </array>

View File

@ -140,8 +140,8 @@ void DolphinApp::OnInitCmdLine(wxCmdLineParser& parser)
{wxCMD_LINE_SWITCH, "l", "logger", "Opens the logger", wxCMD_LINE_VAL_NONE, {wxCMD_LINE_SWITCH, "l", "logger", "Opens the logger", wxCMD_LINE_VAL_NONE,
wxCMD_LINE_PARAM_OPTIONAL}, wxCMD_LINE_PARAM_OPTIONAL},
{wxCMD_LINE_OPTION, "e", "exec", {wxCMD_LINE_OPTION, "e", "exec",
"Loads the specified file (ELF, DOL, GCM, ISO, WBFS, CISO, GCZ, WAD)", wxCMD_LINE_VAL_STRING, "Loads the specified file (ELF, DOL, GCM, ISO, TGC, WBFS, CISO, GCZ, WAD)",
wxCMD_LINE_PARAM_OPTIONAL}, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL},
{wxCMD_LINE_SWITCH, "b", "batch", "Exit Dolphin with emulator", wxCMD_LINE_VAL_NONE, {wxCMD_LINE_SWITCH, "b", "batch", "Exit Dolphin with emulator", wxCMD_LINE_VAL_NONE,
wxCMD_LINE_PARAM_OPTIONAL}, wxCMD_LINE_PARAM_OPTIONAL},
{wxCMD_LINE_OPTION, "c", "confirm", "Set Confirm on Stop", wxCMD_LINE_VAL_STRING, {wxCMD_LINE_OPTION, "c", "confirm", "Set Confirm on Stop", wxCMD_LINE_VAL_STRING,