diff options
Diffstat (limited to 'src/core/file_sys/vfs_concat.cpp')
-rw-r--r-- | src/core/file_sys/vfs_concat.cpp | 77 |
1 files changed, 60 insertions, 17 deletions
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index dc7a279a9..16d801c0c 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp @@ -5,17 +5,22 @@ #include <algorithm> #include <utility> +#include "common/assert.h" #include "core/file_sys/vfs_concat.h" +#include "core/file_sys/vfs_static.h" namespace FileSys { -VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) { - if (files.empty()) - return nullptr; - if (files.size() == 1) - return files[0]; +static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& map) { + const auto last_valid = --map.end(); + for (auto iter = map.begin(); iter != last_valid;) { + const auto old = iter++; + if (old->first + old->second->GetSize() != iter->first) { + return false; + } + } - return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); + return map.begin()->first == 0; } ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) @@ -27,8 +32,48 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s } } +ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std::string name) + : files(std::move(files_)), name(std::move(name)) { + ASSERT(VerifyConcatenationMapContinuity(files)); +} + ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; +VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> files, + std::string name) { + if (files.empty()) + return nullptr; + if (files.size() == 1) + return files[0]; + + return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); +} + +VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, + std::map<u64, VirtualFile> files, + std::string name) { + if (files.empty()) + return nullptr; + if (files.size() == 1) + return files.begin()->second; + + const auto last_valid = --files.end(); + for (auto iter = files.begin(); iter != last_valid;) { + const auto old = iter++; + if (old->first + old->second->GetSize() != iter->first) { + files.emplace(old->first + old->second->GetSize(), + std::make_shared<StaticVfsFile>(filler_byte, iter->first - old->first - + old->second->GetSize())); + } + } + + // Ensure the map starts at offset 0 (start of file), otherwise pad to fill. + if (files.begin()->first != 0) + files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first)); + + return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); +} + std::string ConcatenatedVfsFile::GetName() const { if (files.empty()) return ""; @@ -62,7 +107,7 @@ bool ConcatenatedVfsFile::IsReadable() const { } std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { - auto entry = files.end(); + auto entry = --files.end(); for (auto iter = files.begin(); iter != files.end(); ++iter) { if (iter->first > offset) { entry = --iter; @@ -70,20 +115,17 @@ std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t } } - // Check if the entry should be the last one. The loop above will make it end(). - if (entry == files.end() && offset < files.rbegin()->first + files.rbegin()->second->GetSize()) - --entry; - - if (entry == files.end()) + if (entry->first + entry->second->GetSize() <= offset) return 0; - const auto remaining = entry->second->GetSize() + offset - entry->first; - if (length > remaining) { - return entry->second->Read(data, remaining, offset - entry->first) + - Read(data + remaining, length - remaining, offset + remaining); + const auto read_in = + std::min<u64>(entry->first + entry->second->GetSize() - offset, entry->second->GetSize()); + if (length > read_in) { + return entry->second->Read(data, read_in, offset - entry->first) + + Read(data + read_in, length - read_in, offset + read_in); } - return entry->second->Read(data, length, offset - entry->first); + return entry->second->Read(data, std::min<u64>(read_in, length), offset - entry->first); } std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { @@ -93,4 +135,5 @@ std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std:: bool ConcatenatedVfsFile::Rename(std::string_view name) { return false; } + } // namespace FileSys |