From 655cc7f75cabf3a271e7dbfd4cecb9f214540817 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 12 Feb 2023 22:08:21 +0100 Subject: DiscIO: Add support for CleanRip-style split ISOs. --- Source/Core/DiscIO/SplitFileBlob.cpp | 90 ++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 Source/Core/DiscIO/SplitFileBlob.cpp (limited to 'Source/Core/DiscIO/SplitFileBlob.cpp') 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 +#include +#include +#include + +#include + +#include "Common/Assert.h" +#include "Common/FileUtil.h" +#include "Common/IOFile.h" +#include "Common/MsgHandler.h" + +namespace DiscIO +{ +SplitPlainFileReader::SplitPlainFileReader(std::vector files) + : m_files(std::move(files)) +{ + m_size = 0; + for (const auto& f : m_files) + m_size += f.size; +} + +std::unique_ptr 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 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(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 -- cgit v1.2.3