summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Zach Hilman2018-09-19 22:00:44 -0400
committerGravatar Zach Hilman2018-09-21 19:53:33 -0400
commit44fdac334cef098c46b6e26e2f65b09756574e60 (patch)
tree66fd1e10ab5b30cd8cbc0eee617f58ce38969305 /src
parentvfs_layered: Add LayeredVfsDirectory (diff)
downloadyuzu-44fdac334cef098c46b6e26e2f65b09756574e60.tar.gz
yuzu-44fdac334cef098c46b6e26e2f65b09756574e60.tar.xz
yuzu-44fdac334cef098c46b6e26e2f65b09756574e60.zip
vfs_concat: Rewrite and fix ConcatenatedVfsFile
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/vfs_concat.cpp39
-rw-r--r--src/core/file_sys/vfs_concat.h34
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
10namespace FileSys { 11namespace FileSys {
11 12
13bool 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
12VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) { 24VirtualFile 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
30ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; 42ConcatenatedVfsFile::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
32std::string ConcatenatedVfsFile::GetName() const { 47std::string ConcatenatedVfsFile::GetName() const {
33 if (files.empty()) 48 if (files.empty())
@@ -62,28 +77,25 @@ bool ConcatenatedVfsFile::IsReadable() const {
62} 77}
63 78
64std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { 79std::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
89std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { 101std::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::
93bool ConcatenatedVfsFile::Rename(std::string_view name) { 105bool 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
12namespace FileSys { 14namespace FileSys {
13 15
16class 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.
15VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name = ""); 19VirtualFile 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.
23template <u8 filler_byte>
24VirtualFile 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.
19class ConcatenatedVfsFile : public VfsFile { 47class 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
24public: 56public:
25 ~ConcatenatedVfsFile() override; 57 ~ConcatenatedVfsFile() override;
@@ -36,7 +68,7 @@ public:
36 68
37private: 69private:
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