diff options
author | Zach Hilman <zachhilman@gmail.com> | 2018-08-26 16:53:31 +0200 |
---|---|---|
committer | Zach Hilman <zachhilman@gmail.com> | 2018-09-04 22:24:02 +0200 |
commit | 9664ce255db09f4501db642c1e82d8cf8f274a22 (patch) | |
tree | 5548a6d79f3806c64d7e0d6ee559f619dfe4c6c0 /src | |
parent | main: Make game updates installable (diff) | |
download | yuzu-9664ce255db09f4501db642c1e82d8cf8f274a22.tar yuzu-9664ce255db09f4501db642c1e82d8cf8f274a22.tar.gz yuzu-9664ce255db09f4501db642c1e82d8cf8f274a22.tar.bz2 yuzu-9664ce255db09f4501db642c1e82d8cf8f274a22.tar.lz yuzu-9664ce255db09f4501db642c1e82d8cf8f274a22.tar.xz yuzu-9664ce255db09f4501db642c1e82d8cf8f274a22.tar.zst yuzu-9664ce255db09f4501db642c1e82d8cf8f274a22.zip |
Diffstat (limited to 'src')
-rw-r--r-- | src/core/file_sys/nca_patch.cpp | 126 | ||||
-rw-r--r-- | src/core/file_sys/nca_patch.h | 5 | ||||
-rw-r--r-- | src/core/file_sys/patch_manager.cpp | 35 | ||||
-rw-r--r-- | src/core/file_sys/patch_manager.h | 9 | ||||
-rw-r--r-- | src/core/file_sys/registered_cache.cpp | 21 | ||||
-rw-r--r-- | src/core/file_sys/registered_cache.h | 2 | ||||
-rw-r--r-- | src/core/loader/deconstructed_rom_directory.cpp | 2 | ||||
-rw-r--r-- | src/core/loader/deconstructed_rom_directory.h | 2 | ||||
-rw-r--r-- | src/core/loader/loader.h | 2 | ||||
-rw-r--r-- | src/core/loader/nro.cpp | 2 | ||||
-rw-r--r-- | src/core/loader/nro.h | 2 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 4 |
12 files changed, 109 insertions, 103 deletions
diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp index dd684c38e..22fbba573 100644 --- a/src/core/file_sys/nca_patch.cpp +++ b/src/core/file_sys/nca_patch.cpp @@ -17,7 +17,7 @@ BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock rel relocation(relocation_), relocation_buckets(std::move(relocation_buckets_)), subsection(subsection_), subsection_buckets(std::move(subsection_buckets_)), encrypted(is_encrypted_), key(key_), base_offset(base_offset_), ivfc_offset(ivfc_offset_), - section_ctr(std::move(section_ctr_)) { + section_ctr(section_ctr_) { for (size_t i = 0; i < relocation.number_buckets - 1; ++i) { relocation_buckets[i].entries.push_back({relocation.base_offsets[i + 1], 0, 0}); } @@ -31,6 +31,8 @@ BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock rel relocation_buckets.back().entries.push_back({relocation.size, 0, 0}); } +BKTR::~BKTR() = default; + size_t BKTR::Read(u8* data, size_t length, size_t offset) const { // Read out of bounds. if (offset >= relocation.size) @@ -41,68 +43,66 @@ size_t BKTR::Read(u8* data, size_t length, size_t offset) const { const auto next_relocation = GetNextRelocationEntry(offset); - if (offset + length <= next_relocation.address_patch) { - if (bktr_read) { - if (!encrypted) { - return bktr_romfs->Read(data, length, section_offset); - } - - const auto subsection = GetSubsectionEntry(section_offset); - Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR); - - // Calculate AES IV - std::vector<u8> iv(16); - auto subsection_ctr = subsection.ctr; - auto offset_iv = section_offset + base_offset; - for (u8 i = 0; i < 8; ++i) - iv[i] = section_ctr[0x8 - i - 1]; - offset_iv >>= 4; - for (size_t i = 0; i < 8; ++i) { - iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF); - offset_iv >>= 8; - } - for (size_t i = 0; i < 4; ++i) { - iv[0x7 - i] = static_cast<u8>(subsection_ctr & 0xFF); - subsection_ctr >>= 8; - } - cipher.SetIV(iv); - - const auto next_subsection = GetNextSubsectionEntry(section_offset); - - if (section_offset + length <= next_subsection.address_patch) { - const auto block_offset = section_offset & 0xF; - if (block_offset != 0) { - auto block = bktr_romfs->ReadBytes(0x10, section_offset & ~0xF); - cipher.Transcode(block.data(), block.size(), block.data(), - Core::Crypto::Op::Decrypt); - if (length + block_offset < 0x10) { - std::memcpy(data, block.data() + block_offset, - std::min(length, block.size())); - return std::min(length, block.size()); - } - - const auto read = 0x10 - block_offset; - std::memcpy(data, block.data() + block_offset, read); - return read + Read(data + read, length - read, offset + read); - } - - const auto raw_read = bktr_romfs->Read(data, length, section_offset); - cipher.Transcode(data, raw_read, data, Core::Crypto::Op::Decrypt); - return raw_read; - } else { - const u64 partition = next_subsection.address_patch - section_offset; - return Read(data, partition, offset) + - Read(data + partition, length - partition, offset + partition); - } - } else { - ASSERT(section_offset > ivfc_offset, "Offset calculation negative."); - return base_romfs->Read(data, length, section_offset); - } - } else { + if (offset + length >= next_relocation.address_patch) { const u64 partition = next_relocation.address_patch - offset; return Read(data, partition, offset) + Read(data + partition, length - partition, offset + partition); } + + if (!bktr_read) { + ASSERT_MSG(section_offset > ivfc_offset, "Offset calculation negative."); + return base_romfs->Read(data, length, section_offset); + } + + if (!encrypted) { + return bktr_romfs->Read(data, length, section_offset); + } + + const auto subsection = GetSubsectionEntry(section_offset); + Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR); + + // Calculate AES IV + std::vector<u8> iv(16); + auto subsection_ctr = subsection.ctr; + auto offset_iv = section_offset + base_offset; + for (size_t i = 0; i < section_ctr.size(); ++i) + iv[i] = section_ctr[0x8 - i - 1]; + offset_iv >>= 4; + for (size_t i = 0; i < sizeof(u64); ++i) { + iv[0xF - i] = static_cast<u8>(offset_iv & 0xFF); + offset_iv >>= 8; + } + for (size_t i = 0; i < sizeof(u32); ++i) { + iv[0x7 - i] = static_cast<u8>(subsection_ctr & 0xFF); + subsection_ctr >>= 8; + } + cipher.SetIV(iv); + + const auto next_subsection = GetNextSubsectionEntry(section_offset); + + if (section_offset + length > next_subsection.address_patch) { + const u64 partition = next_subsection.address_patch - section_offset; + return Read(data, partition, offset) + + Read(data + partition, length - partition, offset + partition); + } + + const auto block_offset = section_offset & 0xF; + if (block_offset != 0) { + auto block = bktr_romfs->ReadBytes(0x10, section_offset & ~0xF); + cipher.Transcode(block.data(), block.size(), block.data(), Core::Crypto::Op::Decrypt); + if (length + block_offset < 0x10) { + std::memcpy(data, block.data() + block_offset, std::min(length, block.size())); + return std::min(length, block.size()); + } + + const auto read = 0x10 - block_offset; + std::memcpy(data, block.data() + block_offset, read); + return read + Read(data + read, length - read, offset + read); + } + + const auto raw_read = bktr_romfs->Read(data, length, section_offset); + cipher.Transcode(data, raw_read, data, Core::Crypto::Op::Decrypt); + return raw_read; } template <bool Subsection, typename BlockType, typename BucketType> @@ -116,11 +116,9 @@ std::pair<size_t, size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block, ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block."); } - size_t bucket_id = 0; - for (size_t i = 1; i < block.number_buckets; ++i) { - if (block.base_offsets[i] <= offset) - ++bucket_id; - } + size_t bucket_id = std::count_if(block.base_offsets.begin() + 1, + block.base_offsets.begin() + block.number_buckets, + [&offset](u64 base_offset) { return base_offset < offset; }); const auto bucket = buckets[bucket_id]; diff --git a/src/core/file_sys/nca_patch.h b/src/core/file_sys/nca_patch.h index 8b8d0a4f5..0d9ad95f5 100644 --- a/src/core/file_sys/nca_patch.h +++ b/src/core/file_sys/nca_patch.h @@ -4,9 +4,11 @@ #pragma once +#include <array> +#include <vector> +#include <common/common_funcs.h> #include "core/crypto/key_manager.h" #include "core/file_sys/romfs.h" -#include "core/loader/loader.h" namespace FileSys { @@ -91,6 +93,7 @@ public: std::vector<RelocationBucket> relocation_buckets, SubsectionBlock subsection, std::vector<SubsectionBucket> subsection_buckets, bool is_encrypted, Core::Crypto::Key128 key, u64 base_offset, u64 ivfc_offset, std::array<u8, 8> section_ctr); + ~BKTR() override; size_t Read(u8* data, size_t length, size_t offset) const override; diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 697b8a4c9..5e853c2c0 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -8,24 +8,19 @@ namespace FileSys { -union TitleVersion { - u32 version; - - struct { - u8 v_revision; - u8 v_micro; - u8 v_minor; - u8 v_major; - }; -}; - -std::string FormatTitleVersion(u32 version_, bool full) { - TitleVersion ver{}; - ver.version = version_; +constexpr u64 SINGLE_BYTE_MODULUS = 0x100; + +std::string FormatTitleVersion(u32 version, TitleVersionFormat format) { + std::array<u8, sizeof(u32)> bytes{}; + bytes[0] = version % SINGLE_BYTE_MODULUS; + for (size_t i = 1; i < bytes.size(); ++i) { + version /= SINGLE_BYTE_MODULUS; + bytes[i] = version % SINGLE_BYTE_MODULUS; + } - if (full) - return fmt::format("v{}.{}.{}.{}", ver.v_major, ver.v_minor, ver.v_minor, ver.v_revision); - return fmt::format("v{}.{}.{}", ver.v_major, ver.v_minor, ver.v_micro); + if (format == TitleVersionFormat::FourElements) + return fmt::format("v{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]); + return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]); } constexpr std::array<const char*, 1> PATCH_TYPE_NAMES{ @@ -49,8 +44,9 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); if (update != nullptr) { if (update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS && - update->GetExeFS() != nullptr) + update->GetExeFS() != nullptr) { exefs = update->GetExeFS(); + } } return exefs; @@ -81,8 +77,9 @@ std::map<PatchType, u32> PatchManager::GetPatchVersionNames() const { const auto update_tid = GetUpdateTitleID(title_id); const auto update_version = installed->GetEntryVersion(update_tid); if (update_version != boost::none && - installed->HasEntry(update_tid, ContentRecordType::Program)) + installed->HasEntry(update_tid, ContentRecordType::Program)) { out[PatchType::Update] = update_version.get(); + } return out; } diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index 2a39c473a..803bcb2a2 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h @@ -5,12 +5,19 @@ #pragma once #include <map> +#include <string> #include "common/common_types.h" #include "core/file_sys/vfs.h" namespace FileSys { -std::string FormatTitleVersion(u32 version, bool full = false); +enum class TitleVersionFormat : u8 { + ThreeElements, ///< vX.Y.Z + FourElements, ///< vX.Y.Z.W +}; + +std::string FormatTitleVersion(u32 version, + TitleVersionFormat format = TitleVersionFormat::ThreeElements); enum class PatchType { Update, diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 39c0710e1..7361a67be 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -281,10 +281,14 @@ VirtualFile RegisteredCache::GetEntryUnparsed(RegisteredCacheEntry entry) const } boost::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const { - if (meta.find(title_id) != meta.end()) - return meta.at(title_id).GetTitleVersion(); - if (yuzu_meta.find(title_id) != yuzu_meta.end()) - return yuzu_meta.at(title_id).GetTitleVersion(); + const auto meta_iter = meta.find(title_id); + if (meta_iter != meta.end()) + return meta_iter->second.GetTitleVersion(); + + const auto yuzu_meta_iter = yuzu_meta.find(title_id); + if (yuzu_meta_iter != yuzu_meta.end()) + return yuzu_meta_iter->second.GetTitleVersion(); + return boost::none; } @@ -516,12 +520,9 @@ void RegisteredCacheUnion::Refresh() { } bool RegisteredCacheUnion::HasEntry(u64 title_id, ContentRecordType type) const { - for (const auto& c : caches) { - if (c->HasEntry(title_id, type)) - return true; - } - - return false; + return std::any_of(caches.begin(), caches.end(), [title_id, type](const auto& cache) { + return cache->HasEntry(title_id, type); + }); } bool RegisteredCacheUnion::HasEntry(RegisteredCacheEntry entry) const { diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index dcce3fd16..f487b0cf0 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h @@ -43,7 +43,7 @@ struct RegisteredCacheEntry { std::string DebugInfo() const; }; -constexpr inline u64 GetUpdateTitleID(u64 base_title_id) { +constexpr u64 GetUpdateTitleID(u64 base_title_id) { return base_title_id | 0x800; } diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 6b2230269..223570431 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -189,7 +189,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) return ResultStatus::Success; } -bool AppLoader_DeconstructedRomDirectory::IsRomFSUpdatable() { +bool AppLoader_DeconstructedRomDirectory::IsRomFSUpdatable() const { return false; } diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index a8644516b..8a0dc1b1e 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -44,7 +44,7 @@ public: ResultStatus ReadIcon(std::vector<u8>& buffer) override; ResultStatus ReadProgramId(u64& out_program_id) override; ResultStatus ReadTitle(std::string& title) override; - bool IsRomFSUpdatable() override; + bool IsRomFSUpdatable() const override; private: FileSys::ProgramMetadata metadata; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index b4a3a6573..225c05127 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -210,7 +210,7 @@ public: * the base game it should be set to false. * @return bool whether or not updatable. */ - virtual bool IsRomFSUpdatable() { + virtual bool IsRomFSUpdatable() const { return true; } diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 96f5cd9e5..bb89a9da3 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -233,7 +233,7 @@ ResultStatus AppLoader_NRO::ReadTitle(std::string& title) { return ResultStatus::Success; } -bool AppLoader_NRO::IsRomFSUpdatable() { +bool AppLoader_NRO::IsRomFSUpdatable() const { return false; } diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h index c35c99d14..96d2de305 100644 --- a/src/core/loader/nro.h +++ b/src/core/loader/nro.h @@ -39,7 +39,7 @@ public: ResultStatus ReadProgramId(u64& out_program_id) override; ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; ResultStatus ReadTitle(std::string& title) override; - bool IsRomFSUpdatable() override; + bool IsRomFSUpdatable() const override; private: bool LoadNro(FileSys::VirtualFile file, VAddr load_base); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 3d438df47..b7ce0248b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -871,8 +871,8 @@ void GMainWindow::OnMenuInstallToNAND() { const auto id = nca->GetStatus(); // Game updates necessary are missing base RomFS - if (nca->GetStatus() != Loader::ResultStatus::Success && - nca->GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { + if (id != Loader::ResultStatus::Success && + id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { failed(); return; } |