From 1377be9902b467b89be21a49abc60ab8d3a5b1d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 24 Nov 2019 20:32:10 +0100 Subject: [PATCH] file_sys: Move IPS patching code into separate source file In anticipation of a new BPS patcher. --- src/core/CMakeLists.txt | 2 + src/core/file_sys/ncch_container.cpp | 52 ++------------------------ src/core/file_sys/ncch_container.h | 4 +- src/core/file_sys/patch.cpp | 55 ++++++++++++++++++++++++++++ src/core/file_sys/patch.h | 15 ++++++++ src/core/loader/ncch.cpp | 2 +- 6 files changed, 78 insertions(+), 52 deletions(-) create mode 100644 src/core/file_sys/patch.cpp create mode 100644 src/core/file_sys/patch.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 67167fe5d..064e44f94 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -74,6 +74,8 @@ add_library(core STATIC file_sys/ivfc_archive.h file_sys/ncch_container.cpp file_sys/ncch_container.h + file_sys/patch.cpp + file_sys/patch.h file_sys/path_parser.cpp file_sys/path_parser.h file_sys/romfs_reader.cpp diff --git a/src/core/file_sys/ncch_container.cpp b/src/core/file_sys/ncch_container.cpp index 5e0286494..0412fa288 100644 --- a/src/core/file_sys/ncch_container.cpp +++ b/src/core/file_sys/ncch_container.cpp @@ -12,6 +12,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/ncch_container.h" +#include "core/file_sys/patch.h" #include "core/file_sys/seed_db.h" #include "core/hw/aes/key.h" #include "core/loader/loader.h" @@ -24,53 +25,6 @@ namespace FileSys { static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes) -/** - * Attempts to patch a buffer using an IPS - * @param ips Vector of the patches to apply - * @param buffer Vector to patch data into - */ -static void ApplyIPS(std::vector& ips, std::vector& buffer) { - u32 cursor = 5; - u32 patch_length = ips.size() - 3; - std::string ips_header(ips.begin(), ips.begin() + 5); - - if (ips_header != "PATCH") { - LOG_INFO(Service_FS, "Attempted to load invalid IPS"); - return; - } - - while (cursor < patch_length) { - std::string eof_check(ips.begin() + cursor, ips.begin() + cursor + 3); - - if (eof_check == "EOF") - return; - - u32 offset = ips[cursor] << 16 | ips[cursor + 1] << 8 | ips[cursor + 2]; - std::size_t length = ips[cursor + 3] << 8 | ips[cursor + 4]; - - // check for an rle record - if (length == 0) { - length = ips[cursor + 5] << 8 | ips[cursor + 6]; - - if (buffer.size() < offset + length) - return; - - for (u32 i = 0; i < length; ++i) - buffer[offset + i] = ips[cursor + 7]; - - cursor += 8; - - continue; - } - - if (buffer.size() < offset + length) - return; - - std::memcpy(&buffer[offset], &ips[cursor + 5], length); - cursor += length + 5; - } -} - /** * Get the decompressed size of an LZSS compressed ExeFS file * @param buffer Buffer of compressed file @@ -553,7 +507,7 @@ Loader::ResultStatus NCCHContainer::LoadSectionExeFS(const char* name, std::vect return Loader::ResultStatus::ErrorNotUsed; } -bool NCCHContainer::ApplyIPSPatch(std::vector& code) const { +bool NCCHContainer::ApplyCodePatch(std::vector& code) const { const std::string override_ips = filepath + ".exefsdir/code.ips"; FileUtil::IOFile ips_file{override_ips, "rb"}; @@ -565,7 +519,7 @@ bool NCCHContainer::ApplyIPSPatch(std::vector& code) const { return false; LOG_INFO(Service_FS, "File {} patching code.bin", override_ips); - ApplyIPS(ips, code); + Patch::ApplyIpsPatch(ips, code); return true; } diff --git a/src/core/file_sys/ncch_container.h b/src/core/file_sys/ncch_container.h index 00d44c818..8752ffe39 100644 --- a/src/core/file_sys/ncch_container.h +++ b/src/core/file_sys/ncch_container.h @@ -272,11 +272,11 @@ public: Loader::ResultStatus ReadExtdataId(u64& extdata_id); /** - * Apply an IPS patch for .code (if it exists). + * Apply a patch for .code (if it exists). * This should only be called after allocating .bss. * @return bool true if a patch was applied, false otherwise */ - bool ApplyIPSPatch(std::vector& code) const; + bool ApplyCodePatch(std::vector& code) const; /** * Checks whether the NCCH container contains an ExeFS diff --git a/src/core/file_sys/patch.cpp b/src/core/file_sys/patch.cpp new file mode 100644 index 000000000..4bd7d7246 --- /dev/null +++ b/src/core/file_sys/patch.cpp @@ -0,0 +1,55 @@ +// Copyright 2019 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/logging/log.h" +#include "core/file_sys/patch.h" + +namespace FileSys::Patch { + +bool ApplyIpsPatch(const std::vector& ips, std::vector& buffer) { + u32 cursor = 5; + u32 patch_length = ips.size() - 3; + std::string ips_header(ips.begin(), ips.begin() + 5); + + if (ips_header != "PATCH") { + LOG_INFO(Service_FS, "Attempted to load invalid IPS"); + return false; + } + + while (cursor < patch_length) { + std::string eof_check(ips.begin() + cursor, ips.begin() + cursor + 3); + + if (eof_check == "EOF") + return false; + + u32 offset = ips[cursor] << 16 | ips[cursor + 1] << 8 | ips[cursor + 2]; + std::size_t length = ips[cursor + 3] << 8 | ips[cursor + 4]; + + // check for an rle record + if (length == 0) { + length = ips[cursor + 5] << 8 | ips[cursor + 6]; + + if (buffer.size() < offset + length) + return false; + + for (u32 i = 0; i < length; ++i) + buffer[offset + i] = ips[cursor + 7]; + + cursor += 8; + + continue; + } + + if (buffer.size() < offset + length) + return false; + + std::memcpy(&buffer[offset], &ips[cursor + 5], length); + cursor += length + 5; + } + return true; +} + +} // namespace FileSys::Patch diff --git a/src/core/file_sys/patch.h b/src/core/file_sys/patch.h new file mode 100644 index 000000000..b77ca2bcc --- /dev/null +++ b/src/core/file_sys/patch.h @@ -0,0 +1,15 @@ +// Copyright 2019 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" + +namespace FileSys::Patch { + +bool ApplyIpsPatch(const std::vector& patch, std::vector& buffer); + +} // namespace FileSys::Patch diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 016a11ef2..07edad796 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -101,7 +101,7 @@ ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr& process) bss_page_size; // Apply any IPS patch now that the entire codeset (including .bss) has been allocated - overlay_ncch->ApplyIPSPatch(code); + overlay_ncch->ApplyCodePatch(code); codeset->entrypoint = codeset->CodeSegment().addr; codeset->memory = std::move(code);