From 7506fc9f00a64c2d69e60d7ef0189040d8a2fd36 Mon Sep 17 00:00:00 2001 From: Richard Ainger Date: Sun, 7 Aug 2022 12:48:00 +1000 Subject: [PATCH] Fixed infinite loop and crash which could occur when using "Import from cheat.db". --- UI/CwCheatScreen.cpp | 82 ++++++++++++++++++++++++-------------------- UI/CwCheatScreen.h | 1 + 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index aaf5b8e13a..567eab3f8d 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -201,7 +201,6 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { } std::string line; std::vector title; - bool finished = false; std::vector newList; Path cheatFile = GetSysDirectory(DIRECTORY_CHEATS) / "cheat.db"; @@ -215,43 +214,39 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { } char linebuf[2048]{}; + bool parseGameEntry = false; + bool parseCheatEntry = false; + while (in && !feof(in)) { char *line = GetLineNoNewline(linebuf, sizeof(linebuf), in); - if (line && gameID == line) { - title.push_back(line); - line = GetLineNoNewline(linebuf, sizeof(linebuf), in); - if (line) - title.push_back(line); - do { - if (finished == false){ - line = GetLineNoNewline(linebuf, sizeof(linebuf), in); - } - if (line && line[0] == '_' && line[1] == 'C') { - // Test if cheat already exists. - for (const auto &existing : fileInfo_) { - if (std::string(line).substr(4) == existing.name) { - finished = false; - goto loop; - } - } - newList.push_back(line); - line = GetLineNoNewline(linebuf, sizeof(linebuf), in); - do { - if (line) - newList.push_back(line); - line = GetLineNoNewline(linebuf, sizeof(linebuf), in); - } while ((line[0] == '_' && line[1] == 'L') || line[0] == '/' || line[0] == '#'); - finished = true; - } else { - continue; - } - loop:; - } while (!feof(in) && ((line[0] == '_' && line[1] != 'S') || line[0] == '/' || line[0] == '#')); - finished = true; + if (!line) { + continue; + } + + if (line[0] == '_' && line[1] == 'S') { + parseGameEntry = gameID == line; + parseCheatEntry = false; + } else if (parseGameEntry && line[0] == '_' && line[1] == 'C') { + // Test if cheat already exists. + parseCheatEntry = !HasCheatWithName(std::string(line).substr(4)); + } + + if (!parseGameEntry) { + if (newList.size() > 0) { + // Only parse the first matching game entry. + break; + } else { + // Haven't yet found a matching game entry, continue parsing. + continue; + } + } + + if (line[0] == '_' && (line[1] == 'S' || line[1] == 'G') && title.size() < 2) { + title.push_back(line); + } else if (parseCheatEntry && (line[0] == '_' && (line[1] == 'C' || line[1] == 'L')) || line[0] == '/' || line[0] == '#') { + newList.push_back(line); } - if (finished == true) - break; } fclose(in); @@ -270,12 +265,13 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { if (!append) return UI::EVENT_SKIPPED; - auto it = title.begin(); - if (((title2[0] == '_' && title2[1] != 'S') || title2[0] == '/' || title2[0] == '#') && it != title.end() && (++it) != title.end()) { - fprintf(append, "%s\n%s", title[0].c_str(), title[1].c_str()); + if (title2.size() == 0 || title2[0] != '_' || title2[1] != 'S') { + for (int i = (int)title.size(); i > 0; i--) { + newList.insert(newList.begin(), title[i - 1]); + } } - NOTICE_LOG(COMMON, "Imported %u entries from %s.\n", (int)newList.size(), cheatFile.c_str()); + NOTICE_LOG(COMMON, "Imported %u lines from %s.\n", (int)newList.size(), cheatFile.c_str()); if (newList.size() != 0) { fputc('\n', append); } @@ -303,6 +299,16 @@ UI::EventReturn CwCheatScreen::OnCheckBox(int index) { return UI::EVENT_DONE; } +bool CwCheatScreen::HasCheatWithName(const std::string &name) { + for (const auto &existing : fileInfo_) { + if (name == existing.name) { + return true; + } + } + + return false; +} + bool CwCheatScreen::RebuildCheatFile(int index) { if (!engine_) return false; diff --git a/UI/CwCheatScreen.h b/UI/CwCheatScreen.h index 79f8386ce0..e2e167c771 100644 --- a/UI/CwCheatScreen.h +++ b/UI/CwCheatScreen.h @@ -48,6 +48,7 @@ private: UI::EventReturn OnCheckBox(int index); enum { INDEX_ALL = -1 }; + bool HasCheatWithName(const std::string &name); bool RebuildCheatFile(int index); UI::ScrollView *rightScroll_ = nullptr;