Zach Hilman 8 лет назад
Родитель
Сommit
42114e1df4
2 измененных файлов с 134 добавлено и 0 удалено
  1. 93 0
      src/core/file_sys/vfs_concat.cpp
  2. 41 0
      src/core/file_sys/vfs_concat.h

+ 93 - 0
src/core/file_sys/vfs_concat.cpp

@@ -0,0 +1,93 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <utility>
+
+#include "core/file_sys/vfs_concat.h"
+
+namespace FileSys {
+
+VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string_view name) {
+    if (files.empty())
+        return nullptr;
+    if (files.size() == 1)
+        return files[0];
+
+    return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), name));
+}
+
+ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string_view name)
+    : name(name) {
+    size_t next_offset = 0;
+    for (const auto& file : files_) {
+        files[next_offset] = file;
+        next_offset += file->GetSize();
+    }
+}
+
+std::string ConcatenatedVfsFile::GetName() const {
+    if (files.empty())
+        return "";
+    if (!name.empty())
+        return name;
+    return files.begin()->second->GetName();
+}
+
+size_t ConcatenatedVfsFile::GetSize() const {
+    if (files.empty())
+        return 0;
+    return files.rbegin()->first + files.rbegin()->second->GetSize();
+}
+
+bool ConcatenatedVfsFile::Resize(size_t new_size) {
+    return false;
+}
+
+std::shared_ptr<VfsDirectory> ConcatenatedVfsFile::GetContainingDirectory() const {
+    if (files.empty())
+        return nullptr;
+    return files.begin()->second->GetContainingDirectory();
+}
+
+bool ConcatenatedVfsFile::IsWritable() const {
+    return false;
+}
+
+bool ConcatenatedVfsFile::IsReadable() const {
+    return true;
+}
+
+size_t ConcatenatedVfsFile::Read(u8* data, size_t length, size_t offset) const {
+    auto entry = files.end();
+    for (auto iter = files.begin(); iter != files.end(); ++iter) {
+        if (iter->first > offset) {
+            entry = --iter;
+            break;
+        }
+    }
+
+    if (entry == files.end() && offset < files.rbegin()->first + files.rbegin()->second->GetSize())
+        --entry;
+
+    if (entry == files.end())
+        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);
+    }
+
+    return entry->second->Read(data, length, offset - entry->first);
+}
+
+size_t ConcatenatedVfsFile::Write(const u8* data, size_t length, size_t offset) {
+    return 0;
+}
+
+bool ConcatenatedVfsFile::Rename(std::string_view name) {
+    return false;
+}
+} // namespace FileSys

+ 41 - 0
src/core/file_sys/vfs_concat.h

@@ -0,0 +1,41 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string_view>
+#include <boost/container/flat_map.hpp>
+#include "core/file_sys/vfs.h"
+
+namespace FileSys {
+
+// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
+VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string_view name = "");
+
+// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
+// read-only.
+class ConcatenatedVfsFile : public VfsFile {
+    friend VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string_view name);
+
+    ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string_view name);
+
+public:
+    std::string GetName() const override;
+    size_t GetSize() const override;
+    bool Resize(size_t new_size) override;
+    std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
+    bool IsWritable() const override;
+    bool IsReadable() const override;
+    size_t Read(u8* data, size_t length, size_t offset) const override;
+    size_t Write(const u8* data, size_t length, size_t offset) override;
+    bool Rename(std::string_view name) override;
+
+private:
+    // Maps starting offset to file -- more efficient.
+    boost::container::flat_map<u64, VirtualFile> files;
+    std::string name;
+};
+
+} // namespace FileSys