@@ -43,89 +43,51 @@ using namespace SceCtrl;
4343
4444void hleCheat(u64 userdata, int cyclesLate);
4545
46- static inline std::string TrimString(const std::string & s) {
46+ static inline std::string TrimString(std::string_view s) {
4747 auto wsfront = std::find_if_not(s.begin(), s.end(), [](int c) {
4848 // isspace() expects 0 - 255, so convert any sign-extended value.
49- return std::isspace(c & 0xFF );
49+ return std::isspace((u8)c );
5050 });
5151 auto wsback = std::find_if_not(s.rbegin(), s.rend(), [](int c){
52- return std::isspace(c & 0xFF );
52+ return std::isspace((u8)c );
5353 }).base();
5454 return wsback > wsfront ? std::string(wsfront, wsback) : std::string();
5555}
5656
57- class CheatFileParser {
58- public:
59- CheatFileParser(const Path &filename, const std::string &gameID = "") {
60- fp_ = File::OpenCFile(filename, "rt");
61- validGameID_ = ReplaceAll(gameID, "-", "");
62- }
63- ~CheatFileParser() {
64- if (fp_)
65- fclose(fp_);
66- }
67-
68- bool Parse();
69-
70- std::vector<std::string> GetErrors() const {
71- return errors_;
72- }
73-
74- std::vector<CheatCode> GetCheats() const {
75- return cheats_;
76- }
77-
78- std::vector<CheatFileInfo> GetFileInfo() const {
79- return cheatInfo_;
80- }
57+ CheatFileParser::CheatFileParser(const Path &filename, std::string_view gameID) {
58+ fp_ = File::OpenCFile(filename, "rt");
59+ validGameID_ = ReplaceAll(gameID, "-", "");
60+ }
8161
82- protected:
83- void Flush();
84- void FlushCheatInfo();
85- void AddError(const std::string &msg);
86- void ParseLine(const std::string &line);
87- void ParseDataLine(const std::string &line, CheatCodeFormat format);
88- bool ValidateGameID(const std::string &gameID);
89-
90- FILE *fp_ = nullptr;
91- std::string validGameID_;
92-
93- int line_ = 0;
94- int games_ = 0;
95- std::vector<std::string> errors_;
96- std::vector<CheatFileInfo> cheatInfo_;
97- std::vector<CheatCode> cheats_;
98- std::vector<CheatLine> pendingLines_;
99- CheatCodeFormat codeFormat_ = CheatCodeFormat::UNDEFINED;
100- CheatFileInfo lastCheatInfo_;
101- bool gameEnabled_ = true;
102- bool gameRiskyEnabled_ = false;
103- bool cheatEnabled_ = false;
104- };
62+ CheatFileParser::~CheatFileParser() {
63+ if (fp_)
64+ fclose(fp_);
65+ }
10566
10667bool CheatFileParser::Parse() {
107- for (line_ = 1; fp_ && !feof(fp_); ++line_) {
68+ // Ugh, using a member variable as loop counter is bad.
69+ for (int lineNumber = 1; fp_ && !feof(fp_); ++lineNumber) {
10870 char temp[2048];
10971 char *tempLine = fgets(temp, sizeof(temp), fp_);
11072 if (!tempLine)
11173 continue;
11274
11375 // Detect UTF-8 BOM sequence, and ignore it.
114- if (line_ == 1 && memcmp(tempLine, "\xEF\xBB\xBF", 3) == 0)
76+ if (lineNumber == 1 && memcmp(tempLine, "\xEF\xBB\xBF", 3) == 0)
11577 tempLine += 3;
11678 std::string line = TrimString(tempLine);
11779
11880 // Minimum length 5 is shortest possible _ lines name of the game "_G N+"
11981 // and a minimum of 1 displayable character in cheat name string "_C0 1"
12082 // which both equal to 5 characters.
12183 if (line.length() >= 5 && line[0] == '_') {
122- ParseLine(line);
84+ ParseLine(line, lineNumber );
12385 } else if (line.length() >= 2 && line[0] == '/' && line[1] == '/') {
12486 // Comment, ignore.
12587 } else if (line.length() >= 1 && line[0] == '#') {
12688 // Comment, ignore.
12789 } else if (line.length() > 0) {
128- errors_.push_back(StringFromFormat("Unrecognized content on line %d: expecting _", line_ ));
90+ errors_.push_back(StringFromFormat("Unrecognized content on line %d: expecting _", lineNumber ));
12991 }
13092 }
13193
@@ -136,11 +98,10 @@ bool CheatFileParser::Parse() {
13698
13799void CheatFileParser::Flush() {
138100 if (!pendingLines_.empty()) {
139- cheats_.push_back({ codeFormat_, lastCheatInfo_.name, pendingLines_ });
101+ cheats_.push_back(CheatCode{ lastCheatInfo_.name, pendingLines_});
140102 FlushCheatInfo();
141103 pendingLines_.clear();
142104 }
143- codeFormat_ = CheatCodeFormat::UNDEFINED;
144105}
145106
146107void CheatFileParser::FlushCheatInfo() {
@@ -150,11 +111,11 @@ void CheatFileParser::FlushCheatInfo() {
150111 }
151112}
152113
153- void CheatFileParser::AddError(const std::string &err) {
154- errors_.push_back(StringFromFormat("Error on line %d: %s", line_ , err.c_str()));
114+ void CheatFileParser::AddError(const std::string &err, int lineNumber ) {
115+ errors_.push_back(StringFromFormat("Error on line %d: %s", lineNumber , err.c_str()));
155116}
156117
157- void CheatFileParser::ParseLine(const std::string &line) {
118+ void CheatFileParser::ParseLine(const std::string &line, int lineNumber ) {
158119 switch (line[1]) {
159120 case 'S':
160121 // Disc ID, validate (for multi-disc cheat files)?
@@ -194,47 +155,39 @@ void CheatFileParser::ParseLine(const std::string &line) {
194155
195156 // Cheat name and activation status.
196157 if (line.length() >= 3 && line[2] >= '1' && line[2] <= '9') {
197- lastCheatInfo_ = { line_ , line.length() >= 5 ? line.substr(4) : "", true };
158+ lastCheatInfo_ = { lineNumber , line.length() >= 5 ? line.substr(4) : "", true };
198159 cheatEnabled_ = true;
199160 } else if (line.length() >= 3 && line[2] == '0') {
200- lastCheatInfo_ = { line_ , line.length() >= 5 ? line.substr(4) : "", false };
161+ lastCheatInfo_ = { lineNumber , line.length() >= 5 ? line.substr(4) : "", false };
201162 cheatEnabled_ = false;
202163 } else {
203- AddError("could not parse cheat name line");
164+ AddError("could not parse cheat name line", lineNumber );
204165 cheatEnabled_ = false;
205166 return;
206167 }
207168 return;
208169
209170 case 'L':
210171 // CwCheat data line.
211- ParseDataLine(line.substr(2), CheatCodeFormat::CWCHEAT );
172+ ParseDataLine(line.substr(2), lineNumber );
212173 return;
213174
214175 case 'M':
215176 // TempAR data line.
216- ParseDataLine(line.substr(2), CheatCodeFormat::TEMPAR );
177+ AddError("TempAR codes not supported", lineNumber );
217178 return;
218179
219180 default:
220- AddError("unknown line type");
181+ AddError("unknown line type", lineNumber );
221182 return;
222183 }
223184}
224185
225- void CheatFileParser::ParseDataLine(const std::string &line, CheatCodeFormat format) {
226- if (codeFormat_ == CheatCodeFormat::UNDEFINED) {
227- codeFormat_ = format;
228- } else if (codeFormat_ != format) {
229- AddError("mixed code format (cwcheat/tempar)");
230- lastCheatInfo_ = { 0 };
231- pendingLines_.clear();
232- cheatEnabled_ = false;
233- }
234-
186+ void CheatFileParser::ParseDataLine(const std::string &line, int lineNumber) {
235187 if (!gameEnabled_) {
236188 return;
237189 }
190+
238191 if (!cheatEnabled_) {
239192 FlushCheatInfo();
240193 return;
@@ -244,15 +197,15 @@ void CheatFileParser::ParseDataLine(const std::string &line, CheatCodeFormat for
244197 int len = 0;
245198 if (sscanf(line.c_str(), "%x %x %n", &cheatLine.part1, &cheatLine.part2, &len) == 2) {
246199 if ((size_t)len < line.length()) {
247- AddError("junk after line data");
200+ AddError("junk after line data", lineNumber );
248201 }
249202 pendingLines_.push_back(cheatLine);
250203 } else {
251- AddError("expecting two values");
204+ AddError("expecting two values", lineNumber );
252205 }
253206}
254207
255- bool CheatFileParser::ValidateGameID(const std::string & gameID) {
208+ bool CheatFileParser::ValidateGameID(std::string_view gameID) {
256209 return validGameID_.empty() || ReplaceAll(TrimString(gameID), "-", "") == validGameID_;
257210}
258211
@@ -369,14 +322,14 @@ void hleCheat(u64 userdata, int cyclesLate) {
369322 if (!cheatEngine || !cheatsEnabled)
370323 return;
371324
372- if (g_Config.bReloadCheats) { // Checks if the "reload cheats" button has been pressed.
325+ if (g_Config.bReloadCheats) { // Checks if the "reload cheats" button has been pressed.
373326 cheatEngine->ParseCheats();
374327 g_Config.bReloadCheats = false;
375328 }
376329 cheatEngine->Run();
377330}
378331
379- CWCheatEngine::CWCheatEngine(const std::string & gameID) : gameID_(gameID) {
332+ CWCheatEngine::CWCheatEngine(std::string_view gameID) : gameID_(gameID) {
380333 filename_ = GetSysDirectory(DIRECTORY_CHEATS) / (gameID_ + ".ini");
381334}
382335
@@ -396,28 +349,20 @@ void CWCheatEngine::CreateCheatFile() {
396349 }
397350}
398351
399- Path CWCheatEngine::CheatFilename() {
400- return filename_;
401- }
402-
403352void CWCheatEngine::ParseCheats() {
404353 CheatFileParser parser(filename_, gameID_);
405354
406355 parser.Parse();
407- // TODO: Report errors.
356+ // TODO: Report errors in a user-visible way.
357+ for (auto &error : parser.GetErrors()) {
358+ ERROR_LOG(Log::System, "CwCheat error: %s", error.c_str());
359+ }
408360
409361 cheats_ = parser.GetCheats();
410362}
411363
412- u32 CWCheatEngine::GetAddress(u32 value) {
413- // Returns static address used by ppsspp. Some games may not like this, and causes cheats to not work without offset
414- u32 address = (value + 0x08800000) & 0x3FFFFFFF;
415- return address;
416- }
417-
418- std::vector<CheatFileInfo> CWCheatEngine::FileInfo() {
364+ std::vector<CheatFileInfo> CWCheatEngine::FileInfo() const {
419365 CheatFileParser parser(filename_, gameID_);
420-
421366 parser.Parse();
422367 return parser.GetFileInfo();
423368}
@@ -797,25 +742,6 @@ CheatOperation CWCheatEngine::InterpretNextCwCheat(const CheatCode &cheat, size_
797742 }
798743}
799744
800- CheatOperation CWCheatEngine::InterpretNextTempAR(const CheatCode &cheat, size_t &i) {
801- // TODO
802- return { CheatOp::Invalid };
803- }
804-
805- CheatOperation CWCheatEngine::InterpretNextOp(const CheatCode &cheat, size_t &i) {
806- if (cheat.fmt == CheatCodeFormat::CWCHEAT)
807- return InterpretNextCwCheat(cheat, i);
808- else if (cheat.fmt == CheatCodeFormat::TEMPAR)
809- return InterpretNextTempAR(cheat, i);
810- else {
811- // This shouldn't happen, but apparently does: #14082
812- // Either I'm missing a path or we have memory corruption.
813- // Not sure whether to log here though, feels like we could end up with a
814- // ton of logspam...
815- return { CheatOp::Invalid };
816- }
817- }
818-
819745void CWCheatEngine::ApplyMemoryOperator(const CheatOperation &op, uint32_t(*oper)(uint32_t, uint32_t)) {
820746 if (Memory::IsValidRange(op.addr, op.sz)) {
821747 InvalidateICache(op.addr, op.sz);
@@ -1224,7 +1150,7 @@ void CWCheatEngine::Run() {
12241150 for (const CheatCode &cheat : cheats_) {
12251151 // InterpretNextOp and ExecuteOp move i.
12261152 for (size_t i = 0; i < cheat.lines.size(); ) {
1227- CheatOperation op = InterpretNextOp (cheat, i);
1153+ CheatOperation op = InterpretNextCwCheat (cheat, i);
12281154 ExecuteOp(op, cheat, i);
12291155 }
12301156 }
0 commit comments