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.
This commit is contained in:
parent
70bd2bb1d3
commit
110d578470
|
@ -123,6 +123,22 @@ static std::string EscapeStringSequences(std::string in) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IPSwitchCompiler::ParseFlag(const std::string& line) {
|
||||||
|
if (StartsWith(line, "@flag offset_shift ")) {
|
||||||
|
// Offset Shift Flag
|
||||||
|
offset_shift = std::stoll(line.substr(19), nullptr, 0);
|
||||||
|
} else if (StartsWith(line, "@little-endian")) {
|
||||||
|
// Set values to read as little endian
|
||||||
|
is_little_endian = true;
|
||||||
|
} else if (StartsWith(line, "@big-endian")) {
|
||||||
|
// Set values to read as big endian
|
||||||
|
is_little_endian = false;
|
||||||
|
} else if (StartsWith(line, "@flag print_values")) {
|
||||||
|
// Force printing of applied values
|
||||||
|
print_values = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void IPSwitchCompiler::Parse() {
|
void IPSwitchCompiler::Parse() {
|
||||||
const auto bytes = patch_text->ReadAllBytes();
|
const auto bytes = patch_text->ReadAllBytes();
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
|
@ -141,7 +157,17 @@ void IPSwitchCompiler::Parse() {
|
||||||
auto line = lines[i];
|
auto line = lines[i];
|
||||||
|
|
||||||
// Remove midline comments
|
// Remove midline comments
|
||||||
const auto comment_index = line.find("//");
|
std::size_t comment_index = std::string::npos;
|
||||||
|
bool within_string = false;
|
||||||
|
for (std::size_t k = 0; k < line.size(); ++k) {
|
||||||
|
if (line[k] == '\"' && (k > 0 && line[k - 1] != '\\')) {
|
||||||
|
within_string = !within_string;
|
||||||
|
} else if (line[k] == '\\' && (k < line.size() - 1 && line[k + 1] == '\\')) {
|
||||||
|
comment_index = k;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!StartsWith(line, "//") && comment_index != std::string::npos) {
|
if (!StartsWith(line, "//") && comment_index != std::string::npos) {
|
||||||
last_comment = line.substr(comment_index + 2);
|
last_comment = line.substr(comment_index + 2);
|
||||||
line = line.substr(0, comment_index);
|
line = line.substr(0, comment_index);
|
||||||
|
@ -156,9 +182,6 @@ void IPSwitchCompiler::Parse() {
|
||||||
if (raw_build_id.size() != 0x40)
|
if (raw_build_id.size() != 0x40)
|
||||||
raw_build_id.resize(0x40, '0');
|
raw_build_id.resize(0x40, '0');
|
||||||
nso_build_id = Common::HexStringToArray<0x20>(raw_build_id);
|
nso_build_id = Common::HexStringToArray<0x20>(raw_build_id);
|
||||||
} else if (StartsWith(line, "@flag offset_shift ")) {
|
|
||||||
// Offset Shift Flag
|
|
||||||
offset_shift = std::stoll(line.substr(19), nullptr, 0);
|
|
||||||
} else if (StartsWith(line, "#")) {
|
} else if (StartsWith(line, "#")) {
|
||||||
// Mandatory Comment
|
// Mandatory Comment
|
||||||
LOG_INFO(Loader, "[IPSwitchCompiler ('{}')] Forced output comment: {}",
|
LOG_INFO(Loader, "[IPSwitchCompiler ('{}')] Forced output comment: {}",
|
||||||
|
@ -170,15 +193,6 @@ void IPSwitchCompiler::Parse() {
|
||||||
continue;
|
continue;
|
||||||
if (last_comment.find_first_not_of(' ') != 0)
|
if (last_comment.find_first_not_of(' ') != 0)
|
||||||
last_comment = last_comment.substr(last_comment.find_first_not_of(' '));
|
last_comment = last_comment.substr(last_comment.find_first_not_of(' '));
|
||||||
} else if (StartsWith(line, "@little-endian")) {
|
|
||||||
// Set values to read as little endian
|
|
||||||
is_little_endian = true;
|
|
||||||
} else if (StartsWith(line, "@big-endian")) {
|
|
||||||
// Set values to read as big endian
|
|
||||||
is_little_endian = false;
|
|
||||||
} else if (StartsWith(line, "@flag print_values")) {
|
|
||||||
// Force printing of applied values
|
|
||||||
print_values = true;
|
|
||||||
} else if (StartsWith(line, "@enabled") || StartsWith(line, "@disabled")) {
|
} else if (StartsWith(line, "@enabled") || StartsWith(line, "@disabled")) {
|
||||||
// Start of patch
|
// Start of patch
|
||||||
const auto enabled = StartsWith(line, "@enabled");
|
const auto enabled = StartsWith(line, "@enabled");
|
||||||
|
@ -195,6 +209,18 @@ void IPSwitchCompiler::Parse() {
|
||||||
break;
|
break;
|
||||||
const auto patch_line = lines[++i];
|
const auto patch_line = lines[++i];
|
||||||
|
|
||||||
|
// Start of new patch
|
||||||
|
if (StartsWith(patch_line, "@enabled") || StartsWith(patch_line, "@disabled")) {
|
||||||
|
--i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a flag
|
||||||
|
if (StartsWith(patch_line, "@")) {
|
||||||
|
ParseFlag(patch_line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// 11 - 8 hex digit offset + space + minimum two digit overwrite val
|
// 11 - 8 hex digit offset + space + minimum two digit overwrite val
|
||||||
if (patch_line.length() < 11)
|
if (patch_line.length() < 11)
|
||||||
break;
|
break;
|
||||||
|
@ -205,9 +231,15 @@ void IPSwitchCompiler::Parse() {
|
||||||
// 9 - first char of replacement val
|
// 9 - first char of replacement val
|
||||||
if (patch_line[9] == '\"') {
|
if (patch_line[9] == '\"') {
|
||||||
// string replacement
|
// string replacement
|
||||||
const auto end_index = patch_line.find('\"', 10);
|
auto end_index = patch_line.find('\"', 10);
|
||||||
if (end_index == std::string::npos || end_index < 10)
|
if (end_index == std::string::npos || end_index < 10)
|
||||||
return;
|
return;
|
||||||
|
while (patch_line[end_index - 1] == '\\') {
|
||||||
|
end_index = patch_line.find('\"', end_index + 1);
|
||||||
|
if (end_index == std::string::npos || end_index < 10)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto value = patch_line.substr(10, end_index - 10);
|
auto value = patch_line.substr(10, end_index - 10);
|
||||||
value = EscapeStringSequences(value);
|
value = EscapeStringSequences(value);
|
||||||
replace.reserve(value.size());
|
replace.reserve(value.size());
|
||||||
|
@ -226,10 +258,12 @@ void IPSwitchCompiler::Parse() {
|
||||||
patch_text->GetName(), offset, Common::HexVectorToString(replace));
|
patch_text->GetName(), offset, Common::HexVectorToString(replace));
|
||||||
}
|
}
|
||||||
|
|
||||||
patch.records.emplace(offset, std::move(replace));
|
patch.records.insert_or_assign(offset, std::move(replace));
|
||||||
}
|
}
|
||||||
|
|
||||||
patches.push_back(std::move(patch));
|
patches.push_back(std::move(patch));
|
||||||
|
} else if (StartsWith(line, "@")) {
|
||||||
|
ParseFlag(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
VirtualFile Apply(const VirtualFile& in) const;
|
VirtualFile Apply(const VirtualFile& in) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ParseFlag(const std::string& flag);
|
||||||
void Parse();
|
void Parse();
|
||||||
|
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
|
|
@ -76,7 +76,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||||
static std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
static std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
||||||
const std::string& build_id) {
|
const std::string& build_id) {
|
||||||
std::vector<VirtualFile> out;
|
std::vector<VirtualFile> out;
|
||||||
ips.reserve(patch_dirs.size());
|
out.reserve(patch_dirs.size());
|
||||||
for (const auto& subdir : patch_dirs) {
|
for (const auto& subdir : patch_dirs) {
|
||||||
auto exefs_dir = subdir->GetSubdirectory("exefs");
|
auto exefs_dir = subdir->GetSubdirectory("exefs");
|
||||||
if (exefs_dir != nullptr) {
|
if (exefs_dir != nullptr) {
|
||||||
|
|
Reference in New Issue