summaryrefslogtreecommitdiff
path: root/Source/Core/DiscIO/SplitFileBlob.cpp
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2023-03-09 16:13:15 +0100
committerGitHub <noreply@github.com>2023-03-09 16:13:15 +0100
commit9ed388fc8a75e842bc8400cdc06ac22bbf784bd6 (patch)
treecb71d650a4e8522d220fd772c42c700f347a1b3d /Source/Core/DiscIO/SplitFileBlob.cpp
parent8c7997d6caeca76d663fbb45ab7e3099bd4dda6b (diff)
parent655cc7f75cabf3a271e7dbfd4cecb9f214540817 (diff)
Merge pull request #11557 from AdmiralCurtiss/split-file-reader
DiscIO: Add support for CleanRip-style split ISOs.
Diffstat (limited to 'Source/Core/DiscIO/SplitFileBlob.cpp')
-rw-r--r--Source/Core/DiscIO/SplitFileBlob.cpp90
1 files changed, 90 insertions, 0 deletions
diff --git a/Source/Core/DiscIO/SplitFileBlob.cpp b/Source/Core/DiscIO/SplitFileBlob.cpp
new file mode 100644
index 0000000000..f3a0895614
--- /dev/null
+++ b/Source/Core/DiscIO/SplitFileBlob.cpp
@@ -0,0 +1,90 @@
+// Copyright 2023 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "DiscIO/SplitFileBlob.h"
+
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include <fmt/format.h>
+
+#include "Common/Assert.h"
+#include "Common/FileUtil.h"
+#include "Common/IOFile.h"
+#include "Common/MsgHandler.h"
+
+namespace DiscIO
+{
+SplitPlainFileReader::SplitPlainFileReader(std::vector<SingleFile> files)
+ : m_files(std::move(files))
+{
+ m_size = 0;
+ for (const auto& f : m_files)
+ m_size += f.size;
+}
+
+std::unique_ptr<SplitPlainFileReader> SplitPlainFileReader::Create(std::string_view first_file_path)
+{
+ constexpr std::string_view part0_iso = ".part0.iso";
+ if (!first_file_path.ends_with(part0_iso))
+ return nullptr;
+
+ const std::string_view base_path =
+ first_file_path.substr(0, first_file_path.size() - part0_iso.size());
+ std::vector<SingleFile> files;
+ size_t index = 0;
+ u64 offset = 0;
+ while (true)
+ {
+ File::IOFile f(fmt::format("{}.part{}.iso", base_path, index), "rb");
+ if (!f.IsOpen())
+ break;
+ const u64 size = f.GetSize();
+ if (size == 0)
+ return nullptr;
+ files.emplace_back(SingleFile{std::move(f), offset, size});
+ offset += size;
+ ++index;
+ }
+
+ if (files.size() < 2)
+ return nullptr;
+
+ files.shrink_to_fit();
+ return std::unique_ptr<SplitPlainFileReader>(new SplitPlainFileReader(std::move(files)));
+}
+
+bool SplitPlainFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr)
+{
+ if (offset >= m_size)
+ return false;
+
+ u64 current_offset = offset;
+ u64 rest = nbytes;
+ u8* out = out_ptr;
+ for (auto& file : m_files)
+ {
+ if (current_offset >= file.offset && current_offset < file.offset + file.size)
+ {
+ auto& f = file.file;
+ const u64 seek_offset = current_offset - file.offset;
+ const u64 current_read = std::min(file.size - seek_offset, rest);
+ if (!f.Seek(seek_offset, File::SeekOrigin::Begin) || !f.ReadBytes(out, current_read))
+ {
+ f.ClearError();
+ return false;
+ }
+
+ rest -= current_read;
+ if (rest == 0)
+ return true;
+ current_offset += current_read;
+ out += current_read;
+ }
+ }
+
+ return rest == 0;
+}
+} // namespace DiscIO