WiiEncryptionCache.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // Copyright 2020 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "DiscIO/WiiEncryptionCache.h"
  4. #include <array>
  5. #include <cstring>
  6. #include <limits>
  7. #include <memory>
  8. #include "Common/Align.h"
  9. #include "Common/CommonTypes.h"
  10. #include "DiscIO/Blob.h"
  11. #include "DiscIO/VolumeWii.h"
  12. namespace DiscIO
  13. {
  14. WiiEncryptionCache::WiiEncryptionCache(BlobReader* blob) : m_blob(blob)
  15. {
  16. }
  17. WiiEncryptionCache::~WiiEncryptionCache() = default;
  18. const std::array<u8, VolumeWii::GROUP_TOTAL_SIZE>*
  19. WiiEncryptionCache::EncryptGroup(u64 offset, u64 partition_data_offset,
  20. u64 partition_data_decrypted_size, const Key& key,
  21. const HashExceptionCallback& hash_exception_callback)
  22. {
  23. // Only allocate memory if this function actually ends up getting called
  24. if (!m_cache)
  25. {
  26. m_cache = std::make_unique<std::array<u8, VolumeWii::GROUP_TOTAL_SIZE>>();
  27. m_cached_offset = std::numeric_limits<u64>::max();
  28. }
  29. ASSERT(offset % VolumeWii::GROUP_TOTAL_SIZE == 0);
  30. const u64 group_offset_in_partition =
  31. offset / VolumeWii::GROUP_TOTAL_SIZE * VolumeWii::GROUP_DATA_SIZE;
  32. const u64 group_offset_on_disc = partition_data_offset + offset;
  33. if (m_cached_offset != group_offset_on_disc)
  34. {
  35. std::function<void(VolumeWii::HashBlock * hash_blocks)> hash_exception_callback_2;
  36. if (hash_exception_callback)
  37. {
  38. hash_exception_callback_2 =
  39. [offset, &hash_exception_callback](
  40. VolumeWii::HashBlock hash_blocks[VolumeWii::BLOCKS_PER_GROUP]) {
  41. return hash_exception_callback(hash_blocks, offset);
  42. };
  43. }
  44. if (!VolumeWii::EncryptGroup(group_offset_in_partition, partition_data_offset,
  45. partition_data_decrypted_size, key, m_blob, m_cache.get(),
  46. hash_exception_callback_2))
  47. {
  48. m_cached_offset = std::numeric_limits<u64>::max(); // Invalidate the cache
  49. return nullptr;
  50. }
  51. m_cached_offset = group_offset_on_disc;
  52. }
  53. return m_cache.get();
  54. }
  55. bool WiiEncryptionCache::EncryptGroups(u64 offset, u64 size, u8* out_ptr, u64 partition_data_offset,
  56. u64 partition_data_decrypted_size, const Key& key,
  57. const HashExceptionCallback& hash_exception_callback)
  58. {
  59. while (size > 0)
  60. {
  61. const std::array<u8, VolumeWii::GROUP_TOTAL_SIZE>* group =
  62. EncryptGroup(Common::AlignDown(offset, VolumeWii::GROUP_TOTAL_SIZE), partition_data_offset,
  63. partition_data_decrypted_size, key, hash_exception_callback);
  64. if (!group)
  65. return false;
  66. const u64 offset_in_group = offset % VolumeWii::GROUP_TOTAL_SIZE;
  67. const u64 bytes_to_read = std::min(VolumeWii::GROUP_TOTAL_SIZE - offset_in_group, size);
  68. std::memcpy(out_ptr, group->data() + offset_in_group, bytes_to_read);
  69. offset += bytes_to_read;
  70. size -= bytes_to_read;
  71. out_ptr += bytes_to_read;
  72. }
  73. return true;
  74. }
  75. } // namespace DiscIO