citra-emu
/
citra-canary
Archived
1
0
Fork 0

Merge pull request #4353 from zaksabeast/ips-patches

Add IPS patching
This commit is contained in:
Weiyi Wang 2018-11-18 13:39:41 -05:00 committed by GitHub
commit 1bc253f1be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 62 additions and 0 deletions

View File

@ -24,6 +24,53 @@ namespace FileSys {
static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs static const int kMaxSections = 8; ///< Maximum number of sections (files) in an ExeFs
static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes) 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<u8>& ips, std::vector<u8>& 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 * Get the decompressed size of an LZSS compressed ExeFS file
* @param buffer Buffer of compressed file * @param buffer Buffer of compressed file
@ -483,6 +530,21 @@ Loader::ResultStatus NCCHContainer::LoadSectionExeFS(const char* name, std::vect
dec.ProcessData(&buffer[0], &buffer[0], section.size); dec.ProcessData(&buffer[0], &buffer[0], section.size);
} }
} }
std::string override_ips = filepath + ".exefsdir/code.ips";
if (FileUtil::Exists(override_ips) && strcmp(name, ".code") == 0) {
FileUtil::IOFile ips_file(override_ips, "rb");
std::size_t ips_file_size = ips_file.GetSize();
std::vector<u8> ips(ips_file_size);
if (ips_file.IsOpen() &&
ips_file.ReadBytes(&ips[0], ips_file_size) == ips_file_size) {
LOG_INFO(Service_FS, "File {} patching code.bin", override_ips);
ApplyIPS(ips, buffer);
}
}
return Loader::ResultStatus::Success; return Loader::ResultStatus::Success;
} }
} }