Qt: Validate cheats before saving edits

pull/3586/head
Stenzek 2 weeks ago
parent bfcd3d4220
commit 286f9dddec
No known key found for this signature in database

@ -231,7 +231,8 @@ static void EnumerateChtFiles(const std::string_view serial, std::optional<GameH
static std::optional<CodeOption> ParseOption(const std::string_view value);
static bool ParseOptionRange(const std::string_view value, u16* out_range_start, u16* out_range_end);
extern void ParseFile(CheatCodeList* dst_list, const std::string_view file_contents);
static void ParseFile(CheatCodeList* dst_list, const std::string_view file_contents);
static std::unique_ptr<CheatCode> ParseCode(CheatCode::Metadata metadata, const std::string_view data, Error* error);
static Cheats::FileFormat DetectFileFormat(const std::string_view file_contents);
static bool ImportPCSXFile(CodeInfoList* dst, const std::string_view file_contents, bool stop_on_error, Error* error);
@ -240,9 +241,6 @@ static bool ImportLibretroFile(CodeInfoList* dst, const std::string_view file_co
static bool ImportEPSXeFile(CodeInfoList* dst, const std::string_view file_contents, bool stop_on_error, Error* error);
static bool ImportOldChtFile(const std::string_view serial);
static std::unique_ptr<CheatCode> ParseGamesharkCode(CheatCode::Metadata metadata, const std::string_view data,
Error* error);
const char* PATCHES_CONFIG_SECTION = "Patches";
const char* CHEATS_CONFIG_SECTION = "Cheats";
const char* PATCH_ENABLE_CONFIG_KEY = "Enable";
@ -792,6 +790,24 @@ void Cheats::RemoveAllCodes(const std::string_view serial, const std::string_vie
}
}
bool Cheats::ValidateCodeBody(std::string_view name, CodeType type, CodeActivation activation, std::string_view body,
Error* error)
{
// don't need the full metadata, only enough to get through
CheatCode::Metadata metadata = {};
metadata.name = name;
metadata.type = type;
metadata.activation = activation;
std::unique_ptr<CheatCode> code = ParseCode(std::move(metadata), body, error);
return static_cast<bool>(code);
}
bool Cheats::ValidateCodeBody(const CodeInfo& code, Error* error)
{
return ValidateCodeBody(code.name, code.type, code.activation, code.body, error);
}
std::string Cheats::GetChtFilename(const std::string_view serial, std::optional<GameHash> hash, bool cheats)
{
return Path::Combine(cheats ? EmuFolders::Cheats : EmuFolders::Patches, GetChtTemplate(serial, hash, false));
@ -1457,28 +1473,18 @@ void Cheats::ParseFile(CheatCodeList* dst_list, const std::string_view file_cont
const std::string_view code_body =
file_contents.substr(code_body_start.value(), reader.GetCurrentLineOffset() - code_body_start.value());
std::unique_ptr<CheatCode> code;
if (next_code_metadata.type == CodeType::Gameshark)
{
Error error;
code = ParseGamesharkCode(std::move(next_code_metadata), code_body, &error);
if (!code)
{
WARNING_LOG("Failed to parse gameshark code ending on line {}: {}", reader.GetCurrentLineNumber(),
error.GetDescription());
return;
}
}
else
Error error;
std::unique_ptr<CheatCode> code = ParseCode(std::move(next_code_metadata), code_body, &error);
if (!code)
{
WARNING_LOG("Unknown code type ending at line {}", reader.GetCurrentLineNumber());
return;
WARNING_LOG("Failed to parse gameshark code ending on line {}: {}", reader.GetCurrentLineNumber(),
error.GetDescription());
}
next_code_group = {};
next_code_metadata = {};
code_body_start.reset();
if (std::exchange(next_code_ignored, false))
if (std::exchange(next_code_ignored, false) || !code)
return;
// overwrite existing codes with the same name.
@ -4446,14 +4452,26 @@ void Cheats::GamesharkCheatCode::SetOptionValue(u32 value)
{
Instruction& inst = instructions[index];
const u32 value_mask = ((1u << bit_count) - 1);
;
const u32 fixed_mask = ~(value_mask << bitpos_start);
inst.second = (inst.second & fixed_mask) | ((value & value_mask) << bitpos_start);
}
}
std::unique_ptr<Cheats::CheatCode> Cheats::ParseGamesharkCode(CheatCode::Metadata metadata, const std::string_view data,
Error* error)
std::unique_ptr<Cheats::CheatCode> Cheats::ParseCode(CheatCode::Metadata metadata, const std::string_view data,
Error* error)
{
return GamesharkCheatCode::Parse(std::move(metadata), data, error);
std::unique_ptr<Cheats::CheatCode> ret;
switch (metadata.type)
{
case CodeType::Gameshark:
ret = GamesharkCheatCode::Parse(std::move(metadata), data, error);
break;
default:
Error::SetStringView(error, "Unknown code type");
break;
}
return ret;
}

@ -124,6 +124,11 @@ extern bool SaveCodesToFile(const char* path, const CodeInfoList& codes, Error*
/// Removes any .cht files for the specified game.
extern void RemoveAllCodes(const std::string_view serial, const std::string_view title, std::optional<GameHash> hash);
/// Validates whether a cheat code is properly formatted.
extern bool ValidateCodeBody(std::string_view name, CodeType type, CodeActivation activation, std::string_view body,
Error* error);
extern bool ValidateCodeBody(const CodeInfo& code, Error* error);
/// Returns the path to a new cheat/patch cht for the specified serial and hash.
extern std::string GetChtFilename(const std::string_view serial, std::optional<GameHash> hash, bool cheats);

@ -864,6 +864,23 @@ void CheatCodeEditorDialog::saveClicked()
return;
}
const Cheats::CodeType new_type = static_cast<Cheats::CodeType>(m_ui.type->currentIndex());
const Cheats::CodeActivation new_activation = static_cast<Cheats::CodeActivation>(m_ui.activation->currentIndex());
// Validate it before trying to save it.
Error error;
if (!Cheats::ValidateCodeBody(new_name, new_type, new_activation, new_body, &error))
{
if (QMessageBox::question(QtUtils::GetRootWidget(this), tr("Error"),
tr("The entered cheat code is not valid:\n\n%1\n\nTrying to use this cheat will not work "
"as expected. Do you want to continue?")
.arg(QString::fromStdString(error.GetDescription())),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
{
return;
}
}
// name actually includes the prefix
if (const int index = m_ui.group->currentIndex(); index != 0)
{
@ -894,8 +911,8 @@ void CheatCodeEditorDialog::saveClicked()
.replace(QChar('\n'), QChar(' '))
.trimmed()
.toStdString();
m_code->type = static_cast<Cheats::CodeType>(m_ui.type->currentIndex());
m_code->activation = static_cast<Cheats::CodeActivation>(m_ui.activation->currentIndex());
m_code->type = new_type;
m_code->activation = new_activation;
m_code->body = std::move(new_body);
m_code->option_range_start = 0;
@ -914,7 +931,6 @@ void CheatCodeEditorDialog::saveClicked()
}
std::string path = m_parent->getPathForSavingCheats();
Error error;
if (!Cheats::UpdateCodeInFile(path.c_str(), old_name, m_code, &error))
{
QMessageBox::critical(this, tr("Error"),

Loading…
Cancel
Save