Rev 233 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "GameExe.h"#include "File_IO.h"#include "DirIO.h"/*** Add Exe** Adds an exe name available*/int CGameExe::addExe(const Utils::WString &exe){// search if it already existsint iCount = this->_findExe(exe);if ( iCount != -1 ) return iCount;// not found, we need to addSGameExe *sExe = new SGameExe;sExe->sExe = exe;sExe->iName = 0;sExe->iFlags = 0;sExe->iMaxPatch = 1;sExe->iAddonTo = 0;sExe->iTextNum = 0;m_lExe.push_back(sExe);return m_lExe.size() - 1;}/*** Find Exe** Find an exe and return its position in the file** Argument: exe, String - name of the exe file to find*/int CGameExe::_findExe(const Utils::WString &exe) const{CFileIO File(exe);Utils::WString e = File.filename();int count = 0;for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() ){if ( node->Data()->sExe.Compare(e) )return count;++count;}return -1;}SGameExe *CGameExe::gameExe(const Utils::WString &exe) const{int e = this->_findExe(exe);if ( e < 0 ) return nullptr;return m_lExe.Get(e);}int CGameExe::_findVersion(int exe, int size, Utils::WString *fVersion) const{if ( fVersion ) *fVersion = -1.0;if ( exe < 0 ) return -1;SGameExe *gameExe = m_lExe[exe];if ( !gameExe ) return -1;int count = 0;for ( CListNode<SGameExeVersion> *node = gameExe->lVersions.Front(); node; node = node->next() ) {for ( CListNode<int> *iNode = node->Data()->lSize.Front(); iNode; iNode = iNode->next() ) {int checkSize = *iNode->Data();if ( checkSize == size ) {*fVersion = node->Data()->fVersion;return count;}}++count;}return -1;}int CGameExe::findVersion(const Utils::WString &exe, int size, Utils::WString *fVersion){int iExe = this->_findExe(exe);if ( iExe < 0 )return -1;int iVersion = this->_findVersion(iExe, size, fVersion);if ( iVersion < 0 )return -2 - iExe;return -1;}Utils::WString CGameExe::getModKey(int game) const{if ( game < 0 ) return L"";SGameExe *sExe = m_lExe[game];if ( !sExe ) return L"";return sExe->sModKey;}void CGameExe::getDirectoryData(GameDirectory *gameDir) const{if (!gameDir)return;if (CDirIO::Exists(gameDir->dir)){gameDir->exe = this->gameRunExe(gameDir->dir);if (CDirIO::Exists(gameDir->exe)){int id = _findExe(gameDir->exe);SGameExe *exe = m_lExe.Get(id);if (exe){gameDir->addon = exe->sAddon;gameDir->name = exe->sName;if (exe->iFlags & EXEFLAG_MYDOCLOG)gameDir->logdir = exe->sMyDoc;elsegameDir->logdir = gameDir->dir;gameDir->basename = exe->sName;}this->getGameVersion(gameDir->exe, &gameDir->version);gameDir->name = this->gameName(gameDir->exe);}}}void CGameExe::parseExe(const Utils::WString &line){// get the exe fileUtils::WString exe = line.token(L":", 1);int iTextNum = -1;if ( exe.contains(L"|") ) {iTextNum = exe.token(L"|", 2);exe = exe.token(L"|", 1);}int iExe = this->addExe(exe);SGameExe *sExe = m_lExe[iExe];sExe->iMaxPatch = line.token(L":", 2);sExe->iAudioStream = line.token(L":", 3).toInt();sExe->iFlags = this->parseFlags(line.token(L":", 4));sExe->sModKey = line.token(L":", 5);sExe->iTextNum = iTextNum;// get the nameUtils::WString gameName = line.token(L":", 6);this->_setExeName(&sExe->sName, &sExe->iName, gameName);// get mydocssExe->sMyDoc = line.token(L":", 7);// now get the versionsint pos = EXE_VERSIONPOS;int namestart = EXE_VERSION_NAMESTART;int sizestart = EXE_VERSION_SIZESTART;if ( sExe->iFlags & EXEFLAG_ADDON ) {++pos;++namestart;++sizestart;sExe->sAddon = line.token(L":", EXE_VERSIONPOS);if ( sExe->sAddon.contains(L"!") ) {sExe->iAddonTo = this->_findExe(sExe->sAddon.token(L"!", 2));sExe->sAddon = sExe->sAddon.token(L"!", 1);}}int iVersions = line.token(L":", pos);int i;for ( i = 0; i < iVersions; i++ ){SGameExeVersion *sGameVersion = new SGameExeVersion;sGameVersion->iName = 0;sGameVersion->fVersion = line.token(L":", namestart + (i * 2)).token(L" ", 1);Utils::WString sSize = line.token(L":", sizestart + (i * 2));// multiple versions available, we need to split them upif ( sSize.contains(L"!") ) {std::vector<Utils::WString> sizes;if(sSize.tokenise(L"!", sizes)){for (size_t j = 0; j < sizes.size(); j++ ){int *size = new int;(*size) = sizes[j];if ( *size ) sGameVersion->lSize.push_back(size);}}}else {int *size = new int;(*size) = sSize;if ( *size ) sGameVersion->lSize.push_back(size);}if ( !sGameVersion->lSize.empty() ) {// finally, add the version namesthis->_setExeName(&sGameVersion->sName, &sGameVersion->iName, line.token(L":", namestart + (i * 2)));sExe->lVersions.push_back(sGameVersion);}}}int CGameExe::parseFlags(const Utils::WString &flags){std::vector<Utils::WString> sFlags;if (!flags.tokenise(L"|", sFlags))return EXEFLAG_NONE;int f = 0;for (size_t i = 0; i < sFlags.size(); i++) {Utils::WString str = sFlags[i];if ( str.Compare(L"TC_TEXT") )f |= EXEFLAG_TCTEXT;else if (str.Compare(L"NO_XOR"))f |= EXEFLAG_NOXOR;else if (str.Compare(L"SETTINGFILE"))f |= EXEFLAG_SETTINGFILE;else if ( str.Compare(L"ADDON") )f |= EXEFLAG_ADDON;else if ( str.Compare(L"MYDOCLOG") )f |= EXEFLAG_MYDOCLOG;else if ( str.Compare(L"NOSAVESUBDIR") )f |= EXEFLAG_NOSAVESUBDIR;else {if ( str.isNumber() )f |= (long)str;}}return f;}void CGameExe::_setExeName(Utils::WString *sName, int *iName, const Utils::WString &n){Utils::WString str = n;if ( n.contains(L"!") ){Utils::WString gameNum = str.token(L"!", 1);str = str.token(L"!", 2);if ( gameNum.isNumber() )*iName = gameNum;else*sName = gameNum;}if ( str.isNumber() )*iName = str;else*sName = str;}void CGameExe::Reset(){for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() ){for ( CListNode<SGameExeVersion> *vNode = node->Data()->lVersions.Front(); vNode; vNode = vNode->next() )vNode->Data()->lSize.MemoryClear();node->Data()->lVersions.MemoryClear();}m_lExe.MemoryClear();}bool CGameExe::readFile(const Utils::WString &file){CFileIO File(file);if ( !File.startRead() ) return false;while ( !File.atEnd() ) {Utils::WString line = File.readEndOfLine();line.removeFirstSpace();if ( line.empty() ) continue;if ( line[0] == '/' ) continue;this->parseExe(line);}File.close();return true;}Utils::WString CGameExe::gameRunExe(const Utils::WString &dir) const{CDirIO Dir(dir);int count = 0;for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() ){SGameExe *exe = node->Data();if ( Dir.exists(exe->sExe) )return dir + L"/" + exe->sExe;if ( !exe->sAddon.empty() ) {if ( Dir.topDir().Compare(exe->sAddon) )return this->gameDir(dir) + L"/" + exe->sExe;}++count;}return L"";}Utils::WString CGameExe::gameBaseName(const Utils::WString &gameExe) const{int gameType = this->getGameType(gameExe);Utils::WString gameDir = this->properDir(gameExe);Utils::WString gameName = this->extractGameName(gameDir);if (gameName.empty()) gameName = this->gameNameFromType(gameType);return gameName;}Utils::WString CGameExe::gameName(const Utils::WString &gameExe) const{Utils::WString gameName = gameBaseName(gameExe);if (gameName.empty()) return L"";// no versionUtils::WString fVersion;Utils::WString versionName;if ( this->getGameVersionName(gameExe, &versionName) ){if ( !versionName.empty() )return gameName + L" V" + versionName;elsereturn gameName;}int gameType = this->getGameType(gameExe);Utils::WString sGameVersion = this->gameVersionFromType(gameType, this->getGameVersion(gameExe, &fVersion), fVersion);if ( sGameVersion.empty() ){if ( !fVersion.empty() )return gameName + L" V" + fVersion;elsereturn gameName;}// return the name and the versionreturn gameName + L" " + sGameVersion;}int CGameExe::getGameAddons(const Utils::WString &dir, Utils::WStringList &exes) const{int count = 0;CDirIO Dir(dir);for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() ){SGameExe *exe = node->Data();if ( !(exe->iFlags & EXEFLAG_ADDON) )continue;if ( Dir.exists(exe->sExe) ) {if ( Dir.exists(exe->sAddon) ) {exes.pushBack(exe->sExe, exe->sAddon);++count;}}}return count;}Utils::WString CGameExe::addonDir(const Utils::WString &dir) const{int gameType = this->getGameType(dir);if ( gameType != -1 ) {return m_lExe[gameType]->sAddon;}return L"";}bool CGameExe::isAddon(const Utils::WString &exe) const{SGameExe *e = gameExe(exe);if (e && (e->iFlags & EXEFLAG_ADDON))return true;return false;}int CGameExe::getTextID(const Utils::WString &dir) const{SGameExe *e = gameExe(dir);if (e)return e->iTextNum;e = gameExe(this->gameRunExe(dir));if (e)return e->iTextNum;return 0;}Utils::WString CGameExe::properDir(const Utils::WString &dir) const{CDirIO Dir(dir);int gameType = this->getGameType(dir);if ( gameType != -1 ) {if ( !m_lExe[gameType]->sAddon.empty() ) {if ( CDirIO(dir).isFile() ) return this->gameDir(dir) + L"/" + m_lExe[gameType]->sAddon;return CDirIO(this->gameDir(dir)).dir(m_lExe[gameType]->sAddon);}}return CDirIO(dir).isFile() ? CFileIO(dir).dir() : dir;}int CGameExe::gameFlags(int game){if ( game == -1 )return 0;SGameExe *exe = m_lExe[game];if ( !exe )return 0;return exe->iFlags;}int CGameExe::maxPatch(int game){if ( game == -1 )return 0;SGameExe *exe = m_lExe[game];if ( !exe )return 0;return exe->iMaxPatch;}Utils::WString CGameExe::gameNameFromType(int type) const{if ( type == -1 ) return L"";SGameExe *exe = m_lExe.Get(type);if ( !exe ) return L"";return exe->sName;}Utils::WString CGameExe::gameVersionFromType(int game, int gameVersion, const Utils::WString &fGameVersion) const{SGameExe *exe = m_lExe[game];if ( !exe ) return L"";SGameExeVersion *version = exe->lVersions[gameVersion];if ( !version ){if ( !fGameVersion.empty() ) return fGameVersion;return L"";}return version->sName;}Utils::WString CGameExe::gameDir(const Utils::WString &dir) const{CDirIO Dir(dir);for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() ){SGameExe *exe = node->Data();if ( CDirIO(dir).isFile() ) {if ( CFileIO(dir).filename().Compare(exe->sExe) )return CFileIO(dir).dir();}else {if ( Dir.exists(exe->sExe) ) return dir;// check for addon dirif ( !exe->sAddon.empty() ) {if ( exe->sAddon.Compare(Dir.topDir()) )return Dir.back();}}}return dir;}int CGameExe::findAddonType(const Utils::WString &addon) const{int i = 0;for (CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next()){SGameExe *exe = node->Data();if (exe->iFlags & EXEFLAG_ADDON){if (exe->sAddon.Compare(addon))return i;}++i;}return -1;}int CGameExe::getGameType(const Utils::WString &gameExe) const{CDirIO Dir (gameExe);int count = 0;for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() ){SGameExe *exe = node->Data();if ( CDirIO(gameExe).isFile() ) {if ( CFileIO(gameExe).filename().Compare(exe->sExe) )return count;}else {if ( Dir.exists(exe->sExe) )return count;// check for addon dirif ( !exe->sAddon.empty() ) {if ( exe->sAddon.Compare(Dir.topDir()) )return count;}}++count;}return -1;}Utils::WString CGameExe::extractGameName(const Utils::WString &gameDir, Utils::WString *extra) const{Utils::WString dir = this->properDir(gameDir);CDirIO Dir(dir);Utils::WString sText = this->_extractTextData(this->_readTextFile(dir), 1910, 1216, this->getTextID(gameDir));if ( sText.empty() ) return L"";int end = sText.findPos(L"\\n");if (end >= 0){sText = sText.left(end);sText = sText.findReplace(L"\\(", L"(").findReplace(L"\\)", L")");if (sText.contains(L"(") && sText.contains(L")")){int pos = sText.findPos(L"(");int endPos;for (endPos = sText.length() - 1; endPos > pos; pos--){if (sText[endPos] == ')')break;}Utils::WString e = sText.substr(pos, endPos);sText = sText.findRemove(e).removeEndSpace();if (extra)(*extra) = e.mid(1, -1);}return sText;}return "";}Utils::WString CGameExe::_textFileName(const Utils::WString &sGameDir) const{int lang = 44;CDirIO Dir(sGameDir);if (Dir.exists(L"t")){if (Dir.exists(L"t/0002.pck")) return L"t/0002.pck";else if (Dir.exists(L"t/0002.xml")) return L"t/0002.xml";else if (Dir.exists(Utils::WString::Format(L"t/%d0002.pck", lang))) return Utils::WString::Format(L"t/%d0002.pck", lang);else if (Dir.exists(Utils::WString::Format(L"t/%d0002.xml", lang))) return Utils::WString::Format(L"t/%d0002.xml", lang);else if (Dir.exists(Utils::WString::Format(L"t/0002-L%03d.pck", lang))) return Utils::WString::Format(L"t/0002-L%03d.pck", lang);else if (Dir.exists(Utils::WString::Format(L"t/0002-L%03d.xml", lang))) return Utils::WString::Format(L"t/0002-L%03d.xml", lang);}return L"";}Utils::WString CGameExe::_readTextFile(const Utils::WString &sGameDir) const{Utils::WString textFileName = _textFileName(sGameDir);if ( !textFileName.empty() ){Utils::WString sVersion;CDirIO Dir(sGameDir);CFileIO File(Dir.file(textFileName));size_t fileSize;unsigned char *fileData = File.readAll(&fileSize);if ( fileData && fileSize){if (CFileIO(textFileName).isFileExtension(L"pck")){size_t newFileSize;unsigned char *pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize);delete fileData;pckData[newFileSize - 1] = '\0';Utils::WString Data((char *)pckData);delete pckData;return Data;}else if (CFileIO(textFileName).isFileExtension(L"xml")){Utils::WString Data((char *)fileData);delete fileData;return Data;}}}return L"";}Utils::WString CGameExe::_extractTextData(const Utils::WString &sData, long iPage, long iID, int iGameID) const{Utils::WString sID = Utils::WString(L"<t id=\"") + iID + L"\">";if (iGameID > 0){Utils::WString sPage = Utils::WString(L"<page id=\"") + Utils::WString::Number(iGameID) + iPage + L"\"";int startpage = sData.findPos(sPage);if (startpage >= 0) {int start = sData.findPos(sID, startpage);if (start >= 0) {start += sID.length();int end = sData.findPos(L"</t>", start);return sData.mid(start, end);}}}{Utils::WString sPage = Utils::WString(L"<page id=\"") + iPage + L"\"";int startpage = sData.findPos(sPage);if (startpage >= 0) {int start = sData.findPos(sID, startpage);if (start >= 0) {start += sID.length();int end = sData.findPos(L"</t>", start);return sData.mid(start, end);}}}return L"";}bool CGameExe::getGameVersionName(const Utils::WString &sGameExe, Utils::WString *versionName) const{int gameType = this->getGameType(sGameExe);if ( gameType == -1 )return false;Utils::WString gameExe = this->gameDir(sGameExe) + L"/" + m_lExe[gameType]->sExe;Utils::WString gameDir = this->properDir(gameExe);int size = (int)CFileIO(gameExe).GetFilesize();Utils::WString fVersion;int version = this->_findVersion(gameType, size, &fVersion);// not matched version// lets read the text fileif ( version != -1 ) {(*versionName) = this->gameVersionFromType(gameType, version, fVersion);return true;}Utils::WString sText = this->_extractTextData(this->_readTextFile(gameDir), 1910, 1216, this->getTextID(gameExe));Utils::WString sVersion = sText.between(L"Version ", L", ");if ( sVersion.empty() ) sVersion = sText.between(L"ver=", L"&");if ( !sVersion.empty() ) {// lets match the version(*versionName) = sVersion;float fVersion = sVersion;SGameExe *gameExe = m_lExe[gameType];if ( gameExe ){int count = 0;int lower = -1;for ( CListNode<SGameExeVersion> *node = gameExe->lVersions.Front(); node; node = node->next() ){if ( (float)node->Data()->fVersion == fVersion ){(*versionName) = node->Data()->sName;return true;}++count;}version = lower;}}return true;}int CGameExe::getGameVersion(const Utils::WString &sGameExe, Utils::WString *a_fVersion) const{Utils::WString gameExe = sGameExe;int gameType = this->getGameType(gameExe);if ( gameType == -1 )return -1;Utils::WString gameDir = gameExe;if ( !m_lExe[gameType]->sAddon.empty() )gameExe = CDirIO(gameExe).back() + L"/" + m_lExe[gameType]->sExe;elsegameExe = gameExe + L"/" + m_lExe[gameType]->sExe;int size = (int)CFileIO(gameExe).fileSize();int version = this->_findVersion(gameType, size, a_fVersion);Utils::WString sText = this->_extractTextData(this->_readTextFile(gameDir), 1910, 10000, this->getTextID(gameExe));Utils::WString sVersion = sText.between(L"ver=", L"&");if ( !sVersion.empty() ){// lets match the versionUtils::WString fVersion = sVersion;if ( a_fVersion ) *a_fVersion = fVersion;SGameExe *gameExe = m_lExe[gameType];if ( gameExe ) {int count = 0;int lower = -1;for ( CListNode<SGameExeVersion> *node = gameExe->lVersions.Front(); node; node = node->next() ){if ( fVersion.compareVersion(node->Data()->fVersion) == COMPARE_OLDER )lower = count;if ( fVersion.compareVersion(node->Data()->fVersion) == COMPARE_SAME )return count;++count;}version = lower;}}return version;}int CGameExe::convertGameType(int gametype, int *version){int count = 0, game = 0;switch ( gametype ){case 1:*version = 0;return 1;case 2:*version = 0;return 2;case 3:*version = 1;return 2;case 4:*version = 0;return 3;case 5:*version = 1;return 3;case 6:*version = 2;return 3;}for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() ){++count;++game;SGameExe *exe = node->Data();// found the game type, the version is 0, which is any versionif ( count == gametype ){*version = 0;return game;}int v = 0;for ( CListNode<SGameExeVersion> *vNode = exe->lVersions.Front(); vNode; vNode = vNode->next() ){++count;++v;if ( count == gametype ){*version = v;return game;}}}// not found ?? just set to all versions*version = 0;return 0;}SGameExe *CGameExe::game(int game) const{if (game >= 0 && game < m_lExe.size())return m_lExe.Get(game);return NULL;}unsigned int CGameExe::gameCount() const{return static_cast<unsigned int>(m_lExe.size());}