summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/file_sys/ips_layer.cpp88
-rw-r--r--src/core/file_sys/ips_layer.h15
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
10namespace FileSys {
11
12enum class IPSFileType {
13 IPS,
14 IPS32,
15 Error,
16};
17
18static 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
28VirtualFile 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
11namespace FileSys {
12
13VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips);
14
15} // namespace FileSys