diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/file_sys/ips_layer.cpp | 88 | ||||
| -rw-r--r-- | src/core/file_sys/ips_layer.h | 15 |
2 files changed, 103 insertions, 0 deletions
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp new file mode 100644 index 000000000..df933ee36 --- /dev/null +++ b/src/core/file_sys/ips_layer.cpp | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "common/swap.h" | ||
| 7 | #include "core/file_sys/ips_layer.h" | ||
| 8 | #include "core/file_sys/vfs_vector.h" | ||
| 9 | |||
| 10 | namespace FileSys { | ||
| 11 | |||
| 12 | enum class IPSFileType { | ||
| 13 | IPS, | ||
| 14 | IPS32, | ||
| 15 | Error, | ||
| 16 | }; | ||
| 17 | |||
| 18 | static IPSFileType IdentifyMagic(const std::vector<u8>& magic) { | ||
| 19 | if (magic.size() != 5) | ||
| 20 | return IPSFileType::Error; | ||
| 21 | if (magic == std::vector<u8>{'P', 'A', 'T', 'C', 'H'}) | ||
| 22 | return IPSFileType::IPS; | ||
| 23 | if (magic == std::vector<u8>{'I', 'P', 'S', '3', '2'}) | ||
| 24 | return IPSFileType::IPS32; | ||
| 25 | return IPSFileType::Error; | ||
| 26 | } | ||
| 27 | |||
| 28 | VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) { | ||
| 29 | if (in == nullptr || ips == nullptr) | ||
| 30 | return nullptr; | ||
| 31 | |||
| 32 | const auto type = IdentifyMagic(ips->ReadBytes(0x5)); | ||
| 33 | if (type == IPSFileType::Error) | ||
| 34 | return nullptr; | ||
| 35 | |||
| 36 | auto in_data = in->ReadAllBytes(); | ||
| 37 | |||
| 38 | std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4); | ||
| 39 | u64 offset = 5; // After header | ||
| 40 | while (ips->Read(temp.data(), temp.size(), offset) == temp.size()) { | ||
| 41 | offset += temp.size(); | ||
| 42 | if (type == IPSFileType::IPS32 && temp == std::vector<u8>{'E', 'E', 'O', 'F'} || | ||
| 43 | type == IPSFileType::IPS && temp == std::vector<u8>{'E', 'O', 'F'}) { | ||
| 44 | break; | ||
| 45 | } | ||
| 46 | |||
| 47 | u32 real_offset{}; | ||
| 48 | if (type == IPSFileType::IPS32) | ||
| 49 | real_offset = (temp[0] << 24) | (temp[1] << 16) | (temp[2] << 8) | temp[3]; | ||
| 50 | else | ||
| 51 | real_offset = (temp[0] << 16) | (temp[1] << 8) | temp[2]; | ||
| 52 | |||
| 53 | u16 data_size{}; | ||
| 54 | if (ips->ReadObject(&data_size, offset) != sizeof(u16)) | ||
| 55 | return nullptr; | ||
| 56 | data_size = Common::swap16(data_size); | ||
| 57 | offset += sizeof(u16); | ||
| 58 | |||
| 59 | if (data_size == 0) { // RLE | ||
| 60 | u16 rle_size{}; | ||
| 61 | if (ips->ReadObject(&rle_size, offset) != sizeof(u16)) | ||
| 62 | return nullptr; | ||
| 63 | rle_size = Common::swap16(data_size); | ||
| 64 | offset += sizeof(u16); | ||
| 65 | |||
| 66 | const auto data = ips->ReadByte(offset++); | ||
| 67 | if (data == boost::none) | ||
| 68 | return nullptr; | ||
| 69 | |||
| 70 | if (real_offset + rle_size > in_data.size()) | ||
| 71 | rle_size = in_data.size() - real_offset; | ||
| 72 | std::memset(in_data.data() + real_offset, data.get(), rle_size); | ||
| 73 | } else { // Standard Patch | ||
| 74 | auto read = data_size; | ||
| 75 | if (real_offset + read > in_data.size()) | ||
| 76 | read = in_data.size() - real_offset; | ||
| 77 | if (ips->Read(in_data.data() + real_offset, read, offset) != data_size) | ||
| 78 | return nullptr; | ||
| 79 | offset += data_size; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | if (temp != std::vector<u8>{'E', 'E', 'O', 'F'} && temp != std::vector<u8>{'E', 'O', 'F'}) | ||
| 84 | return nullptr; | ||
| 85 | return std::make_shared<VectorVfsFile>(in_data, in->GetName(), in->GetContainingDirectory()); | ||
| 86 | } | ||
| 87 | |||
| 88 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/ips_layer.h b/src/core/file_sys/ips_layer.h new file mode 100644 index 000000000..81c163494 --- /dev/null +++ b/src/core/file_sys/ips_layer.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | |||
| 9 | #include "core/file_sys/vfs.h" | ||
| 10 | |||
| 11 | namespace FileSys { | ||
| 12 | |||
| 13 | VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips); | ||
| 14 | |||
| 15 | } // namespace FileSys | ||