Subversion Repositories spk

Rev

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(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("&amp", 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("&amp", 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;
}