summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Zach Hilman2018-10-04 12:23:18 -0400
committerGravatar Zach Hilman2018-10-04 12:23:27 -0400
commit110d5784702282c594fe57f84f8d6bda21a82d50 (patch)
tree4d4d2267784e1e0baa76dfb656b91503118f89b0 /src
parentips_layer: Deduplicate resource usage (diff)
downloadyuzu-110d5784702282c594fe57f84f8d6bda21a82d50.tar.gz
yuzu-110d5784702282c594fe57f84f8d6bda21a82d50.tar.xz
yuzu-110d5784702282c594fe57f84f8d6bda21a82d50.zip
ips_layer: Fix inaccuracies with comments and flags
Specifically bugs/crashes that arise when putting them in positions that are legal but not typical, such as midline, between patch data, or between patch records.
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/ips_layer.cpp64
-rw-r--r--src/core/file_sys/ips_layer.h1
-rw-r--r--src/core/file_sys/patch_manager.cpp2
3 files changed, 51 insertions, 16 deletions
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index abe3dcf62..0cadbc375 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -123,6 +123,22 @@ static std::string EscapeStringSequences(std::string in) {
123 return in; 123 return in;
124} 124}
125 125
126void IPSwitchCompiler::ParseFlag(const std::string& line) {
127 if (StartsWith(line, "@flag offset_shift ")) {
128 // Offset Shift Flag
129 offset_shift = std::stoll(line.substr(19), nullptr, 0);
130 } else if (StartsWith(line, "@little-endian")) {
131 // Set values to read as little endian
132 is_little_endian = true;
133 } else if (StartsWith(line, "@big-endian")) {
134 // Set values to read as big endian
135 is_little_endian = false;
136 } else if (StartsWith(line, "@flag print_values")) {
137 // Force printing of applied values
138 print_values = true;
139 }
140}
141
126void IPSwitchCompiler::Parse() { 142void IPSwitchCompiler::Parse() {
127 const auto bytes = patch_text->ReadAllBytes(); 143 const auto bytes = patch_text->ReadAllBytes();
128 std::stringstream s; 144 std::stringstream s;
@@ -141,7 +157,17 @@ void IPSwitchCompiler::Parse() {
141 auto line = lines[i]; 157 auto line = lines[i];
142 158
143 // Remove midline comments 159 // Remove midline comments
144 const auto comment_index = line.find("//"); 160 std::size_t comment_index = std::string::npos;
161 bool within_string = false;
162 for (std::size_t k = 0; k < line.size(); ++k) {
163 if (line[k] == '\"' && (k > 0 && line[k - 1] != '\\')) {
164 within_string = !within_string;
165 } else if (line[k] == '\\' && (k < line.size() - 1 && line[k + 1] == '\\')) {
166 comment_index = k;
167 break;
168 }
169 }
170
145 if (!StartsWith(line, "//") && comment_index != std::string::npos) { 171 if (!StartsWith(line, "//") && comment_index != std::string::npos) {
146 last_comment = line.substr(comment_index + 2); 172 last_comment = line.substr(comment_index + 2);
147 line = line.substr(0, comment_index); 173 line = line.substr(0, comment_index);
@@ -156,9 +182,6 @@ void IPSwitchCompiler::Parse() {
156 if (raw_build_id.size() != 0x40) 182 if (raw_build_id.size() != 0x40)
157 raw_build_id.resize(0x40, '0'); 183 raw_build_id.resize(0x40, '0');
158 nso_build_id = Common::HexStringToArray<0x20>(raw_build_id); 184 nso_build_id = Common::HexStringToArray<0x20>(raw_build_id);
159 } else if (StartsWith(line, "@flag offset_shift ")) {
160 // Offset Shift Flag
161 offset_shift = std::stoll(line.substr(19), nullptr, 0);
162 } else if (StartsWith(line, "#")) { 185 } else if (StartsWith(line, "#")) {
163 // Mandatory Comment 186 // Mandatory Comment
164 LOG_INFO(Loader, "[IPSwitchCompiler ('{}')] Forced output comment: {}", 187 LOG_INFO(Loader, "[IPSwitchCompiler ('{}')] Forced output comment: {}",
@@ -170,15 +193,6 @@ void IPSwitchCompiler::Parse() {
170 continue; 193 continue;
171 if (last_comment.find_first_not_of(' ') != 0) 194 if (last_comment.find_first_not_of(' ') != 0)
172 last_comment = last_comment.substr(last_comment.find_first_not_of(' ')); 195 last_comment = last_comment.substr(last_comment.find_first_not_of(' '));
173 } else if (StartsWith(line, "@little-endian")) {
174 // Set values to read as little endian
175 is_little_endian = true;
176 } else if (StartsWith(line, "@big-endian")) {
177 // Set values to read as big endian
178 is_little_endian = false;
179 } else if (StartsWith(line, "@flag print_values")) {
180 // Force printing of applied values
181 print_values = true;
182 } else if (StartsWith(line, "@enabled") || StartsWith(line, "@disabled")) { 196 } else if (StartsWith(line, "@enabled") || StartsWith(line, "@disabled")) {
183 // Start of patch 197 // Start of patch
184 const auto enabled = StartsWith(line, "@enabled"); 198 const auto enabled = StartsWith(line, "@enabled");
@@ -195,6 +209,18 @@ void IPSwitchCompiler::Parse() {
195 break; 209 break;
196 const auto patch_line = lines[++i]; 210 const auto patch_line = lines[++i];
197 211
212 // Start of new patch
213 if (StartsWith(patch_line, "@enabled") || StartsWith(patch_line, "@disabled")) {
214 --i;
215 break;
216 }
217
218 // Check for a flag
219 if (StartsWith(patch_line, "@")) {
220 ParseFlag(patch_line);
221 continue;
222 }
223
198 // 11 - 8 hex digit offset + space + minimum two digit overwrite val 224 // 11 - 8 hex digit offset + space + minimum two digit overwrite val
199 if (patch_line.length() < 11) 225 if (patch_line.length() < 11)
200 break; 226 break;
@@ -205,9 +231,15 @@ void IPSwitchCompiler::Parse() {
205 // 9 - first char of replacement val 231 // 9 - first char of replacement val
206 if (patch_line[9] == '\"') { 232 if (patch_line[9] == '\"') {
207 // string replacement 233 // string replacement
208 const auto end_index = patch_line.find('\"', 10); 234 auto end_index = patch_line.find('\"', 10);
209 if (end_index == std::string::npos || end_index < 10) 235 if (end_index == std::string::npos || end_index < 10)
210 return; 236 return;
237 while (patch_line[end_index - 1] == '\\') {
238 end_index = patch_line.find('\"', end_index + 1);
239 if (end_index == std::string::npos || end_index < 10)
240 return;
241 }
242
211 auto value = patch_line.substr(10, end_index - 10); 243 auto value = patch_line.substr(10, end_index - 10);
212 value = EscapeStringSequences(value); 244 value = EscapeStringSequences(value);
213 replace.reserve(value.size()); 245 replace.reserve(value.size());
@@ -226,10 +258,12 @@ void IPSwitchCompiler::Parse() {
226 patch_text->GetName(), offset, Common::HexVectorToString(replace)); 258 patch_text->GetName(), offset, Common::HexVectorToString(replace));
227 } 259 }
228 260
229 patch.records.emplace(offset, std::move(replace)); 261 patch.records.insert_or_assign(offset, std::move(replace));
230 } 262 }
231 263
232 patches.push_back(std::move(patch)); 264 patches.push_back(std::move(patch));
265 } else if (StartsWith(line, "@")) {
266 ParseFlag(line);
233 } 267 }
234 } 268 }
235 269
diff --git a/src/core/file_sys/ips_layer.h b/src/core/file_sys/ips_layer.h
index b07cc5673..57da00da8 100644
--- a/src/core/file_sys/ips_layer.h
+++ b/src/core/file_sys/ips_layer.h
@@ -22,6 +22,7 @@ public:
22 VirtualFile Apply(const VirtualFile& in) const; 22 VirtualFile Apply(const VirtualFile& in) const;
23 23
24private: 24private:
25 void ParseFlag(const std::string& flag);
25 void Parse(); 26 void Parse();
26 27
27 bool valid = false; 28 bool valid = false;
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 03df24906..ab2e5e43d 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -76,7 +76,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
76static std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs, 76static std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
77 const std::string& build_id) { 77 const std::string& build_id) {
78 std::vector<VirtualFile> out; 78 std::vector<VirtualFile> out;
79 ips.reserve(patch_dirs.size()); 79 out.reserve(patch_dirs.size());
80 for (const auto& subdir : patch_dirs) { 80 for (const auto& subdir : patch_dirs) {
81 auto exefs_dir = subdir->GetSubdirectory("exefs"); 81 auto exefs_dir = subdir->GetSubdirectory("exefs");
82 if (exefs_dir != nullptr) { 82 if (exefs_dir != nullptr) {