Skip to content

Commit 78a1c46

Browse files
authored
Merge pull request #20857 from hrydgard/cwcheat-code-cleanup
CwCheat code cleanup
2 parents d04e9b0 + f21876b commit 78a1c46

File tree

3 files changed

+86
-129
lines changed

3 files changed

+86
-129
lines changed

Core/CwCheat.cpp

Lines changed: 39 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -43,89 +43,51 @@ using namespace SceCtrl;
4343

4444
void 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

10667
bool 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

13799
void 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

146107
void 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-
403352
void 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-
819745
void 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
}

Core/CwCheat.h

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#pragma once
44

55
#include <string>
6+
#include <string_view>
67
#include <vector>
78
#include <iostream>
89
#include <sstream>
@@ -24,14 +25,7 @@ struct CheatLine {
2425
uint32_t part2;
2526
};
2627

27-
enum class CheatCodeFormat {
28-
UNDEFINED,
29-
CWCHEAT,
30-
TEMPAR,
31-
};
32-
3328
struct CheatCode {
34-
CheatCodeFormat fmt;
3529
std::string name;
3630
std::vector<CheatLine> lines;
3731
};
@@ -46,20 +40,26 @@ struct CheatOperation;
4640

4741
class CWCheatEngine {
4842
public:
49-
CWCheatEngine(const std::string &gameID);
50-
std::vector<CheatFileInfo> FileInfo();
43+
CWCheatEngine(std::string_view gameID);
44+
std::vector<CheatFileInfo> FileInfo() const;
5145
void ParseCheats();
5246
void CreateCheatFile();
53-
Path CheatFilename();
47+
const Path &CheatFilename() const {
48+
return filename_;
49+
}
5450
void Run();
5551
bool HasCheats();
52+
static u32 GetAddress(u32 value) {
53+
// TODO: This comment is weird:
54+
// Returns static address used by ppsspp. Some games may not like this, and causes cheats to not work without offset
55+
u32 address = (value + 0x08800000) & 0x3FFFFFFF;
56+
return address;
57+
}
58+
5659
private:
5760
void InvalidateICache(u32 addr, int size) const;
58-
u32 GetAddress(u32 value);
5961

60-
CheatOperation InterpretNextOp(const CheatCode &cheat, size_t &i);
6162
CheatOperation InterpretNextCwCheat(const CheatCode &cheat, size_t &i);
62-
CheatOperation InterpretNextTempAR(const CheatCode &cheat, size_t &i);
6363

6464
void ExecuteOp(const CheatOperation &op, const CheatCode &cheat, size_t &i);
6565
inline void ApplyMemoryOperator(const CheatOperation &op, uint32_t(*oper)(uint32_t, uint32_t));
@@ -70,3 +70,36 @@ class CWCheatEngine {
7070
std::string gameID_;
7171
Path filename_;
7272
};
73+
74+
class CheatFileParser {
75+
public:
76+
CheatFileParser(const Path &filename, std::string_view gameID = "");
77+
~CheatFileParser();
78+
79+
bool Parse();
80+
81+
const std::vector<std::string> &GetErrors() const { return errors_; }
82+
const std::vector<CheatCode> &GetCheats() const { return cheats_; }
83+
const std::vector<CheatFileInfo> &GetFileInfo() const { return cheatInfo_; }
84+
85+
protected:
86+
void Flush();
87+
void FlushCheatInfo();
88+
void AddError(const std::string &msg, int lineNumber);
89+
void ParseLine(const std::string &line, int lineNumber);
90+
void ParseDataLine(const std::string &line, int lineNumber);
91+
bool ValidateGameID(std::string_view gameID);
92+
93+
FILE *fp_ = nullptr;
94+
std::string validGameID_;
95+
96+
int games_ = 0;
97+
std::vector<std::string> errors_;
98+
std::vector<CheatFileInfo> cheatInfo_;
99+
std::vector<CheatCode> cheats_;
100+
std::vector<CheatLine> pendingLines_;
101+
CheatFileInfo lastCheatInfo_;
102+
bool gameEnabled_ = true;
103+
bool gameRiskyEnabled_ = false;
104+
bool cheatEnabled_ = false;
105+
};

0 commit comments

Comments
 (0)