|
|
@ -19,16 +19,23 @@ namespace Core::Memory { |
|
|
namespace { |
|
|
namespace { |
|
|
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; |
|
|
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; |
|
|
|
|
|
|
|
|
std::string_view ExtractName(std::string_view data, std::size_t start_index, char match) { |
|
|
|
|
|
|
|
|
std::string_view ExtractName(std::size_t& out_name_size, std::string_view data, |
|
|
|
|
|
std::size_t start_index, char match) { |
|
|
auto end_index = start_index; |
|
|
auto end_index = start_index; |
|
|
while (data[end_index] != match) { |
|
|
while (data[end_index] != match) { |
|
|
++end_index; |
|
|
++end_index; |
|
|
if (end_index > data.size() || |
|
|
|
|
|
(end_index - start_index - 1) > sizeof(CheatDefinition::readable_name)) { |
|
|
|
|
|
|
|
|
if (end_index > data.size()) { |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
out_name_size = end_index - start_index; |
|
|
|
|
|
|
|
|
|
|
|
// Clamp name if it's too big
|
|
|
|
|
|
if (out_name_size > sizeof(CheatDefinition::readable_name)) { |
|
|
|
|
|
end_index = start_index + sizeof(CheatDefinition::readable_name); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return data.substr(start_index, end_index - start_index); |
|
|
return data.substr(start_index, end_index - start_index); |
|
|
} |
|
|
} |
|
|
} // Anonymous namespace
|
|
|
} // Anonymous namespace
|
|
|
@ -113,7 +120,8 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const { |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const auto name = ExtractName(data, i + 1, '}'); |
|
|
|
|
|
|
|
|
std::size_t name_size{}; |
|
|
|
|
|
const auto name = ExtractName(name_size, data, i + 1, '}'); |
|
|
if (name.empty()) { |
|
|
if (name.empty()) { |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
@ -125,12 +133,13 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const { |
|
|
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] = |
|
|
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] = |
|
|
'\0'; |
|
|
'\0'; |
|
|
|
|
|
|
|
|
i += name.length() + 1; |
|
|
|
|
|
|
|
|
i += name_size + 1; |
|
|
} else if (data[i] == '[') { |
|
|
} else if (data[i] == '[') { |
|
|
current_entry = out.size(); |
|
|
current_entry = out.size(); |
|
|
out.emplace_back(); |
|
|
out.emplace_back(); |
|
|
|
|
|
|
|
|
const auto name = ExtractName(data, i + 1, ']'); |
|
|
|
|
|
|
|
|
std::size_t name_size{}; |
|
|
|
|
|
const auto name = ExtractName(name_size, data, i + 1, ']'); |
|
|
if (name.empty()) { |
|
|
if (name.empty()) { |
|
|
return {}; |
|
|
return {}; |
|
|
} |
|
|
} |
|
|
@ -142,7 +151,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const { |
|
|
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] = |
|
|
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] = |
|
|
'\0'; |
|
|
'\0'; |
|
|
|
|
|
|
|
|
i += name.length() + 1; |
|
|
|
|
|
|
|
|
i += name_size + 1; |
|
|
} else if (::isxdigit(data[i])) { |
|
|
} else if (::isxdigit(data[i])) { |
|
|
if (!current_entry || out[*current_entry].definition.num_opcodes >= |
|
|
if (!current_entry || out[*current_entry].definition.num_opcodes >= |
|
|
out[*current_entry].definition.opcodes.size()) { |
|
|
out[*current_entry].definition.opcodes.size()) { |
|
|
|