Rev 126 | Rev 182 | 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::String &exe)
{
// search if it already exists
int iCount = this->_findExe(exe);
if ( iCount != -1 ) return iCount;
// not found, we need to add
SGameExe *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::String &exe) const
{
CFileIO File(exe);
Utils::String 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::String &exe) const
{
int e = this->_findExe(exe);
if ( e < 0 ) return NULL;
return m_lExe.Get(e);
}
int CGameExe::_findVersion(int exe, int size, Utils::String *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::String &exe, int size, Utils::String *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::String CGameExe::GetModKey(int game)
{
if ( game < 0 ) return "";
SGameExe *sExe = m_lExe[game];
if ( !sExe ) return "";
return sExe->sModKey;
}
void CGameExe::GetDirectoryData(GameDirectory *gameDir) const
{
if (!gameDir)
return;
if (CDirIO::Exists(gameDir->dir))
{
gameDir->exe = this->GetGameRunExe(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;
else
gameDir->logdir = gameDir->dir;
gameDir->basename = exe->sName;
}
this->GetGameVersion(gameDir->exe, &gameDir->version);
gameDir->name = this->GetGameName(gameDir->exe);
}
}
}
void CGameExe::ParseExe(const Utils::String &line)
{
// get the exe file
Utils::String exe = line.token(":", 1);
int iTextNum = -1;
if ( exe.isin("|") ) {
iTextNum = exe.token("|", 2);
exe = exe.token("|", 1);
}
int iExe = this->AddExe(exe);
SGameExe *sExe = m_lExe[iExe];
sExe->iMaxPatch = line.token(":", 2);
sExe->iFlags = this->ParseFlags(line.token(":", 3));
sExe->sModKey = line.token(":", 4);
sExe->iTextNum = iTextNum;
// get the name
Utils::String gameName = line.token(":", 5);
this->_SetExeName(&sExe->sName, &sExe->iName, gameName);
// get mydocs
sExe->sMyDoc = line.token(":", 6);
// now get the versions
int 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(":", EXE_VERSIONPOS);
if ( sExe->sAddon.isin("!") ) {
sExe->iAddonTo = this->_findExe(sExe->sAddon.token("!", 2));
sExe->sAddon = sExe->sAddon.token("!", 1);
}
}
int iVersions = line.token(":", pos);
int i;
for ( i = 0; i < iVersions; i++ )
{
SGameExeVersion *sGameVersion = new SGameExeVersion;
sGameVersion->iName = 0;
sGameVersion->fVersion = line.token(":", namestart + (i * 2)).token(" ", 1);
Utils::String sSize = line.token(":", sizestart + (i * 2));
// multiple versions available, we need to split them up
if ( sSize.isin("!") ) {
int max = 0;
Utils::String *sizes = sSize.tokenise("!", &max);
if ( sizes && max ) {
for ( int j = 0; j < max; j++ ) {
int *size = new int;
(*size) = sizes[j];
if ( *size ) sGameVersion->lSize.push_back(size);
}
CLEANSPLIT(sizes, max);
}
}
else {
int *size = new int;
(*size) = sSize;
if ( *size ) sGameVersion->lSize.push_back(size);
}
if ( !sGameVersion->lSize.empty() ) {
// finally, add the version names
this->_SetExeName(&sGameVersion->sName, &sGameVersion->iName, line.token(":", namestart + (i * 2)));
sExe->lVersions.push_back(sGameVersion);
}
}
}
int CGameExe::ParseFlags(const Utils::String &flags)
{
int max;
Utils::String *sFlags = flags.tokenise("|", &max);
if ( !sFlags || !max ) return EXEFLAG_NONE;
int f = 0;
for ( int i = 0; i < max; i++ ) {
Utils::String str = sFlags[i];
if ( str.Compare("TC_TEXT") )
f |= EXEFLAG_TCTEXT;
else if ( str.Compare("NO_XOR") )
f |= EXEFLAG_NOXOR;
else if ( str.Compare("ADDON") )
f |= EXEFLAG_ADDON;
else if ( str.Compare("MYDOCLOG") )
f |= EXEFLAG_MYDOCLOG;
else if ( str.Compare("NOSAVESUBDIR") )
f |= EXEFLAG_NOSAVESUBDIR;
else {
if ( str.isNumber() )
f |= (long)str;
}
}
CLEANSPLIT(sFlags, max);
return f;
}
void CGameExe::_SetExeName(Utils::String *sName, int *iName, const Utils::String &n)
{
Utils::String str = n;
if ( n.isin("!") )
{
Utils::String gameNum = str.token("!", 1);
str = str.token("!", 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::String &file)
{
CFileIO File(file);
if ( !File.startRead() ) return false;
while ( !File.atEnd() ) {
Utils::String line = File.readEndOfLine();
line.removeFirstSpace();
if ( line.empty() ) continue;
if ( line[0] == '/' ) continue;
this->ParseExe(line);
}
File.close();
return true;
}
Utils::String CGameExe::GetGameRunExe(const Utils::String &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 + "/" + exe->sExe;
if ( !exe->sAddon.empty() ) {
if ( Dir.topDir().Compare(exe->sAddon) )
return this->GetGameDir(dir) + "/" + exe->sExe;
}
++count;
}
return "";
}
Utils::String CGameExe::GetGameBaseName(const Utils::String &gameExe) const
{
int gameType = this->GetGameType(gameExe);
Utils::String gameDir = this->GetProperDir(gameExe);
Utils::String gameName = this->ExtractGameName(gameDir);
if (gameName.empty()) gameName = this->GetGameNameFromType(gameType);
return gameName;
}
Utils::String CGameExe::GetGameName(const Utils::String &gameExe) const
{
Utils::String gameName = GetGameBaseName(gameExe);
if (gameName.empty()) return "";
// no version
Utils::String fVersion;
Utils::String versionName;
if ( this->GetGameVersionName(gameExe, &versionName) )
{
if ( !versionName.empty() )
return gameName + " V" + versionName;
else
return gameName;
}
int gameType = this->GetGameType(gameExe);
Utils::String sGameVersion = this->GetGameVersionFromType(gameType, this->GetGameVersion(gameExe, &fVersion), fVersion);
if ( sGameVersion.empty() )
{
if ( !fVersion.empty() )
return gameName + " V" + fVersion;
else
return gameName;
}
// return the name and the version
return gameName + " " + sGameVersion;
}
int CGameExe::GetGameAddons(const Utils::String &dir, Utils::CStringList &exes)
{
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::String CGameExe::GetAddonDir(const Utils::String &dir) const
{
int gameType = this->GetGameType(dir);
if ( gameType != -1 ) {
return m_lExe[gameType]->sAddon;
}
return "";
}
bool CGameExe::isAddon(const Utils::String &exe) const
{
SGameExe *e = gameExe(exe);
if (e && (e->iFlags & EXEFLAG_ADDON))
return true;
return false;
}
int CGameExe::getTextID(const Utils::String &dir) const
{
SGameExe *e = gameExe(dir);
if (e)
return e->iTextNum;
e = gameExe(this->GetGameRunExe(dir));
if (e)
return e->iTextNum;
return 0;
}
Utils::String CGameExe::GetProperDir(const Utils::String &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->GetGameDir(dir) + "/" + m_lExe[gameType]->sAddon;
return CDirIO(this->GetGameDir(dir)).dir(m_lExe[gameType]->sAddon);
}
}
return CDirIO(dir).isFile() ? CFileIO(dir).dir() : dir;
}
int CGameExe::GetGameFlags(int game)
{
if ( game == -1 )
return 0;
SGameExe *exe = m_lExe[game];
if ( !exe )
return 0;
return exe->iFlags;
}
int CGameExe::GetMaxPatch(int game)
{
if ( game == -1 )
return 0;
SGameExe *exe = m_lExe[game];
if ( !exe )
return 0;
return exe->iMaxPatch;
}
Utils::String CGameExe::GetGameNameFromType(int type) const
{
if ( type == -1 ) return "";
SGameExe *exe = m_lExe.Get(type);
if ( !exe ) return "";
return exe->sName;
}
Utils::String CGameExe::GetGameVersionFromType(int game, int gameVersion, const Utils::String &fGameVersion) const
{
SGameExe *exe = m_lExe[game];
if ( !exe ) return "";
SGameExeVersion *version = exe->lVersions[gameVersion];
if ( !version )
{
if ( !fGameVersion.empty() ) return fGameVersion;
return "";
}
return version->sName;
}
Utils::String CGameExe::GetGameDir(const Utils::String &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 dir
if ( !exe->sAddon.empty() ) {
if ( exe->sAddon.Compare(Dir.topDir()) )
return Dir.back();
}
}
}
return dir;
}
int CGameExe::findAddonType(const Utils::String &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::String &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 dir
if ( !exe->sAddon.empty() ) {
if ( exe->sAddon.Compare(Dir.topDir()) )
return count;
}
}
++count;
}
return -1;
}
Utils::String CGameExe::ExtractGameName(const Utils::String &gameDir) const
{
Utils::String dir = this->GetProperDir(gameDir);
CDirIO Dir(dir);
Utils::String sText = this->_extractTextData(this->_readTextFile(dir), 1910, 1216, this->getTextID(gameDir));
if ( sText.empty() ) return "";
int end = sText.findPos("\\n");
if ( end >= 0 ) return sText.left(end);
return "";
}
Utils::String CGameExe::_textFileName(const Utils::String &sGameDir) const
{
int lang = 44;
CDirIO Dir(sGameDir);
if (Dir.exists("t"))
{
if (Dir.exists("t/0002.pck")) return "t/0002.pck";
else if (Dir.exists("t/0002.xml")) return "t/0002.xml";
else if (Dir.exists(Utils::String::Format("t/%d0002.pck", lang))) return Utils::String::Format("t/%d0002.pck", lang);
else if (Dir.exists(Utils::String::Format("t/%d0002.xml", lang))) return Utils::String::Format("t/%d0002.xml", lang);
else if (Dir.exists(Utils::String::Format("t/0002-L%03d.pck", lang))) return Utils::String::Format("t/0002-L%03d.pck", lang);
else if (Dir.exists(Utils::String::Format("t/0002-L%03d.xml", lang))) return Utils::String::Format("t/0002-L%03d.xml", lang);
}
return "";
}
Utils::String CGameExe::_readTextFile(const Utils::String &sGameDir) const
{
Utils::String textFileName = _textFileName(sGameDir);
if ( !textFileName.empty() )
{
Utils::String 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("pck"))
{
size_t newFileSize;
unsigned char *pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize);
delete fileData;
pckData[newFileSize - 1] = '\0';
Utils::String Data((char *)pckData);
delete pckData;
return Data;
}
else if (CFileIO(textFileName).isFileExtension("xml"))
{
Utils::String Data((char *)fileData);
delete fileData;
return Data;
}
}
}
return "";
}
Utils::String CGameExe::_extractTextData(const Utils::String &sData, long iPage, long iID, int iGameID) const
{
Utils::String sID = Utils::String("<t id=\"") + iID + "\">";
if (iGameID > 0)
{
Utils::String sPage = Utils::String("<page id=\"") + Utils::String::Number(iGameID) + iPage + "\"";
int startpage = sData.findPos(sPage);
if (startpage >= 0) {
int start = sData.findPos(sID, startpage);
if (start >= 0) {
start += sID.length();
int end = sData.findPos("</t>", start);
return sData.mid(start, end);
}
}
}
{
Utils::String sPage = Utils::String("<page id=\"") + iPage + "\"";
int startpage = sData.findPos(sPage);
if (startpage >= 0) {
int start = sData.findPos(sID, startpage);
if (start >= 0) {
start += sID.length();
int end = sData.findPos("</t>", start);
return sData.mid(start, end);
}
}
}
return "";
}
bool CGameExe::GetGameVersionName(const Utils::String &sGameExe, Utils::String *versionName) const
{
int gameType = this->GetGameType(sGameExe);
if ( gameType == -1 )
return false;
Utils::String gameExe = this->GetGameDir(sGameExe) + "/" + m_lExe[gameType]->sExe;
Utils::String gameDir = this->GetProperDir(gameExe);
int size = (int)CFileIO(gameExe).GetFilesize();
Utils::String fVersion;
int version = this->_findVersion(gameType, size, &fVersion);
// not matched version
// lets read the text file
if ( version != -1 ) {
(*versionName) = this->GetGameVersionFromType(gameType, version, fVersion);
return true;
}
Utils::String sText = this->_extractTextData(this->_readTextFile(gameDir), 1910, 1216, this->getTextID(gameExe));
Utils::String sVersion = sText.between("Version ", ", ");
if ( sVersion.empty() ) sVersion = sText.between("ver=", "&");
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::String &sGameExe, Utils::String *a_fVersion) const
{
Utils::String gameExe = sGameExe;
int gameType = this->GetGameType(gameExe);
if ( gameType == -1 )
return -1;
Utils::String gameDir = gameExe;
if ( !m_lExe[gameType]->sAddon.empty() )
gameExe = CDirIO(gameExe).back() + "/" + m_lExe[gameType]->sExe;
else
gameExe = gameExe + "/" + m_lExe[gameType]->sExe;
int size = (int)CFileIO(gameExe).GetFilesize();
int version = this->_findVersion(gameType, size, a_fVersion);
Utils::String sText = this->_extractTextData(this->_readTextFile(gameDir), 1910, 10000, this->getTextID(gameExe));
Utils::String sVersion = sText.between("ver=", "&");
if ( !sVersion.empty() )
{
// lets match the version
Utils::String 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 version
if ( 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::GetGame(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());
}