summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2016-12-17 14:48:49 +0100
committerJosJuice <josjuice@gmail.com>2016-12-18 18:57:36 +0100
commit9bd514ed1cd02cc0b8c8f22affecaae1892da15f (patch)
treedd9195dd1cef94686cc2f4d38b876135de0eeef1 /Source/Core
parent49384208cfce23d6b9ff12e4a16b1fb98da7735e (diff)
Add TGC disc image compatibility
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/ConfigManager.cpp5
-rw-r--r--Source/Core/DiscIO/Blob.cpp4
-rw-r--r--Source/Core/DiscIO/Blob.h3
-rw-r--r--Source/Core/DiscIO/CMakeLists.txt1
-rw-r--r--Source/Core/DiscIO/DiscIO.vcxproj2
-rw-r--r--Source/Core/DiscIO/DiscIO.vcxproj.filters6
-rw-r--r--Source/Core/DiscIO/TGCBlob.cpp141
-rw-r--r--Source/Core/DiscIO/TGCBlob.h64
-rw-r--r--Source/Core/DolphinQt2/Config/PathDialog.cpp2
-rw-r--r--Source/Core/DolphinQt2/GameList/GameTracker.cpp8
-rw-r--r--Source/Core/DolphinQt2/Info.plist.in1
-rw-r--r--Source/Core/DolphinQt2/MainWindow.cpp2
-rw-r--r--Source/Core/DolphinWX/Config/PathConfigPane.cpp4
-rw-r--r--Source/Core/DolphinWX/FrameTools.cpp7
-rw-r--r--Source/Core/DolphinWX/GameListCtrl.cpp3
-rw-r--r--Source/Core/DolphinWX/Info.plist.in1
-rw-r--r--Source/Core/DolphinWX/Main.cpp4
17 files changed, 242 insertions, 16 deletions
diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp
index 2a594c2c25..e19ecc2ccb 100644
--- a/Source/Core/Core/ConfigManager.cpp
+++ b/Source/Core/Core/ConfigManager.cpp
@@ -842,8 +842,9 @@ bool SConfig::AutoSetup(EBootBS2 _BootBS2)
std::string Extension;
SplitPath(m_strFilename, nullptr, nullptr, &Extension);
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(), ".gcz") || bootDrive)
+ !strcasecmp(Extension.c_str(), ".tgc") || !strcasecmp(Extension.c_str(), ".wbfs") ||
+ !strcasecmp(Extension.c_str(), ".ciso") || !strcasecmp(Extension.c_str(), ".gcz") ||
+ bootDrive)
{
m_BootType = BOOT_ISO;
std::unique_ptr<DiscIO::IVolume> pVolume(DiscIO::CreateVolumeFromFilename(m_strFilename));
diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp
index a3d9d8deb8..d7aad9332a 100644
--- a/Source/Core/DiscIO/Blob.cpp
+++ b/Source/Core/DiscIO/Blob.cpp
@@ -17,6 +17,7 @@
#include "DiscIO/CompressedBlob.h"
#include "DiscIO/DriveBlob.h"
#include "DiscIO/FileBlob.h"
+#include "DiscIO/TGCBlob.h"
#include "DiscIO/WbfsBlob.h"
namespace DiscIO
@@ -188,6 +189,9 @@ std::unique_ptr<IBlobReader> CreateBlobReader(const std::string& filename)
if (IsCISOBlob(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.
return PlainFileReader::Create(filename);
}
diff --git a/Source/Core/DiscIO/Blob.h b/Source/Core/DiscIO/Blob.h
index de7bbbbc4e..fa068c33ef 100644
--- a/Source/Core/DiscIO/Blob.h
+++ b/Source/Core/DiscIO/Blob.h
@@ -30,7 +30,8 @@ enum class BlobType
DIRECTORY,
GCZ,
CISO,
- WBFS
+ WBFS,
+ TGC
};
class IBlobReader
diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt
index 56f5b92314..e7c88c6af0 100644
--- a/Source/Core/DiscIO/CMakeLists.txt
+++ b/Source/Core/DiscIO/CMakeLists.txt
@@ -10,6 +10,7 @@ set(SRCS Blob.cpp
FileSystemGCWii.cpp
Filesystem.cpp
NANDContentLoader.cpp
+ TGCBlob.cpp
Volume.cpp
VolumeCreator.cpp
VolumeDirectory.cpp
diff --git a/Source/Core/DiscIO/DiscIO.vcxproj b/Source/Core/DiscIO/DiscIO.vcxproj
index 107c6e05bf..db5ef8d44e 100644
--- a/Source/Core/DiscIO/DiscIO.vcxproj
+++ b/Source/Core/DiscIO/DiscIO.vcxproj
@@ -46,6 +46,7 @@
<ClCompile Include="Filesystem.cpp" />
<ClCompile Include="FileSystemGCWii.cpp" />
<ClCompile Include="NANDContentLoader.cpp" />
+ <ClCompile Include="TGCBlob.cpp" />
<ClCompile Include="Volume.cpp" />
<ClCompile Include="VolumeCreator.cpp" />
<ClCompile Include="VolumeDirectory.cpp" />
@@ -67,6 +68,7 @@
<ClInclude Include="Filesystem.h" />
<ClInclude Include="FileSystemGCWii.h" />
<ClInclude Include="NANDContentLoader.h" />
+ <ClInclude Include="TGCBlob.h" />
<ClInclude Include="Volume.h" />
<ClInclude Include="VolumeCreator.h" />
<ClInclude Include="VolumeDirectory.h" />
diff --git a/Source/Core/DiscIO/DiscIO.vcxproj.filters b/Source/Core/DiscIO/DiscIO.vcxproj.filters
index 664eed5801..382915d4b8 100644
--- a/Source/Core/DiscIO/DiscIO.vcxproj.filters
+++ b/Source/Core/DiscIO/DiscIO.vcxproj.filters
@@ -75,6 +75,9 @@
<ClCompile Include="Volume.cpp">
<Filter>Volume</Filter>
</ClCompile>
+ <ClCompile Include="TGCBlob.cpp">
+ <Filter>Volume\Blob</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="DiscScrubber.h">
@@ -134,6 +137,9 @@
<ClInclude Include="Enums.h">
<Filter>Volume</Filter>
</ClInclude>
+ <ClCompile Include="TGCBlob.h">
+ <Filter>Volume\Blob</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
diff --git a/Source/Core/DiscIO/TGCBlob.cpp b/Source/Core/DiscIO/TGCBlob.cpp
new file mode 100644
index 0000000000..85a5a854aa
--- /dev/null
+++ b/Source/Core/DiscIO/TGCBlob.cpp
@@ -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
diff --git a/Source/Core/DiscIO/TGCBlob.h b/Source/Core/DiscIO/TGCBlob.h
new file mode 100644
index 0000000000..c1057afc27
--- /dev/null
+++ b/Source/Core/DiscIO/TGCBlob.h
@@ -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
diff --git a/Source/Core/DolphinQt2/Config/PathDialog.cpp b/Source/Core/DolphinQt2/Config/PathDialog.cpp
index 1f0a73a635..c99b82acac 100644
--- a/Source/Core/DolphinQt2/Config/PathDialog.cpp
+++ b/Source/Core/DolphinQt2/Config/PathDialog.cpp
@@ -54,7 +54,7 @@ void PathDialog::BrowseDefaultGame()
{
QString file = QFileDialog::getOpenFileName(
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 (*)"));
if (!file.isEmpty())
{
diff --git a/Source/Core/DolphinQt2/GameList/GameTracker.cpp b/Source/Core/DolphinQt2/GameList/GameTracker.cpp
index 93adfbb8c8..30b73da389 100644
--- a/Source/Core/DolphinQt2/GameList/GameTracker.cpp
+++ b/Source/Core/DolphinQt2/GameList/GameTracker.cpp
@@ -9,10 +9,10 @@
#include "DolphinQt2/GameList/GameTracker.h"
#include "DolphinQt2/Settings.h"
-static const QStringList game_filters{QStringLiteral("*.gcm"), QStringLiteral("*.iso"),
- QStringLiteral("*.ciso"), QStringLiteral("*.gcz"),
- QStringLiteral("*.wbfs"), QStringLiteral("*.wad"),
- QStringLiteral("*.elf"), QStringLiteral("*.dol")};
+static const QStringList game_filters{
+ QStringLiteral("*.gcm"), QStringLiteral("*.iso"), QStringLiteral("*.tgc"),
+ QStringLiteral("*.ciso"), QStringLiteral("*.gcz"), QStringLiteral("*.wbfs"),
+ QStringLiteral("*.wad"), QStringLiteral("*.elf"), QStringLiteral("*.dol")};
GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent)
{
diff --git a/Source/Core/DolphinQt2/Info.plist.in b/Source/Core/DolphinQt2/Info.plist.in
index 50bd100d11..0e6c6b5c50 100644
--- a/Source/Core/DolphinQt2/Info.plist.in
+++ b/Source/Core/DolphinQt2/Info.plist.in
@@ -13,6 +13,7 @@
<string>gcm</string>
<string>gcz</string>
<string>iso</string>
+ <string>tgc</string>
<string>wad</string>
<string>wbfs</string>
</array>
diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp
index 8f4383eb69..0a91f77221 100644
--- a/Source/Core/DolphinQt2/MainWindow.cpp
+++ b/Source/Core/DolphinQt2/MainWindow.cpp
@@ -137,7 +137,7 @@ void MainWindow::Open()
{
QString file = QFileDialog::getOpenFileName(
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 (*)"));
if (!file.isEmpty())
StartGame(file);
diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.cpp b/Source/Core/DolphinWX/Config/PathConfigPane.cpp
index cb4943f9bf..d9efea5ca1 100644
--- a/Source/Core/DolphinWX/Config/PathConfigPane.cpp
+++ b/Source/Core/DolphinWX/Config/PathConfigPane.cpp
@@ -41,8 +41,8 @@ void PathConfigPane::InitializeGUI()
m_default_iso_filepicker = new wxFilePickerCtrl(
this, wxID_ANY, wxEmptyString, _("Choose a default ISO:"),
- _("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") +
- wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad|%s",
+ _("All GC/Wii files (elf, dol, gcm, iso, tgc, wbfs, ciso, gcz, wad)") +
+ wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.tgc;*.wbfs;*.ciso;*.gcz;*.wad|%s",
wxGetTranslation(wxALL_FILES)),
wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL);
m_dvd_root_dirpicker =
diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp
index 81db8f6d40..e3e10438f1 100644
--- a/Source/Core/DolphinWX/FrameTools.cpp
+++ b/Source/Core/DolphinWX/FrameTools.cpp
@@ -332,9 +332,10 @@ void CFrame::DoOpen(bool Boot)
wxString path = wxFileSelector(
_("Select the file to load"), wxEmptyString, wxEmptyString, wxEmptyString,
- _("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") +
- wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad;*.dff;*.tmd|%s",
- wxGetTranslation(wxALL_FILES)),
+ _("All GC/Wii files (elf, dol, gcm, iso, tgc, wbfs, ciso, gcz, wad)") +
+ wxString::Format(
+ "|*.elf;*.dol;*.gcm;*.iso;*.tgc;*.wbfs;*.ciso;*.gcz;*.wad;*.dff;*.tmd|%s",
+ wxGetTranslation(wxALL_FILES)),
wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
if (path.IsEmpty())
diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp
index a6663be6b8..99777b2b4a 100644
--- a/Source/Core/DolphinWX/GameListCtrl.cpp
+++ b/Source/Core/DolphinWX/GameListCtrl.cpp
@@ -566,7 +566,10 @@ void CGameListCtrl::ScanForISOs()
std::vector<std::string> Extensions;
if (SConfig::GetInstance().m_ListGC)
+ {
Extensions.push_back(".gcm");
+ Extensions.push_back(".tgc");
+ }
if (SConfig::GetInstance().m_ListWii || SConfig::GetInstance().m_ListGC)
{
Extensions.push_back(".iso");
diff --git a/Source/Core/DolphinWX/Info.plist.in b/Source/Core/DolphinWX/Info.plist.in
index d0482418e7..f5564f088a 100644
--- a/Source/Core/DolphinWX/Info.plist.in
+++ b/Source/Core/DolphinWX/Info.plist.in
@@ -13,6 +13,7 @@
<string>gcm</string>
<string>gcz</string>
<string>iso</string>
+ <string>tgc</string>
<string>wad</string>
<string>wbfs</string>
</array>
diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp
index f87de73a0c..65d2370397 100644
--- a/Source/Core/DolphinWX/Main.cpp
+++ b/Source/Core/DolphinWX/Main.cpp
@@ -137,8 +137,8 @@ void DolphinApp::OnInitCmdLine(wxCmdLineParser& parser)
{wxCMD_LINE_SWITCH, "l", "logger", "Opens the logger", wxCMD_LINE_VAL_NONE,
wxCMD_LINE_PARAM_OPTIONAL},
{wxCMD_LINE_OPTION, "e", "exec",
- "Loads the specified file (ELF, DOL, GCM, ISO, WBFS, CISO, GCZ, WAD)", wxCMD_LINE_VAL_STRING,
- wxCMD_LINE_PARAM_OPTIONAL},
+ "Loads the specified file (ELF, DOL, GCM, ISO, TGC, WBFS, CISO, GCZ, WAD)",
+ wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL},
{wxCMD_LINE_SWITCH, "b", "batch", "Exit Dolphin with emulator", wxCMD_LINE_VAL_NONE,
wxCMD_LINE_PARAM_OPTIONAL},
{wxCMD_LINE_OPTION, "c", "confirm", "Set Confirm on Stop", wxCMD_LINE_VAL_STRING,