blob: 2b43927cb5365fe95753e56f1034d5043c2da5ed (
plain) (
tree)
|
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/file_sys/fssystem/fs_i_storage.h"
namespace FileSys {
class RegionSwitchStorage : public IReadOnlyStorage {
YUZU_NON_COPYABLE(RegionSwitchStorage);
YUZU_NON_MOVEABLE(RegionSwitchStorage);
public:
struct Region {
s64 offset;
s64 size;
};
public:
RegionSwitchStorage(VirtualFile&& i, VirtualFile&& o, Region r)
: m_inside_region_storage(std::move(i)), m_outside_region_storage(std::move(o)),
m_region(r) {}
virtual size_t Read(u8* buffer, size_t size, size_t offset) const override {
// Process until we're done.
size_t processed = 0;
while (processed < size) {
// Process on the appropriate storage.
s64 cur_size = 0;
if (this->CheckRegions(std::addressof(cur_size), offset + processed,
size - processed)) {
m_inside_region_storage->Read(buffer + processed, cur_size, offset + processed);
} else {
m_outside_region_storage->Read(buffer + processed, cur_size, offset + processed);
}
// Advance.
processed += cur_size;
}
return size;
}
virtual size_t GetSize() const override {
return m_inside_region_storage->GetSize();
}
private:
bool CheckRegions(s64* out_current_size, s64 offset, s64 size) const {
// Check if our region contains the access.
if (m_region.offset <= offset) {
if (offset < m_region.offset + m_region.size) {
if (m_region.offset + m_region.size <= offset + size) {
*out_current_size = m_region.offset + m_region.size - offset;
} else {
*out_current_size = size;
}
return true;
} else {
*out_current_size = size;
return false;
}
} else {
if (m_region.offset <= offset + size) {
*out_current_size = m_region.offset - offset;
} else {
*out_current_size = size;
}
return false;
}
}
private:
VirtualFile m_inside_region_storage;
VirtualFile m_outside_region_storage;
Region m_region;
};
} // namespace FileSys
|