// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/service/am/am_results.h" #include "core/hle/service/am/library_applet_storage.h" #include "core/memory.h" namespace Service::AM { namespace { Result ValidateOffset(s64 offset, size_t size, size_t data_size) { R_UNLESS(offset >= 0, AM::ResultInvalidOffset); const size_t begin = offset; const size_t end = begin + size; R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset); R_SUCCEED(); } class BufferLibraryAppletStorage final : public LibraryAppletStorage { public: explicit BufferLibraryAppletStorage(std::vector&& data) : m_data(std::move(data)) {} ~BufferLibraryAppletStorage() = default; Result Read(s64 offset, void* buffer, size_t size) override { R_TRY(ValidateOffset(offset, size, m_data.size())); std::memcpy(buffer, m_data.data() + offset, size); R_SUCCEED(); } Result Write(s64 offset, const void* buffer, size_t size) override { R_TRY(ValidateOffset(offset, size, m_data.size())); std::memcpy(m_data.data() + offset, buffer, size); R_SUCCEED(); } s64 GetSize() override { return m_data.size(); } Kernel::KTransferMemory* GetHandle() override { return nullptr; } private: std::vector m_data; }; class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage { public: explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory, Kernel::KTransferMemory* trmem, bool is_writable, s64 size) : m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) { m_trmem->Open(); } ~TransferMemoryLibraryAppletStorage() { m_trmem->Close(); m_trmem = nullptr; } Result Read(s64 offset, void* buffer, size_t size) override { R_TRY(ValidateOffset(offset, size, m_size)); m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size); R_SUCCEED(); } Result Write(s64 offset, const void* buffer, size_t size) override { R_UNLESS(m_is_writable, ResultUnknown); R_TRY(ValidateOffset(offset, size, m_size)); m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size); R_SUCCEED(); } s64 GetSize() override { return m_size; } Kernel::KTransferMemory* GetHandle() override { return nullptr; } protected: Core::Memory::Memory& m_memory; Kernel::KTransferMemory* m_trmem; bool m_is_writable; s64 m_size; }; class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage { public: explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory, Kernel::KTransferMemory* trmem, s64 size) : TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {} ~HandleLibraryAppletStorage() = default; Kernel::KTransferMemory* GetHandle() override { return m_trmem; } }; } // namespace LibraryAppletStorage::~LibraryAppletStorage() = default; std::vector LibraryAppletStorage::GetData() { std::vector data(this->GetSize()); this->Read(0, data.data(), data.size()); return data; } std::shared_ptr CreateStorage(std::vector&& data) { return std::make_shared(std::move(data)); } std::shared_ptr CreateTransferMemoryStorage(Core::Memory::Memory& memory, Kernel::KTransferMemory* trmem, bool is_writable, s64 size) { return std::make_shared(memory, trmem, is_writable, size); } std::shared_ptr CreateHandleStorage(Core::Memory::Memory& memory, Kernel::KTransferMemory* trmem, s64 size) { return std::make_shared(memory, trmem, size); } } // namespace Service::AM