bktr: Fix missing includes and optimize style
This commit is contained in:
		| @@ -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]; | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -8,24 +8,19 @@ | ||||
|  | ||||
| namespace FileSys { | ||||
|  | ||||
| union TitleVersion { | ||||
|     u32 version; | ||||
| constexpr u64 SINGLE_BYTE_MODULUS = 0x100; | ||||
|  | ||||
|     struct { | ||||
|         u8 v_revision; | ||||
|         u8 v_micro; | ||||
|         u8 v_minor; | ||||
|         u8 v_major; | ||||
|     }; | ||||
| }; | ||||
| 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; | ||||
|     } | ||||
|  | ||||
| std::string FormatTitleVersion(u32 version_, bool full) { | ||||
|     TitleVersion ver{}; | ||||
|     ver.version = version_; | ||||
|  | ||||
|     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; | ||||
| } | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user