diff options
| author | 2018-09-19 22:00:44 -0400 | |
|---|---|---|
| committer | 2018-09-21 19:53:33 -0400 | |
| commit | 44fdac334cef098c46b6e26e2f65b09756574e60 (patch) | |
| tree | 66fd1e10ab5b30cd8cbc0eee617f58ce38969305 | |
| parent | vfs_layered: Add LayeredVfsDirectory (diff) | |
| download | yuzu-44fdac334cef098c46b6e26e2f65b09756574e60.tar.gz yuzu-44fdac334cef098c46b6e26e2f65b09756574e60.tar.xz yuzu-44fdac334cef098c46b6e26e2f65b09756574e60.zip | |
vfs_concat: Rewrite and fix ConcatenatedVfsFile
| -rw-r--r-- | src/core/file_sys/vfs_concat.cpp | 39 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.h | 34 |
2 files changed, 59 insertions, 14 deletions
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index dc7a279a9..0c07e162e 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -5,10 +5,22 @@ | |||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <utility> | 6 | #include <utility> |
| 7 | 7 | ||
| 8 | #include "common/assert.h" | ||
| 8 | #include "core/file_sys/vfs_concat.h" | 9 | #include "core/file_sys/vfs_concat.h" |
| 9 | 10 | ||
| 10 | namespace FileSys { | 11 | namespace FileSys { |
| 11 | 12 | ||
| 13 | bool VerifyConcatenationMap(std::map<u64, VirtualFile> map) { | ||
| 14 | for (auto iter = map.begin(); iter != --map.end();) { | ||
| 15 | const auto old = iter++; | ||
| 16 | if (old->first + old->second->GetSize() != iter->first) { | ||
| 17 | return false; | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | return map.begin()->first == 0; | ||
| 22 | } | ||
| 23 | |||
| 12 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) { | 24 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) { |
| 13 | if (files.empty()) | 25 | if (files.empty()) |
| 14 | return nullptr; | 26 | return nullptr; |
| @@ -27,7 +39,10 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::s | |||
| 27 | } | 39 | } |
| 28 | } | 40 | } |
| 29 | 41 | ||
| 30 | ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; | 42 | ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std::string name) |
| 43 | : files(std::move(files_)), name(std::move(name)) { | ||
| 44 | ASSERT(VerifyConcatenationMap(files)); | ||
| 45 | } | ||
| 31 | 46 | ||
| 32 | std::string ConcatenatedVfsFile::GetName() const { | 47 | std::string ConcatenatedVfsFile::GetName() const { |
| 33 | if (files.empty()) | 48 | if (files.empty()) |
| @@ -62,28 +77,25 @@ bool ConcatenatedVfsFile::IsReadable() const { | |||
| 62 | } | 77 | } |
| 63 | 78 | ||
| 64 | std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { | 79 | std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { |
| 65 | auto entry = files.end(); | 80 | std::pair<u64, VirtualFile> entry = *files.rbegin(); |
| 66 | for (auto iter = files.begin(); iter != files.end(); ++iter) { | 81 | for (auto iter = files.begin(); iter != files.end(); ++iter) { |
| 67 | if (iter->first > offset) { | 82 | if (iter->first > offset) { |
| 68 | entry = --iter; | 83 | entry = *--iter; |
| 69 | break; | 84 | break; |
| 70 | } | 85 | } |
| 71 | } | 86 | } |
| 72 | 87 | ||
| 73 | // Check if the entry should be the last one. The loop above will make it end(). | 88 | if (entry.first + entry.second->GetSize() <= offset) |
| 74 | if (entry == files.end() && offset < files.rbegin()->first + files.rbegin()->second->GetSize()) | ||
| 75 | --entry; | ||
| 76 | |||
| 77 | if (entry == files.end()) | ||
| 78 | return 0; | 89 | return 0; |
| 79 | 90 | ||
| 80 | const auto remaining = entry->second->GetSize() + offset - entry->first; | 91 | const auto read_in = |
| 81 | if (length > remaining) { | 92 | std::min(entry.first + entry.second->GetSize() - offset, entry.second->GetSize()); |
| 82 | return entry->second->Read(data, remaining, offset - entry->first) + | 93 | if (length > read_in) { |
| 83 | Read(data + remaining, length - remaining, offset + remaining); | 94 | return entry.second->Read(data, read_in, offset - entry.first) + |
| 95 | Read(data + read_in, length - read_in, offset + read_in); | ||
| 84 | } | 96 | } |
| 85 | 97 | ||
| 86 | return entry->second->Read(data, length, offset - entry->first); | 98 | return entry.second->Read(data, std::min(read_in, length), offset - entry.first); |
| 87 | } | 99 | } |
| 88 | 100 | ||
| 89 | std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { | 101 | std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { |
| @@ -93,4 +105,5 @@ std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std:: | |||
| 93 | bool ConcatenatedVfsFile::Rename(std::string_view name) { | 105 | bool ConcatenatedVfsFile::Rename(std::string_view name) { |
| 94 | return false; | 106 | return false; |
| 95 | } | 107 | } |
| 108 | |||
| 96 | } // namespace FileSys | 109 | } // namespace FileSys |
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index 717d04bdc..c65c20d15 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h | |||
| @@ -4,22 +4,54 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <map> | ||
| 7 | #include <memory> | 8 | #include <memory> |
| 8 | #include <string_view> | 9 | #include <string_view> |
| 9 | #include <boost/container/flat_map.hpp> | 10 | #include <boost/container/flat_map.hpp> |
| 10 | #include "core/file_sys/vfs.h" | 11 | #include "core/file_sys/vfs.h" |
| 12 | #include "core/file_sys/vfs_static.h" | ||
| 11 | 13 | ||
| 12 | namespace FileSys { | 14 | namespace FileSys { |
| 13 | 15 | ||
| 16 | class ConcatenatedVfsFile; | ||
| 17 | |||
| 14 | // Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases. | 18 | // Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases. |
| 15 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name = ""); | 19 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name = ""); |
| 16 | 20 | ||
| 21 | // Convenience function that turns a map of offsets to files into a concatenated file, filling gaps | ||
| 22 | // with template parameter. | ||
| 23 | template <u8 filler_byte> | ||
| 24 | VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name = "") { | ||
| 25 | if (files.empty()) | ||
| 26 | return nullptr; | ||
| 27 | if (files.size() == 1) | ||
| 28 | return files.begin()->second; | ||
| 29 | |||
| 30 | for (auto iter = files.begin(); iter != --files.end();) { | ||
| 31 | const auto old = iter++; | ||
| 32 | if (old->first + old->second->GetSize() != iter->first) { | ||
| 33 | files.emplace(old->first + old->second->GetSize(), | ||
| 34 | std::make_shared<StaticVfsFile<filler_byte>>(iter->first - old->first - | ||
| 35 | old->second->GetSize())); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | if (files.begin()->first != 0) | ||
| 40 | files.emplace(0, std::make_shared<StaticVfsFile<filler_byte>>(files.begin()->first)); | ||
| 41 | |||
| 42 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 43 | } | ||
| 44 | |||
| 17 | // Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently | 45 | // Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently |
| 18 | // read-only. | 46 | // read-only. |
| 19 | class ConcatenatedVfsFile : public VfsFile { | 47 | class ConcatenatedVfsFile : public VfsFile { |
| 20 | friend VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name); | 48 | friend VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name); |
| 21 | 49 | ||
| 50 | template <u8 filler_byte> | ||
| 51 | friend VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name); | ||
| 52 | |||
| 22 | ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); | 53 | ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); |
| 54 | ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); | ||
| 23 | 55 | ||
| 24 | public: | 56 | public: |
| 25 | ~ConcatenatedVfsFile() override; | 57 | ~ConcatenatedVfsFile() override; |
| @@ -36,7 +68,7 @@ public: | |||
| 36 | 68 | ||
| 37 | private: | 69 | private: |
| 38 | // Maps starting offset to file -- more efficient. | 70 | // Maps starting offset to file -- more efficient. |
| 39 | boost::container::flat_map<u64, VirtualFile> files; | 71 | std::map<u64, VirtualFile> files; |
| 40 | std::string name; | 72 | std::string name; |
| 41 | }; | 73 | }; |
| 42 | 74 | ||