diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 17eed7e047..0f6e9a5f55 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -182,6 +182,18 @@ UI::EventReturn CwCheatScreen::OnEditCheatFile(UI::EventParams ¶ms) { return UI::EVENT_DONE; } +static char *GetLineNoNewline(char *temp, int sz, FILE *fp) { + char *line = fgets(temp, sz, fp); + if (!line) + return nullptr; + + // If the last character is \n, just make it the terminator. + char *end = line + strlen(line) - 1; + if (*end == '\n') + *end = '\0'; + return line; +} + UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { if (gameID_.length() != 9 || !engine_) { WARN_LOG(COMMON, "CWCHEAT: Incorrect ID(%s) - can't import cheats.", gameID_.c_str()); @@ -195,73 +207,85 @@ UI::EventReturn CwCheatScreen::OnImportCheat(UI::EventParams ¶ms) { std::string cheatFile = GetSysDirectory(DIRECTORY_CHEATS) + "cheat.db"; std::string gameID = StringFromFormat("_S %s-%s", gameID_.substr(0, 4).c_str(), gameID_.substr(4).c_str()); - std::fstream fs; - File::OpenCPPFile(fs, cheatFile, std::ios::in); + FILE *in = File::OpenCFile(cheatFile, "rt"); - if (!fs.is_open()) { + if (!in) { WARN_LOG(COMMON, "Unable to open %s\n", cheatFile.c_str()); } - while (fs.good()) { - getline(fs, line); // get line from file - if (line == gameID) { - title.push_back(line); - getline(fs, line); + char linebuf[2048]{}; + 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){ - getline(fs, line); + line = GetLineNoNewline(linebuf, sizeof(linebuf), in); } - if (line[0] == '_' && line[1] == 'C') { + if (line && line[0] == '_' && line[1] == 'C') { // Test if cheat already exists. for (const auto &existing : fileInfo_) { - if (line.substr(4) == existing.name) { + if (std::string(line).substr(4) == existing.name) { finished = false; goto loop; } } newList.push_back(line); - getline(fs, line); + line = GetLineNoNewline(linebuf, sizeof(linebuf), in); do { - newList.push_back(line); - getline(fs, line); + 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 (fs.good() && ((line[0] == '_' && line[1] != 'S') || line[0] == '/' || line[0] == '#')); + } while (!feof(in) && ((line[0] == '_' && line[1] != 'S') || line[0] == '/' || line[0] == '#')); finished = true; } if (finished == true) break; } - fs.close(); + fclose(in); + std::string title2; - File::OpenCPPFile(fs, engine_->CheatFilename(), std::ios::in); - getline(fs, title2); - fs.close(); - File::OpenCPPFile(fs, engine_->CheatFilename(), std::ios::out | std::ios::app); + // Hmm, this probably gets confused about BOMs? + FILE *inTitle2 = File::OpenCFile(engine_->CheatFilename(), "rt"); + if (inTitle2) { + char temp[2048]; + char *line = GetLineNoNewline(temp, sizeof(temp), inTitle2); + if (line) + title2 = line; + fclose(inTitle2); + } + + FILE *append = File::OpenCFile(engine_->CheatFilename(), "at"); + 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()) { - fs << title[0] << "\n" << title[1]; + fprintf(append, "%s\n%s", title[0].c_str(), title[1].c_str()); } NOTICE_LOG(COMMON, "Imported %u entries from %s.\n", (int)newList.size(), cheatFile.c_str()); if (newList.size() != 0) { - fs << "\n"; + fputc('\n', append); } for (int i = 0; i < (int)newList.size(); i++) { - fs << newList[i]; + fprintf(append, "%s", newList[i].c_str()); if (i < (int)newList.size() - 1) { - fs << "\n"; + fputc('\n', append); } } - fs.close(); + fclose(append); g_Config.bReloadCheats = true; RecreateViews(); @@ -279,19 +303,23 @@ UI::EventReturn CwCheatScreen::OnCheckBox(int index) { } bool CwCheatScreen::RebuildCheatFile(int index) { - std::fstream fs; - if (!engine_ || !File::OpenCPPFile(fs, engine_->CheatFilename(), std::ios::in)) { + if (!engine_) + return false; + FILE *in = File::OpenCFile(engine_->CheatFilename(), "rt"); + if (!in) return false; - } // In case lines were edited while we weren't looking, reload them. std::vector lines; - for (; fs && !fs.eof(); ) { - std::string line; - std::getline(fs, line, '\n'); + for (; !feof(in); ) { + char temp[2048]; + char *line = GetLineNoNewline(temp, sizeof(temp), in); + if (!line) + break; + lines.push_back(line); } - fs.close(); + fclose(in); auto updateLine = [&](const CheatFileInfo &info) { // Line numbers start with one, not zero. @@ -324,17 +352,17 @@ bool CwCheatScreen::RebuildCheatFile(int index) { } } - - if (!File::OpenCPPFile(fs, engine_->CheatFilename(), std::ios::out | std::ios::trunc)) { + FILE *out = File::OpenCFile(engine_->CheatFilename(), "wt"); + if (!out) { return false; } for (int i = 0; i < lines.size(); ++i) { - fs << lines[i]; - if (i != lines.size()-1) - fs << '\n'; + fprintf(out, "%s", lines[i].c_str()); + if (i != lines.size() - 1) + fputc('\n', out); } - fs.close(); + fclose(out); // Cheats will need to be reparsed now. g_Config.bReloadCheats = true;