dolphin/Source/Core/DiscIO/WiiEncryptionCache.cpp

80 lines
2.4 KiB
C++

// Copyright 2020 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DiscIO/WiiEncryptionCache.h"
#include <array>
#include <cstring>
#include <limits>
#include <memory>
#include "Common/Align.h"
#include "Common/CommonTypes.h"
#include "DiscIO/Blob.h"
#include "DiscIO/VolumeWii.h"
namespace DiscIO
{
WiiEncryptionCache::WiiEncryptionCache(BlobReader* blob) : m_blob(blob)
{
}
WiiEncryptionCache::~WiiEncryptionCache() = default;
const std::array<u8, VolumeWii::GROUP_TOTAL_SIZE>*
WiiEncryptionCache::EncryptGroup(u64 offset, u64 partition_data_offset,
u64 partition_data_decrypted_size, const Key& key)
{
// Only allocate memory if this function actually ends up getting called
if (!m_cache)
{
m_cache = std::make_unique<std::array<u8, VolumeWii::GROUP_TOTAL_SIZE>>();
ASSERT(m_blob->SupportsReadWiiDecrypted());
}
ASSERT(offset % VolumeWii::GROUP_TOTAL_SIZE == 0);
const u64 group_offset_in_partition =
offset / VolumeWii::GROUP_TOTAL_SIZE * VolumeWii::GROUP_DATA_SIZE;
const u64 group_offset_on_disc = partition_data_offset + offset;
if (m_cached_offset != group_offset_on_disc)
{
if (!VolumeWii::EncryptGroup(group_offset_in_partition, partition_data_offset,
partition_data_decrypted_size, key, m_blob, m_cache.get()))
{
m_cached_offset = std::numeric_limits<u64>::max(); // Invalidate the cache
return nullptr;
}
m_cached_offset = group_offset_on_disc;
}
return m_cache.get();
}
bool WiiEncryptionCache::EncryptGroups(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset,
u64 partition_data_decrypted_size, const Key& key)
{
while (size > 0)
{
const std::array<u8, VolumeWii::GROUP_TOTAL_SIZE>* group =
EncryptGroup(Common::AlignDown(offset, VolumeWii::GROUP_TOTAL_SIZE), partition_data_offset,
partition_data_decrypted_size, key);
if (!group)
return false;
const u64 offset_in_group = offset % VolumeWii::GROUP_TOTAL_SIZE;
const u64 bytes_to_read = std::min(VolumeWii::GROUP_TOTAL_SIZE - offset_in_group, size);
std::memcpy(out_ptr, group->data() + offset_in_group, bytes_to_read);
offset += bytes_to_read;
size -= bytes_to_read;
out_ptr += bytes_to_read;
}
return true;
}
} // namespace DiscIO