diff --git a/out/boot.dol b/out/boot.dol index a79861ca..cefad639 100644 Binary files a/out/boot.dol and b/out/boot.dol differ diff --git a/source/cheats/gct.cpp b/source/cheats/gct.cpp index 39ad02f8..badfef59 100644 --- a/source/cheats/gct.cpp +++ b/source/cheats/gct.cpp @@ -1,254 +1,231 @@ -#include -#include +/**************************************************************************** + * Copyright (C) 2009 nIxx + * Copyright (C) 2012 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include #include #include #include "gct.h" #define ERRORRANGE "Error: CheatNr out of range" +//Header and Footer +static const char GCT_Header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde }; +static const char GCT_Footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + GCTCheats::GCTCheats(void) { - Reset(); } GCTCheats::~GCTCheats(void) { - string sGameID =""; - string sGameTitle = ""; } -unsigned int GCTCheats::getCnt() +void GCTCheats::Clear(void) { - return iCntCheats; + cheatList.clear(); + sGameID.clear(); + sGameTitle.clear(); + sCheatSelected.clear(); } -string GCTCheats::getGameName(void) +std::string GCTCheats::getGameName(void) { return sGameTitle; } -string GCTCheats::getGameID(void) +std::string GCTCheats::getGameID(void) { return sGameID; } -string GCTCheats::getCheat(unsigned int nr) +std::vector GCTCheats::getCheat(int nr) { - if (nr <= (iCntCheats-1)) - return sCheats[nr]; - return ERRORRANGE; + if((unsigned int)nr >= cheatList.size()) + return std::vector(); + + return cheatList[nr].sCheats; } -string GCTCheats::getCheatName(unsigned int nr) +std::string GCTCheats::getCheatName(int nr) { - if (nr <= (iCntCheats-1)) - return sCheatName[nr]; - return ERRORRANGE; + if((unsigned int)nr >= cheatList.size()) + return ERRORRANGE; + + return cheatList[nr].sCheatName; } -string GCTCheats::getCheatComment(unsigned int nr) +std::string GCTCheats::getCheatComment(int nr) { - if (nr <= (iCntCheats-1)) - return sCheatComment[nr]; - return ERRORRANGE; + if((unsigned int)nr >= cheatList.size()) + return ERRORRANGE; + + return cheatList[nr].sCheatComment; } -//creates gct from internal array -int GCTCheats::createGCT(const char * filename) +int GCTCheats::createGCT(const char *filename) { - std::ofstream filestr; - filestr.open(filename); - if (filestr.fail()) return 0; + if (!filename) + return 0; - //Header and Footer - char header[] = { 0x00, 0xd0, 0xc0, 0xde, 0x00, 0xd0, 0xc0, 0xde}; - char footer[] = { 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + FILE *pFile = fopen(filename, "wb"); - filestr.write(header,sizeof(header)); + if (!pFile) + return 0; - for (unsigned int i=0; i < iCntCheats; ++i) - if (sCheatSelected[i] == true) - { - // cheat is selected, export it - string buf = getCheat(i); + fwrite(GCT_Header, sizeof(GCT_Header), 1, pFile); - int x = 0; - while (x < (int)buf.size()) - { - string temp = buf.substr(x,2); - long int li = strtol(temp.c_str(),NULL,16); - temp = li; - filestr.write(temp.c_str(),1); - x +=2; - } - } - filestr.write(footer,sizeof(footer)); - filestr.close(); - - return 1; -} - -//rewrite and save code.txt to mark which codes are #selected# -int GCTCheats::createTXT(const char * filename) -{ - - // save txt file - std::fstream file; - file.open(filename, std::ios::out); - - file << sGameID << std::endl; - file << sGameTitle << std::endl << std::endl; - - for (unsigned int i=0; i < iCntCheats; ++i) - if (sCheatSelected[i]) - { - file << sCheatName[i] << std::endl; - for (unsigned int j=0; j+8 < sCheats[i].size(); j+=16) - file << sCheats[i].substr(j,8) << " " << sCheats[i].substr(j+8,8) << std::endl; - - file << "#selected#" << sCheatComment[i] << std::endl; - file << std::endl; - } - - for (unsigned int i=0; i < iCntCheats; ++i) - if (!sCheatSelected[i]) - { - file << sCheatName[i] << std::endl; - for (unsigned int j=0; j+8 < sCheats[i].size(); j+=16) - file << sCheats[i].substr(j,8) << " " << sCheats[i].substr(j+8,8) << std::endl; - - if (sCheatComment[i].size() > 1) - file << sCheatComment[i] << std::endl; - file << std::endl; - } - - file.close(); - return 1; -} - - -int GCTCheats::openTxtfile(const char * filename) -{ - Reset(); - - std::ifstream filestr; - filestr.open(filename); - if (filestr.fail()) return 0; - - int i = 0; - string str; - - filestr.seekg(0, std::ios_base::end); - int size = filestr.tellg(); - if (size <= 0) return -1; - filestr.seekg(0, std::ios_base::beg); - - getline(filestr,sGameID); - if (sGameID[sGameID.length() - 1] == '\r') - sGameID.erase(sGameID.length() - 1); - - getline(filestr,sGameTitle); - if (sGameTitle[sGameTitle.length() - 1] == '\r') - sGameTitle.erase(sGameTitle.length() - 1); - - while (!filestr.eof()) + for(unsigned int i = 0; i < cheatList.size(); ++i) { - getline(filestr,sCheatName[i]); - if (sCheatName[i][sCheatName[i].length() - 1] == '\r') - sCheatName[i].erase(sCheatName[i].length() - 1); - - if (sCheatName[i].length() == 0) - continue; - - string cheatdata; - - while (!filestr.eof()) + if(sCheatSelected[i]) { - getline(filestr,str); - if (str[str.length() - 1] == '\r') - str.erase(str.length() - 1); - - if (str == "" || str[0] == '\r' || str[0] == '\n') + std::vector &cheatBuf = cheatList[i].sCheats; + if(cheatBuf.size() > 0) + fwrite((char*)&cheatBuf[0], cheatBuf.size() * sizeof(unsigned int), 1, pFile); + } + } + + fwrite(GCT_Footer, sizeof(GCT_Footer), 1, pFile); + fclose(pFile); + return 1; +} + +static inline void RemoveLineEnds(char *str) +{ + const char *strPtr = str; + while(*strPtr != 0) + { + if(*strPtr == '\n' || *strPtr == '\r') + { + strPtr++; + continue; + } + + *str = *strPtr; + str++; + strPtr++; + } + *str = 0; +} + +int GCTCheats::openTxtfile(const char *filename) +{ + //! clear already loaded things + Clear(); + + FILE *pFile = fopen(filename, "rb"); + if (!pFile) + return 0; + + fseek(pFile, 0, SEEK_END); + int size = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + + if (size <= 0) { + fclose(pFile); + return -1; + } + + const int max_line_size = 4096; + char *line = new (std::nothrow) char[max_line_size]; + if (!line) + { + fclose(pFile); + return -1; + } + + fgets(line, max_line_size, pFile); + RemoveLineEnds(line); + sGameID = line; + fgets(line, max_line_size, pFile); + RemoveLineEnds(line); + sGameTitle = line; + + while (fgets(line, max_line_size, pFile)) + { + RemoveLineEnds(line); + + if (*line == 0) + continue; + + // first line is the cheat name + CheatEntry cheatEntry; + cheatEntry.sCheatName = line; + + while (fgets(line, max_line_size, pFile)) + { + RemoveLineEnds(line); + + if (*line == 0) // empty line means start of new cheat break; - if (IsCode(str)) + if (IsCode(line)) { // remove any garbage (comment) after code - while (str.size() > 17) - str.erase(str.length() - 1); + line[8] = 0; + line[17] = 0; - cheatdata.append(str); - size_t found=cheatdata.find(' '); - cheatdata.replace(found,1,""); + cheatEntry.sCheats.push_back(strtoul(&line[0], 0, 16)); + cheatEntry.sCheats.push_back(strtoul(&line[9], 0, 16)); } else - sCheatComment[i] = str; + { + cheatEntry.sCheatComment = line; + } } - if (cheatdata.size() > 0) - { - sCheats[i] = cheatdata; - sCheatSelected[i] = false; - // wiiflow rewrites and saves code.txt with #selected# added to comments if cheat selected - if (sCheatComment[i].compare(0,10,"#selected#") == 0) - { - sCheatSelected[i] = true; - sCheatComment[i].erase(0,10); - } - i++; - } - else - sCheatComment[i] = ""; - - if (i == MAXCHEATS) break; + if (!cheatEntry.sCheats.empty()) + cheatList.push_back(cheatEntry); } - iCntCheats = i; - filestr.close(); + fclose(pFile); + delete [] line; return 1; } -bool GCTCheats::IsCode(const std::string& str) +bool GCTCheats::IsCode(const char *str) { - if (str[8] == ' ' && str.size() >= 17) + if (strlen(str) >= 17 && str[8] == ' ') { // accept strings longer than 17 in case there is a comment on the same line as the code char part1[9]; char part2[9]; - snprintf(part1,sizeof(part1),"%c%c%c%c%c%c%c%c",str[0],str[1],str[2],str[3],str[4],str[5],str[6],str[7]); - snprintf(part2,sizeof(part2),"%c%c%c%c%c%c%c%c",str[9],str[10],str[11],str[12],str[13],str[14],str[15],str[16]); - if ((strtok(part1,"0123456789ABCDEFabcdef") == NULL) && (strtok(part2,"0123456789ABCDEFabcdef") == NULL)) + snprintf(part1, sizeof(part1), "%c%c%c%c%c%c%c%c", str[0], str[1], str[2], str[3], str[4], str[5], str[6], + str[7]); + snprintf(part2, sizeof(part2), "%c%c%c%c%c%c%c%c", str[9], str[10], str[11], str[12], str[13], str[14], + str[15], str[16]); + if ((strtok(part1, "0123456789ABCDEFabcdef") == NULL) && (strtok(part2, "0123456789ABCDEFabcdef") == NULL)) + { return true; + } } return false; } - -int GCTCheats::IsCodeEx(const std::string& str) +bool GCTCheats::IsCheatIncluded(int iCheat, const unsigned char *gctBuf, unsigned int gctSize) { - int status = 2; - if (str[8] == ' ' && str.size() >= 17) + if(!gctBuf || (unsigned int)iCheat >= cheatList.size()) + return false; + + std::vector &Cheat = cheatList[iCheat].sCheats; + int len = Cheat.size() * sizeof(unsigned int); + + for(unsigned int i = sizeof(GCT_Header); i + len <= gctSize - sizeof(GCT_Footer); i += 4) { - // accept strings longer than 17 in case there is a comment on the same line as the code - for (int i = 0; i < 17; ++i) - { - if (!(str[i] == '0' || str[i] == '1' || str[i] == '2' || str[i] == '3' || - str[i] == '4' || str[i] == '5' || str[i] == '6' || str[i] == '7' || - str[i] == '8' || str[i] == '9' || str[i] == 'a' || str[i] == 'b' || - str[i] == 'c' || str[i] == 'd' || str[i] == 'e' || str[i] == 'f' || - str[i] == 'A' || str[i] == 'B' || str[i] == 'C' || str[i] == 'D' || - str[i] == 'E' || str[i] == 'F' || str[i] == 'x' || str[i] == 'X') && i!=8 ) - status = 0; // not even x -> no code - if ((str[i] == 'x' || str[i] == 'X') && i!=8 && status >= 1) - status = 1; - } - return status; + if(memcmp(&Cheat[0], &gctBuf[i], len) == 0) + return true; } - return 0; // no code + return false; } - -void GCTCheats::Reset() -{ - iCntCheats = 0; - for (int i=0;i. + ****************************************************************************/ #ifndef _GCT_H #define _GCT_H -#include - -#define MAXCHEATS 100 - -using std::string; +#include +#include //!Handles Ocarina TXT Cheatfiles -class GCTCheats +class GCTCheats { private: - string sGameID; - string sGameTitle; - string sCheatName[MAXCHEATS]; - string sCheatComment[MAXCHEATS]; - string sCheats[MAXCHEATS]; - unsigned int iCntCheats; - + std::string sGameID; + std::string sGameTitle; + struct CheatEntry + { + std::string sCheatName; + std::string sCheatComment; + std::vector sCheats; + }; + std::vector cheatList; public: - //!Array which shows which cheat is selected - bool sCheatSelected[MAXCHEATS]; + std::vector sCheatSelected; //!Constructor GCTCheats(void); //!Destructor @@ -34,42 +43,38 @@ class GCTCheats //!Open txt file with cheats //!\param filename name of TXT file //!\return error code - int openTxtfile(const char * filename); + int openTxtfile(const char *filename); //!Creates GCT file + //!\param nr[] array of selected Cheat Numbers + //!\param cnt size of array //!\param filename name of GCT file //!\return error code - int createGCT(const char * filename); - //!Creates TXT file - //!\param filename name of GCT file - //!\return error code - int createTXT(const char * filename); + int createGCT(const char *filename); //!Gets Count cheats //!\return Count cheats - unsigned int getCnt(); + unsigned int getCnt() const { return cheatList.size(); } //!Gets Game Name //!\return Game Name - string getGameName(void); + std::string getGameName(void); //!Gets GameID //!\return GameID - string getGameID(void); + std::string getGameID(void); //!Gets cheat data //!\return cheat data - string getCheat(unsigned int nr); + std::vector getCheat(int nr); //!Gets Cheat Name //!\return Cheat Name - string getCheatName(unsigned int nr); + std::string getCheatName(int nr); //!Gets Cheat Comment //!\return Cheat Comment - string getCheatComment(unsigned int nr); + std::string getCheatComment(int nr); + //!Clear all loaded cheats + void Clear(void); //!Check if string is a code //!\return true/false - bool IsCode(const std::string& s); - //!Check if string is a code - //!\return 0=ok, 1="X", 2=no code - int IsCodeEx(const std::string& s); - private: - //!Resets the internal state, as if no file was loaded - void Reset(); + bool IsCode(const char *s); + //!Check if cheat is included in GCT buffer + bool IsCheatIncluded(int iCheat, const unsigned char *gctBuf, unsigned int gctSize); }; -#endif /* _GCT_H */ \ No newline at end of file +#endif /* _GCT_H */ diff --git a/source/menu/menu_cheat.cpp b/source/menu/menu_cheat.cpp index 4371da1a..99586c7b 100644 --- a/source/menu/menu_cheat.cpp +++ b/source/menu/menu_cheat.cpp @@ -47,11 +47,24 @@ int CMenu::_downloadCheatFileAsync() void CMenu::_CheatSettings() { SetupInput(); + m_cheatSettingsPage = 1; const char *id = CoverFlow.getId(); - - m_cheatSettingsPage = 1; - txtavailable = m_cheatfile.openTxtfile(fmt("%s/%s.txt", m_txtCheatDir.c_str(), id)); + txtavailable = m_cheatfile.openTxtfile(fmt("%s/%s.txt", m_txtCheatDir.c_str(), id)); + + u32 gctSize = 0; + u8 *gctBuf = NULL; + if(txtavailable > 0) + gctBuf = fsop_ReadFile(fmt("%s/%s.gct", m_cheatDir.c_str(), id), &gctSize); + + u8 chtsCnt = m_cheatfile.getCnt(); + for(u8 i = 0; i < chtsCnt; ++i) + { + if(gctBuf && m_cheatfile.IsCheatIncluded(i, gctBuf, gctSize)) + m_cheatfile.sCheatSelected.push_back(true); + else + m_cheatfile.sCheatSelected.push_back(false); + } _textCheatSettings(); _showCheatSettings(); @@ -130,7 +143,7 @@ void CMenu::_CheatSettings() m_gcfg2.remove(id, "cheat"); m_gcfg2.remove(id, "hooktype"); } - m_cheatfile.createTXT(fmt("%s/%s.txt", m_txtCheatDir.c_str(), id)); + //m_cheatfile.createTXT(fmt("%s/%s.txt", m_txtCheatDir.c_str(), id)); break; } else if (m_btnMgr.selected(m_cheatBtnDownload)) @@ -173,6 +186,17 @@ void CMenu::_CheatSettings() } } txtavailable = m_cheatfile.openTxtfile(fmt("%s/%s.txt", m_txtCheatDir.c_str(), id)); + if(txtavailable > 0) + gctBuf = fsop_ReadFile(fmt("%s/%s.gct", m_cheatDir.c_str(), id), &gctSize); + + chtsCnt = m_cheatfile.getCnt(); + for(u8 i = 0; i < chtsCnt; ++i) + { + if(gctBuf && m_cheatfile.IsCheatIncluded(i, gctBuf, gctSize)) + m_cheatfile.sCheatSelected.push_back(true); + else + m_cheatfile.sCheatSelected.push_back(false); + } _showCheatSettings(); } }