Rev 1 | 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(CyString exe)
{
// search if it already exists
int count = 0;
for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() )
{
if ( node->Data()->sExe.Compare(exe) )
return count;
--count;
}
// 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;
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(CyString exe)
{
int count = 0;
for ( CListNode<SGameExe> *node = m_lExe.Front(); node; node = node->next() )
{
if ( node->Data()->sExe.Compare(exe) )
return count;
++count;
}
return -1;
}
SGameExe *CGameExe::GetGameExe(CyString exe)
{
int e = FindExe(exe);
if ( e < 0 ) return NULL;
return m_lExe[e];
}
int CGameExe::FindVersion(int exe, int size, CyString *fVersion)
{
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() )
{
// check each size of a watch
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(CyString exe, int size, CyString *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;
}
CyString CGameExe::GetModKey(int game)
{
if ( game < 0 )
return NullString;
SGameExe *sExe = m_lExe[game];
if ( !sExe )
return NullString;
return sExe->sModKey;
}
void CGameExe::ParseExe(CyString line)
{
// get the exe file
CyString exe = line.GetToken(":", 1, 1);
int iExe = this->AddExe(exe);
SGameExe *sExe = m_lExe[iExe];
sExe->iMaxPatch = line.GetToken(":", 2, 2).ToInt();
sExe->iFlags = this->ParseFlags(line.GetToken(":", 3, 3));
sExe->sModKey = line.GetToken(":", 4, 4);
// get the name
CyString gameName = line.GetToken(":", 5, 5);
this->_SetExeName(&sExe->sName, &sExe->iName, gameName);
// get mydocs
sExe->sMyDoc = line.GetToken(":", 6, 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.GetToken(":", EXE_VERSIONPOS, EXE_VERSIONPOS);
if ( sExe->sAddon.IsIn("!") ) {
sExe->iAddonTo = this->FindExe(sExe->sAddon.GetToken("!", 2, 2));
sExe->sAddon = sExe->sAddon.GetToken("!", 1, 1);
}
}
int iVersions = line.GetToken(":", pos, pos).ToInt();
int i;
for ( i = 0; i < iVersions; i++ )
{
SGameExeVersion *sGameVersion = new SGameExeVersion;
sGameVersion->iName = 0;
sGameVersion->fVersion = line.GetToken(":", namestart + (i * 2), namestart + (i * 2)).GetToken(" ", 1, 1).ToFloat();
CyString sSize = line.GetToken(":", sizestart + (i * 2), sizestart + (i * 2));
// multiple versions available, we need to split them up
if ( sSize.IsIn("!") )
{
int max = 0;
CyString *sizes = sSize.SplitToken('!', &max);
if ( sizes && max )
{
for ( int j = 0; j < max; j++ )
{
int *size = new int;
(*size) = sizes[j].ToInt();
if ( *size )
sGameVersion->lSize.push_back(size);
}
CLEANSPLIT(sizes, max);
}
}
else
{
int *size = new int;
(*size) = sSize.ToInt();
if ( *size )
sGameVersion->lSize.push_back(size);
}
if ( !sGameVersion->lSize.empty() )
{
// finally, add the version names
this->_SetExeName(&sGameVersion->sName, &sGameVersion->iName, line.GetToken(":", namestart + (i * 2), namestart + (i * 2)));
sExe->lVersions.push_back(sGameVersion);
}
}
}
int CGameExe::ParseFlags(CyString flags)
{
int max;
CyString *sFlags = flags.SplitToken("|", &max);
if ( !sFlags || !max )
return EXEFLAG_NONE;
int f = 0;
for ( int i = 0; i < max; i++ )
{
CyString 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 |= str.ToInt();
}
}
CLEANSPLIT(sFlags, max);
return f;
}
void CGameExe::_SetExeName(CyString *sName, int *iName, CyString n)
{
if ( n.IsIn("!") )
{
CyString gameNum = n.GetToken("!", 1, 1);
n = n.GetToken("!", 2, 2);
if ( gameNum.IsNumber() )
*iName = gameNum.ToInt();
else
*sName = gameNum;
}
if ( n.IsNumber() )
*iName = n.ToInt();
else
*sName = n;
}
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(CyString file)
{
FILE *id = fopen(file.c_str(), "rb");
if ( !id )
return false;
CyString line;
while ( !feof(id) )
{
line.GetEndOfLine(id, NULL, false);
if ( line.Empty() )
continue;
CyString lineNoSpace = line;
lineNoSpace.RemoveFirstSpace();
if ( lineNoSpace.Empty() )
continue;
if ( lineNoSpace.Left(1) == "/" )
continue;
this->ParseExe(line);
}
fclose(id);
return true;
}
CyString CGameExe::GetGameRunExe(CyString dir)
{
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 NullString;
}
CyString CGameExe::GetGameName(CyString gameExe)
{
int gameType = this->GetGameType(gameExe);
CyString gameName = ExtractGameName(gameExe);
if ( gameName.Empty() )
gameName = this->GetGameNameFromType(gameType);
if ( gameName.Empty() )
return NullString;
// no version
CyString fVersion;
CyString versionName;
if ( this->GetGameVersionName(gameExe, &versionName) )
{
if ( !versionName.Empty() )
return gameName + " V" + versionName;
else
return gameName;
}
CyString 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(CyString dir, CyStringList &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;
}
CyString CGameExe::GetAddonDir(CyString dir)
{
int gameType = this->GetGameType(dir);
if ( gameType != -1 ) {
return m_lExe[gameType]->sAddon;
}
return "";
}
CyString CGameExe::GetProperDir(CyString dir)
{
CDirIO Dir(dir);
int gameType = this->GetGameType(dir);
if ( gameType != -1 ) {
if ( !m_lExe[gameType]->sAddon.Empty() ) {
if ( CDirIO(dir).IsFile() )
return CFileIO(dir).GetDir() + "/" + m_lExe[gameType]->sAddon;
return Dir.Dir(m_lExe[gameType]->sAddon);
}
}
return 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;
}
CyString CGameExe::GetGameNameFromType(int type)
{
if ( type == -1 )
return NullString;
SGameExe *exe = m_lExe[type];
if ( !exe )
return NullString;
return exe->sName;
}
CyString CGameExe::GetGameVersionFromType(int game, int gameVersion, CyString fGameVersion)
{
SGameExe *exe = m_lExe[game];
if ( !exe )
return NullString;
SGameExeVersion *version = exe->lVersions[gameVersion];
if ( !version )
{
if ( !fGameVersion.Empty() )
return fGameVersion;
return NullString;
}
return version->sName;
}
CyString CGameExe::GetGameDir(CyString dir)
{
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).GetFilename().Compare(exe->sExe) )
return CFileIO(dir).GetDir();
}
else {
if ( Dir.Exists(exe->sExe) )
return dir;
// check for addon dir
if ( !exe->sAddon.Empty() ) {
CyString top = Dir.TopDir();
if ( exe->sAddon.Compare(Dir.TopDir()) )
return Dir.Back();
}
}
}
return dir;
}
int CGameExe::GetGameType(CyString gameExe)
{
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).GetFilename().Compare(exe->sExe) )
return count;
}
else {
if ( Dir.Exists(exe->sExe) )
return count;
// check for addon dir
if ( !exe->sAddon.Empty() ) {
CyString top = Dir.TopDir();
if ( exe->sAddon.Compare(Dir.TopDir()) )
return count;
}
}
++count;
}
return -1;
}
CyString CGameExe::ExtractGameName(CyString gameDir)
{
CDirIO Dir(gameDir);
CyString textFileName;
if ( Dir.Exists("t") && Dir.Exists("t/0002.pck") )
textFileName = "t/0002.pck";
else if ( Dir.Exists("t") && Dir.Exists("t/440002.pck") )
textFileName = "t/440002.pck";
else if ( Dir.Exists("t") && Dir.Exists("t/0002-L044.pck") )
textFileName = "t/0002-L044.pck";
CyString sName;
if ( !textFileName.Empty() )
{
CFileIO File(Dir.File(textFileName));
size_t fileSize;
char *fileData = File.ReadToData(&fileSize);
if ( fileData && fileSize)
{
size_t newFileSize;
unsigned char *pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize);
if ( pckData )
{
if ( newFileSize )
{
pckData[newFileSize -1] = '\0';
CyString data((char *)pckData);
int startpage = data.FindPos("<page id=\"1910\"");
if ( startpage >= 0 )
{
int start = data.FindPos("<t id=\"1216\">", startpage);
if ( start >= 0 )
{
start += 14;
int end = data.FindPos("</t>", start);
end++;
CyString text = data.Mid(start, end - start);
end = text.FindPos("\\n");
if ( end >= 0 )
sName = text.Left(end);
}
}
}
delete pckData;
}
}
}
return sName;
}
bool CGameExe::GetGameVersionName(CyString gameExe, CyString *versionName)
{
int gameType = this->GetGameType(gameExe);
if ( gameType == -1 )
return false;
CyString gameDir = gameExe;
gameExe = this->GetGameDir(gameExe) + "/" + m_lExe[gameType]->sExe;
int size = (int)CFileIO(gameExe).GetFilesize();
CyString 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;
}
CDirIO Dir(gameDir);
CyString textFileName;
if ( Dir.Exists("t") && Dir.Exists("t/0002.pck") )
textFileName = "t/0002.pck";
else if ( Dir.Exists("t") && Dir.Exists("t/440002.pck") )
textFileName = "t/440002.pck";
else if ( Dir.Exists("t") && Dir.Exists("t/0002-L044.pck") )
textFileName = "t/0002-L044.pck";
if ( !textFileName.Empty() )
{
CyString sVersion;
CFileIO File(Dir.File(textFileName));
size_t fileSize;
char *fileData = File.ReadToData(&fileSize);
if ( fileData && fileSize)
{
size_t newFileSize;
unsigned char *pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize);
if ( pckData )
{
if ( newFileSize )
{
pckData[newFileSize -1] = '\0';
CyString data((char *)pckData);
int startpage = data.FindPos("<page id=\"1910\"");
if ( startpage >= 0 )
{
int start = data.FindPos("<t id=\"1216\">", startpage);
if ( start >= 0 )
{
start += 15;
int end = data.FindPos("</t>", start);
end++;
CyString text = data.Mid(start, end - start);
int pos = text.FindPos("Version ");
if ( pos >= 0 )
{
pos += 9;
end = text.FindPos(", ", pos);
if ( end >= 0 )
sVersion = text.Mid(pos, (end + 1) - pos);
}
}
if ( sVersion.Empty() )
{
int start = data.FindPos("<t id=\"1216\">", startpage);
if ( start >= 0 )
{
start += 15;
int end = data.FindPos("</t>", start);
end++;
CyString text = data.Mid(start, end - start);
int pos = text.FindPos("ver=");
if ( pos >= 0 )
{
pos += 5;
end = text.FindPos("&", pos);
if ( end >= 0 )
sVersion = text.Mid(pos, (end + 1) - pos);
}
}
}
}
}
delete pckData;
}
}
if ( !sVersion.Empty() )
{
// lets match the version
(*versionName) = sVersion;
float fVersion = sVersion.ToFloat();
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 ( node->Data()->fVersion == fVersion )
{
(*versionName) = node->Data()->sName;
return true;
}
++count;
}
version = lower;
}
}
}
return true;
}
int CGameExe::GetGameVersion(CyString gameExe, CyString *a_fVersion)
{
int gameType = this->GetGameType(gameExe);
if ( gameType == -1 )
return -1;
CyString 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);
// not matched version
// lets read the text file
if ( version == -1 )
{
CDirIO Dir(gameDir);
CyString textFileName;
if ( Dir.Exists("t") && Dir.Exists("t/0002.pck") )
textFileName = "t/0002.pck";
else if ( Dir.Exists("t") && Dir.Exists("t/440002.pck") )
textFileName = "t/440002.pck";
else if ( Dir.Exists("t") && Dir.Exists("t/0002-L044.pck") )
textFileName = "t/0002-L044.pck";
if ( !textFileName.Empty() )
{
CyString sVersion;
CFileIO File(Dir.File(textFileName));
size_t fileSize;
char *fileData = File.ReadToData(&fileSize);
if ( fileData && fileSize)
{
size_t newFileSize;
unsigned char *pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize);
if ( pckData )
{
if ( newFileSize )
{
pckData[newFileSize -1] = '\0';
CyString data((char *)pckData);
int start = data.FindPos("<t id=\"10000\">");
if ( start >= 0 )
{
start += 15;
int end = data.FindPos("</t>", start);
end++;
CyString text = data.Mid(start, end - start);
int pos = text.FindPos("ver=");
if ( pos >= 0 )
{
pos += 5;
end = text.FindPos("&", pos);
if ( end >= 0 )
sVersion = text.Mid(pos, (end + 1) - pos);
}
}
}
delete pckData;
}
}
if ( !sVersion.Empty() )
{
// lets match the version
CyString 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;
}