Rev 64 | Rev 76 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "spk.h"#include "emp.h"#include <time.h>#include <vector>#ifdef _RAR#include <unrar.h>#endifenum {READ_START, READ_GLOBAL, READ_SCRIPT, READ_SCRIPTFILE, READ_WARES};enum { EXTRACT, TEST, PRINT, LIST };typedef struct SDummyEntry {CyString sSection;CyStringList lEntries;} SDummyEntry;typedef struct SComponantEntry2 {CyString sSection;CyStringList lEntries;} SComponantEntry2;typedef struct SComponantEntry {CyString sSection;CLinkList<SComponantEntry2> lEntries;} SComponantEntry;CPackages::CPackages() : m_pCurrentGameExe(NULL){m_bRenameText = false;m_iLanguage = 0;m_iGame = -1;m_iGameVersion = -1;m_iGameFlags = 0;m_bSurpressProtectedWarning = false;m_iMaxPatch = 1;m_iLastUpdated = 0;m_iFakePatch = -1;m_bVanilla = true;m_pEnabledMod = NULL;m_bForceModInstall = false;m_bLoaded = false;m_bRedo = false;m_bOldPlugin = false;m_bUsedWare = false;m_pPackageNode = NULL;m_bRemoveDir = false;m_bDisableVanilla = false;m_bLoadVFS = true;m_iSaveGame = -1;m_iSaveGameManager = -1;m_bForceEMP = false;for ( int i = 0; i < WAREBUFFERS; i++ )m_iWareBuffer[i] = 0;m_iShipBuffer = 0;}CPackages::~CPackages (){m_lDisableList.clear();m_lEnableList.clear();this->Reset();}void CPackages::SetVanilla(bool b){if ( m_bVanilla != b && b ) {for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() ) {pNode->Data()->SetModifiedEnabled(pNode->Data()->IsEnabled());}}m_bVanilla = b;}void CPackages::Reset(){m_lFiles.MemoryClear();m_lUninstallFiles.MemoryClear();for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() )pNode->Data()->GetFileList()->clear();m_lPackages.MemoryClear();m_lOriginalFiles.MemoryClear();m_iFakePatch = -1;m_bVanilla = false;m_pEnabledMod = NULL;m_bLoaded = false;m_iLanguage = 0;m_bOldPlugin = false;m_bRemoveDir = false;m_bDisableVanilla = false;m_bSurpressProtectedWarning = false;m_iSaveGame = -1;m_iSaveGameManager = -1;m_sSetMod = "";for ( int i = 0; i < WAREBUFFERS; i++ ){m_iWareBuffer[i] = 0;m_lGameWares[i].MemoryClear();}m_iShipBuffer = 0;m_lGameShips.MemoryClear();m_lAvailablePackages.MemoryClear();m_lInstallList.MemoryClear();m_lEnableList.MemoryClear();m_lDisableList.MemoryClear();m_lCreatedFiles.Clear();m_lNonRemovedFiles.Clear();m_lGlobals.Clear();m_lFakePatchOrder.Clear();}void CPackages::LoadVirtualFileSystem(){if ( !m_bLoadVFS )return;m_pGameVFS.SetAddon(this->GetAddonDir().ToString());if ( m_pEnabledMod ){C_File *f;for ( f = m_pEnabledMod->GetFirstFile(FILETYPE_MOD); f; f = m_pEnabledMod->GetNextFile(f) ){if ( f->IsFakePatch() ) continue;if ( f->CheckFileExt("cat") ) break;}if ( f )m_pGameVFS.LoadFilesystem(m_sCurrentDir.ToString(), f->GetFilePointer().ToString(), 0);elsem_pGameVFS.LoadFilesystem(m_sCurrentDir.ToString(), 0);}elsem_pGameVFS.LoadFilesystem(m_sCurrentDir.ToString(), 0);}bool CPackages::IsOldDir(CyString dir){bool oldPlugin = false;dir = dir.FindReplace("\\", "/");CFileIO datFile(dir + "/PluginManager/pluginmanager.dat");if ( datFile.exists() ){std::vector<CyString> *readFile = datFile.ReadLines();if ( readFile ){for ( int i = 0; i < (int)readFile->size(); i++ ){CyString line(readFile->at(i));CyString cmd = line.GetToken(":", 1, 1).lower();if ( cmd == "<script>" || cmd == "</scripts>" )break;else if ( cmd == "spkinstaller" || cmd == "globalfiles" )break;else if ( cmd == "pluginmanager" ){oldPlugin = true;break;}}delete readFile;}}return oldPlugin;}bool CPackages::Read ( CyString dir, CProgressInfo *progress ){m_sCurrentDir = dir;m_sCurrentDir = m_sCurrentDir.FindReplace("\\", "/");m_bOldPlugin = false;m_lCreatedFiles.Clear();m_bRemoveDir = false;m_bSurpressProtectedWarning = false;m_iSaveGame = -1;m_iSaveGameManager = -1;m_lNonRemovedFiles.Clear();m_lGlobals.Clear();m_lFakePatchOrder.Clear();m_bVanilla = true;// check the pluginmanager data file existsCFileIO datFile(m_sCurrentDir + "/PluginManager/pluginmanager.dat");if ( datFile.exists() ){std::vector<CyString> *readFile = datFile.ReadLines();if ( readFile ){float fVersion = 0;bool spkinstaller = false;float fBeta = 0;int iStatus = READ_START;int iCount = 0;int iWare = -1;int iShip = -1;CBaseFile *packageFile = 0;for ( int i = 0; i < (int)readFile->size(); i++ ){CyString line(readFile->at(i));CyString cmd = line.GetToken(":", 1, 1).lower();CyString rest = line.GetToken(":", 2).RemoveFirstSpace();if ( iStatus == READ_GLOBAL ){if ( cmd == "<script>" ){packageFile = new CSpkFile();iStatus = READ_SCRIPT;}else if ( cmd == "<ship>" ){packageFile = new CXspFile();iStatus = READ_SCRIPT;}else if ( cmd == "<base>" ){packageFile = new CBaseFile();iStatus = READ_SCRIPT;}else if ( cmd == "<archive>" ){packageFile = new CArchiveFile();iStatus = READ_SCRIPT;}else if ( cmd != "</scripts>" ){int game = 0;bool disabled = false;CyString fileName = line.GetToken(":", 5);CyString origName;if ( fileName.Left(2) == "D#" ){fileName.Erase(0, 2);disabled = true;}if ( fileName.Left(2) == "G#" ) {fileName.Erase(0, 2);game = fileName.GetToken("#", 1, 1).ToInt();fileName = fileName.GetToken("#", 2);}if ( fileName.IsIn("O#") ){origName = fileName.GetToken("O#", 2, 2);fileName = fileName.GetToken("O#", 1, 1);}C_File *newFile = new C_File( m_sCurrentDir + fileName );newFile->SetGame(game);newFile->SetOriginalName(origName);newFile->SetDisabled(disabled);newFile->SetFileType(line.GetToken(":", 1, 1).ToInt());newFile->SetCreationTime((time_t)line.GetToken(":", 2, 2).ToInt());newFile->SetDir(line.GetToken(":", 3, 3));if ( line.GetToken(":", 4, 4).ToInt() )newFile->SetShared(true);newFile->UpdateSigned();m_lFiles.push_back(newFile);}}else if ( iStatus == READ_SCRIPT ){if ( cmd == "installspk" )packageFile->setFilename(rest.ToString());else if ( cmd == "files" ){iStatus = READ_SCRIPTFILE;if ( spkinstaller ){int max;CyString *files = rest.SplitToken(' ', &max);for ( int i = 0; i < max; i++ ){int fileNum = files[i].ToInt();if ( fileNum >= 0 && fileNum < m_lFiles.size() )packageFile->AddFile(m_lFiles[fileNum]);}CLEANSPLIT(files, max);}}else if ( cmd == "disabled" )packageFile->SetEnabled(false);else if ( cmd == "modifieddisabled" )packageFile->SetModifiedEnabled(false);else if ( cmd == "icon" ){C_File *icon = new C_File(rest.GetToken(" ", 2));packageFile->SetIcon(icon, rest.GetToken(" ", 1, 1));}elsepackageFile->ParseValueLine(line.ToString());}else if ( iStatus == READ_SCRIPTFILE ){if ( cmd == "<script>" ){if ( packageFile->IsMod() && packageFile->IsEnabled() )m_pEnabledMod = packageFile;m_lPackages.push_back(packageFile);this->ConvertOldPackage(packageFile);packageFile = new CSpkFile();iStatus = READ_SCRIPT;}else if ( cmd == "<ship>" ){m_lPackages.push_back(packageFile);this->ConvertOldPackage(packageFile);packageFile = new CXspFile();iStatus = READ_SCRIPT;}else if ( cmd == "<base>" ){m_lPackages.push_back(packageFile);this->ConvertOldPackage(packageFile);packageFile = new CBaseFile();iStatus = READ_SCRIPT;}else if ( cmd == "<archive>" ){m_lPackages.push_back(packageFile);this->ConvertOldPackage(packageFile);packageFile = new CArchiveFile();iStatus = READ_SCRIPT;}else if ( cmd == "</scripts>" ){if ( packageFile->IsMod() && packageFile->IsEnabled() )m_pEnabledMod = packageFile;m_lPackages.push_back(packageFile);this->ConvertOldPackage(packageFile);}else{int fileNum = line.GetToken("::", 1, 1).ToInt();if ( fileNum >= 0 && fileNum < m_lFiles.size() )packageFile->AddFile(m_lFiles[fileNum]);}}else if ( iWare != -1 ){--iCount;SGameWare *gm = new SGameWare;gm->iPos = line.GetToken(" ", 1, 1).ToInt();gm->iType = line.GetToken(" ", 2, 2).ToInt();gm->cType = line.GetToken(" ", 3, 3)[0];gm->pWare = NULL;gm->sWareName = line.GetToken(" ", 4);m_lGameWares[iWare].push_back(gm);if ( iCount <= 0 )iWare = -1;}else if ( iShip != -1 ){--iCount;SGameShip *gm = new SGameShip;gm->iType = line.GetToken(" ", 1, 1).ToInt();if ( line.GetToken(" ", 2, 2).Left(4) == "$#C:" ){gm->sShipClass = line.GetToken(" ", 2, 2).Right(-4);gm->sShipID = line.GetToken(" ", 3);}else{gm->sShipID = line.GetToken(" ", 2);gm->sShipClass = "OBJ_SHIP_M5";}gm->pPackage = NULL;m_lGameShips.push_back(gm);if ( iCount <= 0 )iShip = -1;}else if ( cmd.Compare("savegamemanager") )m_iSaveGameManager = rest.ToInt();else if ( cmd.Compare("savegame") )m_iSaveGame = rest.ToInt();else if ( cmd == "fakepatch" )m_iFakePatch = rest.ToInt();else if ( cmd == "updatetime" )m_iLastUpdated = rest.ToInt();else if ( cmd == "surpressprotectedwarning" )m_bSurpressProtectedWarning = true;else if ( cmd == "pluginmanager" ){fVersion = rest.ToFloat();m_bOldPlugin = true;}else if ( cmd == "setmod" )m_sSetMod = rest;else if ( cmd == "shipbuffer" )m_iShipBuffer = rest.ToInt();else if ( cmd == "warebuffers" ){int max = rest.NumToken(" ");for ( int i = 0; i < WAREBUFFERS; i++ ){if ( i > max )m_iWareBuffer[i] = 0;elsem_iWareBuffer[i] = rest.GetToken(" ", i + 1, i + 1).ToInt();}}else if ( cmd == "createdfile" )m_lCreatedFiles.PushBack(rest);else if ( cmd == "wares" ){iWare = rest.GetToken(" ", 1, 1).ToInt();iCount = rest.GetToken(" ", 2, 2).ToInt();}else if ( cmd == "ships" ){iShip = 1;iCount = rest.GetToken(" ", 1, 1).ToInt();}else if ( cmd == "modified" )m_bVanilla = false;else if ( cmd == "spkinstaller" ){fVersion = rest.ToFloat();spkinstaller = true;}else if ( cmd == "BetaVersion" )fBeta = rest.ToFloat();else if ( cmd == "Uninstall" ){C_File *uf = new C_File();uf->SetFileType(FILETYPE_SCRIPT);uf->SetCreationTime(rest.GetToken(" ", 1, 1).ToInt());uf->SetFilename(m_sCurrentDir + "/Scripts/" + rest.GetToken(" ", 2));m_lUninstallFiles.push_back(uf);}else if ( cmd == "NonRemovedFile" ){if ( !CFileIO::Remove(rest.ToString()) )m_lNonRemovedFiles.PushBack(rest);}else if ( cmd == "Original" ){C_File *uf = new C_File();uf->SetFileType(rest.GetToken(" ", 1, 1).ToInt());if ( uf->GetFileType() == FILETYPE_EXTRA ){uf->SetDir(rest.GetToken(" ", 2).GetToken(":", 2));uf->SetFilename(rest.GetToken(" ", 2).GetToken(":", 1, 1));}elseuf->SetFilename(rest.GetToken(" ", 2));uf->SetFilename(m_sCurrentDir + "/" + uf->GetNameDirectory(NULL));m_lOriginalFiles.push_back(uf);}else if ( cmd.Compare("GlobalSetting") )m_lGlobals.PushBack(rest.GetToken(":", 1, 1), rest.GetToken(":", 2));else if ( cmd.Compare("FakePatchOrder") )m_lFakePatchOrder.PushBack(rest.GetToken(":", 1, 1), rest.GetToken(":", 2));else if ( cmd == "globalfiles" )iStatus = READ_GLOBAL;if ( progress ){progress->UpdateProgress((long)i, (long)readFile->size());}}readFile->clear();if ( !spkinstaller )m_bRedo = true;delete readFile;}}if ( m_pEnabledMod && !m_pEnabledMod->IsEnabled() )m_pEnabledMod = NULL;m_iGame = m_gameExe.GetGameType(m_sCurrentDir.ToString()) + 1;m_pCurrentGameExe = m_gameExe.GetGame(m_gameExe.GetGameType(m_sCurrentDir.ToString()));Utils::String sGameVersion;m_iGameVersion = m_gameExe.GetGameVersion(m_sCurrentDir.ToString(), &sGameVersion) + 1;m_sGameVersion = sGameVersion;m_iGameFlags = m_gameExe.GetGameFlags(m_iGame - 1);m_iMaxPatch = m_gameExe.GetMaxPatch(m_iGame - 1);// find the fake patchif ( !ReadyFakePatch() )return false;this->RemoveCreatedFiles();// match up waresfor ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){if ( node->Data()->GetType() == TYPE_SPK ){CSpkFile *p = (CSpkFile *)node->Data();for ( CListNode<SWares> *wNode = p->GetWaresList()->Front(); wNode; wNode = wNode->next() ){SWares *w = wNode->Data();for ( CListNode<SGameWare> *gNode = m_lGameWares[CPackages::ConvertWareType(w->cType)].Front(); gNode; gNode = gNode->next() ){if ( w->sID == gNode->Data()->sWareName.ToString() ){gNode->Data()->pWare = w;break;}}}}else if ( node->Data()->GetType() == TYPE_XSP ){CXspFile *p = (CXspFile *)node->Data();for ( CListNode<SGameShip> *gNode = m_lGameShips.Front(); gNode; gNode = gNode->next() ){if ( p->GetShipID().Compare(gNode->Data()->sShipID.ToString()) ){gNode->Data()->pPackage = p;break;}}}}// check the purged timethis->PurgeGameObjects();m_bLoaded = true;return true;}void CPackages::RemoveCreatedFiles(){for ( SStringList *node = m_lCreatedFiles.Head(); node; node = node->next ){if ( CFileIO(node->str).ExistsOld() )CFileIO::Remove(node->str.ToString());else if ( CFileIO(m_sCurrentDir + "/" + node->str).ExistsOld() )CFileIO::Remove((m_sCurrentDir + "/" + node->str).ToString());}m_lCreatedFiles.Clear();}void CPackages::PurgeGameObjects(){// check for the log fileCyString logDir = GetLogDirectory();CFileIO LogFile(logDir + "/log0" + CyString::Number(PMTEXTFILE).PadNumber(4) + ".txt");if ( LogFile.exists() ){// read the log file to memorystd::vector<CyString> *lines = LogFile.ReadLines();if ( lines ){for ( int i = 0; i < (int)lines->size(); i++ ){CyString line(lines->at(i));CyString start = line.GetToken(":", 1, 1).ToLower();CyString rest = line.GetToken(":", 2, 2).RemoveFirstSpace();if ( start.Compare("purged") ){long time = rest.ToLong();if ( time == m_iLastUpdated ){this->PurgeWares();this->PurgeShips();this->RemoveUninstallScripts();}}}delete lines;}// remove the log fileLogFile.remove();}}void CPackages::PurgeWares(){// mark all delete wares as availablefor ( int i = 0; i < WAREBUFFERS; i++ ){for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() ){SGameWare *w = node->Data();if ( !w ) continue;if ( w->iType == WARETYPE_DELETED )w->iType = WARETYPE_NONE;}m_lGameWares[i].RemoveEmpty();}}void CPackages::PurgeShips(){for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){if ( !node->Data() )continue;if ( node->Data()->iType == WARETYPE_DELETED )node->Data()->iType = WARETYPE_NONE;}m_lGameShips.RemoveEmpty();}CyString CPackages::GetLogDirectory(){CyString logDir = m_sCurrentDir;if ( m_iGameFlags & EXEFLAG_MYDOCLOG ) {SGameExe *exe = m_gameExe.GetGame(m_iGame - 1);if ( exe ) {if ( !exe->sMyDoc.empty() )logDir = m_sMyDoc + "/" + exe->sMyDoc;}}return logDir;}CyString CPackages::GetLogDirectory(CyString gameExe){CyString logDir = m_sCurrentDir;if ( m_iGameFlags & EXEFLAG_MYDOCLOG ){SGameExe *exe = m_gameExe.gameExe(CFileIO(gameExe).filename());if ( exe ){if ( !exe->sMyDoc.empty() )logDir = m_sMyDoc + "/" + exe->sMyDoc;}}return CFileIO(logDir).GetFullFilename();}CyString CPackages::GetSaveDirectory(){CyString logDir = this->GetLogDirectory();if ( m_iGameFlags & EXEFLAG_NOSAVESUBDIR )return logDir;return logDir + "/save";}bool CPackages::ReadyFakePatch(){// already exists, lets skip itif ( CFileIO(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat").ExistsOld() && CFileIO(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat").ExistsOld() )return true;// if only one of them exists, lets remove themif ( CFileIO(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat").ExistsOld() )CFileIO::Remove(m_sCurrentDir.ToString() + "/PluginManager/PlugMan_Fake.cat");if ( CFileIO(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat").ExistsOld() )CFileIO::Remove(m_sCurrentDir.ToString() + "/PluginManager/PlugMan_Fake.dat");// now lets find the fake patchCyString useFile;if ( m_iFakePatch > 0 ){CyString file = CyString::Number(m_iFakePatch).PadNumber(2);if ( CheckValidPluginManagerFile(file) )useFile = file;else if ( CheckIfPluginManagerFile(file) )useFile = file;}if ( useFile.Empty() ){int nextfree = this->FindNextFakePatch();--nextfree; // gets the end fake patch// work backwards till we find a valid onewhile ( nextfree > m_iMaxPatch ){CyString file = CyString::Number(nextfree).PadNumber(2);if ( CheckValidPluginManagerFile(file) ){useFile = file;break;}--nextfree;}}CyString addonDir = this->GetAddonDir();// couldn't find the correct file, lets search for itif ( useFile.Empty() ) {int nextfree = this->FindNextFakePatch();--nextfree; // gets the end fake patch// work backwards till we find a valid onewhile ( nextfree > m_iMaxPatch ){CyString file = CyString::Number(nextfree).PadNumber(2);if ( CheckIfPluginManagerFile(file) ){useFile = file;break;}--nextfree;}}if ( !useFile.Empty() ){// lets check whats in the file firstCCatFile openCat;if ( openCat.Open(m_sCurrentDir + "/" + useFile + ".cat", addonDir, CATREAD_CATDECRYPT, false) == CATERR_NONE ){CLinkList<SInCatFile> *files = openCat.GetFiles();bool found = false;if ( files ){CyString useAddonDir = addonDir;if ( !useAddonDir.Empty() ) useAddonDir += "\\";for ( SInCatFile *inCat = files->First(); inCat; inCat = files->Next() ){if ( inCat->sFile.Compare("PlugMan\\TFake.pck") )continue;if ( inCat->sFile.Compare(useAddonDir + "t\\44" + CyString::Number(PMTEXTFILE).PadNumber(4) + ".pck") )continue;if ( inCat->sFile.Compare(useAddonDir + "t\\" + CyString::Number(PMTEXTFILE).PadNumber(4) + "-L044.pck") )continue;found = true;break;}}// no files, jsut delete themCFileIO catFile(m_sCurrentDir + "/" + useFile + ".cat");if ( !files || !found ){if ( catFile.remove() ){CFileIO datFile(m_sCurrentDir + "/" + useFile + ".dat");if ( datFile.remove() )return true;}}else{if ( catFile.Rename(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat") ){CFileIO datFile(m_sCurrentDir + "/" + useFile + ".dat");if ( datFile.Rename(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat") )return true;// TODO: it failed, restore cat file and do error}}}// if we're here, we tryed, and failedreturn false;}// otherwise we didn't need to (hopefully)return true;}bool CPackages::CheckIfPluginManagerFile(CyString filename){bool found = false;CFileIO catFile(m_sCurrentDir + "/" + filename + ".cat");if ( catFile.exists() && CFileIO(m_sCurrentDir + "/" + filename + ".dat").ExistsOld() ){CCatFile openFile;if ( openFile.Open(catFile.GetFullFilename(), this->GetAddonDir(), CATREAD_CATDECRYPT, false) == CATERR_NONE ){int count = 0;int noncount = 0;// check for some of the filesfor ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {if ( node->Data()->GetFullDir().IsIn("::") ) {if (CFileIO(node->Data()->GetFullDir().GetToken("::", 1, 1)).GetFilename().Compare("PlugMan_Fake.cat") ) {CyString filename = node->Data()->GetFilePointer().GetToken("::", 2, 2);filename = filename.findreplace("/", "\\");if ( openFile.FindData(filename) )++count;else++noncount;}}}if ( (count && !noncount) || (count > noncount) )found = true;}}return found;}bool CPackages::CheckValidPluginManagerFile(CyString filename){bool found = false;// both the cat file and dat file exists, lets open itCFileIO catFile(m_sCurrentDir + "/" + filename + ".cat");if ( catFile.exists() && CFileIO(m_sCurrentDir + "/" + filename + ".dat").ExistsOld() ){CCatFile openFile;if ( openFile.Open(catFile.GetFullFilename(), this->GetAddonDir(), CATREAD_CATDECRYPT, false) == CATERR_NONE ){if ( openFile.FindData("PlugMan\\TFake.pck") )return true;if ( openFile.FindData("pluginmanagerfake.pck") )return true;}}return found;}/*** Converts a package in old format** Some entries in older packages need to be changed for the new installer* These Include:* - Game Version, old format is an id of position in the Data/exe file, new is 2 values, one for game, one for the version*/void CPackages::ConvertOldPackage(CBaseFile *package){for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {if ( gNode->Data()->iGame == -1 ) {// all versionsif ( gNode->Data()->iVersion == 0 )gNode->Data()->iGame = 0;else{int version = 0;gNode->Data()->iGame = m_gameExe.ConvertGameType(gNode->Data()->iVersion, &version);gNode->Data()->iVersion = version;}}}if ( package->forumLink().empty() && package->webSite().isin("forum.egosoft")) {package->setForumLink(package->webSite());package->setWebSite("");}// convert the versionif ( package->GetType() == TYPE_SPK ){CSpkFile *spk = (CSpkFile *)package;if ( spk->GetScriptType() == CSpkFile::SCRIPTTYPE_CUSTOM ){CyString type = spk->GetScriptTypeString(44);if ( type.Compare("Ship Upgrade") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_SHIPUPGRADE);else if ( type.Compare("Trade Script") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_TRADE);else if ( type.Compare("Fleet Management") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_FLEET);else if ( type.Compare("Navigation Script") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_NAVIGATION);else if ( type.Compare("Piracy") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_PIRACY);else if ( type.Compare("Other") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_OTHER);else if ( type.Compare("Ship Command") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_SHIPCOMMAND);else if ( type.Compare("Station Command") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_STATIONCOMMAND);else if ( type.Compare("al plugin") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_ALPLUGIN);else if ( type.Compare("combat script") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_COMBAT);else if ( type.Compare("bbs and missions") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_MISSION);else if ( type.Compare("extension mod") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_EXTENSION);else if ( type.Compare("rebalance mod") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_REBALANCE);else if ( type.Compare("general mod") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_GENERALMOD);else if ( type.Compare("total conversion") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_TOTAL);else if ( type.Compare("cheat script") )spk->SetScriptType(CSpkFile::SCRIPTTYPE_CHEAT);else if ( type == "Library Script" ){spk->SetScriptType("");spk->SetLibrary();}if ( spk->GetScriptType() != CSpkFile::SCRIPTTYPE_CUSTOM )spk->SetScriptType("");}}else if ( package->GetType() == TYPE_XSP ){CXspFile *xsp = (CXspFile *)package;Utils::String data = xsp->GetShipData();for ( int i = 17; i <= 18; i++ ){Utils::String model = data.token(";", i);Utils::String modelExt = model.right(4);// check file extensionif ( modelExt.Compare(".bod") || modelExt.Compare(".pbd") )data = data.replaceToken(";", i, model.left(-4));}xsp->SetShipData(data);}// any extra files that are in director folderif ( package->AnyFileType(FILETYPE_EXTRA) ){for ( C_File *f = package->GetFirstFile(FILETYPE_EXTRA); f; f = package->GetNextFile(f) ){if ( !f->GetDir().Compare("director") )continue;if ( f->CheckFileExt("xml") || f->CheckFileExt("pck") ){f->SetDir("");f->SetFileType(FILETYPE_MISSION);}}}}void CPackages::UpdatePackage(CBaseFile *p){if ( p->GetType() != TYPE_SPK )return;CSpkFile *package = (CSpkFile *)p;// update the signed statuspackage->UpdateSigned(true);// check for another modif ( !package->IsAnotherMod() )return;package->SetParent((CSpkFile *)FindSpkPackage(package->GetOtherName(), package->GetOtherAuthor()));}/*** Updates the package list once data has been read** Finds any original Files* Updates Signed status of all packages*/bool CPackages::UpdatePackages(int doStatus, bool individual){// if theres no original files, then set the current structure as the baseif ( doStatus == 0 || doStatus == -1 ){if ( m_lOriginalFiles.empty() || m_bRedo ){StoreOriginalFiles(FILETYPE_SCRIPT, "scripts");StoreOriginalFiles(FILETYPE_TEXT, "t");StoreOriginalFiles(FILETYPE_SOUND, "soundtrack");StoreOriginalFiles(FILETYPE_EXTRA, "mov");}}// update each package// parent/child, signed statusif ( doStatus == -1 || doStatus == 1 ){if ( individual ){// no package, most likly none installedif ( !m_pPackageNode )return false;this->UpdatePackage(m_pPackageNode->Data());// move to the next packagem_pPackageNode = m_pPackageNode->next();if ( !m_pPackageNode )return false;}else{for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )this->UpdatePackage(node->Data());}}if ( doStatus == -1 || doStatus == 2 )this->LoadVirtualFileSystem();// adjust save gamesif ( doStatus == -1 || doStatus == 3 ){/*// load our save games to the active mydocsif ( m_iSaveGame != -1 ){// check we have a valid save game directoryCDirIO Dir(this->GetSaveDirectory());if ( Dir.Exists() ){// now check our directory already exists// if we are vanilla mode, then make sure we use the vanilla saves if existsCyString d = CyString("game_") + (long)m_iSaveGame + "/";if ( m_bVanilla )d += "Vanilla";elsed += "Modified";// copy the files back overif ( Dir.Exists(d) ){// if vanilla, remove files firstif ( m_bVanilla ){CyStringList *lDirs = Dir.DirList();if ( lDirs ){for ( SStringList *node = lDirs->Head(); node; node = node->next ){if ( !Dir.IsFile(node->str) || !CFileIO(node->str).CheckFileExtension("sav") )continue;CFileIO(Dir.File(node->str)).Remove();}delete lDirs;}}// copy files to normal save game directoryCDirIO FromDir(Dir.Dir(d));CyStringList *lDirs = FromDir.DirList();if ( lDirs ){for ( SStringList *node = lDirs->Head(); node; node = node->next ){if ( !FromDir.IsFile(node->str) || !CFileIO(node->str).CheckFileExtension("sav") )continue;CFileIO F(FromDir.File(node->str));F.Copy(Dir.File(F.GetFilename()));}delete lDirs;}}}}*/}m_bRedo = false;return true;}int CPackages::CheckOpenPackage(CyString file, int *error){// first check if it existsif ( !CFileIO(file).ExistsOld() ){*error = INSTALLERR_NOEXIST;return -1;}// open the spk filefloat fVersion = 0.0f;int check = CBaseFile::CheckFile(file, &fVersion);// wrong versionif ( fVersion > (float)FILEVERSION ){*error = INSTALLERR_VERSION;return -1;}return check;}CMultiSpkFile *CPackages::OpenMultiPackage(CyString file, int *error, CProgressInfo *progress){int check = CheckOpenPackage(file, error);if ( *error == -1 )return false;if ( check != SPKFILE_MULTI ){*error = INSTALLERR_NOMULTI;return false;}*error = INSTALLERR_NONE;CMultiSpkFile *package = new CMultiSpkFile;bool ret = false;if ( package->ReadFile(file, true) ){if ( package->ReadAllPackages(SPKREAD_NODATA) ){for ( CListNode<SMultiSpkFile> *node = package->GetFileList()->Front(); node; node = node->next() )this->ConvertOldPackage(node->Data()->pFile);ret = true;}}if ( ret )return package;delete package;return NULL;}bool CPackages::OpenMultiPackage ( CyString file, CLinkList<CBaseFile> *packageList, int *error, CProgressInfo *progress ){int check = CheckOpenPackage(file, error);if ( *error == -1 )return false;if ( check != SPKFILE_MULTI ){*error = INSTALLERR_NOMULTI;return false;}*error = INSTALLERR_NONE;CMultiSpkFile *package = new CMultiSpkFile;bool ret = false;if ( package->ReadFile(file, true) ){if ( package->ReadAllPackages(SPKREAD_ALL, packageList) ){for ( CListNode<CBaseFile> *node = packageList->Front(); node; node = node->next() )this->ConvertOldPackage(node->Data());ret = true;}}delete package;return ret;}int CPackages::PrepareMultiPackage ( CyString file, CLinkList<CBaseFile> *errorPackageList, int *error, CProgressInfo *progress ){int check = CheckOpenPackage(file, error);if ( *error == -1 )return 0;if ( check != SPKFILE_MULTI ){*error = INSTALLERR_NOMULTI;return 0;}*error = INSTALLERR_NONE;CMultiSpkFile *package = new CMultiSpkFile;int count = 0;if ( package->ReadFile(file, true) ){CLinkList<CBaseFile> packageList;if ( package->ReadAllPackages(SPKREAD_ALL, &packageList) ){for ( CListNode<CBaseFile> *node = packageList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();this->ConvertOldPackage(p);int error = this->PrepareInstallPackage(p);if ( error ){node->Data()->SetLoadError(error);errorPackageList->push_back(p);}else++count;}}packageList.clear();}for ( SMultiSpkFile *ms = package->GetFileList()->First(); ms; ms = package->GetFileList()->Next() )ms->pFile = NULL;delete package;return count;}CBaseFile *CPackages::OpenPackage(CyString file, int *error, CProgressInfo *progress, int readtype, int flags){int check = CheckOpenPackage(file, error);if ( *error == -1 )return NULL;CBaseFile *installFile = 0;if ( progress )progress->DoHalf();switch (check){case SPKFILE_OLD:*error = INSTALLERR_OLD;return NULL;case SPKFILE_INVALID:// convert xspif ( CFileIO(file).CheckFileExtension("xsp") ){installFile = new CXspFile();if ( !((CXspFile *)installFile)->ConvertOld(file.ToString()) ){delete installFile;return NULL;}break;}*error = INSTALLERR_INVALID;return NULL;case SPKFILE_BASE:installFile = new CBaseFile();if ( !installFile->ReadFile(file, readtype, progress) ){delete installFile;return NULL;}break;case SPKFILE_SINGLE:installFile = new CSpkFile();if ( !((CSpkFile *)installFile)->ReadFile(file, readtype, progress) ){delete installFile;return NULL;}break;case SPKFILE_MULTI:*error = INSTALLERR_NOMULTI;return NULL;case SPKFILE_SINGLESHIP:installFile = new CXspFile();if ( !((CXspFile *)installFile)->ReadFile(file, readtype, progress) ){delete installFile;return NULL;}break;default:*error = INSTALLERR_UNKNOWN;return NULL;}if ( progress )progress->SecondHalf();// now uncomress all filesif ( !(flags & READFLAG_NOUNCOMPRESS) )installFile->UncompressAllFiles(progress);this->ConvertOldPackage (installFile);return installFile;}void CPackages::PurgeUninstallScripts(CBaseFile *package, CyStringList *errors){for ( CListNode<C_File> *fNode = m_lUninstallFiles.Front(); fNode; fNode = fNode->next() ){C_File *uf = fNode->Data();// check against any script filesfor ( CListNode<C_File> *checkNode = package->GetFileList()->Front(); checkNode; checkNode = checkNode->next() ){C_File *checkFile = checkNode->Data();if ( !checkFile ) continue;if ( checkFile->GetFileType() != FILETYPE_UNINSTALL && checkFile->GetFileType() != FILETYPE_SCRIPT )continue;if ( uf->GetFilename().Compare(checkFile->GetFilename()) ){if ( RemoveUninstallFile(uf, errors) )fNode->DeleteData();break;}}}m_lUninstallFiles.RemoveEmpty();this->WriteData();}int CPackages::InstallPreparedPackages(CyStringList *errors, CProgressInfo *progress, CLinkList<CBaseFile> *errored, CLinkList<CBaseFile> *installedList){if ( m_lInstallList.empty() ) return false;int installed = 0;for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( this->InstallPackage(p, errors, progress, !p->IsEnabled()) ){++installed;if ( installedList )installedList->push_back(p);}else if ( errored ){m_lPackages.remove(p);errored->push_back(p);}}m_lInstallList.clear();this->WriteData();return installed;}void CPackages::_addToFakePatch(CBaseFile *pPackage){CCatFile cat;if ( CCatFile::Opened(cat.Open(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat", this->GetAddonDir(), CATREAD_DAT)) ) {for ( CListNode<C_File> *f = pPackage->GetFileList()->Front(); f; f = f->next() ) {if ( f->Data()->GetFileType() != FILETYPE_SHIPSCENE && f->Data()->GetFileType() != FILETYPE_COCKPITSCENE && f->Data()->GetFileType() != FILETYPE_SHIPMODEL && f->Data()->GetFileType() != FILETYPE_SHIPOTHER ) {continue;}if ( CCatFile::IsAddonDir(f->Data()->GetNameDirectory(pPackage)) ) {continue;}// check if its already in the fake patchif ( f->Data()->GetFullDir().IsIn("::") ) {continue;}Utils::String toFile;if ( cat.AppendFile(f->Data()->GetFilePointer().ToString(), f->Data()->GetNameDirectory(pPackage).ToString(), true, (m_iGameFlags & EXEFLAG_NOXOR) ? false : true, &toFile) ) {CLog::logf(CLog::Log_Install, 2, "Adding file: %s into the fake patch", f->Data()->GetNameDirectory(pPackage).c_str());CFileIO::Remove(f->Data()->GetFilePointer().ToString());f->Data()->SetFilename(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat::" + toFile);}}}}bool CPackages::InstallPackage ( CBaseFile *package, CyStringList *errors, CProgressInfo *progress, bool disabled ){CLog::logf(CLog::Log_Install, 1, "Starting to install new package, %s by %s (Version: %s)", package->name().c_str(), package->author().c_str(), package->version().c_str());// first check if we are installed a modbool prevDisabled = disabled;if ( package->IsMod() && m_pEnabledMod && !m_bForceModInstall ) {disabled = true;CLog::log(CLog::Log_Install, 2, "Package is a mod and another mod is already enabled, setting to disabled");}// if vanilla nad package aint signedif ( m_bVanilla && !package->IsSigned() ) {disabled = true;CLog::log(CLog::Log_Install, 2, "Package is a not signed and are we in vanilla mode, setting to disabled");}// check any depanciesif ( !disabled && !this->CheckEnabledDependacy(package) ) {disabled = true;CLog::log(CLog::Log_Install, 2, "Dependacies missing for package, setting to disabled");}// search for an old versionCBaseFile *oldPackage = FindPackage(package);if ( oldPackage && oldPackage == m_pEnabledMod && disabled )disabled = prevDisabled;// update packages must have an old package installed already (should have been checked for already)if ( package->GetType() == TYPE_SPK ){if ( ((CSpkFile *)package)->IsPackageUpdate() ){CLog::log(CLog::Log_Install, 3, "Package is an Update, checking for existing package installed");if ( !oldPackage ) {CLog::log(CLog::Log_Install, 2, "Package is an Update but no existing package found, cancelling install");return false;}// change any mods to temp onesfor ( CListNode<C_File> *f = package->GetFileList()->Front(); f; f = f->next() ){if ( f->Data()->GetFileType() != FILETYPE_MOD )continue;f->Data()->SetDir("temp");if ( f->Data()->IsFakePatch() ) {CLog::logf(CLog::Log_Install, 2, "Moving fake package to temporary location to preper for update, %s", f->Data()->GetFilePointer().c_str());f->Data()->SetName(CyString("Fake_") + f->Data()->GetName());}}}}// no need to backup if we're disabling themif ( !disabled ){// find any uninstall files and remove themCLog::log(CLog::Log_Install, 3, "Purging uninstall scripts");this->PurgeUninstallScripts(package, errors);// backup any original files before installingCLog::log(CLog::Log_Install, 3, "Checking for any original files to backup");CDirIO oDir(m_sCurrentDir + "/PluginManager/Original");for ( CListNode<C_File> *oNode = m_lOriginalFiles.Front(); oNode; oNode = oNode->next() ){C_File *of = oNode->Data();for ( CListNode<C_File> *checkNode = package->GetFileList()->Front(); checkNode; checkNode = checkNode->next() ){C_File *f = checkNode->Data();// match the same filetypeif ( of->GetFileType() != f->GetFileType() )continue;// same fileif ( of->GetFilename().Compare(f->GetFilename()) ){// check if original file already exists (assume already backed up)if ( !BackupOriginalFile(of, errors) )continue;break;}}}}// install all the filesCLog::log(CLog::Log_Install, 3, "Checking for any existing files");if ( oldPackage ){CLog::logf(CLog::Log_Install, 3, "Excluding existing package (%s) from file check list", oldPackage->version().c_str());CLinkList<CBaseFile> excludeList;excludeList.push_back(oldPackage);this->UpdateUsedFiles(&excludeList, true);}elsethis->UpdateUsedFiles(0, true);CLog::log(CLog::Log_Install, 3, "Reading all files into memory");package->ReadAllFilesToMemory();CLog::log(CLog::Log_Install, 3, "Starting to install files");if ( !package->InstallFiles (m_sCurrentDir, progress, &m_lFiles, errors, !disabled, this) ){CLog::log(CLog::Log_Install, 2, "There was an error installing files!!");// TODO: clear up installed filesreturn false;}// if we're installing an addon, lets use the fake patch method for object filesif ( m_iGameFlags & EXEFLAG_ADDON ) this->_addToFakePatch(package);bool shuffle = false;// merge the update into the old packagebool dontAdd = false;if ( package->GetType() == TYPE_SPK ){if ( ((CSpkFile *)package)->IsPackageUpdate() ){// now copy any files from a modfor ( CListNode<C_File> *f = package->GetFileList()->Front(); f; f = f->next() ){if ( !f->Data() )continue;if ( f->Data()->GetFileType() != FILETYPE_MOD )continue;// we only need the cat fileif ( !f->Data()->CheckFileExt("cat") )continue;// if fake patch, find first fake patch in packageC_File *findMatching = NULL;if ( f->Data()->GetBaseName().Left(5).Compare("fake_") ){for ( CListNode<C_File> *node = oldPackage->GetFileList()->Front(); node; node = node->next() ){if ( !node->Data() )continue;if ( node->Data()->GetFileType() != FILETYPE_MOD )continue;// we only need the cat fileif ( !node->Data()->CheckFileExt("cat") )continue;if ( !node->Data()->IsFakePatch() )continue;findMatching = node->Data();break;}}// otherwise, just add to the mod of the same nameelse{for ( CListNode<C_File> *node = oldPackage->GetFileList()->Front(); node; node = node->next() ){if ( !node->Data() )continue;if ( node->Data()->GetFileType() != FILETYPE_MOD )continue;// we only need the cat fileif ( !node->Data()->CheckFileExt("cat") )continue;if ( node->Data()->GetName().Compare(f->Data()->GetName()) ){findMatching = node->Data();break;}}}if ( findMatching ){// copy accross all modsCCatFile catTo, catFrom;if ( catFrom.Open(f->Data()->GetFilePointer(), this->GetAddonDir(), CATREAD_CATDECRYPT, false) == CATERR_NONE ){if ( catTo.Open(findMatching->GetFilePointer(), this->GetAddonDir(), CATREAD_CATDECRYPT, false) == CATERR_NONE ){for ( int i = 0; i < catFrom.GetNumFiles(); i++ ){SInCatFile *c = catFrom.GetFile(i);catTo.AppendFile((f->Data()->GetFilePointer() + "::" + c->sFile).ToString(), c->sFile.ToString());}}}// now remove the filesC_File *m = package->FindMatchingMod(f->Data());RemoveFile(f->Data(), errors);m_lFiles.remove(f->Data());f->ChangeData(NULL);if ( m ){int pos = package->GetFileList()->FindPos(m);RemoveFile(m, errors);m_lFiles.remove(m);if ( pos != -1 )package->GetFileList()->GetNode(pos)->ChangeData(NULL);}}// no matching file, then we shall just renaming backelse{if ( f->Data()->GetBaseName().Left(5).Compare("fake_") ){shuffle = true;C_File *match = package->FindMatchingMod(f->Data());CyString next = CyString::Number(this->FindNextFakePatch()).PadNumber(2);CyString oldFilePointer = f->Data()->GetFilePointer();f->Data()->SetDir("");f->Data()->ChangeBaseName(next);if ( CFileIO(oldFilePointer).Rename(m_sCurrentDir + "/" + f->Data()->GetNameDirectory(package)) )f->Data()->SetFilename(m_sCurrentDir + "/" + f->Data()->GetNameDirectory(package));if ( match ){CyString oldFilePointer = match->GetFilePointer();match->SetDir("");match->ChangeBaseName(next);if ( CFileIO(oldFilePointer).Rename(m_sCurrentDir + "/" + match->GetNameDirectory(package)) )match->SetFilename(m_sCurrentDir + "/" + match->GetNameDirectory(package));}}else{C_File *match = package->FindMatchingMod(f->Data());f->Data()->SetDir("");if ( CFileIO(f->Data()->GetFilePointer()).Rename(m_sCurrentDir + "/" + f->Data()->GetNameDirectory(package)) )f->Data()->SetFilename(m_sCurrentDir + "/" + f->Data()->GetNameDirectory(package));if ( match ){match->SetDir("");if ( CFileIO(match->GetFilePointer()).Rename(m_sCurrentDir + "/" + match->GetNameDirectory(package)) )match->SetFilename(m_sCurrentDir + "/" + match->GetNameDirectory(package));}}}}package->GetFileList()->RemoveEmpty();((CSpkFile *)oldPackage)->MergePackage(package);delete package;package = oldPackage;oldPackage = false;dontAdd = true;CDirIO(m_sCurrentDir).RemoveDir("temp");CDirIO(m_sCurrentDir).RemoveDir("Mods/temp");}}// if theres an icon, write itif ( package->GetIcon() ){CLog::log(CLog::Log_Install, 3, "Checking to install icon display file");C_File *icon = package->GetIcon();if ( !icon->GetData() || !icon->GetDataSize() ) {package->SetIcon(NULL, "");CLog::log(CLog::Log_Install, 2, "Unable to extract icon, clearing");}else{CDirIO Dir(m_sCurrentDir);bool ready = true;if ( !Dir.Exists("PluginManager") ){if ( !Dir.Create("PluginManager") )ready = false;}if ( ready && !Dir.Exists("PluginManager/Icons") ){if ( !Dir.Create("PluginManager/Icons") )ready = false;}if ( ready ){if ( !icon->UncompressData() )package->SetIcon(NULL, "");else{CFileIO iconFile(m_sCurrentDir + "/PluginManager/Icons/" + package->author() + "_" + package->name() + "." + package->GetIconExt());if ( iconFile.WriteData((const char *)icon->GetData(), icon->GetDataSize()) ){icon->SetFilename(CyString(package->author()) + "_" + package->name() + "." + package->GetIconExt());icon->SetFullDir(m_sCurrentDir + "/PluginManager/Icons");}elsepackage->SetIcon(NULL, "");}}if ( package->GetIcon() )package->GetIcon()->DeleteData();}}// remove all dataCLog::log(CLog::Log_Install, 3, "Clearing all unneeded file data");package->ClearFileData();// add to listif ( !dontAdd ){CLog::log(CLog::Log_Install, 1, "Adding package into main list");if ( oldPackage ){m_lPackages.insert(oldPackage, package);m_lPackages.remove(oldPackage, false);}elsem_lPackages.push_back (package);}CLog::log(CLog::Log_Install, 2, "Updating file used count");UpdateUsedFiles();if ( disabled ) package->SetEnabled(false);// remove any files no longer used by old packageif ( oldPackage ){CLog::log(CLog::Log_Install, 3, "Removing any unused files from previous package");CListNode<C_File> *fnode = oldPackage->GetFileList()->Front();while ( fnode ){C_File *f = fnode->Data();// no longer usedif ( !f->GetUsed() ){// remove from file listm_lFiles.remove(f, false);// remove from hard driveif ( RemoveFile(f, errors) ){CLog::logf(CLog::Log_Install, 1, "Removed unused file: %s", f->GetFilePointer().c_str());// if a fake patch, we need to shufleif ( f->IsFakePatch() )shuffle = true;else if ( f->IsAutoTextFile() )shuffle = true;}}fnode = fnode->next();}}if ( shuffle ){CLog::log(CLog::Log_Install, 2, "Shuffling Fake patches");ShuffleFakePatches(errors);CLog::log(CLog::Log_Install, 2, "Shuffling Text Files");ShuffleTextFiles(errors);}// now we need to link any child/parent packagesif ( package->GetType() == TYPE_SPK ){CSpkFile *spk = (CSpkFile *)package;if ( spk->IsAnotherMod() ) {spk->SetParent((CSpkFile *)FindSpkPackage(spk->GetOtherName(), spk->GetOtherAuthor()));CLog::logf(CLog::Log_Install, 2, "Linking to parent package: %s by %s (Version: %s)", spk->name().c_str(), spk->author().c_str(), spk->version().c_str());}}// store enabled modif ( package->IsMod() && !disabled ) {m_pEnabledMod = package;CLog::log(CLog::Log_Install, 1, "Setting package as primary mod");}m_bRemoveDir = true;CLog::log(CLog::Log_Install, 1, "Saving data to file");this->WriteData();CLog::log(CLog::Log_Install, 1, "Installation Finished");return true;}bool CPackages::UninstallPreparedPackages(CyStringList *errors, CProgressInfo *progress, CLinkList<CBaseFile> *uninstalledPackages, CLinkList<CBaseFile> *disabledPackages){if ( m_lInstallList.empty() ) return false;// update the used status, excluding all packages we are about to removeUpdateUsedFiles(&m_lInstallList);CyStringList removeDirs;CLinkList<C_File> uninstallFiles;CLinkList<C_File> fileList;bool readme = false, original = false, shuffle = false;// find all files that need to be removedint maxFiles = 0;for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();maxFiles += this->GetAllPackageFiles(p, &fileList, true);// disable any dependantsif ( p->GetType() == TYPE_SPK && ((CSpkFile *)p)->IsLibrary() ){CLinkList<CBaseFile> depList;if ( this->GetDependacyList(p, &depList) ){for ( CBaseFile *depP = depList.First(); depP; depP = depList.Next() ){if ( depP->IsEnabled() )this->PrepareDisablePackage(depP);}if ( m_lDisableList.size() )this->DisablePreparedPackages(errors, progress, disabledPackages);}}}// interate through all the files in the packageint fileCount = 0;for ( CListNode<C_File> *node = fileList.Front(); node; node = node->next() ){C_File *f = node->Data();// display progress if neededif ( progress ){progress->UpdateProgress(fileCount++, maxFiles);progress->UpdateFile(f);}// skip uninstall filesif ( f->GetFileType() == FILETYPE_UNINSTALL ){uninstallFiles.push_back(f);continue;}// only delete files that are not used// if its a shared file, we skip itif ( f->GetUsed() || f->IsShared() )continue;if ( f->GetFileType() == FILETYPE_README )readme = true;else if ( f->GetFileType() == FILETYPE_UNINSTALL || f->GetFileType() == FILETYPE_MAP || f->GetFileType() == FILETYPE_SOUND || f->GetFileType() == FILETYPE_EXTRA || f->GetFileType() == FILETYPE_SHIPSCENE || f->GetFileType() == FILETYPE_COCKPITSCENE || f->GetFileType() == FILETYPE_SHIPOTHER || f->GetFileType() == FILETYPE_SHIPMODEL || f->GetFileType() == FILETYPE_ADVERT ){CyString dir = f->GetDirectory(NULL);removeDirs.PushBack(dir, true);dir = dir.FindReplace("\\", "/");if ( dir.IsIn("/") ){for ( int i = dir.NumToken("/"); i; i-- ){CyString remDir = dir.GetToken("/", 1, i);removeDirs.PushBack(remDir, true);}}}if ( f->GetFileType() == FILETYPE_EXTRA && f->GetDir().Left(6).lower() == "extras" )removeDirs.PushBack("Extras", true);if ( RemoveFile(f, errors) ){// check if its an original file and restoreif ( IsOriginalFile(f) ){CFileIO of(m_sCurrentDir + "/PluginManager/Original/" + f->GetNameDirectory(NULL));if ( of.exists() ){original = true;if ( of.Rename(m_sCurrentDir + "/" + f->GetNameDirectory(NULL)) )this->AddLogEntry(SPKINSTALL_ORIGINAL_RESTORE, f->GetNameDirectory(NULL), errors);elsethis->AddLogEntry(SPKINSTALL_ORIGINAL_RESTORE_FAIL, f->GetNameDirectory(NULL), errors);}}}else // problem removeing (try when the program closes)m_lNonRemovedFiles.PushBack(f->GetFilePointer());// check for fake patchsif ( f->IsFakePatch() )shuffle = true;else if ( f->IsAutoTextFile() )shuffle = true;// remove the file from the main list as swellm_lFiles.remove(f, false);delete f;}// remove all the packages from memoryfor ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();p->GetFileList()->clear();m_lPackages.remove(p);if ( p == m_pEnabledMod )m_pEnabledMod = NULL;if ( uninstalledPackages )uninstalledPackages->push_back(p);elsedelete p;}m_lInstallList.clear();// check unistall filesif ( !uninstallFiles.empty() ){removeDirs.PushBack(CyString("PluginManager/Uninstall"));// make sure the scripts directory is created, even thou it should always be there anywaysCDirIO scriptDir(m_sCurrentDir);if ( !scriptDir.Exists("scripts") ){if ( scriptDir.Create("Scripts") )this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY, "Scripts", errors);elsethis->AddLogEntry(SPKINSTALL_CREATEDIRECTORY_FAIL, "Scripts", errors);}for ( C_File *uf = uninstallFiles.First(); uf; uf = uninstallFiles.Next() ){C_File *newFile = new C_File();newFile->SetFileType(FILETYPE_SCRIPT);newFile->SetFilename(uf->GetFilename());newFile->SetCreationTime(uf->GetCreationTime());// other installed packages use this file as well, copy itCyString newFilename = m_sCurrentDir + "/" + newFile->GetNameDirectory(NULL);CFileIO file(uf->GetFilePointer());if ( uf->GetUsed() ){if ( file.copy(newFilename.ToString()) )this->AddLogEntry(SPKINSTALL_UNINSTALL_COPY, newFile->GetNameDirectory(NULL), errors);else{this->AddLogEntry(SPKINSTALL_UNINSTALL_COPY_FAIL, newFile->GetNameDirectory(NULL), errors);delete newFile;newFile = NULL;}}// otherwise just move itelse{if ( file.Rename(newFilename) )this->AddLogEntry(SPKINSTALL_UNINSTALL_MOVE, newFile->GetNameDirectory(NULL), errors);else{this->AddLogEntry(SPKINSTALL_UNINSTALL_MOVE_FAIL, newFile->GetNameDirectory(NULL), errors);delete newFile;newFile = NULL;}m_lFiles.remove(uf, false);delete uf;}// add to the listif ( newFile ){// first check if theres a matching onebool found = false;for ( CListNode<C_File> *node = m_lUninstallFiles.Front(); node; node = node->next() ){C_File *checkFile = node->Data();if ( checkFile->GetFilename().Compare(newFile->GetFilename()) ){found = true;break;}}// not found, so add itif ( !found )m_lUninstallFiles.push_back(newFile);elsedelete newFile;}}}uninstallFiles.clear();// remove all directies that we're not usingif ( readme ){removeDirs.PushBack(CyString("PluginManager/Readme"));removeDirs.PushBack(CyString("Readme"));}if ( original )removeDirs.PushBack(CyString("PluginManager/Original"));removeDirs.PushBack(CyString("PluginManager/Disabled"));RemoveUnusedDirectories(removeDirs, errors);// finally lets shuffle any fake patchs to fill in gapsif ( shuffle ){ShuffleFakePatches(errors);ShuffleTextFiles(errors);}this->WriteData();return true;}/*** Prepares a package to be uninstalled** Adds the package, and all its children onto the uninstall list to be used by UninstallPreparePackages*/void CPackages::PrepareUninstallPackage(CBaseFile *package){// add package to listif ( !m_lInstallList.FindData(package) )m_lInstallList.push_back(package);// add all childrenCLinkList<CBaseFile> children;if ( this->GetChildPackages(package, &children, true) ){for ( CBaseFile *p = children.First(); p; p = children.Next() ){if ( !m_lInstallList.FindData(p) )m_lInstallList.push_back(p);}}}bool CPackages::PrepareEnablePackage(CBaseFile *package){ClearError();if ( package->GetParent() && !package->GetParent()->IsEnabled() ){m_iError = PKERR_NOPARENT;return false;}if ( m_bVanilla && !package->IsSigned() ){m_iError = PKERR_MODIFIED;return false;}// check if it needs depanciesif ( package->AnyDependacies() ){if ( this->GetMissingDependacies(package, NULL, true) ){m_iError = PKERR_MISSINGDEP;return false;}}if ( !m_lEnableList.FindData(package) ){if ( !package->IsEnabled() )m_lEnableList.push_back(package);// do all the children as wellif ( m_bAutoEnableChild ){CLinkList<CBaseFile> childList;this->GetChildPackages(package, &childList, true);// add all disabled packages to listfor ( CBaseFile *p = childList.First(); p; p = childList.Next() ){if ( !p->IsEnabled() )m_lEnableList.push_back(p);}}}m_bRemoveDir = true;return true;}bool CPackages::PrepareDisableForVanilla(){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( !p->IsSigned() && p->IsEnabled() ){this->PrepareDisablePackage(p);m_bDisableVanilla = true;}}return true;}bool CPackages::PrepareEnableLibrarys(){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( p->GetType() != TYPE_SPK )continue;if ( !p->IsEnabled() && ((CSpkFile *)p)->IsLibrary() )this->PrepareEnablePackage(p);}return true;}bool CPackages::PrepareEnableFromVanilla(){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( !p->IsEnabled() && p->IsModifiedEnabled() ) {this->PrepareEnablePackage(p);}}return true;}int CPackages::GetDependacyList(CBaseFile *package, CLinkList<CBaseFile> *list){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( p->IsPackageNeeded(package->name(), package->author()) )list->push_back(p);}return list->size();}bool CPackages::PrepareDisablePackage(CBaseFile *package){if ( !m_lDisableList.FindData(package) ){if ( package->IsEnabled() )m_lDisableList.push_back(package);CLinkList<CBaseFile> childList;this->GetChildPackages(package, &childList, true);// add all disabled packages to listfor ( CBaseFile *p = childList.First(); p; p = childList.Next() ){if ( p->IsEnabled() && !m_lDisableList.FindData(p) )m_lDisableList.push_back(p);}// if its a library, check for any dependaciesif ( package->GetType() == TYPE_SPK && ((CSpkFile *)package)->IsLibrary() ){CLinkList<CBaseFile> depList;if ( this->GetDependacyList(package, &depList) ){for ( CBaseFile *p = depList.First(); p; p = depList.Next() ){if ( !m_lDisableList.FindData(p) )this->PrepareDisablePackage(p);}}}}return true;}/*** Prepares a package to be installed*/int CPackages::PrepareInstallPackage(CBaseFile *package, bool disabled, bool force, int check){// add package to listif ( !m_lInstallList.FindData(package) ){int error = this->CheckInstallPackage(package, check);if ( error == INSTALLCHECK_OK || force ){if ( disabled )package->SetEnabled(false);bool added = false;if ( package->GetType() == TYPE_SPK ){// find other mods in the currently added listCSpkFile *spk = (CSpkFile *)package;if ( spk->IsAnotherMod() ){for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( spk->GetOtherName().Compare(p->name()) && spk->GetOtherAuthor().Compare(p->author()) ){m_lInstallList.insert(m_lInstallList.FindPos(p) + 2, package);added = true;break;}}}}if ( !added ){// check if we are a parentfor ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() ){if ( node->Data()->GetType() != TYPE_SPK )continue;CSpkFile *spk = (CSpkFile *)node->Data();if ( !spk->IsAnotherMod() )continue;if ( spk->GetOtherName().Compare(package->name()) && spk->GetOtherAuthor().Compare(package->author()) ){added = true;m_lInstallList.insert(node->Data(), package);break;}}if ( !added )m_lInstallList.push_back(package);}return INSTALLCHECK_OK;}package->SetLoadError(error);return error;}return INSTALLCHECK_ALREADYQUEUED;}void CPackages::RemovePreparedInstall(CBaseFile *package){if ( !package ){m_lInstallList.MemoryClear();}else{if ( m_lInstallList.FindData(package) ){m_lInstallList.remove(package, true);}}}char CPackages::ConvertWareTypeBack(int w){switch ( w ){case WARES_BIO:return 'b';case WARES_ENERGY:return 'e';case WARES_FOOD:return 'f';case WARES_MINERAL:return 'm';case WARES_TECH:return 't';case WARES_NATURAL:return 'n';}return 't';}int CPackages::ConvertWareType(char w){switch ( LOWER(w) ){case 'b':return WARES_BIO;case 'e':return WARES_ENERGY;case 'f':return WARES_FOOD;case 'm':return WARES_MINERAL;case 't':return WARES_TECH;case 'n':return WARES_NATURAL;}return WARES_TECH;}void CPackages::SetupShips(){for ( CListNode<SGameShip> *wNode = m_lGameShips.Front(); wNode; wNode = wNode->next() ){if ( wNode->Data()->iType != WARETYPE_NONE )wNode->Data()->iType = WARETYPE_DELETED;}// find any new ships to add to the listfor ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() ){if ( pNode->Data()->GetType() != TYPE_XSP )continue;CXspFile *p = (CXspFile *)pNode->Data();bool found = false;for ( CListNode<SGameShip> *wNode = m_lGameShips.Front(); wNode; wNode = wNode->next() ){if ( wNode->Data()->sShipID.Compare(p->GetShipID().c_str()) ){if ( !p->IsEnabled() )wNode->Data()->iType = WARETYPE_DISABLED;elsewNode->Data()->iType = WARETYPE_ADDED;found = true;wNode->Data()->pPackage = p;wNode->Data()->sShipClass = p->GetShipClass();break;}}if ( found || !p->IsEnabled() )continue;// first find any freeSGameShip *gw = NULL;for ( CListNode<SGameShip> *wNode = m_lGameShips.Front(); wNode; wNode = wNode->next() ){if ( (!gw) && (wNode->Data()->iType == WARETYPE_NONE) )gw = wNode->Data();// find an old entry for the ware and add it to the same placeif ( wNode->Data()->sShipID.Compare(p->GetShipID().c_str()) ){gw = wNode->Data();break;}}// none found, create oneif ( !gw ){gw = new SGameShip;gw->sShipID = p->GetShipID();gw->sShipClass = p->GetShipClass();gw->pPackage = p;m_lGameShips.push_back(gw);}gw->iType = WARETYPE_ADDED;}}void CPackages::SetupWares(){for ( int i = 0; i < WAREBUFFERS; i++ ){for ( CListNode<SGameWare> *wNode = m_lGameWares[i].Front(); wNode; wNode = wNode->next() ){if ( wNode->Data()->iType != WARETYPE_NONE )wNode->Data()->iType = WARETYPE_DELETED;}}// find any new wares to add to the listfor ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() ){if ( pNode->Data()->GetType() != TYPE_SPK )continue;CSpkFile *p = (CSpkFile *)pNode->Data();for ( CListNode<SWares> *node = p->GetWaresList()->Front(); node; node = node->next() ){SWares *w = node->Data();int wareType = CPackages::ConvertWareType(w->cType);// check if its on the listbool found = false;for ( CListNode<SGameWare> *wNode = m_lGameWares[wareType].Front(); wNode; wNode = wNode->next() ){if ( wNode->Data()->sWareName == w->sID ){if ( !p->IsEnabled() )wNode->Data()->iType = WARETYPE_DISABLED;elsewNode->Data()->iType = WARETYPE_ADDED;wNode->Data()->pWare = w;found = true;break;}}if ( found || !p->IsEnabled() )continue;// first find any freeSGameWare *gw = NULL;for ( CListNode<SGameWare> *wNode = m_lGameWares[wareType].Front(); wNode; wNode = wNode->next() ){if ( (!gw) && (wNode->Data()->iType == WARETYPE_NONE) )gw = wNode->Data();// find an old entry for the ware and add it to the same placeif ( wNode->Data()->sWareName == w->sID ){gw = wNode->Data();break;}}// none found, create oneif ( !gw ){gw = new SGameWare;gw->sWareName = w->sID;gw->iPos = m_lGameWares[wareType].size();gw->pWare = w;gw->cType = w->cType;m_lGameWares[wareType].push_back(gw);}gw->iType = WARETYPE_ADDED;}}}/*** Closing the current directory** When existing, program needs to close the directory*/bool CPackages::CloseDir ( CyStringList *errors, CProgressInfo *progress, bool removedir ){if ( m_sCurrentDir.Empty() )return true;if ( !m_bLoaded )return true;m_sActiveDir = m_sCurrentDir;if ( m_bRenameText )CreateLanguageTextFiles(errors);this->BackupSaves();if ( CFileIO(m_sCurrentDir + "/mods/PluginManager.dat").ExistsOld() )CFileIO::Remove(m_sCurrentDir.ToString() + "/mods/PluginManager.dat");if ( CFileIO(m_sCurrentDir + "/mods/PluginManager.cat").ExistsOld() )CFileIO::Remove(m_sCurrentDir.ToString() + "/mods/PluginManager.cat");if ( !m_bVanilla ){// base mode for Reunionif ( m_iGame == GAME_X3 && m_pEnabledMod ){C_File *fDat = m_pEnabledMod->GetFirstFile(FILETYPE_MOD);while ( fDat && !fDat->IsFakePatch() && !fDat->CheckFileExt("dat") )fDat = m_pEnabledMod->GetNextFile(fDat);if ( fDat ){C_File *fCat = m_pEnabledMod->GetFirstFile(FILETYPE_MOD);while ( fCat && !fCat->IsFakePatch() && !fCat->CheckFileExt("cat") && !fCat->GetBaseName().Compare(fDat->GetBaseName()) )fCat = m_pEnabledMod->GetNextFile(fCat);if ( fCat ){CFileIO(fDat->GetFilePointer()).copy(m_sCurrentDir.ToString() + "/mods/PluginManager.dat");CFileIO(fCat->GetFilePointer()).copy(m_sCurrentDir.ToString() + "/mods/PluginManager.cat");}}}else if ( m_iGame == GAME_X3 && !m_sSetMod.Empty() && CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".cat").ExistsOld() && CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".dat").ExistsOld() ){CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".dat").copy(m_sCurrentDir.ToString() + "/mods/PluginManager.dat");CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".cat").copy(m_sCurrentDir.ToString() + "/mods/PluginManager.cat");}if ( !CDirIO(m_sCurrentDir).Exists("mods") )CDirIO(m_sCurrentDir).Create("mods");SetupWares();SetupShips();CreateEMPFile();CreateWareFiles();CreateDummies();CreateComponants();CreateTShips();CreateCutData();CreateBodies();CreateAnimations();CreateCustomStarts();CreateGlobals();CreatePluginManagerText();RestoreFakePatch();}RemoveFailedFiles();WriteData();if ( removedir && m_bRemoveDir ){m_bRemoveDir = false;CyStringList removeDirs;removeDirs.PushBack(".");RemoveUnusedDirectories(removeDirs, errors);}m_bLoaded = false;return true;}CyString CPackages::GetModKey(){return m_gameExe.GetModKey(m_iGame - 1);}CyString CPackages::GetSelectedModName(){if ( !m_pEnabledMod ){if ( m_sSetMod.Empty() && m_iGame == GAME_X3 )return "PluginManager";return m_sSetMod;}if ( !m_pEnabledMod->IsEnabled() )return m_sSetMod;C_File *f = m_pEnabledMod->GetFirstFile(FILETYPE_MOD);if ( !f )return m_sSetMod;CyString name = f->GetFilename();name = name.Left(-4);return name;}bool CPackages::RestoreFakePatch(){m_iFakePatch = -1;CFileIO catFile(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat");CFileIO datFile(m_sCurrentDir + "/PluginManager/PlugMan_Fake.dat");// if only 1 exists, remove itif ( catFile.exists() && !datFile.exists() ) {if ( !catFile.remove() ) return false;}else if ( !catFile.exists() && datFile.exists() ) {if ( !datFile.remove() ) return false;}// if both exists, lets rename themif ( catFile.exists() && datFile.exists() ){// we need to add the plugin manager file inCyString file = m_sTempDir;if ( !file.Empty() )file += "/";file += "pluginmanagerfake.txt";file = file.FindReplace("\\", "/");CFileIO fakeFile(file);std::vector<CyString> lines;lines.push_back("//pluginmanager fake patch");fakeFile.WriteFile(&lines);CCatFile fakePatch;if ( fakePatch.Open(m_sCurrentDir + "/PluginManager/PlugMan_Fake.cat", this->GetAddonDir(), CATREAD_DAT, false) == CATERR_NONE ){if ( fakePatch.AppendFile(file.ToString(), "PlugMan\\TFake.pck") ){// find next available fake patchm_iFakePatch = this->FindNextFakePatch();fakePatch.WriteCatFile();CyString filename = CyString::Number(m_iFakePatch).PadNumber(2);if ( catFile.Rename(m_sCurrentDir + "/" + filename + ".cat") ){if ( datFile.Rename(m_sCurrentDir + "/" + filename + ".dat") ){fakeFile.remove();return true;}// TODO: restore cat file}}}fakeFile.remove();return false;}return true;}/*** Save package detail to date file** Writes the current package list data into pluginmanager.dat file*/void CPackages::WriteData(){if ( m_sCurrentDir.Empty() )return;CyStringList lines;CyString version;version.FromFloat(GetLibraryVersion(), 2);version.Prepend("SpkInstaller: ");lines.PushBack(version);lines.PushBack(CyString("UpdateTime: ") + (long)m_iLastUpdated);if ( m_iFakePatch != -1 )lines.PushBack(CyString("FakePatch: ") + (long)m_iFakePatch);if ( m_iSaveGame != -1 )lines.PushBack(CyString("SaveGame: ") + (long)m_iSaveGame);lines.PushBack(CyString("SaveGameManager: ") + (long)m_iSaveGameManager);if ( !m_bVanilla )lines.PushBack("Modified");if ( m_bUsedWare )lines.PushBack("UsedWare");if ( m_bSurpressProtectedWarning )lines.PushBack("SurpressProtectedWarning");if ( !m_sSetMod.Empty() )lines.PushBack(CyString("SetMod: ") + m_sSetMod);lines.PushBack(CyString("ShipBuffer: ") + (long)m_iShipBuffer);CyString wareBuffer = "WareBuffers:";for ( int i = 0; i < WAREBUFFERS; i++ )wareBuffer += CyString(" ") + (long)m_iWareBuffer[i];lines.PushBack(wareBuffer);for ( int i = 0; i < WAREBUFFERS; i++ ){if ( !m_lGameWares[i].size() )continue;lines.PushBack(CyString("Wares: ") + (long)i + " " + (long)m_lGameWares[i].size());for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() ){SGameWare *gm = node->Data();lines.PushBack(CyString((long)gm->iPos) + " " + (long)gm->iType + " " + CyString((char)gm->cType) + " " + gm->sWareName);}}for ( SStringList *str = m_lNonRemovedFiles.Head(); str; str = str->next )lines.PushBack(CyString("NonRemovedFile: ") + str->str);if ( m_lGameShips.size() ){lines.PushBack(CyString("Ships: ") + (long)m_lGameShips.size());for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *gm = node->Data();lines.PushBack(CyString((long)gm->iType) + " $#C:" + gm->sShipClass + " " + gm->sShipID);}}// write created Filesif ( !m_lCreatedFiles.Empty() ){for ( SStringList *node = m_lCreatedFiles.Head(); node; node = node->next )lines.PushBack(CyString("CreatedFile: ") + node->str.Remove(m_sCurrentDir));}// write uninstall filesif ( !m_lUninstallFiles.empty() ){for ( CListNode<C_File> *node = m_lUninstallFiles.Front(); node; node = node->next() ){C_File *uf = node->Data();CyString uString = "Uninstall: ";uString += CyString::Number((long)uf->GetCreationTime()) + " ";uString += uf->GetFilename();lines.PushBack(uString);}}// write the original file dataif ( !m_lOriginalFiles.empty() ){for ( CListNode<C_File> *node = m_lOriginalFiles.Front(); node; node = node->next() ){C_File *uf = node->Data();CyString uString = "Original: ";uString += CyString::Number((long)uf->GetFileType()) + " ";uString += uf->GetFilename();if ( uf->GetFileType() == FILETYPE_EXTRA && !uf->GetDir().Empty()){uString += ":";uString += uf->GetDir();}lines.PushBack(uString);}}// write the global changesif ( !m_lGlobals.Empty() ){for ( SStringList *str = m_lGlobals.Head(); str; str = str->next )lines.PushBack(CyString("GlobalSetting: ") + str->str + ":" + str->data.Remove(";"));}// write the fake patch orderingif ( !m_lFakePatchOrder.Empty() ){for ( SStringList *str = m_lFakePatchOrder.Head(); str; str = str->next )lines.PushBack(CyString("FakePatchOrder: ") + str->str + ":" + str->data);}// write the global file listlines.PushBack("GlobalFiles:");int num = 0;for ( CListNode<C_File> *fn = m_lFiles.Front(); fn; fn = fn->next() ){C_File *f = fn->Data();f->SetPos(num++);CyString line = CyString::Number(f->GetFileType()) + ":" + CyString::Number((long)f->GetCreationTime()) + ":" + f->GetDir() + ":";if ( f->IsShared() && !f->IsFakePatch() )line += "1:";elseline += "0:";CyString filename = f->GetFilePointer();filename.Remove(m_sCurrentDir);if ( f->IsDisabled() )line += "D#";line += "G#";line += (long)f->GetGame();line += "#";line += filename;if ( !f->GetOriginalName().Empty() ){line += "O#";line += f->GetOriginalName();}lines.PushBack(line);}// write the package listfor ( CListNode<CBaseFile> *pn = m_lPackages.Front(); pn; pn = pn->next() ){CBaseFile *package = pn->Data();if ( package->GetType() == TYPE_SPK )lines.PushBack("<script>");else if ( package->GetType() == TYPE_XSP )lines.PushBack("<ship>");else if ( package->GetType() == TYPE_ARCHIVE )lines.PushBack("<archive>");else if ( package->GetType() == TYPE_BASE )lines.PushBack("<base>");elsecontinue;if ( !package->filename().empty() )lines.PushBack(CyString("Installspk: ") + package->filename());CyString valuesline = package->CreateValuesLine();if ( valuesline.Right(1) == '\n' )valuesline.Truncate((int)valuesline.Length() - 1);lines.PushBack(valuesline);if ( !package->IsEnabled() )lines.PushBack("Disabled");if ( !package->IsModifiedEnabled() )lines.PushBack("ModifiedDisabled");if ( package->GetIcon() )lines.PushBack(CyString("Icon: ") + package->GetIconExt() + " " + package->GetIcon()->GetFilePointer() );CyString fileline("Files:");for ( CListNode<C_File> *fn = package->GetFileList()->Front(); fn; fn = fn->next() ){C_File *f = fn->Data();fileline += " ";fileline += CyString::Number(f->GetPos());}lines.PushBack(fileline);}lines.PushBack("</scripts>");CFileIO datFile(m_sCurrentDir + "/PluginManager/PluginManager.dat");CDirIO Dir(m_sCurrentDir);if ( !Dir.Exists("PluginManager") )Dir.Create("PluginManager");if ( !datFile.WriteFile(&lines) ){}}/*** Get All Files** Gets a list of all files, includes any child package files*/int CPackages::GetAllPackageFiles(CBaseFile *package, CLinkList<C_File> *fileList, bool includeChild){for ( CListNode<C_File> *node = package->GetFileList()->Front(); node; node = node->next() ){C_File *f = node->Data();if ( !fileList->FindData(f) )fileList->push_back(f);}if ( includeChild ){CLinkList<CBaseFile> childList;if ( this->GetChildPackages(package, &childList) ){for ( CBaseFile *child = childList.First(); child; child = childList.Next() )this->GetAllPackageFiles(child, fileList, includeChild);}}// disablign for vanilla, make sure we add all filesif ( m_bDisableVanilla ){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( !fileList->FindData(f) )fileList->push_back(f);}}return fileList->size();}int CPackages::GetAllPackageFiles(CLinkList<CBaseFile> *list, CLinkList<C_File> *fileList, bool includeChild){for ( CListNode<CBaseFile> *node = list->Front(); node; node = node->next() )this->GetAllPackageFiles(node->Data(), fileList, includeChild);return fileList->size();}/*** Add Log** Adds a log entry to displayed at end*/void CPackages::AddLogEntry(int type, CyString args, CyStringList *errors){if ( !errors )return;errors->PushBack(args, ERRORLOG(type));}/*** Enable a package** Enables all files in the package, unless they are already enabled, ie, used by other packages* Backs up any original files before attempting to enable the file** Fake patches are renamed to the next available slot** Clears up the "PluginManager/Disabled" directory** param: package - The package class to be removed* param: errors - The string list for all the status for debugging, ie has an entry for whats happened to every file* param: progress - The progress class, updates a progress screen of the derived class** return: boolen - Returns true if the package enabling was successful*/bool CPackages::EnablePackage ( CBaseFile *package, CyStringList *errors, CProgressInfo *progress ){ClearError();// if already enabled, just skipif ( package->IsEnabled() )return true;// check if parent is enabledif ( package->GetParent() && !package->GetParent()->IsEnabled() ){m_iError = PKERR_NOPARENT;return false;}// check for modifiedif ( m_bVanilla && !package->IsSigned() ){m_iError = PKERR_MODIFIED;return false;}if ( this->PrepareEnablePackage(package) )return this->EnablePreparedPackages(errors, progress);return false;}bool CPackages::EnablePreparedPackages ( CyStringList *errors, CProgressInfo *progress, CLinkList<CBaseFile> *enabledPackages ){ClearError();// get all files, including childrenCLinkList<C_File> fileList;int maxFiles = this->GetAllPackageFiles(&m_lEnableList, &fileList, false);int fileCount = 0;// we use this list to match cat and dat filesCyStringList fakePatches;for ( CListNode<C_File> *node = fileList.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f->GetGame() && m_iGame ) {if ( f->GetGame() != m_iGame )continue;}CBaseFile *package = NULL;for ( CListNode<CBaseFile> *node = m_lEnableList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( p->IsFileAdded(f) ){package = p;break;}}if ( progress ){progress->UpdateProgress(fileCount++, maxFiles);progress->UpdateFile(f);}// only move fiels that are disabledif ( !f->IsDisabled() )continue;// make the directory if it dont existCDirIO Dir(m_sCurrentDir);// fake patches are in the root, no need for directoryif ( !f->IsFakePatch() ){if ( !Dir.Exists(f->GetDirectory(package)) ){if ( !Dir.Create(f->GetDirectory(package)) ){this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY_FAIL, f->GetDirectory(package), errors);continue;}this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY, f->GetDirectory(package), errors);}}// check if theres an original file to backupC_File *of = GetOriginalFile(f);if ( of ){// check if the orignal file is already backed upif ( !CFileIO(m_sCurrentDir + "/PluginManager/Original/" + f->GetNameDirectory(package)).ExistsOld() ){// lets back up the file nowBackupOriginalFile(of, errors);}}CyString newFilename = f->GetNameDirectory(package);// fake patches need to be renamedif ( f->IsFakePatch() ){// first check if the matching file has been done alreadySStringList *foundStr = fakePatches.FindString(f->GetBaseName());// already done one, simply change this to matchif ( foundStr )newFilename = foundStr->data + "." + f->GetFileExt();// we need to find the next available number insteadelse{CyString newPos = CyString::Number(FindNextFakePatch()).PadNumber(2);newFilename = newPos + "." + f->GetFileExt();// and wee need to push this onto the string list so we can adjust the matchign pairfakePatches.PushBack(f->GetBaseName(), newPos);}}// lets actually move the file back now// !!error checking!!CFileIO currentFile(f->GetFilePointer());CFileIO newFile(m_sCurrentDir + "/" + newFilename);if ( !currentFile.exists() ){// missing file ??if ( !newFile.exists() ){this->AddLogEntry(SPKINSTALL_MISSINGFILE, newFilename, errors);continue;}}// remove existing file// file exists, so lets try to move itelse{if ( newFile.exists() )newFile.remove();if ( !currentFile.Rename(newFile.GetFullFilename()) ){this->AddLogEntry(SPKINSTALL_ENABLEFILE_FAIL, newFilename, errors);continue;}}this->AddLogEntry(SPKINSTALL_ENABLEFILE, newFilename, errors);// adjust the internal name to match the new filenamef->SetFilename(m_sCurrentDir + "/" + newFilename);// no longer disabled, we need to remove the flagf->SetDisabled(false);}// recursive, auto enable all childrenCBaseFile *oldMod = m_pEnabledMod;CBaseFile *pMod = NULL;for ( CListNode<CBaseFile> *node = m_lEnableList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();p->SetEnabled(true);if ( p->IsMod() && !pMod )pMod = p;if ( enabledPackages )enabledPackages->push_back(p);}if ( pMod )m_pEnabledMod = pMod;// disabled the modif ( oldMod && oldMod != m_pEnabledMod && !m_bForceModInstall )this->DisablePackage(oldMod, errors, progress);// lets remove all the directories we might have left emptyCyStringList removeDirs;removeDirs.PushBack(CyString("PluginManager/Disabled"));RemoveUnusedDirectories(removeDirs, errors);m_lEnableList.clear();this->WriteData();return true;}bool CPackages::DisablePreparedPackages ( CyStringList *errors, CProgressInfo *progress, CLinkList<CBaseFile> *disabledPackages ){if ( progress )progress->UpdateStatus(PROGRESS_DISABLEFILE);UpdateUsedFiles(&m_lDisableList, false);// checks if there are any original files to restore and if any fake patches were disabled to reshufflebool original = false, shuffle = false;// holds our list of directories that we might need to remove, only empty ones from this list will actually be removedCyStringList removeDirs;// get all files, including childrenCLinkList<C_File> fileList;int maxFiles = this->GetAllPackageFiles(&m_lDisableList, &fileList, true);// interate through all the files in the packageint fileCount = 0;for ( CListNode<C_File> *node = fileList.Front(); node; node = node->next() ){C_File *f = node->Data();CBaseFile *checkPackage = NULL;for ( CListNode<CBaseFile> *node = m_lDisableList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( p->IsFileAdded(f) ){checkPackage = p;break;}}// update the progress count for the current fileif ( progress ){progress->UpdateProgress(++fileCount, maxFiles);progress->UpdateFile(f);}// only delete files that are not used by any other enabled packages, counter from UpdateUsedFiles()if ( f->GetUsed() || (f->IsShared() && !m_bDisableVanilla) )continue;// file is already disabled, no need to disable againif ( f->IsDisabled() )continue;// readmes, uninstall and extra files dont need to be disabled// Extra files not in the "Extras" directory could be anywhere, so these should be disabled incase they are game changing files, ie in "types"if ( f->GetFileType() == FILETYPE_README || f->GetFileType() == FILETYPE_UNINSTALL || (f->GetFileType() == FILETYPE_EXTRA && f->GetDir().Left(5).lower() == "Extra") )continue;// check if there is a matching uninstall file, ie there the script file is also an uninstall script file for a previously uninstalled package that has yet to be removedif ( f->GetFileType() == FILETYPE_SCRIPT ){bool found = false;for ( CListNode<C_File> *uNode = m_lUninstallFiles.Front(); uNode; uNode = uNode->next() ){C_File *uFile = uNode->Data();if ( uFile->GetFilename().Compare(f->GetFilename()) ){found = true;break;}}if ( found )continue;}if ( f->GetFileType() == FILETYPE_MOD && !f->IsFakePatch() && f->CheckFileExt("cat") ){if ( f->GetBaseName().Compare(m_sSetMod) )m_sSetMod = NullString;}// file is not being used by any enabled package// set disabled and move to disabled directoryCDirIO Dir(m_sCurrentDir);CyString newFilename = "PluginManager/Disabled/";// fake patches have thier own special directoryif ( f->IsFakePatch() )newFilename += "FakePatches";// otherwise we put them in thier usual directory structure inside the disabled direlsenewFilename += f->GetDirectory(NULL);// make sure the directory exists so we can move the fileif ( !Dir.Exists(newFilename) ){// we couldn't create the directory for some reason, this is not goodif ( !Dir.Create(newFilename) ){this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY_FAIL, newFilename, errors);continue;}this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY, newFilename, errors);}// fake patches need a special directory and filename so they dont overright each other as thier filenames are always changes// if a package with a fake patch is installed while another one is disabled, it will fill the gap left by the disabled one// they will then end up with the same filename, if it gets disabled they would overright each other, so we change the filename to prevent that from happeningif ( f->IsFakePatch() ){// find package the fake patch belongs toif ( checkPackage ){newFilename = m_sCurrentDir + "/PluginManager/Disabled/FakePatches/FakePatch_" + checkPackage->GetNameValidFile() + "_" + checkPackage->author() + "_" + f->GetName();shuffle = true;}}else if ( f->IsAutoTextFile() ){if ( checkPackage ){newFilename = m_sCurrentDir + "/PluginManager/Disabled/TextFiles/Text_" + checkPackage->GetNameValidFile() + "_" + checkPackage->author() + "_" + f->GetName();shuffle = true;}}// otherwise we can just use the standard filenameelsenewFilename = m_sCurrentDir + "/PluginManager/Disabled/" + f->GetNameDirectory(checkPackage);// now to move the file by renameing it to its new location// !!error checking!!// check the file, if it doesn't exist, and exists as disabled, we should just adjust the setting instead of an errorCFileIO currentFile(f->GetFilePointer());if ( !currentFile.exists() ){if ( !CFileIO(newFilename).exists() ){this->AddLogEntry(SPKINSTALL_MISSINGFILE, f->GetNameDirectory(checkPackage), errors);continue;}}// otherwise the file must exists, so lets move itelse if ( !currentFile.Rename(newFilename) ){this->AddLogEntry(SPKINSTALL_DISABLEFILE_FAIL, f->GetNameDirectory(checkPackage), errors);continue;}// must have been finethis->AddLogEntry(SPKINSTALL_DISABLEFILE, f->GetNameDirectory(checkPackage), errors);// check if its an original file and restoreif ( IsOriginalFile(f) ){CFileIO of(m_sCurrentDir + "/PluginManager/Original/" + f->GetNameDirectory(checkPackage));if ( of.exists() ){original = true;if ( of.Rename(m_sCurrentDir + "/" + f->GetNameDirectory(checkPackage)) )this->AddLogEntry(SPKINSTALL_ORIGINAL_RESTORE, f->GetNameDirectory(checkPackage), errors);elsethis->AddLogEntry(SPKINSTALL_ORIGINAL_RESTORE_FAIL, f->GetNameDirectory(checkPackage), errors);}}// extra file thats not in the extras directoryif ( f->GetFileType() == FILETYPE_EXTRA || f->GetFileType() == FILETYPE_MAP || f->GetFileType() == FILETYPE_SOUND )removeDirs.PushBack(f->GetDirectory(checkPackage), NullString, true);// change the filenamef->SetFilename(newFilename);// finally mark the file as disabled so we know not to try to move it againf->SetDisabled(true);}// a fake patch has been disabled, we need to reshuffle the rest to fill in any gapsif ( shuffle ){if ( progress )progress->UpdateStatus(PROGRESS_SHUFFLEFAKE);ShuffleFakePatches(errors);ShuffleTextFiles(errors);}// original files were restored, check to remove the original file directory if its now emptyif ( original )removeDirs.PushBack(CyString("PluginManager/Original"));// remove any empty directories that we might have leftif ( !removeDirs.Empty() )RemoveUnusedDirectories(removeDirs, errors);// finally mark the whole package as disabled// recursive, we need to disable all childrenfor ( CBaseFile *child = m_lDisableList.First(); child; child = m_lDisableList.Next() ){if ( m_pEnabledMod == child )m_pEnabledMod = NULL;child->SetEnabled(false);if ( disabledPackages )disabledPackages->push_back(child);}// disabling has completed successfully, we hopem_bDisableVanilla = false;m_lDisableList.clear();this->WriteData();return true;}/*** Disables the selected package** Disables all enabled files that are not being used by any other enabled package* Any files that are being used by other enabled packages are skipped and left enabled** Original Files are restored when file is disabled** Fake patches are shuffled to fill in any gaps caused by disabling fake patches** All files go into the Plugin/Disabled directory into thier respective directories.** Any directories left empty when disabling files are then removed** param: package - Package file to be disabled* param: errors - A string list used to add the status as it progresses, used in debugging output* param: progress - The progress class, updates the progress of the current disabling. Needs a divered class to report the progress somewhere** return: boolean, true if there was no errors, otherwise false*/bool CPackages::DisablePackage ( CBaseFile *package, CyStringList *errors, CProgressInfo *progress ){// if already disabled, just skipif ( !package->IsEnabled() )return true;m_lDisableList.clear();if ( this->PrepareDisablePackage(package) )return this->DisablePreparedPackages(errors, progress);return false;}/*** Find a Package** Finds a matching package so we can find if one is already installed** Uses seperate functions for each package type, ie for SPK and XSP packages*/CBaseFile *CPackages::FindPackage(CBaseFile *package){// no point checking if we've been sent a null pointerif ( !package )return 0;// we are checking against a SPK package, so we match the name and authorif ( package->GetType() == TYPE_SPK )return FindSpkPackage(package->name(), package->author());else if ( package->GetType() == TYPE_XSP )return FindXspPackage(((CXspFile *)package)->GetShipID());else if ( package->GetType() == TYPE_ARCHIVE )return FindArchivePackage(package->name());// nothing found obviouslyreturn 0;}CBaseFile *CPackages::FindFirstPackageWithFile(C_File *f){return FindNextPackageWithFile(NULL, f);}CBaseFile *CPackages::FindNextPackageWithFile(CBaseFile *p, C_File *f){bool startCheck = (p) ? false : true;for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){if ( startCheck ){if ( node->Data()->IsFileAdded(f) )return node->Data();}else if ( p == node->Data() )startCheck = true;}return NULL;}/*** Find a File** Searches for a file matching the filetype and filename* Optional dir is used for extras files*/C_File *CPackages::FindFile(int filetype, CyString filename, CyString dir){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f->GetFileType() != filetype )continue;if ( !f->GetFilename().Compare(filename) )continue;if ( !dir.Empty() && f->GetDir().Compare(dir) )continue;return f;}return NULL;}CArchiveFile *CPackages::FindArchivePackage(CyString name){// interate through all packagesfor ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *file = node->Data();// only look for archive packagesif ( file->GetType() != TYPE_ARCHIVE )continue;// now compare the name and author, "Compare" is a non case senseative check, opposed to ==.if ( file->name().Compare(name.ToString()) )return (CArchiveFile *)file;}// nothing foundreturn 0;}/*** Find a SPK Package** This searching all installed packages for a SPK Package matching the name and author*/CBaseFile *CPackages::FindSpkPackage(CyString name, CyString author){// interate through all packagesfor ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *file = node->Data();// only look for spk packagesif ( file->GetType() != TYPE_SPK )continue;// now compare the name and author, "Compare" is a non case senseative check, opposed to ==.if ( file->name().Compare(name.ToString()) && file->author().Compare(author.ToString()) )return file;}// nothing foundreturn 0;}CBaseFile *CPackages::FindPackage(CyString name, CyString author){// interate through all packagesfor ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *file = node->Data();// now compare the name and author, "Compare" is a non case senseative check, opposed to ==.if ( file->name().Compare(name.ToString()) && file->author().Compare(author.ToString()) )return file;}// nothing foundreturn 0;}/*** Find a XSP Package** This searching all installed packages for a XSP Package matching the object id*/CBaseFile *CPackages::FindXspPackage(CyString id){// interate through all packagesfor ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *file = node->Data();// only look for spk packagesif ( file->GetType() != TYPE_XSP )continue;// now compare the id, "Compare" is a non case senseative check, opposed to ==.if ( ((CXspFile *)file)->GetShipID().Compare(id.ToString()) )return file;}// nothing foundreturn 0;}/*** Update the used files count** counts how many packages are currently using the file*/void CPackages::UpdateUsedFiles(CLinkList<CBaseFile> *ignoreList, bool includedisabled){// clear amounts for all filesCListNode<C_File> *fnode = m_lFiles.Front();while ( fnode ){fnode->Data()->ClearUsed();fnode = fnode->next();}// update for all packagesfor ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node= node->next() ){CBaseFile *file = node->Data();if ( (ignoreList) && (ignoreList->FindData(file)) )continue;if ( !includedisabled && !file->IsEnabled() )continue;// now mark all filesCListNode<C_File> *fnode = file->GetFileList()->Front();while ( fnode ){fnode->Data()->IncUsed();fnode = fnode->next();}}}/*** Removes all empty directories that might have been created*/void CPackages::RemoveUnusedDirectories(CyStringList &dirs, CyStringList *errors){CDirIO Dir(m_sCurrentDir);for ( SStringList *str = dirs.Head(); str; str = str->next ){CyString dir = str->str;CyStringList removedDir;if ( Dir.RemoveDir(dir, false, true, &removedDir) || !removedDir.Empty() ){for ( SStringList *node = removedDir.Head(); node; node = node->next ){CyString displayName = node->str;displayName = displayName.Remove(m_sCurrentDir);this->AddLogEntry(SPKINSTALL_REMOVEDIR, displayName, errors);}}}}/*** Update signed status** Updates the signed status of all packages*/void CPackages::UpdateSigned(){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( p->GetType() != TYPE_SPK )continue;((CSpkFile *)p)->UpdateSigned(false);}}/*** Check validity of package file** Checks if there is a newer version of the package installed*/int CPackages::CheckInstallPackage(CBaseFile *package, int check){if ( package->GetType() == TYPE_XSP && m_iGame == GAME_X2 )return INSTALLCHECK_NOSHIP;// search for an old versionCBaseFile *oldPackage = FindPackage(package);// check versions are newerif (oldPackage && (check & IC_OLDVERSION)){if ( oldPackage->version().compareVersion(package->version()) == COMPARE_OLDER )return INSTALLCHECK_OLDVERSION;}// now check for game versionif ((check & IC_WRONGGAME) || (check & IC_WRONGVERSION)){if ( package->AnyGameCompatability() ){if ( (check & IC_WRONGGAME) && (!package->CheckGameCompatability(m_iGame)) )return INSTALLCHECK_WRONGGAME;else if ( (check & IC_WRONGVERSION) && (!package->CheckGameVersionCompatability(m_iGame, m_sGameVersion, m_iGameVersion)) )return INSTALLCHECK_WRONGVERSION;}}// check for modifiedif (m_bVanilla && (check & IC_MODIFIED)){if ( !package->IsSigned() )return INSTALLCHECK_MODIFIED;}return INSTALLCHECK_OK;}bool CPackages::CheckOtherPackage(CBaseFile *package){// check the need for another modif ( package->GetType() == TYPE_SPK ){CSpkFile *spk = (CSpkFile *)package;if ( spk->IsAnotherMod() ){if ( !FindSpkPackage(spk->GetOtherName(), spk->GetOtherAuthor()) ){// check the install listif ( m_lInstallList.empty() )return false;bool found = false;for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() ){if ( spk->GetOtherName().Compare(node->Data()->name()) && spk->GetOtherAuthor().Compare(node->Data()->author()) ){found = true;break;}}if ( !found )return false;}}}return true;}bool CPackages::CheckEnabledDependacy(CBaseFile *p){// check the for another modif ( p->GetType() == TYPE_SPK ){if ( ((CSpkFile *)p)->IsAnotherMod() ){CBaseFile *parent = this->FindSpkPackage(((CSpkFile *)p)->GetOtherName(), ((CSpkFile *)p)->GetOtherAuthor());if ( parent ){if ( !parent->IsEnabled() )return false;}elsereturn false;}}// check any dependaciesif ( p->AnyDependacies() ){for ( CListNode<SNeededLibrary> *dNode = p->GetNeededLibraries()->Front(); dNode; dNode = dNode->next() ){if ( dNode->Data()->sName.Compare("<package>") )continue;if ( !this->CheckInstalledDependacy(dNode->Data()->sName, dNode->Data()->sAuthor, dNode->Data()->sMinVersion, true, true) )return false;}}return true;}bool CPackages::CheckInstalledDependacy(CyString name, CyString author, CyString version, bool onlyEnabled, bool includePrepared){CBaseFile *p = this->FindSpkPackage(name, author);if ( p ){// now check versionif ( version.CompareVersion(p->version()) == COMPARE_OLDER )return false;if ( onlyEnabled && !p->IsEnabled() )return false;return true;}// now check the prepared listif ( includePrepared ){for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() ){p = node->Data();if ( !p )continue;if ( p->name().Compare(name.ToString()) && p->author().Compare(author.ToString()) ){if ( version.CompareVersion(p->version()) == COMPARE_OLDER )continue;if ( onlyEnabled && !p->IsEnabled() )continue;return true;}}m_lInstallList.RemoveEmpty();}return false;}int CPackages::GetMissingDependacies(CBaseFile *p, CyStringList *list, bool onlyEnabled, bool includePrepared){int count = 0;CLinkList<SNeededLibrary> *neededList = p->GetNeededLibraries();if ( neededList ){for ( CListNode<SNeededLibrary> *node = neededList->Front(); node; node = node->next() ){SNeededLibrary *nl = node->Data();if ( !CheckInstalledDependacy((nl->sName.Compare("<package>")) ? p->name() : nl->sName, (nl->sAuthor.Compare("<author>")) ? p->author() : nl->sAuthor, nl->sMinVersion, (nl->sName.Compare("<package>")) ? false : onlyEnabled, (nl->sName.Compare("<package>")) ? false : includePrepared) ){if ( list )list->PushBack(((nl->sName.Compare("<package>")) ? CyString(p->name()) : nl->sName) + "|" + nl->sMinVersion, (nl->sAuthor.Compare("<author>")) ? CyString(p->author()) : nl->sAuthor);++count;}}}if ( p->GetType() == TYPE_SPK ){CSpkFile *spk = (CSpkFile *)p;if ( spk->IsAnotherMod() ){bool found = true;if ( !this->FindSpkPackage(spk->GetOtherName(), spk->GetOtherAuthor()) ){if ( includePrepared ){found = false;for ( CListNode<CBaseFile> *pNode = m_lInstallList.Front(); pNode; pNode = pNode->next() ){CBaseFile *checkP = pNode->Data();if ( p->author().Compare(checkP->author()) && p->name().Compare(checkP->name()) ){found = true;break;}}}elsefound = false;}if ( !found ){if ( list )list->PushBack(CyString(spk->GetOtherName()), CyString(spk->GetOtherAuthor()));++count;}}}return count;}int CPackages::CheckPreparedInstallRequired(CLinkList<CBaseFile> *list){// loop through all packagesint count = 0;for ( CListNode<CBaseFile> *node = m_lInstallList.Front(); node; node = node->next() ){CBaseFile *p = node->Data();// no requirements found, remove from listbool missingDep = false;if ( !this->CheckOtherPackage(p) )missingDep = true;else if ( this->GetMissingDependacies(p, NULL, false, true) )missingDep = true;if ( missingDep ){if ( list ){node->ChangeData(NULL);list->push_back(p);}elsenode->DeleteData();++count;}}m_lInstallList.RemoveEmpty();return count;}/*** Remove uninstall file** Removes a single uninstall file*/bool CPackages::RemoveUninstallFile(C_File *file, CyStringList *errors){CFileIO fio(file->GetFilePointer());if ( fio.exists() ){if ( fio.remove() ) {this->AddLogEntry(SPKINSTALL_UNINSTALL_REMOVE, file->GetNameDirectory(NULL), errors);return true;}else if ( errors )this->AddLogEntry(SPKINSTALL_UNINSTALL_REMOVE_FAIL, file->GetNameDirectory(NULL), errors);}return false;}/*** Remove uninstall scripts** Removes any unused unisntall scripts* Finds if any scripts are in the current package*/int CPackages::RemoveUninstallScripts(CyStringList *errors, CProgressInfo *progress){if ( m_lUninstallFiles.empty() )return 0;UpdateUsedFiles();int files = 0;for ( CListNode<C_File> *node = m_lUninstallFiles.Back(); node; node = node->prev() ){if ( progress )progress->UpdateProgress(files, m_lUninstallFiles.size());files++;C_File *file = node->Data();// first check if there is a matching filebool found = false;for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() ){C_File *checkFile = fNode->Data();if ( checkFile->GetFileType() != FILETYPE_SCRIPT )continue;if ( checkFile->GetFilename().Compare(file->GetFilename()) ){found = true;break;}}// not found a matching file, we can safetly remove itif ( !found ){if ( RemoveUninstallFile(file) )node->DeleteData();}}m_lUninstallFiles.RemoveEmpty();return files;}/*** Remove unused shared file** Removes a single file*/bool CPackages::RemoveSharedFile(C_File *file, CyStringList *errors){CFileIO fio(file->GetFilePointer());if ( fio.exists() ){if ( fio.remove() ) {this->AddLogEntry(SPKINSTALL_SHARED, file->GetNameDirectory(NULL), errors);delete file;return true;}else if ( errors )this->AddLogEntry(SPKINSTALL_SHARED_FAIL, file->GetNameDirectory(NULL), errors);}return false;}/*** Remove Unused Shared Files** Files that have been marked as shared will not be removed or disabled when the last package is removed* This function will remove any that are no longer connected with packages** Marked shared fiels are mainly used for library scripts that arn't always added to packages*/int CPackages::RemoveUnusedSharedFiles(CyStringList *errors, CProgressInfo *progress){UpdateUsedFiles();int files = 0;int done = 0;for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() ){if ( progress )progress->UpdateProgress(files, m_lFiles.size());files++;C_File *file = node->Data();// only do marked shared filesif ( !file->IsShared() )continue;// only do ones that are no longer neededif ( file->GetUsed() )continue;if ( RemoveSharedFile(file, errors) )++done;node->ChangeData(NULL);}m_lFiles.RemoveEmpty();return done;}/*** Any Unused Shared** Checks if theres any unused shared files available** Any file thats marked as shared, and is no longer connected to any installed package*/bool CPackages::AnyUnusedShared(){UpdateUsedFiles();for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() ){C_File *file = node->Data();// only do marked shared filesif ( !file->IsShared() )continue;// only do ones that are no longer neededif ( file->GetUsed() )continue;return true;}return false;}/*** Update original files list** Scan the current directory for any fiels that are already there, ie ones that have not been installed* Original files should be all the scripts/sounds, etc that are in an unmodified game directory** Save list of files and check if any packages overright these files* Any file that gets overrighten from this list will automatically be backed up, and restored once the packages are removed*/void CPackages::StoreOriginalFiles(int filetype, CyString searchPath){CyString ext = "pck";switch ( filetype ){case FILETYPE_SOUND:ext = "mp3";break;}CDirIO Dir(m_sCurrentDir + "/" + searchPath);CyStringList *files = Dir.DirList();if ( !files )return;for ( SStringList *node = files->Head(); node; node = node->next ){CFileIO File(Dir.File(node->str));if ( File.GetFileExtension().Compare(ext) )AddOriginalFile(filetype, File.GetFilename(), searchPath);}delete files;}/*** Adds a file onto the original files list** Checks if it already exists so we dont create multiples*/void CPackages::AddOriginalFile(int filetype, CyString filename, CyString searchPath){// dont add plugin manager as original filesif ( filetype == FILETYPE_SCRIPT && filename.IsIn("!init.pmanager") )return;// first check if a matching one existsfor ( CListNode<C_File> *node = m_lOriginalFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != filetype )continue;if ( file->GetFilename().Compare(filename) )return;}// check that no packages are currently using them either, not original if being used alreadyfor ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != filetype )continue;if ( file->GetFilename().Compare(filename) )return;}C_File *of = new C_File(filename);of->SetFileType(filetype);if ( filetype == FILETYPE_EXTRA )of->SetDir(searchPath);of->SetFilename(m_sCurrentDir + "/" + of->GetNameDirectory(NULL));m_lOriginalFiles.push_back(of);}/*** Check for original file** Checks if the file is an original file or not*/bool CPackages::IsOriginalFile(C_File *file){if ( GetOriginalFile(file) )return true;return false;}/*** Get original file** Finds a matching original file entry and returns it*/C_File *CPackages::GetOriginalFile(C_File *file){if ( !file )return NULL;for ( CListNode<C_File> *node = m_lOriginalFiles.Front(); node; node = node->next() ){C_File *of = node->Data();// not of the same file typeif ( of->GetFileType() != file->GetFileType() )continue;// same file name, must be the same fileif ( of->GetFilename().Compare(file->GetFilename()) )return of;}return NULL;}/*** Backs up an original file** Moves the file into the PluginManager/Original directory so packages dont replace them* Allows these files to be restored when the package is remove to prevent breaking the game*/bool CPackages::BackupOriginalFile(C_File *f, CyStringList *errors){CyString newDir = CyString("PluginManager/Original/") + f->GetDirectory(NULL);CDirIO oDir(m_sCurrentDir);if ( oDir.Exists(newDir + "/" + f->GetFilename()) )return true;// make sure the directory exisstsif ( !oDir.Exists(newDir) ){if ( !oDir.Create(newDir) ){CLog::logf(CLog::Log_Install, 2, "Unable to create directory to backup original files, %s", newDir.c_str());this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY_FAIL, newDir, errors);return false;}CLog::logf(CLog::Log_Install, 2, "Created new directory, %s", newDir.c_str());this->AddLogEntry(SPKINSTALL_CREATEDIRECTORY, newDir, errors);}// now lets copy the fileCFileIO CopyFile(f->GetFilePointer());if ( CopyFile.copy(oDir.File(newDir + "/" + f->GetFilename()).ToString()) ){CLog::logf(CLog::Log_Install, 2, "Original file: %s has been backed up", f->GetNameDirectory(NULL).c_str());this->AddLogEntry(SPKINSTALL_ORIGINAL_BACKUP, f->GetNameDirectory(NULL), errors);return true;}else{CLog::logf(CLog::Log_Install, 2, "Failed to backup the original file: %s", f->GetNameDirectory(NULL).c_str());this->AddLogEntry(SPKINSTALL_ORIGINAL_BACKUP_FAIL, f->GetNameDirectory(NULL), errors);return false;}}void CPackages::ShuffleTextFiles(CyStringList *errors){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();// only do files that are enabledif ( f->IsDisabled() )continue;if ( f->GetFileType() != FILETYPE_TEXT )continue;// check if the file is an auto text fileif ( !f->IsAutoTextFile() )continue;// we need to rename itint current = FindNextTextFile();if ( current < f->GetTextFileID() ){CFileIO moveFile(f->GetFilePointer());CyString newName = SPK::FormatTextName(current, m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT)) + "." + moveFile.GetFileExtension();if ( moveFile.Rename(m_sCurrentDir + "/t/" + newName) ){this->AddLogEntry(SPKINSTALL_AUTOTEXT, f->GetName() + "~" + newName, errors);f->SetName(newName);}elsethis->AddLogEntry(SPKINSTALL_AUTOTEXT_FAIL, f->GetName() + "~" + newName, errors);}}}/*** Shuffle Fake Patches** Rename the fake patches so they are always in sequence to be loaded into the game** IE, when one is removed, the rest need to be shuffled down so theres no gaps*/void CPackages::ShuffleFakePatches(CyStringList *errors){int check = FindNextFakePatch();// lets make sure our order is correct// find Lowest Fake Patch InstalledCLinkList<C_File> doneList;int lowest = FindLowestFakePatchInstalled();if ( check < lowest ) lowest = check; // gap at the beginning, lets use that// lets define the orderCyStringList fakePatchOrder;for ( SStringList *str = m_lFakePatchOrder.Head(); str; str = str->next )fakePatchOrder.PushBack(str->str, str->data);// add any other packages that need to be ordered// we need to work out the correct orderCLinkList<CBaseFile> packages;for ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() ){CBaseFile *p = pNode->Data();// search for any fake patches in packageif ( !p->IsEnabled() ) continue;if ( !p->AnyFileType(FILETYPE_MOD) ) continue;// must have an order defineif ( !p->AnyFakePatchOrder() ) continue;// check if theres any already ordered (manual)bool added = false;for ( SStringList *sCheck = fakePatchOrder.Head(); sCheck; sCheck = sCheck->next ){if ( sCheck->str.Compare(CyString(p->name())) && sCheck->data.Compare(CyString(p->author())) ){added = true;break;}}if ( added ) continue;bool anyFound = false;for ( C_File *file = p->GetFirstFile(FILETYPE_MOD); file; file = p->GetNextFile(file) ){if ( !file->IsFakePatch() ) continue;if ( !file->CheckFileExt("cat") ) continue;if ( doneList.FindData(file) ) continue;anyFound = true;break;}// we have some fake patches that need to be shuffledif ( anyFound )packages.push_back(p);}// lets adjust the order (only if theres more than 1if ( packages.size() > 1 ){CLinkList<CBaseFile> sortedPackages;// first add all the packages that dont need to be installed afterfor ( CListNode<CBaseFile> *pNode = packages.Front(); pNode; pNode = pNode->next() ){CBaseFile *p = pNode->Data();// we have a before and not afterif ( !p->GetFakePatchBeforeOrder().Empty() && p->GetFakePatchAfterOrder().Empty() ){// if we have to install before, check if any on the listint earliestPos = -1;bool notAdded = true;for ( SStringList *str = p->GetFakePatchBeforeOrder().Head(); str; str = str->next ){int pos = 0;for ( CListNode<CBaseFile> *sNode = sortedPackages.Front(); sNode; sNode = sNode->next() ){if ( str->str.Compare(CyString(sNode->Data()->name())) && str->data.Compare(CyString(sNode->Data()->author())) ){if ( earliestPos == -1 || pos < earliestPos )earliestPos = pos;break;}++pos;}}if ( earliestPos > -1 )sortedPackages.insert(earliestPos, p);// otherwise just add it at the backelsesortedPackages.push_back(p);// remove from the listpNode->ChangeData(NULL);}}// now do the packages that have both before and afterpackages.RemoveEmpty();for ( CListNode<CBaseFile> *pNode = packages.Front(); pNode; pNode = pNode->next() ){CBaseFile *p = pNode->Data();if ( !p->GetFakePatchBeforeOrder().Empty() && !p->GetFakePatchAfterOrder().Empty() ){}}// add them onto the listfor ( CListNode<CBaseFile> *pNode = sortedPackages.Front(); pNode; pNode = pNode->next() )fakePatchOrder.PushBack(CyString(pNode->Data()->name()), CyString(pNode->Data()->author()));}// now add to do listfor ( CListNode<CBaseFile> *pNode = packages.Front(); pNode; pNode = pNode->next() )fakePatchOrder.PushBack(CyString(pNode->Data()->name()), CyString(pNode->Data()->author()));for ( SStringList *str = fakePatchOrder.Head(); str; str = str->next ){CBaseFile *package = FindPackage(str->str, str->data);if ( package ){// might have more than 1 fake patch for the file, so we'll need the lowestwhile ( true ){C_File *lowestFile = NULL;for ( C_File *file = package->GetFirstFile(FILETYPE_MOD); file; file = package->GetNextFile(file) ){if ( !file->IsFakePatch() ) continue;if ( !file->CheckFileExt("cat") ) continue; // only do the cat file, we can shuffle the dat file to match laterif ( doneList.FindData(file) ) continue; // already done?if ( !lowestFile )lowestFile = file;else{if ( file->GetBaseName().ToInt() < lowestFile->GetBaseName().ToInt() )lowestFile = file;}}if ( !lowestFile ) // no more files ?break;// check its filename, it might already be in the correct placeif ( lowestFile->GetBaseName().ToInt() != lowest ){// if the file already exists, we need to move it elsewhereCyString nextName = CyString::Number(lowest).PadNumber(2);if ( CFileIO(m_sCurrentDir + "/" + nextName + ".cat").ExistsOld() ){// find the file in our internal file listC_File *moveFile = FindFile(FILETYPE_MOD, nextName + ".cat");if ( !moveFile ) // must not have it in our list ? lets move to the next{lowest++;continue;}// now we can move the the cat/dat file elsewhere, lets shuffle it to the highest free numberShufflePatchTo(moveFile, FindLastFakePatch(), errors);}// space should be free, now lets shuffle itShufflePatchTo(lowestFile, lowest, errors);}doneList.push_back(lowestFile); // we've done this file nowlowest++; // move up the lowest ready for the next patch}}}// now lets shuffle the rest// now find any packages with greater fake patchs and fill the gapsfor ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();// already done?if ( doneList.FindData(f) )continue;// only do files that are enabledif ( f->IsDisabled() )continue;// check if the file is a fake patchif ( !f->IsFakePatch() )continue;// we only want cat and dat files, all fake patchs should be, but incase theres an error in the package somewhere we can checkif ( !f->CheckFileExt("cat") )continue;// now lets check if its greater than our gapint check = FindNextFakePatch();int patchNum = f->GetFilename().GetToken(".", 1, 1).ToInt();if ( patchNum <= check )continue;ShufflePatchTo(f, check, errors);}}void CPackages::ShufflePatchTo(C_File *file, int to, CyStringList *errors){// it is, we need to shift this to fill the gapCyString newName = CyString::Number(to).PadNumber(2) + "." + file->GetFileExt();// now rename the fileCFileIO moveFile(file->GetFilePointer());if ( moveFile.Rename(m_sCurrentDir + "/" + newName) ){// display moveingthis->AddLogEntry(SPKINSTALL_FAKEPATCH, file->GetName() + "~" + newName, errors);// now find the matching pairing if it existsfor ( CListNode<C_File> *node2 = m_lFiles.Front(); node2; node2 = node2->next() ){C_File *f2 = node2->Data();if ( f2->IsDisabled() || !f2->IsFakePatch() || f2->CheckFileExt(file->GetFileExt()) )continue;// needs to be the same fileif ( f2->GetBaseName() != file->GetBaseName() )continue;CyString newName2 = CyString::Number(to).PadNumber(2) + "." + f2->GetFileExt();CFileIO moveFile(f2->GetFilePointer());if ( moveFile.Rename(m_sCurrentDir + "/" + newName2) ){this->AddLogEntry(SPKINSTALL_FAKEPATCH, f2->GetName() + "~" + newName2, errors);f2->SetName(newName2);}elsethis->AddLogEntry(SPKINSTALL_FAKEPATCH_FAIL, f2->GetName() + "~" + newName2, errors);}// finally make sure the internal name matches the new onefile->SetName(newName);}elsethis->AddLogEntry(SPKINSTALL_FAKEPATCH_FAIL, file->GetName() + "~" + newName, errors);}int CPackages::FindLowestFakePatchInstalled(){int lowest = 99;for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( !p->IsEnabled() ) continue;if ( !p->AnyFileType(FILETYPE_MOD) ) continue;// now get all fake patchesfor ( C_File *file = p->GetFirstFile(FILETYPE_MOD); file; file = p->GetNextFile(file) ){if ( !file->IsFakePatch() ) continue;if ( file->CheckFileExt("dat") ) continue;int check = file->GetBaseName().ToInt();if ( check < lowest )lowest = check;}}return lowest;}int CPackages::FindLastFakePatch(int start, CyString dir){CDirIO Dir((dir.Empty()) ? m_sCurrentDir : dir);int check = start;while ( check > 0 ){CyString checkStr = CyString::Number(check).PadNumber(2);// check if a cat file existsif ( !Dir.Exists(checkStr + ".cat") ){// it doen't, check if theres a dat file (incase of package error)if ( !Dir.Exists(checkStr + ".dat") )break;}--check;}return check;}/*** Find next fake patch** Searching for the next gap in patches, starting with 01.cat to 99.cat*/int CPackages::FindNextFakePatch(int start, CyString dir){CDirIO Dir((dir.Empty()) ? m_sCurrentDir : dir);int check = start;while ( check < 99 ){++check;CyString checkStr = CyString::Number(check).PadNumber(2);// check if a cat file existsif ( !Dir.Exists(checkStr + ".cat") ){// it doen't, check if theres a dat file (incase of package error)if ( !Dir.Exists(checkStr + ".dat") )break;}}return check;}/*** Find next text file** Searching for the next gap in automatic text files, start with 0003-LXXX or XX0003*/int CPackages::FindNextTextFile(int start, CyString dir){int check = start;if ( check < 2 ) check = 2;while ( check < 9999 ){++check;Utils::String newFilename = SPK::FormatTextName(check, m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT)).ToString();// check the vfsif ( m_pGameVFS.isFileAvailable("t/" + newFilename + ".pck") ) continue;if ( m_pGameVFS.isFileAvailable("t/" + newFilename + ".xml") ) continue;break;}return check;}int CPackages::FindLastTextFile(int start, CyString dir){CDirIO Dir((dir.Empty()) ? m_sCurrentDir : dir);Dir.cd("t");int check = start;while ( check < 9999 ){++check;CyString newFilename = SPK::FormatTextName(check, m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT));// check if a packed file existsif ( !Dir.Exists(newFilename + ".pck") ){// it doen't, check if theres an unpacked fileif ( !Dir.Exists(newFilename + ".xml") )break;}}return check;}/*** Read game language** Reads the lang.dat file from the game directory for the language id*/void CPackages::ReadGameLanguage(bool force){// check if lauguage is already setif ( !force && m_iLanguage )return;CDirIO Dir(m_sCurrentDir);// check for lang.dat fileif ( Dir.Exists("lang.dat") ){CFileIO File(Dir.File("lang.dat"));size_t size;char *data = File.ReadToData(&size);if ( data ){CyString str(data);m_iLanguage = str.GetToken("\n", 1, 1).GetToken(" ", 1, 1).ToInt();}}}/*** Create Language Text File** Creates text files for all packages into the correct language*/void CPackages::CreateLanguageTextFiles(CyStringList *errors){// no need to create them if theres no language to useif ( !m_iLanguage )return;// find all text filesCyStringList ids;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();// only do text fielsif ( f->GetFileType() != FILETYPE_TEXT )continue;CyString id, lang;if ( m_iGameFlags & EXEFLAG_TCTEXT ){id = f->GetBaseName().GetToken("-", 1, 1);lang = f->GetBaseName().GetToken("-", 2, 2);if ( lang.Empty() )lang = "NULL";elselang = lang.Erase(0, 1); // remove the "L"}else{lang = f->GetBaseName().Left((int)f->GetBaseName().Length() - 4).PadNumber(3);id = f->GetBaseName().Mid(((int)f->GetBaseName().Length() - 4) + 1, 4);}SStringList *strList = ids.FindString(id);// not added, add a new oneif ( !strList )strList = ids.PushBack(id, lang);else{if ( strList->data.Empty() )strList->data = lang;else{strList->data += ":";strList->data += lang;}}}// we should now have a list of all text files, we need to remove those that have a matching languagefor ( SStringList *sNode = ids.Head(); sNode; sNode = sNode->next ){int size = 0;CyString *data = sNode->data.SplitToken(':', &size);// huh ? we shouldn't have thisif ( !size )continue;// lets search for a matching idint useId = 0;bool found = false;for ( int i = 0; i < size; i++ ){if ( data[i] == "NULL" )useId = -1;else{int num = data[i].ToInt();if ( num == m_iLanguage ){found = true;useId = m_iLanguage;break;}// prioities the text file to use, no language first, then 44, then 49, otherwise, we pick the first availableelse if ( num == 44 && useId != -1)useId = 44;// if we have a german language, and its not yet found english or nullelse if ( num == 49 && useId != 44 && useId != -1 )useId = 49;// if we have not found a valid language yet, we will use this oneelse if ( !useId )useId = num;}}if ( found )continue;if ( !useId )useId = data[0].ToInt();if ( !useId )useId = -1;CLEANSPLIT(data, size);RenameTextFile(sNode->str, useId, errors);}}/*** Rename a text file** Creates a new text file and copies an existing one*/bool CPackages::RenameTextFile(CyString textid, int languageid, CyStringList *errors){// lets check if the file already existsCyString newFilename = SPK::FormatTextName(textid.ToInt(), m_iLanguage, (m_iGameFlags & EXEFLAG_TCTEXT));C_File *addFile = FindFile(FILETYPE_TEXT, newFilename + ".xml");if ( !addFile )addFile = FindFile(FILETYPE_TEXT, newFilename + ".pck");// we have found the file, lets just add it to our scriptsif ( addFile ){AddTextFileToScripts(addFile, textid);return true;}// first we need to find our text fileCyString filename;if ( languageid != -1 )filename = SPK::FormatTextName(textid.ToInt(), languageid, (m_iGameFlags & EXEFLAG_TCTEXT));elsefilename = textid;C_File *textFile = FindFile(FILETYPE_TEXT, filename + ".xml");if ( !textFile ){textFile = FindFile(FILETYPE_TEXT, filename + ".pck");if ( !textFile )return false;}// now lets create out new text fileCFileIO readFile(textFile->GetFilePointer());std::vector<CyString> *lines = readFile.ReadLines();// find the language id in the linesstd::vector<CyString> frontLines;for(std::vector<CyString>::iterator it = lines->begin(); it != lines->end(); ++it){CyString line = *it;int pos = line.FindPos("<language id");if ( pos != -1){CyString newLine = "<language id=\"";newLine += CyString::Number(m_iLanguage);newLine += "\">";newLine += line.GetToken(">", 2);frontLines.insert(frontLines.begin(), newLine);lines->erase(lines->begin(), ++it);break;}frontLines.insert(frontLines.begin(), line);}for(std::vector<CyString>::iterator it = frontLines.begin(); it != frontLines.end(); ++it)lines->insert(lines->begin(), *it);addFile = new C_File(newFilename + ".xml");addFile->SetFileType(FILETYPE_TEXT);CFileIO writeFile(m_sCurrentDir + "/" + addFile->GetNameDirectory(NULL));if ( writeFile.WriteFile(lines) ){this->AddLogEntry(SPKINSTALL_WRITEFILE, addFile->GetNameDirectory(NULL), errors);addFile->SetFilename(m_sCurrentDir + "/" + addFile->GetNameDirectory(NULL));// now we have the file wrriten, we need to add it to all scripts that need it// first we add it to the global listm_lFiles.push_back(addFile);// now add it to the scriptsAddTextFileToScripts(addFile, textid);}else{this->AddLogEntry(SPKINSTALL_WRITEFILE_FAIL, addFile->GetNameDirectory(NULL), errors);if ( lines )delete lines;return false;}if ( lines )delete lines;return true;}/*** Add file to scripts** Adds a file to all scripts that need it*/void CPackages::AddTextFileToScripts(C_File *file, CyString textid){// now we need to find all scripts that have a matching file and add this to the listfor ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *package = node->Data();// first make sure it doesn't already existif ( package->GetFileList()->FindData(file) )continue;bool found = false;for ( CListNode<C_File> *fNode = package->GetFileList()->Front(); fNode; fNode = fNode->next() ){C_File *tFile = fNode->Data();if ( tFile->GetFileType() != FILETYPE_TEXT )continue;CyString id = tFile->GetBaseName().GetToken("-", 1, 1);if ( id == textid ){found = true;break;}}if ( found )package->GetFileList()->push_back(file);}}bool CPackages::RemoveFile(C_File *file, CyStringList *errors){if ( !file )return true;CyString remFileStr = file->GetFilePointer();remFileStr.FindReplace(m_sCurrentDir, "");if ( file->GetFilePointer().IsIn("::") ) {CFileIO CatFile(file->GetFilePointer().GetToken("::", 1, 1));if ( CatFile.exists() ) {CCatFile cat;if ( cat.Open(CatFile.GetFullFilename(), this->GetAddonDir(), CATREAD_DAT, false) == CATERR_NONE ) {CyString fileName = file->GetFilePointer().GetToken("::", 2, 2);if ( cat.FindData(fileName) ) {if ( cat.RemoveFile(fileName) ) {this->AddLogEntry(SPKINSTALL_DELETEFILE, remFileStr, errors);}else {this->AddLogEntry(SPKINSTALL_DELETEFILE_FAIL, remFileStr, errors);return false;}}}}}else {CFileIO f(file->GetFilePointer());if ( f.exists() ){if ( f.remove() ) this->AddLogEntry(SPKINSTALL_DELETEFILE, remFileStr, errors);else if ( errors ){this->AddLogEntry(SPKINSTALL_DELETEFILE_FAIL, remFileStr, errors);return false;}elsereturn false;}}return true;}int CPackages::RemoveAllPackages(CyStringList *errors, CProgressInfo *progress){int files = 0;// remove all filesint max = m_lFiles.size() + m_lOriginalFiles.size() + m_lUninstallFiles.size();for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){// update the progressif ( progress )progress->UpdateProgress(files, max);++files;RemoveFile(node->Data());delete node->Data();}m_lFiles.clear();// restore any original files that are backed upfor ( CListNode<C_File> *oNode = m_lOriginalFiles.Front(); oNode; oNode = oNode->next() ){// update the progressif ( progress )progress->UpdateProgress(files, max);++files;C_File *f = oNode->Data();CFileIO of(m_sCurrentDir + "/PluginManager/Original/" + f->GetNameDirectory(NULL));if ( of.exists() )of.Rename(m_sCurrentDir + "/" + f->GetNameDirectory(NULL));//RemoveFile(oNode->Data());delete oNode->Data();}m_lOriginalFiles.clear();// remove any uninstall files that remainfor ( CListNode<C_File> *uNode = m_lUninstallFiles.Front(); uNode; uNode = uNode->next() ){// update the progressif ( progress )progress->UpdateProgress(files, max);++files;RemoveFile(uNode->Data());delete uNode->Data();}m_lUninstallFiles.clear();// delete all packagesfor ( CListNode<CBaseFile> *pNode = m_lPackages.Front(); pNode; pNode = pNode->next() ){// clear file list as we have removed them alreadypNode->Data()->GetFileList()->clear();// delete the memory for the packagedelete pNode->Data();}m_lPackages.clear();return files;}/*** Get Install Before Text** Returns the install before text for the package in the correct language*/CyString CPackages::GetInstallBeforeText(CBaseFile *package){return package->installText(m_iLanguage, true);}CyString CPackages::GetInstallAfterText(CBaseFile *package){return package->installText(m_iLanguage, false);}CyString CPackages::GetUninstallBeforeText(CBaseFile *package){return package->uninstallText(m_iLanguage, true);}CyString CPackages::GetUninstallAfterText(CBaseFile *package){return package->uninstallText(m_iLanguage, false);}int CPackages::GetChildPackages(CBaseFile *package, CLinkList<CBaseFile> *children, bool recursive){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( p->GetParent() == package ){children->push_back(p);if ( recursive )this->GetChildPackages(p, children, recursive);}}return children->size();}void CPackages::AssignPackageNumbers(){int num = 0;for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() )node->Data()->SetNum(num++);}CyString CPackages::FindDataDir(CyString dir, CyString file){CDirIO Dir(dir);// data files could be in 4 places depending on what program is used, check for all of theseif ( Dir.Exists(file) )return Dir.File(file);else if ( Dir.Exists(CyString("Data/") + file) )return Dir.File(CyString("Data/") + file);else if ( Dir.Exists(CyString("../") + file) )return Dir.File(CyString("../") + file);else if ( Dir.Exists(CyString("../Data/") + file) )return Dir.File(CyString("../Data/") + file);return NullString;}void CPackages::Startup(CyString dir, CyString tempDir, CyString myDoc, CyString mod){this->SetTempDirectory(tempDir);this->SetMyDocuments(myDoc);m_sSetMod = mod;// need to read the game exe versionsm_gameExe.Reset();CyString exeFile = this->FindDataDir(dir, "exe");// if file exists, read it, otherwise, just addif ( !exeFile.Empty() && CFileIO(exeFile).ExistsOld() )m_gameExe.ReadFile(exeFile.ToString());else{m_gameExe.ParseExe("x2.exe|0:5:NOSAVESUBDIR:HKCU/Software/EgoSoftware/X2/ModName:X2 The Threat:!GAMEDIR!:2:1604608!2150400:1.4 Artifical Life:1974272:1.5 Uplink");m_gameExe.ParseExe("x3.exe|30:5:0:HKCU/Software/Egosoft/X3/ModName:X3 Reunion:Egosoft/X3:2:2347008:2.0 Bala Gi:2367488!2375680:2.5 Uplink");m_gameExe.ParseExe("x3tc.exe|35:5:NO_XOR|TC_TEXT|MYDOCLOG:HKCU/Software/Egosoft/X3TC/ModName:X3 Terran Conflict:Egosoft/X3TC:3:1933464!1933520:2.0 Aldrin Expansion:-1:2.5 A New Home (Superbox):-1:3.0 Balance of Power");m_gameExe.ParseExe("x3ap.exe|38:2:NO_XOR|TC_TEXT|MYDOCLOG|ADDON:HKCU/Software/Egosoft/X3AP/ModName:X3 Albion Prelude:Egosoft/X3AP:addon!x3tc.exe:0");}}int CPackages::GetGameLanguage(CyString dir){if ( dir.Empty() )dir = m_sCurrentDir;CDirIO Dir(dir);// check for lang.dat fileif ( Dir.Exists("lang.dat") ){CFileIO File(Dir.File("lang.dat"));size_t size;char *data = File.ReadToData(&size);if ( data ){CyString str(data);return str.GetToken("\n", 1, 1).GetToken(" ", 1, 1).ToInt();}}return 0;}CyString CPackages::GetGameRunExe(CyString dir){return m_gameExe.GetGameRunExe((dir.Empty()) ? m_sCurrentDir.ToString() : dir.ToString());}CyString CPackages::GetGameNameFromType(int game){return m_gameExe.GetGameNameFromType(game - 1);}CyString CPackages::GetGameName(CyString dir){return m_gameExe.GetGameName((dir.Empty()) ? m_sCurrentDir.ToString() : dir.ToString());}CyString CPackages::GetProperDir(CyString dir){return m_gameExe.GetProperDir((dir.Empty()) ? m_sCurrentDir.ToString() : dir.ToString());}CyString CPackages::GetAddonDir(CyString dir){return m_gameExe.GetAddonDir((dir.Empty()) ? m_sCurrentDir.ToString() : dir.ToString());}int CPackages::GetGameAddons(CyStringList &exes, CyString dir){return m_gameExe.GetGameAddons((dir.Empty()) ? m_sCurrentDir.ToString() : dir.ToString(), exes);}CyString CPackages::GetGameTypesString(CBaseFile *package, bool includeVersion){if ( !package->AnyGameCompatability() )return NullString;CyString sGames;for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {if ( !sGames.Empty() )sGames += ", ";sGames += m_gameExe.GetGameNameFromType(gNode->Data()->iGame - 1);if ( includeVersion ) {sGames += " (";sGames += m_gameExe.GetGameVersionFromType(gNode->Data()->iGame - 1, gNode->Data()->iVersion - 1, gNode->Data()->sVersion);sGames += ")";}}return sGames;}CyString CPackages::GetGameVersionString(CBaseFile *package){for ( CListNode<SGameCompat> *gNode = package->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {if ( gNode->Data()->iGame == m_iGame ) {return m_gameExe.GetGameVersionFromType(m_iGame - 1, gNode->Data()->iVersion - 1, gNode->Data()->sVersion);}}return NullString;}CyString CPackages::GetGameVersionFromType(int game, int version, CyString sVersion){return m_gameExe.GetGameVersionFromType(game - 1, version - 1, sVersion.ToString());}int CPackages::CountBuiltInPackages(bool onlyEnabled){int count = 0;for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){if ( !node->Data()->CheckGameCompatability(m_iGame) )continue;if ( onlyEnabled && !node->Data()->IsEnabled() )continue;if ( node->Data()->author().Compare("PluginManager") )++count;}return count;}int CPackages::CountPackages(int type, bool onlyEnabled){int count = 0;for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( (type != TYPE_BASE) && (p->GetType() != type) )continue;if ( (onlyEnabled) && (!p->IsEnabled()) )continue;++count;}return count;}int CPackages::ExtractGameFile(CyString aFilename, CyString aTo, CyString dir, CyString addon){// first check the enabled modif ( dir.Empty() )dir = m_sCurrentDir;CyString addonDir = addon;if ( addonDir.Empty() ) addonDir = this->GetAddonDir(dir);if ( m_pEnabledMod && m_pEnabledMod->AnyFileType(FILETYPE_MOD) ){for ( C_File *file = m_pEnabledMod->GetFirstFile(FILETYPE_MOD); file; file = m_pEnabledMod->GetNextFile(file) ){if ( !file->CheckFileExt("cat") )continue;CCatFile catFile;if ( catFile.Open(file->GetFilePointer(), addonDir, CATREAD_CATDECRYPT, false) == CATERR_NONE ){if ( catFile.ExtractFile(aFilename, aTo) )return 1;if ( catFile.Error() == CATERR_INVALIDDEST || catFile.Error() == CATERR_CANTCREATEDIR ){if ( catFile.ExtractFile(aFilename) )return -1;}}}}else if ( !m_sSetMod.Empty() ){if ( CFileIO(m_sCurrentDir + "/mods/" + m_sSetMod + ".cat").ExistsOld() ){CCatFile catFile;if ( catFile.Open(m_sCurrentDir + "/mods/" + m_sSetMod + ".cat", addonDir, CATREAD_CATDECRYPT, false) == CATERR_NONE ){if ( catFile.ExtractFile(aFilename, aTo) )return 1;if ( catFile.Error() == CATERR_INVALIDDEST || catFile.Error() == CATERR_CANTCREATEDIR ){if ( catFile.ExtractFile(aFilename) )return -1;}}}}// find the highest cat numberint catNumber = 1;while ( CFileIO(dir + "/" + CyString::Number(catNumber).PadNumber(2) + ".cat").ExistsOld() && catNumber < 99 )++catNumber;// get the last one, not the next free one--catNumber;// work backwards until we find the filefor ( ; catNumber; catNumber-- ){CCatFile catFile;if ( catFile.Open(dir + "/" + CyString::Number(catNumber).PadNumber(2) + ".cat", addonDir, CATREAD_CATDECRYPT, false) == CATERR_NONE ){// check for the fileif ( catFile.ExtractFile(aFilename, aTo) )return 1;if ( catFile.Error() == CATERR_INVALIDDEST || catFile.Error() == CATERR_CANTCREATEDIR ){if ( catFile.ExtractFile(aFilename) )return -1;}}}return 0;}void CPackages::CreateWareFiles(){// do each wareint wareTextID = WARETEXTSTART;for ( int i = 0; i < WAREBUFFERS; i++ ){// its empty, no need to create ware filesif ( !m_lGameWares[i].size() )continue;// lets extract the ware filechar wareType = CPackages::ConvertWareTypeBack(i);CyString wareFile = "TWare";wareFile += (char)UPPER(wareType);CyString openFile;int e;if ( i == WARES_TECH && CFileIO(m_sTempDir + "/TWareT.txt").ExistsOld() )openFile = m_sTempDir + "/TWareT.txt";else {e = ExtractGameFile(CyString("types/") + wareFile + ".pck", m_sTempDir + "/" + wareFile + ".txt");if ( e == 1 )openFile = m_sTempDir + "/" + wareFile + ".txt";else if ( e == -2 )openFile = wareFile + ".txt";}if ( !openFile.Empty() ){// read the file into memoryCyStringList wareLines;int oldSize = -1;int version = -1;// read first numberCFileIO readFile(m_sTempDir + "/" + wareFile + ".txt");CyStringList *lines = readFile.ReadLinesStr();if ( lines ){for ( SStringList *str = lines->Head(); str; str = str->next ){CyString line(str->str);line.RemoveFirstSpace();line.RemoveChar(9);line.RemoveChar('\r');if ( line.Empty() )continue;if ( line[0] == '/' )continue;if ( oldSize == -1 ){version = line.GetToken(";", 1, 1).ToInt();oldSize = line.GetToken(";", 2, 2).ToInt();}else{line.RemoveEndSpace();if ( line.Right(1) != ';' )line += ";";wareLines.PushBack(line);if ( wareLines.Count() >= oldSize )break;}}delete lines;// apply the bufferif ( m_iWareBuffer[i] <= 0 )m_iWareBuffer[i] = wareLines.Count() + 10;// last resort, readjust the bufferelse if ( wareLines.Count() > m_iWareBuffer[i] )m_iWareBuffer[i] = wareLines.Count();// add the bufferswhile ( wareLines.Count() < m_iWareBuffer[i] )wareLines.PushBack("27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_FILLER;");// add the ware linesbool create = false;for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() ){SGameWare *w = node->Data();if ( w->iType == WARETYPE_NONE )continue;else if ( w->iType == WARETYPE_DISABLED ){create = true;wareLines.PushBack(CyString("27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;") + w->sWareName + "_DISABLED;");}else if ( w->iType == WARETYPE_DELETED || !w->pWare ){create = true;wareLines.PushBack("27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_DELETED;");}else if ( w->iType == WARETYPE_ADDED ){create = true;w->pWare->iDescID = wareTextID;w->iText = wareTextID;wareTextID += 10;w->iPos = wareLines.Count();wareLines.PushBack(CyString("28;0;0;0;0;") + (long)wareLines.Count() + ";" + (long)(w->iText + 3) + ";" + (long)w->pWare->iVolumn + ";" + (long)w->pWare->iPrice + ";1;1;" + (long)w->pWare->iSize + ";" + (long)w->pWare->iPrice + ";" + (long)w->pWare->iNotority + ";0;0;" + w->sWareName.ToUpper() + ";");}}if ( create ){wareLines.PushFront(CyString::Number(version) + ";" + CyString::Number(wareLines.Count()) + ";", NullString);CyString strV;strV.FromFloat(GetLibraryVersion(), 2);wareLines.PushFront(CyString("// Created by SPKInstaller Libraries V") + strV, NullString);if ( readFile.WriteFile(&wareLines) )this->PackFile(&readFile, CyString("types\\") + wareFile + ".pck");}}readFile.remove();}}}void CPackages::CreateEMPFile(CyString progDir){// do emp waresint maxsize = 0;Utils::String empWares;if ( m_iGame == GAME_X3TC ){maxsize = EMP_X3TC;empWares = GetX3TCEmp();}else if ( m_iGame == GAME_X3AP ){maxsize = EMP_X3AP;empWares = GetX3TCEmp();}else if ( m_iGame == GAME_X3 ){maxsize = EMP_X3;empWares = GetX3Emp();}if ( maxsize ){int e = ExtractGameFile("types/TWareT.pck", m_sTempDir + "/TWareT.txt");if ( e ){// read the file into memoryCyStringList wareLines;int oldSize = -1;int version = -1;// read first numberCFileIO readFile((e == -1) ? "TWareT.txt" : m_sTempDir + "/TWareT.txt");std::vector<CyString> *lines = readFile.ReadLines();if ( lines ){for ( int i = 0; i < (int)lines->size(); i++ ){CyString line(lines->at(i));line.RemoveFirstSpace();line.RemoveChar('\r');line.RemoveChar(9);if ( line[0] == '/' )continue;if ( oldSize == -1 ){version = line.GetToken(";", 1, 1).ToInt();oldSize = line.GetToken(";", 2, 2).ToInt();}else{line.RemoveEndSpace();if ( line.Right(1) != ";" )line += ";";wareLines.PushBack(line);if ( wareLines.Count() >= oldSize )break;}}delete lines;}// now we too add/remove entries to match// need filler entrieswhile ( wareLines.Count() < maxsize )wareLines.PushBack("27;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;SS_WARE_FILLER;");int empEntries = 0;CyString *empStr = CyString(empWares).SplitToken("\n", &empEntries);if ( empEntries && empStr ){// remove any empty end entrieswhile ( empStr[empEntries - 1].Empty() )--empEntries;CyStringList addAfter;if ( wareLines.Count() > maxsize ){// force emp, remove entries to allow them to be addedif ( m_bForceEMP ){// more after empif ( wareLines.Count() > (maxsize + empEntries) ){SStringList *node = wareLines.GetAt(maxsize + empEntries);while ( node ){addAfter.PushBack(node->str);node = node->next;}}// no remove them allwareLines.DeleteFrom(maxsize);}else if ( m_iGame == GAME_X3TC || m_iGame == GAME_X3AP ) // check if old emp is included, and convert it{if ( wareLines.Count() > 128 ){CyString test = wareLines.GetAt(128)->str;if ( test.GetToken(";", -2).Compare("SS_WARE_SW_CUSTOM16_1;") ){// if theres any at the end, remove the last emp entryif ( wareLines.Count() > (maxsize + empEntries - 1) ){SStringList *node = wareLines.GetAt(maxsize + empEntries - 2);if ( node )node->remove = true;}wareLines.Insert(128, "0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;128;");wareLines.RemoveMarked();}}}}// too many entries, need to remove the first set of EMP waresint i = 0;if ( wareLines.Count() > maxsize )i = wareLines.Count() - maxsize;for ( ; i < empEntries; i++ ){CyString str = empStr[i];str.RemoveEndSpace();str.RemoveChar(9);str.RemoveChar('\r');if ( str.Empty() )continue;if ( str.Right(1) != ";" )str += ";";wareLines.PushBack(str);}for ( SStringList *afterNode = addAfter.Head(); afterNode; afterNode = afterNode->next )wareLines.PushBack(afterNode->str);// finally we write the whole filewareLines.PushFront(CyString::Number(version) + ";" + CyString::Number(wareLines.Count()) + ";", NullString);CyString strV;strV.FromFloat(GetLibraryVersion(), 2);wareLines.PushFront(CyString("// Created by SPKInstaller Libraries V") + strV, NullString);if ( readFile.WriteFile(&wareLines) )this->PackFile(&readFile, "types\\TWareT.pck");}CLEANSPLIT(empStr, empEntries);}}}CyString parseXmlText(const CyString &str){CyString newStr(str);CyStringList changes;// find all XML commands, &<command>;std::string sStr = str.ToString();std::string::size_type pos = sStr.find_first_of("&", 0);while ( pos != std::string::npos ) {// find the next space and next ;. If ; comes first, assume its acommandstd::string::size_type spacePos = sStr.find_first_of(" ", pos);std::string::size_type colonPos = sStr.find_first_of(";", pos);if ( colonPos != std::string::npos && colonPos < spacePos ) {// replace with <::command::> so they the & doesn't get replacedstd::string repStr = sStr.substr(pos, (colonPos + 1) - pos);std::string repWithStr = "<::" + sStr.substr(pos + 1, colonPos - pos - 1) + "::>";newStr.FindReplace(repStr, repWithStr);changes.PushBack(repStr, repWithStr);}// find the next commandpos = sStr.find_first_of("&", pos + 1);}// replace the & nownewStr = newStr.FindReplace("&", "&");// restore the commandsfor ( SStringList *strNode = changes.Head(); strNode; strNode = strNode->next ) {newStr.FindReplace(strNode->data, strNode->str);}return newStr;}CyString CPackages::ConvertTextString(CyString text){//process any &text = parseXmlText(text);// change special casestext = text.FindReplace("(", "\\(");text = text.FindReplace(")", "\\)");text = text.FindReplace("[", "{");text = text.FindReplace("]", "}");text = text.FindReplace(">", ">");text = text.FindReplace("<", "<");return text;}int CPackages::_gameTextNumber() const{int gameNumber = (m_pCurrentGameExe) ? m_pCurrentGameExe->iTextNum : -1;if ( gameNumber != -1 ) return gameNumber;switch(m_iGame) {case GAME_X3: return 30;case GAME_X3TC: return 35;case GAME_X3AP: return 38;default: return 0;}}void CPackages::CreatePluginManagerText(){int gameNumber = _gameTextNumber();int lang = m_iLanguage;if ( !lang || lang < 0 )lang = 44;CDirIO Dir(m_sCurrentDir);if ( !Dir.Exists("t") )Dir.Create("t");m_iLastUpdated = (int)time(NULL);CyString filename = SPK::FormatTextName(PMTEXTFILE, lang, (m_iGameFlags & EXEFLAG_TCTEXT));CFileIO textFile(m_sCurrentDir + "/t/" + filename + ".xml");std::vector<CyString> writeData;CLinkList<SGameWare> lWares;CLinkList<SGameShip> lShips;for ( int i = 0; i < WAREBUFFERS; i++ ){for ( CListNode<SGameWare> *node = m_lGameWares[i].Front(); node; node = node->next() ){SGameWare *w = node->Data();if ( w->iType == WARETYPE_NONE )continue;lWares.push_back(w);}}for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){if ( node->Data()->iType == WARETYPE_NONE )continue;lShips.push_back(node->Data());}writeData.push_back(CyString("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"));writeData.push_back(CyString("<language id=\"") + CyString::Number(lang) + "\">");if ( !gameNumber )writeData.push_back(CyString(" <page id=\"") + CyString::Number(PMTEXTFILE) + "\" title=\"Plugin Manager Text File\" descr=\"Contains text used for the plugin manager, packages, settings, wares, ship, etc\">");elsewriteData.push_back(CyString(" <page id=\"") + (long)gameNumber + CyString::Number(PMTEXTFILE).PadNumber(4) + "\" title=\"Plugin Manager Text File\" descr=\"Contains text used for the plugin manager, packages, settings, wares, ship, etc\">");// write the headingint start = 10000;writeData.push_back(CyString(" <t id=\"1\">") + CyString::Number(m_iLastUpdated) + "</t>");writeData.push_back(CyString(" <t id=\"2\">") + CyString::Number(this->CountPackages(TYPE_SPK, true)) + "</t>");writeData.push_back(CyString(" <t id=\"3\">") + CyString::Number(start) + "</t>");writeData.push_back(CyString(" <t id=\"4\">") + CyString::Number(lWares.size()) + "</t>");writeData.push_back(CyString(" <t id=\"6\">") + CyString::Number(lShips.size()) + "</t>");// write some generic textswriteData.push_back(CyString(" <t id=\"110\">") + (long)m_iLanguage + "</t>");writeData.push_back(CyString(" <t id=\"109\">Plugin Manager: \\033GPoll Gui Data\\033X</t>"));writeData.push_back(CyString(" <t id=\"107\">Plugin Manager: \\033GExport Game Data\\033X </t>"));writeData.push_back(CyString(" <t id=\"100\">\\n</t>"));writeData.push_back(CyString(" <t id=\"101\">\\033B</t>"));writeData.push_back(CyString(" <t id=\"102\">\\033G</t>"));writeData.push_back(CyString(" <t id=\"103\">\\033B</t>"));writeData.push_back(CyString(" <t id=\"104\">\\033X</t>"));writeData.push_back(CyString(" <t id=\"105\">\\033Y</t>"));writeData.push_back(CyString(" <t id=\"106\">\\033C</t>"));writeData.push_back(CyString(" <t id=\"108\">\\033</t>"));// now write each packageint settingStart = 100000;for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( !p->IsEnabled() )continue;if ( p->GetType() != TYPE_SPK )continue;CSpkFile *spk = (CSpkFile *)p;// count text filesCyString textEntries;int textCount = 0;C_File *f = p->GetFirstFile(FILETYPE_TEXT);while ( f ){CyString sLang;CyString id;if ( m_iGameFlags & EXEFLAG_TCTEXT ){id = f->GetBaseName().GetToken("-", 1, 1);sLang = f->GetBaseName().GetToken("-", 2, 2);if ( sLang.Empty() )sLang = "NULL";elsesLang = sLang.Erase(0, 1); // remove the "L"}else{sLang = f->GetBaseName().Left((int)f->GetBaseName().Length() - 4).PadNumber(3);id = f->GetBaseName().Mid(((int)f->GetBaseName().Length() - 4) + 1, 4);}if ( sLang != "NULL" ){if ( sLang.ToInt() == lang ){++textCount;if ( !textEntries.Empty() )textEntries += " ";textEntries += id;}}f = p->GetNextFile(f);}CyString sTextCount((long)textCount);writeData.push_back(CyString(" <t id=\"") + (long)start + "\">" + this->ConvertTextString(p->name()) + "</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 1) + "\">" + this->ConvertTextString(p->author()) + "</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 2) + "\">" + this->ConvertTextString(p->version()) + "</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 3) + "\">" + this->ConvertTextString(p->GetLanguageName(lang)) + "</t>");CLinkList<SSettingType> *settings = spk->GetSettingsList();if ( settings && settings->size() ){writeData.push_back(CyString(" <t id=\"") + (long)(start + 4) + "\">" + (long)settings->size() + "</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 5) + "\">" + (long)settingStart + "</t>");for ( CListNode<SSettingType> *sNode = settings->Front(); sNode; sNode = sNode->next() ){SSettingType *st = sNode->Data();writeData.push_back(CyString(" <t id=\"") + (long)(settingStart++) + "\">" + st->sKey + "</t>");writeData.push_back(CyString(" <t id=\"") + (long)(settingStart++) + "\">" + spk->GetSetting(st) + "</t>");}}elsewriteData.push_back(CyString(" <t id=\"") + (long)(start + 4) + "\">0</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 6) + "\">" + sTextCount + "</t>");if ( textCount )writeData.push_back(CyString(" <t id=\"") + (long)(start + 7) + "\">" + textEntries + "</t>");start += 10;}// write ware namesif ( lWares.size() ){writeData.push_back(CyString(" <t id=\"5\">") + CyString::Number(start) + "</t>");for ( CListNode<SGameWare> *node = lWares.Front(); node; node = node->next() ){SGameWare *w = node->Data();if ( w->pWare && w->iType == WARETYPE_ADDED )writeData.push_back(CyString(" <t id=\"") + (long)start + "\">" + this->ConvertTextString(w->sWareName) + "</t>");elsewriteData.push_back(CyString(" <t id=\"") + (long)start + "\">-1</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 1) + "\">" + CyString((char)w->cType) + "</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 2) + "\">" + (long)w->iPos + "</t>");start += 10;}}if ( lShips.size() ){writeData.push_back(CyString(" <t id=\"7\">") + CyString::Number(start) + "</t>");for ( CListNode<SGameShip> *node = lShips.Front(); node; node = node->next() ){SGameShip *gs = node->Data();if ( gs->iType == WARETYPE_NONE )continue;if ( gs->pPackage && gs->iType == WARETYPE_ADDED )writeData.push_back(CyString(" <t id=\"") + (long)start + "\">" + gs->sShipID + "</t>");elsewriteData.push_back(CyString(" <t id=\"") + (long)start + "\">-1</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 1) + "\">" + (long)gs->iPos + "</t>");writeData.push_back(CyString(" <t id=\"") + (long)(start + 2) + "\">Ship</t>");// write shipyard infoif ( gs->pPackage ){int doStart = start + 5;for ( int i = SHIPYARD_ARGON; i <= SHIPYARD_MAX; i *= 2 ){writeData.push_back(CyString(" <t id=\"") + (long)(doStart) + "\">" + ((gs->pPackage->IsShipyard(i)) ? CyString::Number(1) : CyString::Number(0)) + "</t>");++doStart;}}start += 20;}}writeData.push_back(CyString(" </page>"));// waresif ( m_iGame == GAME_X3AP || m_iGame == GAME_X3TC || m_iGame == GAME_X3 || lWares.size() || lShips.size() ){if ( !gameNumber )writeData.push_back(CyString(" <page id=\"17\" title=\"Plugin Manager Objects\">"));elsewriteData.push_back(CyString(" <page id=\"") + (long)gameNumber + "0017\" title=\"Plugin Manager Objects\">");writeData.push_back(CyString(" <t id=\"") + (long)(SHIPSTARTTEXT - 1) + "\">ZZ_BLANKSHIP</t>");// do empif ( m_iGame == GAME_X3TC || m_iGame == GAME_X3 || m_iGame == GAME_X3AP )writeData.push_back(GetEMPText());// object namesfor ( CListNode<SGameWare> *node = lWares.Front(); node; node = node->next() ){SGameWare *w = node->Data();if ( !w->pWare || w->iType != WARETYPE_ADDED )continue;// find the correct text for the languageCyString name = CSpkFile::GetWareText(w->pWare, m_iLanguage);CyString desc = CSpkFile::GetWareDesc(w->pWare, m_iLanguage);if ( !name.Empty() )writeData.push_back(CyString(" <t id=\"") + (long)(w->iText + 3) + "\">" + this->ConvertTextString(name) + "</t>");if ( !desc.Empty() )writeData.push_back(CyString(" <t id=\"") + (long)(w->iText + 4) + "\">" + this->ConvertTextString(desc) + "</t>");}for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( !s->pPackage || s->iType != WARETYPE_ADDED )continue;if ( s->pPackage->GetOriginalDescription() )continue;CyString name = s->pPackage->GetTextName(m_iLanguage);CyString desc = s->pPackage->GetTextDescription(m_iLanguage);if ( !name.Empty() )writeData.push_back(CyString(" <t id=\"") + (long)s->iText + "\">" + this->ConvertTextString(name) + "</t>");if ( !desc.Empty() )writeData.push_back(CyString(" <t id=\"") + (long)(s->iText + 1) + "\">" + this->ConvertTextString(desc) + "</t>");}writeData.push_back(CyString(" </page>"));}writeData.push_back(CyString("</language>"));textFile.WriteFileUTF(&writeData);size_t fileSize;char *fileData = CFileIO(textFile.GetFullFilename()).ReadToData(&fileSize);if ( fileData && fileSize){size_t newFileSize;unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);if ( pckData ){CFileIO pckFile(m_sCurrentDir + "/t/" + filename + ".pck");pckFile.WriteData((char *)pckData, newFileSize);this->AddCreatedFile(pckFile.GetFullFilename());}}textFile.remove();}bool CPackages::IsCurrentDir(CyString dir){if ( dir.Compare(m_sCurrentDir) )return true;CyString checkDir = m_sCurrentDir;checkDir = checkDir.FindReplace("/", "\\");if ( checkDir.Compare(dir) )return true;checkDir = checkDir.FindReplace("\\", "/");if ( checkDir.Compare(dir) )return true;return false;}void CPackages::BackupSaves(bool vanilla){// copy any saves into the vanilla directoryCyString dir = (vanilla) ? "Vanilla" : "Modified";// make sure the directory existsCDirIO saveDir(this->GetSaveDirectory());CDirIO gameSaveDir(m_sCurrentDir);if ( !gameSaveDir.Exists("PluginManager") )gameSaveDir.Create("PluginManager");gameSaveDir.cd("PluginManager");if ( !gameSaveDir.Exists("Saves") )gameSaveDir.Create("Saves");gameSaveDir.cd("Saves");if ( !gameSaveDir.Exists(dir) )gameSaveDir.Create(dir);gameSaveDir.cd(dir);// backup the savesCyStringList *dirs = saveDir.DirList();if ( dirs ){for ( SStringList *node = dirs->Head(); node; node = node->next ){CFileIO File(saveDir.File(node->str));if ( !File.CheckFileExtension("sav") )continue;// remove the file if already existsif ( gameSaveDir.Exists(node->str) )CFileIO::Remove(gameSaveDir.File(node->str).ToString());// copy the file into the games save dir for backupFile.copy(gameSaveDir.File(File.GetFilename()).ToString(), true);}delete dirs;}}void CPackages::RestoreSaves(bool vanilla){// get dir to restore fromCyString dir = (vanilla) ? "Vanilla" : "Modified";CDirIO restoreDir(m_sCurrentDir + "/PluginManager/Saves/" + dir);CDirIO toDir(this->GetSaveDirectory());CyStringList *dirs = restoreDir.DirList();if ( dirs ){for ( SStringList *node = dirs->Head(); node; node = node->next ){CFileIO File(restoreDir.File(node->str));// remove the file if already existsif ( toDir.Exists(node->str) ) CFileIO::Remove(toDir.File(node->str).ToString());// move file overFile.copy(toDir.File(node->str).ToString(), true);}delete dirs;}}bool CPackages::RemoveCurrentDirectory(){if ( !m_bLoaded )return false;// remove all package filesthis->RemoveAllPackages();// remove all plugin manager filesthis->RemoveCreatedFiles();// restore any vanilla saves/*if ( !m_bVanilla ){this->BackupSaves();m_bVanilla = true;this->RestoreSaves();}*/this->Reset();m_bLoaded = false;// clear the plugin manager directoryCDirIO Dir(m_sCurrentDir);Dir.RemoveDir("PluginManager", true, true, 0);Dir.RemoveDir("dds", false, true, 0);Dir.RemoveDir("objects", false, true, 0);Dir.RemoveDir("types", false, true, 0);Dir.RemoveDir("textures", false, true, 0);// remove the plugin manager mod filesif ( Dir.Exists("mods/PluginManager.cat") ) CFileIO::Remove(Dir.File("mods/PluginManager.cat").ToString());if ( Dir.Exists("mods/PluginManager.dat") ) CFileIO::Remove(Dir.File("mods/PluginManager.dat").ToString());return true;}void CPackages::CreateDummies(){// first check we have any shipsif ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )return;CLinkList<SDummyEntry> dummyList;// now extract the existing dummiesint e = ExtractGameFile("types/Dummies.pck", m_sTempDir + "/Dummies.txt");if ( e ){// read the dummiesCFileIO File;if ( File.Open((e == -1) ? "Dummies.txt" : m_sTempDir + "/Dummies.txt") ){std::vector<CyString> *lines = File.ReadLines();if ( lines ){int insection = 0;SDummyEntry *currentSection = NULL;for ( int j = 0; j < (int)lines->size(); j++ ){CyString line(lines->at(j));line.RemoveChar(9);line.RemoveChar('\r');line.RemoveFirstSpace();line.RemoveEndSpace();if ( line.Empty() )continue;if ( line[0] == '/' )continue;// read the section, first entry is section, second is sizewhile ( !line.Empty() ){if ( !insection ){CyString section = line.GetToken(";", 1, 1);insection = line.GetToken(";", 2, 2).ToInt();// search for the sectionscurrentSection = NULL;for ( CListNode<SDummyEntry> *node = dummyList.Front(); node; node = node->next() ){SDummyEntry *d = node->Data();if ( d->sSection.Compare(section) ){currentSection = node->Data();break;}}if ( !currentSection ){currentSection = new struct SDummyEntry;currentSection->sSection = section;dummyList.push_back(currentSection);}// we have some more ?line = line.DelToken(";", 1, 2);}else{--insection;// check the last entry for number of statesif ( currentSection->sSection.Compare("SDTYPE_GUN") ){int states = line.GetToken(";", 3, 3).ToInt();int parts = line.GetToken(";", 4 + (states * 2), 4 + (states * 2)).ToInt();CyString data = line.GetToken(";", 1, 4 + (states * 2) + (parts * 2)) + ";";currentSection->lEntries.PushBack(data);// remove doneline = line.DelToken(";", 1, 4 + (states * 2) + (parts * 2));}else{int states = line.GetToken(";", 3, 3).ToInt();CyString data = line.GetToken(";", 1, 3 + (states * 2)) + ";";currentSection->lEntries.PushBack(data);// remove doneline = line.DelToken(";", 1, 3 + (states * 2));}}}}delete lines;}File.remove();}// add the new entries for the shipsfor ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;// no dummies to add?if ( !s->pPackage->AnyDummies() )continue;// add each dummy to listfor ( CListNode<SDummy> *dNode = s->pPackage->GetDummies()->Front(); dNode; dNode = dNode->next() ){SDummy *dummy = dNode->Data();SDummyEntry *found = NULL;for ( CListNode<SDummyEntry> *eNode = dummyList.Front(); eNode; eNode = eNode->next() ){if ( eNode->Data()->sSection.Compare(CyString(dummy->sSection)) ){found = eNode->Data();break;}}if ( !found ){found = new SDummyEntry;found->sSection = dummy->sSection;dummyList.push_back(found);}// check if its already on the listelse{bool f = false;for ( SStringList *strNode = found->lEntries.Head(); strNode; strNode = strNode->next ){if ( strNode->str.GetToken(";", 1, 1).Compare(CyString(dummy->sData.token(";", 1))) ){f = true;break;}}if ( f )continue;}found->lEntries.PushBack(CyString(dummy->sData));}}// finally, write the filestd::vector<CyString> lines;lines.push_back(CyString("// Dummies file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2));for ( SDummyEntry *dummy = dummyList.First(); dummy; dummy = dummyList.Next() ){lines.push_back("");lines.push_back(CyString("// Section: ") + dummy->sSection + " Entries: " + (long)dummy->lEntries.Count());lines.push_back(dummy->sSection + ";" + CyString::Number(dummy->lEntries.Count()) + ";");for ( SStringList *str = dummy->lEntries.Head(); str; str = str->next ){CyString strLine = str->str;strLine.RemoveChar(9);strLine.RemoveChar('\r');strLine.RemoveEndSpace();strLine.RemoveFirstSpace();strLine = strLine.FindReplace("<::PiPe::>", "|");if ( strLine.Right(1) != ";" )strLine += ";";lines.push_back(strLine);}}lines.push_back("");// write the file to diskCFileIO WriteFile(m_sTempDir + "/dummies.txt");if ( WriteFile.WriteFile(&lines) ){this->PackFile(&WriteFile, "types\\dummies.pck");WriteFile.remove();}}}void CPackages::CreateCutData(){// first check we have any shipsif ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )return;bool found = false;for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;// no dummies to add?if ( !s->pPackage->AnyCutData() )continue;found = true;break;}if ( !found )return;CyStringList cutList;int e = ExtractGameFile("types/CutData.pck", m_sTempDir + "/CutData.txt");if ( e ){CFileIO File;if ( File.Open((e == -1) ? "CutData.txt" : m_sTempDir + "/CutData.txt") ){std::vector<CyString> *lines = File.ReadLines();if ( lines ){int entries = -1;for ( int j = 0; j < (int)lines->size(); j++ ){CyString line(lines->at(j));line.RemoveChar(9);line.RemoveChar('\r');line.RemoveChar(' ');if ( line.Empty() || line[0] == '/' )continue;if ( entries == -1 )entries = line.GetToken(";", 1, 1).ToInt();else{if ( line.Right(1) != ";" )line += ";";cutList.PushBack(line);if ( cutList.Count() == entries )break;}}delete lines;}File.remove();}}for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;// no dummies to add?if ( !s->pPackage->AnyCutData() )continue;// add each dummy to listfor ( SStringList *strNode = s->pPackage->GetCutData()->Head(); strNode; strNode = strNode->next ){CyString str = strNode->str;str.RemoveChar(' ');if ( str.Right(1) != ";" )str += ";";cutList.PushBack(str, true);}}cutList.PushFront(CyString::Number(cutList.Count()) + ";");cutList.PushFront("/cut id;filename (leave blank to use id)");cutList.PushFront(CyString("// Cut Data file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2));// write the file to diskCFileIO WriteFile(m_sTempDir + "/CutData.txt");if ( WriteFile.WriteFile(&cutList) ){this->PackFile(&WriteFile, "types\\CutData.pck");WriteFile.remove();}}void CPackages::CreateAnimations(){// first check we have any shipsif ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )return;bool found = false;for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;// no dummies to add?if ( !s->pPackage->AnyAnimations() )continue;found = true;break;}if ( !found )return;CyStringList aniList;int e = ExtractGameFile("types/Animations.pck", m_sTempDir + "/Animations.txt");if ( e ){CFileIO File;if ( File.Open((e == -1) ? "Animations.txt" : m_sTempDir + "/Animations.txt") ){std::vector<CyString> *lines = File.ReadLines();if ( lines ){for ( int j = 0; j < (int)lines->size(); j++ ){CyString line(lines->at(j));aniList.PushBack(line);}delete lines;}File.remove();}}CyStringList parsedAniList;CXspFile::ReadAnimations(&aniList, &parsedAniList, 0);for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;// no dummies to add?if ( !s->pPackage->AnyAnimations() )continue;// add each dummy to listfor ( SStringList *strNode = s->pPackage->GetAnimations()->Head(); strNode; strNode = strNode->next )parsedAniList.PushBack(strNode->str);}// format the list with added spacesCyStringList formatedAniList;int lineCount = -1;for ( SStringList *strNode = parsedAniList.Head(); strNode; strNode = strNode->next ){// format the comment to match the line numberlineCount++;CyString oldComment = strNode->str.GetToken("//", 2);CyString comment = CyString("//") + CyString::Number(lineCount);if ( !oldComment.Empty() ){comment += " ";oldComment.RemoveFirstSpace();if ( oldComment.GetToken(" ", 1, 1).IsNumber() )comment += oldComment.GetToken(" ", 2);elsecomment += oldComment;}CyString line = strNode->str.GetToken("//", 1, 1);// split into seperate linesCyString first = line.GetToken(";", 1, 1);if ( first.Compare("TAT_TAGSINGLESTEP") ){formatedAniList.PushBack(line.GetToken(";", 1, 5) + ";");int max;CyString *sLines = line.GetToken(";", 6).SplitToken(";", &max);if ( max && sLines ){if ( sLines[max - 1].Empty() )--max; // remove the last ";"for ( int i = 0; i < max; i++ ){CyString l = CyString("\t") + sLines[i] + ";";if ( i == (max - 1) )formatedAniList.PushBack(l + comment);elseformatedAniList.PushBack(l);}}CLEANSPLIT(sLines, max);}else if ( (first.Compare("TAT_TAGONESHOT") || first.Compare("TAT_TAGLOOP")) && (line.IsIn("TATF_COORDS")) ){formatedAniList.PushBack(line.GetToken(";", 1, 5) + ";");int max;CyString *sLines = line.GetToken(";", 6).SplitToken(";", &max);if ( max && sLines ){if ( sLines[max - 1].Empty() )--max; // remove the last ";"CyString prevLine;for ( int i = 0; i < max; i++ ){CyString l = sLines[i] + ";";if ( l.IsIn("TATF_COORDS") && !prevLine.Empty() ){formatedAniList.PushBack(CyString("\t") + prevLine);prevLine = "";}prevLine += l;}if ( !prevLine.Empty() )formatedAniList.PushBack(CyString("\t") + prevLine + comment);}CLEANSPLIT(sLines, max);}elseformatedAniList.PushBack(line + comment);}formatedAniList.PushFront(CyString::Number(parsedAniList.Count()) + ";");formatedAniList.PushFront(CyString("// Animations, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2));// write the file to diskCFileIO WriteFile(m_sTempDir + "/Animations.txt");if ( WriteFile.WriteFile(&formatedAniList) ){this->PackFile(&WriteFile, "types\\Animations.pck");WriteFile.remove();}}void CPackages::CreateBodies(){// first check we have any shipsif ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )return;bool found = false;for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;// no dummies to add?if ( !s->pPackage->AnyBodies() )continue;found = true;break;}if ( !found )return;// lets read our current bodies fileCLinkList<SBodies> bodiesList;SBodies *currentSection = NULL;int e = ExtractGameFile("types/Bodies.pck", m_sTempDir + "/Bodies.txt");if ( e ){CFileIO File;if ( File.Open((e == -1) ? "Bodies.txt" : m_sTempDir + "/Bodies.txt") ){std::vector<CyString> *lines = File.ReadLines();if ( lines ){int entries = 0;for ( int j = 0; j < (int)lines->size(); j++ ){CyString line(lines->at(j));line.RemoveChar(' ');line.RemoveChar(9);if ( line.Empty() || line[0] == '/' )continue;if ( entries <= 0 ){entries = line.GetToken(";", 2, 2).ToInt();currentSection = new SBodies;currentSection->sSection = line.GetToken(";", 1, 1);bodiesList.push_back(currentSection);}else if ( currentSection ){int num;CyString *strs = line.SplitToken(";", &num);if ( num && strs ){for ( int i = 0; i < num; i++ ){if ( strs[i].Empty() )continue;currentSection->lEntries.PushBack(strs[i] + ";", true);--entries;}}CLEANSPLIT(strs, num);}}delete lines;}File.remove();}}// lets now add any new entriesfor ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;// no dummies to add?if ( !s->pPackage->AnyBodies() )continue;// add each dummy to listfor ( SStringList *strNode = s->pPackage->GetBodies()->Head(); strNode; strNode = strNode->next ){CyString section = strNode->str.GetToken(";", 1, 1);CyString body = strNode->str.GetToken(";", 2).Remove(' ');if ( body.Right(1) != ";" )body += ";";// find the section to add intoSBodies *foundSection = NULL;for ( CListNode<SBodies> *checkBody = bodiesList.Front(); checkBody; checkBody = checkBody->next() ){if ( checkBody->Data()->sSection.Compare(section) ){foundSection = checkBody->Data();break;}}if ( !foundSection ){foundSection = new SBodies;foundSection->sSection = section;bodiesList.push_back(foundSection);}foundSection->lEntries.PushBack(body, true);}}// now write the fileCyStringList writeList;// the header firstwriteList.PushBack(CyString("// Bodies file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2));writeList.PushBack("//body type;num bodies;");writeList.PushBack("//[body id/name]");// now our sectionsfor ( SBodies *bSection = bodiesList.First(); bSection; bSection = bodiesList.Next() ){writeList.PushBack("");writeList.PushBack(CyString("// Section: ") + bSection->sSection);writeList.PushBack(bSection->sSection + ";" + CyString::Number(bSection->lEntries.Count()) + ";");for ( SStringList *strNode = bSection->lEntries.Head(); strNode; strNode = strNode->next ){CyString str = strNode->str;str.RemoveChar(9);str.RemoveChar(' ');if ( str.Right(1) != ";" )str += ";";writeList.PushBack(str);}}// write the file to diskCFileIO WriteFile(m_sTempDir + "/Bodies.txt");if ( WriteFile.WriteFile(&writeList) ){this->PackFile(&WriteFile, "types\\Bodies.pck");WriteFile.remove();}}void CPackages::CreateCustomStarts(){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){// find all spk files (only ones that can be custom startsif ( node->Data()->GetType() != TYPE_SPK )continue;CSpkFile *p = (CSpkFile *)node->Data();// only use custom startsif ( !p->IsCustomStart() )continue;// get the name of the start to useCyString name = p->GetCustomStartName();if ( name.Empty() )continue;// find if maps file existsCyStringList createFiles;createFiles.PushBack(name, "maps/x3_universe");createFiles.PushBack(name, "types/Jobs");createFiles.PushBack(name, "types/JobWings");for ( SStringList *str = createFiles.Head(); str; str = str->next ){CyString dir = CFileIO(str->data).GetDir();int type = FILETYPE_EXTRA;if ( dir.Compare("maps") )type = FILETYPE_MAP;if ( !p->FindFile(str->str + ".xml", type) && !p->FindFile(str->str + ".pck", type) ){// create a maps filesint e = this->ExtractGameFile(str->data + ".pck", m_sTempDir + "/" + str->data + ".pck");if ( e ){CFileIO File((e == -1) ? (str->data + ".pck") : (m_sTempDir + "/" + str->data + ".pck"));if ( File.exists() ){File.Rename(m_sCurrentDir + "/" + dir + "/" + str->str + ".pck");this->AddCreatedFile(dir + "/" + str->str + ".pck");}}}}}}void CPackages::AddCreatedFile(CyString file){file = file.Remove(m_sCurrentDir);while ( file[0] == '/' )file.Erase(0, 1);while ( file[0] == '\\' )file.Erase(0, 1);m_lCreatedFiles.PushBack(file, true);}void CPackages::CreateComponants(){// first check we have any shipsif ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )return;CLinkList<SComponantEntry> dummyList;// now extract the existing dummiesint e = ExtractGameFile("types/Components.pck", m_sTempDir + "/Components.txt");if ( e ){// read the dummiesCFileIO File;if ( File.Open((e == -1) ? "Components.txt" : m_sTempDir + "/Components.txt") ){std::vector<CyString> *lines = File.ReadLines();if ( lines ){int insection = 0;int insubsection = 0;SComponantEntry *currentSection = NULL;SComponantEntry2 *currentSubSection = NULL;for ( int j = 0; j < (int)lines->size(); j++ ){CyString line(lines->at(j));if ( line[0] == '/' )continue;line.RemoveChar('\r');line = line.RemoveFirstSpace();line = line.RemoveEndSpace();if ( line.Empty() )continue;// read the section, first entry is section, second is sizewhile ( !line.Empty() ){line = line.RemoveFirstSpace();if ( line.Empty() )break;if ( !insection && !insubsection ){CyString section = line.GetToken(";", 1, 1);insection = line.GetToken(";", 2, 2).ToInt();// search for the sectionscurrentSection = NULL;for ( CListNode<SComponantEntry> *node = dummyList.Front(); node; node = node->next() ){SComponantEntry *d = node->Data();if ( d->sSection.Compare(section) ){currentSection = node->Data();break;}}if ( !currentSection ){currentSection = new SComponantEntry;currentSection->sSection = section;dummyList.push_back(currentSection);}// we have some more ?line = line.DelToken(";", 1, 2);}else if ( !insubsection ){--insection;CyString section = line.GetToken(";", 1, 1);insubsection = line.GetToken(";", 2, 2).ToInt();currentSubSection = new SComponantEntry2;currentSubSection->sSection = section;currentSection->lEntries.push_back(currentSubSection);line = line.DelToken(";", 1, 2);}else{--insubsection;currentSubSection->lEntries.PushBack(line.Remove(' '), true);line = "";}}}delete lines;}File.remove();}// add the new entries for the shipsfor ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;// no dummies to add?if ( !s->pPackage->AnyComponents() )continue;// add each dummy to listfor ( CListNode<SComponent> *dNode = s->pPackage->GetComponents()->Front(); dNode; dNode = dNode->next() ){SComponent *dummy = dNode->Data();SComponantEntry *found = NULL;SComponantEntry2 *found2 = NULL;for ( CListNode<SComponantEntry> *eNode = dummyList.Front(); eNode; eNode = eNode->next() ){if ( eNode->Data()->sSection.Compare(CyString(dummy->sSection)) ){found = eNode->Data();break;}}if ( !found ){found = new SComponantEntry;found->sSection = dummy->sSection;dummyList.push_back(found);found2 = new SComponantEntry2;found2->sSection = dummy->sSection2;found->lEntries.push_back(found2);}// else check for the 2nd sectionelse{for ( CListNode<SComponantEntry2> *cNode = found->lEntries.Front(); cNode; cNode = cNode->next() ){if ( cNode->Data()->sSection.Compare(CyString(dummy->sSection2)) ){found2 = cNode->Data();break;}}if ( !found2 ){found2 = new SComponantEntry2;found2->sSection = dummy->sSection2;found->lEntries.push_back(found2);}else{bool f = false;for ( SStringList *strNode = found2->lEntries.Head(); strNode; strNode = strNode->next ){if ( dummy->sData.remove(' ').Compare(strNode->str.ToString()) ){f = true;break;}}if ( f )continue;}}found2->lEntries.PushBack(CyString(dummy->sData.remove(' ')));}}// finally, write the filestd::vector<CyString> lines;lines.push_back(CyString("// Components file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2));for ( SComponantEntry *dummy = dummyList.First(); dummy; dummy = dummyList.Next() ){lines.push_back("");lines.push_back(CyString("// Section: ") + dummy->sSection + " Entries: " + (long)dummy->lEntries.size());lines.push_back(dummy->sSection + ";" + CyString::Number(dummy->lEntries.size()) + ";");for ( CListNode<SComponantEntry2> *comp = dummy->lEntries.Front(); comp; comp = comp->next() ){lines.push_back(comp->Data()->sSection + ";" + (long)comp->Data()->lEntries.Count() + ";");for ( SStringList *str = comp->Data()->lEntries.Head(); str; str = str->next ){CyString cStr = str->str;cStr.RemoveEndSpace();cStr.RemoveChar(9);cStr.RemoveChar('\r');if ( cStr.Right(1) != ";" )cStr += ";";lines.push_back(cStr);}}}// write the file to diskCFileIO WriteFile(m_sTempDir + "/Components.txt");if ( WriteFile.WriteFile(&lines) ){this->PackFile(&WriteFile, "types\\Components.pck");WriteFile.remove();}}}bool CPackages::ReadGlobals(CyStringList &globals){int e = ExtractGameFile("types/Globals.pck", m_sTempDir);if ( e ){CFileIO File(((e == -1) ? "." : m_sTempDir) + "/Globals.txt");if ( File.exists() ){CyStringList *lines = File.ReadLinesStr();if ( lines ){int entries = -1;for ( SStringList *str = lines->Head(); str; str = str->next ){str->str.RemoveChar('\r');str->str.RemoveChar(9);str->str.RemoveFirstSpace();if ( str->str.Empty() )continue;if ( str->str[0] == '/' )continue;// remove commentsCyString l = str->str;if ( l.IsIn("/") )l = l.GetToken("/", 1, 1);if ( entries == -1 )entries = l.GetToken(";", 1, 1).ToInt();elseglobals.PushBack(l.GetToken(";", 1, 1), l.GetToken(";", 2, 2));}delete lines;return true;}}}return false;}void CPackages::CreateGlobals(){if ( m_lGlobals.Empty() )return; // no global settingsCyStringList globals;if ( ReadGlobals(globals) ){// apply out settingsfor ( SStringList *str = m_lGlobals.Head(); str; str = str->next ){SStringList *found = globals.FindString(str->str);if ( found )found->data = str->data;}// now write itCyStringList writeList;for ( SStringList *str = globals.Head(); str; str = str->next )writeList.PushBack(str->str + ";" + str->data + ";");// finally, write the filewriteList.PushFront(CyString::Number(writeList.Count()) + "; /globals amount", "");writeList.PushFront(CyString("// Globals file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2), "");CFileIO WriteFile(m_sTempDir + "/Globals.txt");if ( WriteFile.WriteFile(&writeList) ){this->PackFile(&WriteFile, "types/Globals.pck");WriteFile.remove();}}}void CPackages::CreateTShips(){// no ships ?if ( m_lGameShips.empty() )return;// get the cockpit list to match with ships turretsCyStringList Cockpits;CyStringList *cockpitList = this->CreateCockpits();if ( cockpitList ){for ( SStringList *str = cockpitList->Head(); str; str = str->next ){CyString id = str->str.GetToken(";", 19, 19);Cockpits.PushBack(id);}delete cockpitList;}CLinkList<SGameShip> shipOverrides;for ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){if ( node->Data()->iType != WARETYPE_ADDED || !node->Data()->pPackage )continue;if ( !node->Data()->pPackage->IsExistingShip() )continue;shipOverrides.push_back(node->Data());}// read the existing tships fileint e = ExtractGameFile("types/TShips.pck", m_sTempDir + "/TShips.txt");if ( e ){int fileType = 51;CyStringList tshipsList;// if we have no buffer, lets create oneCFileIO File;if ( File.Open((e == -1) ? "TShips.txt" : m_sTempDir + "/TShips.txt") ){int shiptext = SHIPSTARTTEXT;std::vector<CyString> *lines = File.ReadLines();if ( lines ){int count = -1;for ( int j = 0; j < (int)lines->size(); j++ ){CyString line(lines->at(j));if ( line[0] == '/' )continue;line.RemoveChar('\r');line.RemoveChar(9);line = line.RemoveFirstSpace();line = line.RemoveEndSpace();if ( line.Empty() )continue;if ( count == -1 ){fileType = line.GetToken(";", 1, 1).ToInt();count = line.GetToken(";", 2, 2).ToInt();}else{if ( line.Right(1) != ";" )line += ";";// check for any ship overridesbool added = false;if ( !shipOverrides.empty() ){CShipData shipData;if ( shipData.ReadShipData(line) ){for ( CListNode<SGameShip> *node = shipOverrides.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( !s->pPackage->GetShipID().Compare(shipData.sID.ToString()) )continue;s->iText = shiptext;if ( !s->pPackage->GetOriginalDescription() )shiptext += 2;s->iPos = tshipsList.Count();added = true;tshipsList.PushBack(CyString(s->pPackage->FormatShipData(&Cockpits, &s->iText, m_iGame)));shipOverrides.remove(node);break;}}}if ( !added )tshipsList.PushBack(line);--count;if ( count < 0 )break;}}delete lines;}File.remove();// assign the ship bufferif ( !m_iShipBuffer )m_iShipBuffer = tshipsList.Count() + 15;// there seems to be too many additional entries, we have no choise but to change the bufferelse if ( m_iShipBuffer <= tshipsList.Count() )m_iShipBuffer = tshipsList.Count() + 15;CyString bufferStart;if ( m_iGame == GAME_X3 )bufferStart = "0;0;0;0;0;2;499999;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0.049988;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;4;1;0;0;0;0;0;0;2092;1;1;-1;0;0;1;1;0;1;1;1;0;0;0;;-1;0;0;0;0;0;0;0;0;0;";elsebufferStart = "0;0;0;0;0;SG_SH_M5;499999;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0.049988;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;4;1;0;0;0;0;0;0;OBJ_BEACON;1;1;-1;0;0;1;1;0;1;1;1;0;0;0;;-1;0;0;0;0;0;0;0;0;0;";// add the buffers nowfor ( int i = tshipsList.Count(); i < m_iShipBuffer; i++ )tshipsList.PushBack(bufferStart + "SHIP_BUFFER;");// now lets add our tships linefor ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->pPackage && s->pPackage->IsExistingShip() )continue;s->iPos = tshipsList.Count();if ( s->iType == WARETYPE_ADDED && s->pPackage ){s->iText = shiptext;if ( !s->pPackage->GetOriginalDescription() )shiptext += 2;tshipsList.PushBack(CyString(s->pPackage->FormatShipData(&Cockpits, &s->iText, m_iGame)));}else if ( s->iType == WARETYPE_DELETED )tshipsList.PushBack(bufferStart + "SHIP_DELETED;");else if ( s->iType == WARETYPE_DISABLED )tshipsList.PushBack(bufferStart + "SHIP_DISABLED;");elsetshipsList.PushBack(bufferStart + "SHIP_SPACER;");}// finally, write the filetshipsList.PushFront(CyString::Number(fileType) + ";" + CyString::Number(tshipsList.Count()) + ";", "");tshipsList.PushFront(CyString("// TShips file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2), "");CFileIO WriteFile(m_sTempDir + "/TShips.txt");if ( WriteFile.WriteFile(&tshipsList) ){this->PackFile(&WriteFile, "types/TShips.pck");WriteFile.remove();}}}}bool CPackages::PackFile(CyString filename){// compress the fileCFileIO File(filename);size_t fileSize;char *fileData = File.ReadToData(&fileSize);if ( fileData && fileSize){size_t newFileSize;unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);if ( pckData ){CyString ext = "pck";if ( File.CheckFileExtension("bob") )ext = "pbb";else if ( File.CheckFileExtension("bod") )ext = "pbd";CFileIO pckFile(File.ChangeFileExtension(ext));if ( !CDirIO(pckFile.GetDir()).Exists() )CDirIO(pckFile.GetDir()).Create();pckFile.WriteData((char *)pckData, newFileSize);return true;}}return false;}bool CPackages::UnPackFile(CyString filename, bool checkxml){// compress the fileCFileIO File(filename);size_t fileSize;char *fileData = File.ReadToData(&fileSize);if ( fileData && fileSize){size_t newFileSize;unsigned char *pckData = UnPCKData((unsigned char *)fileData, fileSize, &newFileSize, true);if ( pckData ){CyString ext = "txt";if ( File.CheckFileExtension("pbb") )ext = "bob";else if ( File.CheckFileExtension("pbd") )ext = "bod";CFileIO pckFile(File.ChangeFileExtension(ext));if ( !CDirIO(pckFile.GetDir()).Exists() )CDirIO(pckFile.GetDir()).Create();pckFile.WriteData((char *)pckData, newFileSize);// check for xml and renameif ( checkxml ){int readmaxlines = 20;bool isxml = false;do {CyString line = pckFile.readEndOfLine();if ( line.IsIn("<language id=") ){isxml = true;break;}else if ( line.IsIn("<page id=") ){isxml = true;break;}else if ( line.IsIn("<?xml") || line.IsIn("<script>") ){isxml = true;break;}--readmaxlines;if ( readmaxlines <= 0 )break;} while (pckFile.isOpened());if ( pckFile.isOpened() )pckFile.StopRead();if ( isxml )pckFile.Rename(pckFile.ChangeFileExtension("xml"));}return true;}}return false;}bool CPackages::PackFile(CFileIO *File, CyString filename){filename = filename.FindReplace("\\", "/");if ( m_iGame == GAME_X3 ){CCatFile catFile;int error = catFile.Open(m_sCurrentDir + "/mods/PluginManager.cat", this->GetAddonDir(), CATREAD_CATDECRYPT, true);if ( error == CATERR_NONE || error == CATERR_CREATED ){// it it wrote ok, remove the old onesif ( !catFile.AppendFile(File->GetFullFilename().ToString(), filename.ToString(), true, true) )return false;return true;}}else{// compress the filesize_t fileSize;char *fileData = CFileIO(File->GetFullFilename()).ReadToData(&fileSize);if ( fileData && fileSize){size_t newFileSize;unsigned char *pckData = PCKData((unsigned char *)fileData, fileSize, &newFileSize, true);if ( pckData ){// if ( !this->GetAddonDir().Empty() && CCatFile::IsAddonDir(filename) )// filename = this->GetAddonDir() + "/" + filename;CFileIO pckFile(m_sCurrentDir + "/" + filename);if ( !CDirIO(pckFile.GetDir()).Exists() )CDirIO(pckFile.GetDir()).Create();pckFile.WriteData((char *)pckData, newFileSize);this->AddCreatedFile(pckFile.GetFullFilename());return true;}}}return false;}CyStringList *CPackages::CreateCockpits(){// first check we have any shipsif ( m_lGameShips.empty() || !this->CountPackages(TYPE_XSP, true) )return NULL;CyStringList *cockpitList = new CyStringList;// now extract the existing cockpitsint fileType = 51;int e = ExtractGameFile("types/TCockpits.pck", m_sTempDir + "/TCockpits.txt");if ( e ){// read the dummiesCFileIO File;if ( File.Open((e == -1) ? "TCockpits.txt" : m_sTempDir + "/TCockpits.txt") ){CyStringList *lines = File.ReadLinesStr();if ( lines ){int count = -1;for ( SStringList *str = lines->Head(); str; str = str->next ){CyString line(str->str);line.RemoveChar('\r');line.RemoveChar(9);line = line.RemoveFirstSpace();line = line.RemoveEndSpace();if ( line.Empty() )continue;if ( line[0] == '/' )continue;if ( count == -1 ){fileType = line.GetToken(";", 1, 1).ToInt();count = line.GetToken(";", 2, 2).ToInt();}else{while ( !line.Empty() ){CyString data = line.GetToken(";", 1, 19);cockpitList->PushBack(data + ";");line = line.DelToken(";", 1, 19);--count;if ( count < 1 )break;}}}delete lines;}File.remove();}// now add the new onesfor ( CListNode<SGameShip> *node = m_lGameShips.Front(); node; node = node->next() ){SGameShip *s = node->Data();if ( s->iType != WARETYPE_ADDED || !s->pPackage )continue;if ( !s->pPackage->AnyCockpits() )continue;for ( CListNode<SCockpit> *cn = s->pPackage->GetCockpits()->Front(); cn; cn = cn->next() ){bool foundEntry = false;CyString cockpitStr = cn->Data()->sCockpit;// search for matching game entryfor ( CListNode<SWeaponMask> *wm = cn->Data()->lWeaponMask.Front(); wm; wm = wm->next() ){if ( wm->Data()->iGame == (m_iGame - 1) ){if ( wm->Data()->iMask != -1 )cockpitStr = cockpitStr.RepToken(";", 9, CyString::Number(wm->Data()->iMask));foundEntry = true;break;}}bool found = false;for ( SStringList *str = cockpitList->Head(); str; str = str->next ){if ( str->str.GetToken(";", 19, 19).Compare(CyString(cn->Data()->sCockpit.token(";", 19))) ){// only replace existing entry if we have sepeperate weapon masks setif ( foundEntry )str->str = cockpitStr;found = true;break;}}if ( !found )cockpitList->PushBack(cockpitStr);}}// finally, write the filecockpitList->PushFront(CyString::Number(fileType) + ";" + CyString::Number(cockpitList->Count()) + ";", "");cockpitList->PushFront(CyString("// TCockpits file, created by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2), "");CFileIO WriteFile(m_sTempDir + "/TCockpits.txt");if ( WriteFile.WriteFile(cockpitList) ){this->PackFile(&WriteFile, "types\\TCockpits.pck");WriteFile.remove();}// remove those entryscockpitList->PopFront();cockpitList->PopFront();}return cockpitList;}CBaseFile *CPackages::FindScriptByAuthor(CyString author, CBaseFile *prev){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){CBaseFile *p = node->Data();if ( prev ){if ( p == prev )prev = NULL;continue;}if ( p->author().Compare(author.ToString()) )return p;}return NULL;}CBaseFile *CPackages::LoadPackagerScript(CyString filename, int compression, CyString (*askFunc)(CyString), CyStringList *malformedLines, CyStringList *unknownCommands, CyStringList *variables){// check the file existsif ( !CFileIO(filename).ExistsOld() )return NULL;// read all the linesCFileIO File(filename);std::vector<CyString> *lines = File.ReadLines();if ( !lines )return NULL;CBaseFile *package = NULL;// filter out blank lines and commentsCyStringList fileData;for ( int i = 0; i < (int)lines->size(); i++ ){CyString line(lines->at(i));// dont include empty lines (whitespace)if ( line.Empty() )continue;// filter out any spaces, tabs in frontline.RemoveChar('\t');line.RemoveChar('\r');CyString linenospace = line;linenospace.RemoveFirstSpace();if ( linenospace.Empty() )continue;// check for any commentsif ( linenospace.Left(2) == "//" )continue;if ( linenospace[0] == '#' )continue;// all commands start with a keyword followed by a colon, if one doesn't exist, it cant be a valid lineif ( !line.IsIn(':') ){// there are some exeptions, and these are one word entrys onlyline.RemoveEndSpace();if ( line.IsIn(" ") ){if ( malformedLines )malformedLines->PushBack(line, CyString::Number(i));continue;}}// check for the type lineif ( !package && line.GetToken(":", 1, 1).Compare("FileType") ){CyString sFileType = line.GetToken(":", 2).RemoveFirstSpace();if ( sFileType.Compare("Ship") )package = new CXspFile();else if ( sFileType.Compare("Script") )package = new CSpkFile();else if ( sFileType.Compare("Base") )package = new CBaseFile();}fileData.PushBack(line, CyString::Number(i));}delete lines;// assume its a script if no type is set (all old versions are scripts)if ( !package )package = new CSpkFile();if ( compression != -1 )package->SetDataCompression(compression);CyString ftpaddr;CyString ftpuser;CyString ftppass;CyString ftpdir;// now lets read the rest of the dayCyStringList listVaribles;for ( SStringList *strNode = fileData.Head(); strNode; strNode = strNode->next ){CyString first = strNode->str.GetToken(":", 1, 1);CyString rest = strNode->str.GetToken(":", 2).RemoveFirstSpace();if ( first.Compare("Varible") || first.Compare("Variable") )listVaribles.PushBack(rest.GetToken(" ", 1, 1), rest.GetToken(" ", 2), true);else{// replace variablesif ( rest.IsIn("$") ){for ( SStringList *strVar = listVaribles.Head(); strVar; strVar = strVar->next ){if ( rest.IsIn(strVar->str) )rest.FindReplace(strVar->str, strVar->data);}if ( variables ){for ( SStringList *strVar = variables->Head(); strVar; strVar = strVar->next ){if ( rest.IsIn(strVar->str) )rest.FindReplace(strVar->str, strVar->data);}}}//check for the built in variblesif ( rest.IsIn("$ASK") ){CyString replace = "$ASK";CyString result;if ( askFunc )result = askFunc(first);if ( rest.IsIn("$ASK(") ){replace = rest.GetToken("$ASK(", 2).GetToken(")", 1, 1);if ( result.Empty() )result = replace;replace = CyString("$ASK(") + replace + ")";}if ( !result.Empty() )rest.FindReplace(replace, result);}// todays dateif ( rest.IsIn("$DATE") ){time_t now;time(&now);struct tm *timeinfo = localtime(&now);CyString result = CyString::Number(timeinfo->tm_mday) + "." + CyString::Number(timeinfo->tm_mon + 1) + "." + CyString::Number(timeinfo->tm_year + 1900);if ( !result.Empty() )rest.FindReplace("$DATE", result);}// mydocumentsif ( rest.IsIn("$MYDOCUMENTS") ){if ( !m_sMyDoc.Empty() )rest.FindReplace("$MYDOCUMENTS", m_sMyDoc);}// current pathif ( rest.IsIn("$PATH") ){CyString currentDir = CFileIO(filename).GetDir();if ( !currentDir.Empty() )rest.FindReplace("$PATH", currentDir);}// now parse the rest of the valuesif ( first.Compare("FtpUpload") )ftpaddr = rest.GetToken(" ", 1, 1) + ":" + rest.GetToken(" ", 2, 2);else if ( first.Compare("FtpUser") )ftpuser = rest;else if ( first.Compare("FtpPass") )ftppass = rest;else if ( first.Compare("FtpDir") )ftpdir = rest;else if ( !package->LoadPackageData(first.ToString(), rest.ToString()) ){if ( unknownCommands )unknownCommands->PushBack(first, rest);}}}if ( package->filename().empty() )package->LoadPackageData("AutoSave", "$AUTOSAVE");if ( !ftpaddr.Empty() ){if ( !ftpuser.Empty() ){if ( !ftppass.Empty() )ftpaddr = ftpuser + ":" + ftppass + "@" + ftpaddr;elseftpaddr = ftpuser + "@" + ftpaddr;}if ( !ftpdir.Empty() )ftpaddr += ftpdir;package->SetFtpAddr(ftpaddr);}return package;}CyString CPackages::GetLanguageName(){return CPackages::ConvertLanguage(m_iLanguage);}CyString CPackages::ConvertLanguage(int lang){switch ( lang ){case 44:return "English";case 49:return "German";case 7:return "Russian";case 33:return "French";case 30:return "Greek";case 31:return "Dutch";case 32:return "Belgian";case 34:return "Spanish";case 36:return "Hungarian";case 39:return "Italian";case 40:return "Romanian";case 41:return "Swiss";case 42:return "Czech";case 43:return "Austrian";case 45:return "Danish";case 46:return "Swedish";case 47:return "Norweigen";case 48:return "Polish";}return CyString::Number(lang);}bool CPackages::CheckAccessRights(CyString dir){if ( dir.Empty() )dir = m_sCurrentDir;// write a file, then read the contentsCFileIO File(dir + "/accessrightscheck.dat");// check if file exists and remove itif ( File.exists() ){// if we cant remove it, we dont have enough rightsif ( !File.remove() )return false;// if its still there, we dont have enough rightsif ( File.exists() )return false;}// now create the fileif ( !File.WriteString("testing access rights") )return false;// now check it existsif ( !File.exists() )return false;// now read the file for the correct contentsCyStringList *lines = File.ReadLinesStr();if ( !lines )return false;// check that one of the lines is correctfor ( SStringList *s = lines->Head(); s; s = s->next ){if ( s->str == "testing access rights" ){delete lines;return true;}}delete lines;return false;}bool CPackages::LoadShipData(CyString file, CyStringList *list){CFileIO File;bool deleteFile = false;// load from cat fileif ( CFileIO(file).CheckFileExtension("cat") ){CCatFile cat;if ( cat.Open(file, this->GetAddonDir(), CATREAD_CATDECRYPT, false) != CATERR_NONE )return false;if ( !cat.ExtractFile("types\\TShips.pck", m_sTempDir + "/tships.txt") )return false;File.Open(m_sTempDir + "/tships.txt");deleteFile = true;}// otherwise its a normal fileelse if ( CFileIO(file).CheckFileExtension("pck") ){C_File f(file);if ( !f.ReadFromFile() )return false;f.UnPCKFile();f.SetFilename(m_sTempDir + "/tships.txt");if ( !f.WriteFilePointer() )return false;File.Open(m_sTempDir + "/tships.txt");deleteFile = true;}elseFile.Open(file);if ( !File.exists() )return false;bool ret = false;CyStringList *lines = File.ReadLinesStr();if ( lines ){bool readFirst = false;for ( SStringList *str = lines->Head(); str; str = str->next ){if ( str->str.Empty() )continue;str->str.RemoveChar('\r');str->str.RemoveChar(9);str->str.RemoveFirstSpace();if ( str->str.Empty() )continue;if ( str->str[0] == '/' || str->str[0] == '#' )continue;if ( !readFirst )readFirst = true;else{CyString t = str->str.GetToken(";", -2);while ( t.Right(1) == ";" )t.Truncate((int)t.Length() - 1);list->PushBack(t, str->str);}}delete lines;ret = true;}if ( deleteFile )File.remove();return ret;}CyString CPackages::ReadShipData(CyString file, CyString id){CyStringList *list = this->LoadShipData(file);if ( !list )return NullString;CShipData data;for ( SStringList *str = list->Head(); str; str = str->next ){if ( str->str.Compare(id) ){delete list;return str->data;}}delete list;return NullString;}CyStringList *CPackages::LoadShipData(CyString file){CyStringList *list = new CyStringList;if ( this->LoadShipData(file, list) )return list;delete list;return NULL;}bool CPackages::ReadTextPage(CyString file, CyStringList *list, bool search, int page){CFileIO File;bool deleteFile = false;// read all text files from modif ( CFileIO(file).CheckFileExtension("cat") ){bool done = false;CCatFile cat;if ( cat.Open(file, this->GetAddonDir(), CATREAD_CATDECRYPT, false) != CATERR_NONE )return false;// extract 1 at a timefor ( int i = 0; i < cat.GetNumFiles(); i++ ){SInCatFile *f = cat.GetFile(i);CyString sF = f->sFile;// is a text filesF = sF.FindReplace("\\", "/");if ( !sF.GetToken("/", 1, 1).Compare("t") )continue;CyString baseFile = CFileIO(sF.ToString()).baseName();// check languageint lang = 0;if ( baseFile.FindPos("-L") != -1 ) // new language filelang = baseFile.Right(3).ToInt();else{baseFile.Truncate((int)baseFile.Length() - 4);lang = baseFile.ToInt();}if ( lang != m_iLanguage )continue;// now extract and parseif ( cat.ExtractFile(f->sFile, m_sTempDir + "/" + CFileIO(f->sFile).baseName() + ".xml") ){if ( this->ReadTextPage(m_sTempDir + "/" + CFileIO(f->sFile).baseName() + ".xml", list, search, page) )done = true;}}return done;}// otherwise its a normal fileelse if ( CFileIO(file).CheckFileExtension("pck") ){C_File f(file);if ( !f.ReadFromFile() )return false;f.UnPCKFile();f.SetFilename(m_sTempDir + "/textfile.xml");if ( !f.WriteFilePointer() )return false;File.Open(m_sTempDir + "/textfile.xml");deleteFile = true;}elseFile.Open(file);if ( !File.exists() )return false;// open and read fileCyStringList *lines = File.ReadLinesStr();if ( !lines )return false;bool inPage = false;for ( SStringList *str = lines->Head(); str; str = str->next ){// search for pageif ( !inPage ){if ( str->str.FindPos("<page") > -1 ){// find the page idint pos = str->str.FindPos("\"");if ( pos > -1 ){int endpos = str->str.FindPos("\"", pos + 1);if ( endpos > -1 ){CyString p = str->str.Mid(pos + 2, endpos - pos - 1);if ( p.Length() > 4 )p = p.Right(4);int checkPage = p.ToInt();if ( checkPage == page )inPage = true;}}}}// add each idelse{if ( str->str.FindPos("</page") > -1 )break;if ( str->str.FindPos("<t id") > -1 ){int pos = str->str.FindPos("\"");if ( pos > -1 ){int endpos = str->str.FindPos("\"", pos + 1);if ( endpos > -1 ){int id = str->str.Mid(pos + 2, endpos - pos - 1).ToInt();pos = str->str.FindPos(">", endpos);if ( pos > -1 ){++pos;endpos = str->str.FindPos("</", pos);if ( endpos > -1 ){CyString text = str->str.Mid(pos + 1, endpos - pos);while ( text.FindPos('(') != -1 && text.FindPos(')') != -1 ){int s = text.FindPos('(');text = text.Erase(s, text.FindPos(')') - s + 1);}list->PushBack(CyString::Number(id), text, search);}}}}}}}delete lines;return true;}CyStringList *CPackages::ReadTextPage(CyString file, bool search, int page){CyStringList *list = new CyStringList;if ( this->ReadTextPage(file, list, search, page) )return list;delete list;return NULL;}int CPackages::AdjustFileType(CyString file, int filetype){CFileIO File(file);CyString dir = File.GetDirIO().TopDir();CyString basename = File.baseName();// mod filesif ( File.CheckFileExtension("cat") || File.CheckFileExtension("dat") )return FILETYPE_MOD;// check for text filesif ( File.GetFilename().IsIn("-L") && File.GetFilename().Left(4).ToInt() )return FILETYPE_TEXT;if ( File.baseName().Compare("conversations") )return FILETYPE_TEXT;if ( basename.Length() <= 4 && basename.IsNumber() && (File.CheckFileExtension("xml") || File.CheckFileExtension("pck")) )return FILETYPE_TEXT;// X2/X3 text fileif ( basename.Length() >= 5 && basename.Length() <= 8 && ((int)File.baseName()) )return FILETYPE_TEXT;if ( filetype == FILETYPE_TEXT ) // should no longer be anything textreturn FILETYPE_SCRIPT;if ( File.CheckFileExtension("wav") || File.CheckFileExtension("mp3") )return FILETYPE_SOUND;return filetype;}void CPackages::RemoveFailedFiles(){for ( SStringList *str = m_lNonRemovedFiles.Head(); str; str = str->next ){if ( CFileIO::Remove(str->str.ToString()) )str->remove = true;}m_lNonRemovedFiles.RemoveMarked();}CXspFile *CPackages::extractShip(const Utils::String &sCatFile, const Utils::String &sId, CProgressInfo *progress){CVirtualFileSystem *pVfs = new CVirtualFileSystem();if ( !pVfs->addMod(sCatFile) ) {delete pVfs;return NULL;}CXspFile *newShip = new CXspFile;if ( !newShip->extractShip(pVfs, sId, progress) ) {delete newShip;newShip = NULL;}delete pVfs;return newShip;}CyStringList *CPackages::GetMergedFiles(CCatFile *cat1, CCatFile *cat2){CyStringList *list = new CyStringList;// first add all files from the "primary" modfor ( SInCatFile *f = cat1->GetFiles()->First(); f; f = cat1->GetFiles()->Next() )list->PushBack(f->sFile.findreplace("\\", "/"), "1");// now add the ones from the secondaryfor ( SInCatFile *f = cat2->GetFiles()->First(); f; f = cat2->GetFiles()->Next() ){CyString sFile = f->sFile.findreplace("\\", "/");// if its found on the 2nd list, dont add, just adjust the typeSStringList *found = list->FindString(sFile);if ( found )found->data = "-1"; // found in bothelselist->PushBack(sFile, "2");}return list;}bool CPackages::CanWeMerge(const Utils::String &file) const{return CModDiff::CanBeDiffed(file);}bool CPackages::NeedToMerge(CyString file){CyString firstDir = file.GetToken("/", 1, 1);if ( firstDir.Compare("t") )return true;if ( firstDir.Compare("types") )return true;if ( firstDir.Compare("maps") )return true;return false;}bool CPackages::MergeMods(CCatFile *mod1, CCatFile *mod2, CyString outFile, CyStringList *cantMerge){CyStringList *list = this->GetMergedFiles(mod1, mod2);if ( !list )return false;CCatFile newCat;if ( newCat.Open(outFile, this->GetAddonDir()) != CATERR_CREATED )return false;// add all the files to the new mod firstCyStringList conflicts;for ( SStringList *str = list->Head(); str; str = str->next ){int status = str->data.ToInt();if ( status == 1 ){if ( !newCat.WriteFromCat(mod1, str->str) ){if ( cantMerge )cantMerge->PushBack(str->str, "1");}}else if ( status == 2 ){if ( !newCat.WriteFromCat(mod2, str->str) ){if ( cantMerge )cantMerge->PushBack(str->str, "2");}}else if ( status == -1 ){if ( this->NeedToMerge(str->str) ){if ( this->CanWeMerge(str->str.ToString()) )conflicts.PushBack(str->str);else if ( cantMerge )cantMerge->PushBack(str->str, "-1");}else{if ( !newCat.WriteFromCat(mod1, str->str) ){if ( cantMerge )cantMerge->PushBack(str->str, "1");}}}}delete list;/*Merging Files* Text Files: Join all text entries into a single file (excluding page 17)* Weapons: TBullets and TLaser (grab matching entrys from text files and adjust ids)*/// new merge the conflicting files// first the text files// CyStringList *text = this->MergeTextFiles(conflicts, mod1, mod2);// delete text;// write the cat file when we're doneif ( !newCat.WriteCatFile() )return false;return true;}/*** Gets the file list from a mod that might have compatability problems** This includes all types and text files** Returns true if it finds any files*/bool CPackages::GetModCompatabilityList(C_File *file, CyStringList *list){// not a valid fileif ( !file ) return false;if ( file->GetFileType() != FILETYPE_MOD ) return false;if ( !file->GetFileExt().Compare("cat") ) return false;// we need to read the file list for the modCCatFile cat;if ( cat.Open(file->GetFilePointer(), this->GetAddonDir(), CATREAD_JUSTCONTENTS, false) == CATERR_NONE ){for ( int i = 0; i < cat.GetNumFiles(); i++ ){SInCatFile *f = cat.GetFile(i);CyString filename = f->sFile;filename = filename.FindReplace("\\", "/");bool found = false;if ( filename.Left(2).Compare("t/") || filename.Left(6).Compare("types/") )found = true;else if ( filename.Left(8).Compare("addon/t/") || filename.Left(12).Compare("addon/types/") )found = true;if ( found ) {if ( list )list->PushBack(filename, CyString(f->lSize));elsereturn true;}}}if ( list && !list->Empty() )return true;return false;}/*** Gets the files that are not compatable with each other** Returns true if theres any files that are not compatable** If list is specified, fills up with all files that were found*/bool CPackages::CheckCompatabilityBetweenModFiles(C_File *from, C_File *to, CyStringList *list){// not a valid fileif ( !from || !to ) return false;if ( from->GetFileType() != FILETYPE_MOD ) return false;if ( to->GetFileType() != FILETYPE_MOD ) return false;if ( !from->GetFileExt().Compare("cat") ) return false;if ( !to->GetFileExt().Compare("cat") ) return false;// get file lists from each fileCyStringList fromList;if ( GetModCompatabilityList(from, &fromList) ){CyStringList toList;if ( GetModCompatabilityList(to, &toList) ){// both have files we need to check, compare themfor ( SStringList *str = fromList.Head(); str; str = str->next ){CyString fromFile = str->str;fromFile = fromFile.FindReplace("\\", "/");fromFile = fromFile.FindReplace("//", "/");for ( SStringList *toStr = toList.Head(); toStr; toStr = toStr->next ){CyString toFile = toStr->str;toFile = toFile.FindReplace("\\", "/");toFile = toFile.FindReplace("//", "/");if ( fromFile.Compare(toFile) ){if ( list )list->PushBack(from->GetFilename() + "::" + str->str, to->GetFilename() + "::" + toStr->str);elsereturn true;}}}}}if ( list && !list->Empty() )return true;return false;}bool CPackages::CheckCompatabilityBetweenMods(CBaseFile *from, CBaseFile *to, CyStringList *list){if ( !from || !to ) return false;if ( !from->IsEnabled() || !to->IsEnabled() ) return false;if ( !from->AnyFileType(FILETYPE_MOD) ) return false;if ( !to->AnyFileType(FILETYPE_MOD) ) return false;if ( from == to ) return false; // cant have incompatabilities to itselfint count = 0;for ( C_File *f = from->GetFirstFile(FILETYPE_MOD); f; f = from->GetNextFile(f) ){if ( !f->IsFakePatch() ) continue;if ( f->GetFileExt().Compare("dat") ) continue;for ( C_File *compareFile = to->GetFirstFile(FILETYPE_MOD); compareFile; compareFile = to->GetNextFile(compareFile) ){if ( compareFile == f ) continue; // same file we're checking againstif ( !compareFile->IsFakePatch() ) continue;if ( compareFile->GetFileExt().Compare("dat") ) continue;// now we have to files to compareif ( CheckCompatabilityBetweenModFiles(f, compareFile, list) )++count;}}if ( count )return true;return false;}int CPackages::CheckCompatabilityAgainstPackages(CBaseFile *newFile, CyStringList *list, CLinkList<CBaseFile> *packages){if ( !newFile->IsEnabled() ) return 0;if ( !newFile->AnyFileType(FILETYPE_MOD) ) return 0;// we need to extract all mod filesfor ( CListNode<C_File> *fNode = newFile->GetFileList()->Front(); fNode; fNode = fNode->next() ){C_File *f = fNode->Data();if ( f->GetFileType() != FILETYPE_MOD ) continue;if ( !f->IsFakePatch() ) continue;if ( !f->CheckFileExt("cat") ) continue;if ( newFile->ExtractFile(f, m_sTempDir) )f->SetFullDir(m_sTempDir);}// compare mod files against all installed packagesint count = 0;for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){if ( !node->Data() ) continue;CBaseFile *p = node->Data();if ( !p->IsEnabled() ) continue;if ( !p->AnyFileType(FILETYPE_MOD) ) continue;if ( this->IsSamePackage(p, newFile) ) continue; // dont include selfif ( CheckCompatabilityBetweenMods(newFile, p, list) ){++count;if ( packages && !packages->FindData(p) )packages->push_back(p);}}for ( CListNode<C_File> *fNode = newFile->GetFileList()->Front(); fNode; fNode = fNode->next() ){C_File *f = fNode->Data();CFileIO::Remove(f->GetFilePointer().ToString());f->SetFullDir("");}return count;}bool CPackages::IsSamePackage(CBaseFile *p1, CBaseFile *p2){if ( !p1 || !p2 ) return false;if ( p1 == p2 ) return true;if ( p1->name().Compare(p2->name()) && p1->author().Compare(p2->author()) )return true;return false;}void CPackages::ApplyFakePatchOrder(CyStringList *list){if ( !list ) return;m_lFakePatchOrder.Clear();for ( SStringList *str = list->Head(); str; str = str->next )m_lFakePatchOrder.PushBack(str->str, str->data);}SAvailablePackage *CPackages::CreateAvailablePackageData(CBaseFile *package){if ( !package ) return NULL;SAvailablePackage *p = new SAvailablePackage;for ( CListNode<SGameCompat> *node = package->GetGameCompatabilityList()->Front(); node; node = node->next() ) {SGameCompat *gc = new SGameCompat;gc->iGame = node->Data()->iGame;gc->iVersion = node->Data()->iVersion;gc->sVersion = node->Data()->sVersion;p->lGames.push_back(gc);}p->bSigned = package->IsSigned();p->iChanging = package->gameChanging();p->iEase = package->easeOfUse();p->iPluginType = package->pluginType();p->iRec = package->recommended();p->iScriptType = -1;if ( package->GetType() == TYPE_XSP )p->iType = PACKAGETYPE_SHIP;else if ( package->IsMod() )p->iType = PACKAGETYPE_MOD;else{p->iType = ((CSpkFile *)package)->GetPackageType();p->iScriptType = ((CSpkFile *)package)->GetScriptType();}p->sAuthor = package->author();p->sDesc = package->description().findReplace("\n", "::newline::");p->sName = package->name();p->sUpdated = package->creationDate();p->sVersion = package->version();p->sFilename = CFileIO(package->filename()).GetFilename();return p;}CyString CPackages::FormatAvailablePackageData(CBaseFile *package){SAvailablePackage *p = CPackages::CreateAvailablePackageData(package);CyString ret = CPackages::FormatAvailablePackageData(p);delete p;return ret;}CyString CPackages::FormatAvailablePackageData(SAvailablePackage *package){CyString ret = (long)package->iType;CyString gameCompat;for ( CListNode<SGameCompat> *node = package->lGames.Front(); node; node = node->next() ) {if ( !gameCompat.Empty() )gameCompat += "!";gameCompat += CyString::Number(node->Data()->iGame);}if ( gameCompat.Empty() )gameCompat = "0";ret.AddToken("::", gameCompat);ret.AddToken("::", package->sName);ret.AddToken("::", package->sAuthor);ret.AddToken("::", package->sVersion);ret.AddToken("::", package->sUpdated);ret.AddToken("::", package->sFilename);ret.AddToken("::", CyString::Number(package->iEase));ret.AddToken("::", CyString::Number(package->iChanging));ret.AddToken("::", CyString::Number(package->iRec));ret.AddToken("::", CyString::Number(package->iPluginType));ret.AddToken("::", CyString::Number(package->iScriptType));ret.AddToken("::", (package->bSigned) ? "1" : "0");ret.AddToken("::", package->sDesc);return ret;}void CPackages::ParseAvailablePackage(CyString str, CyString webaddress){// first check gameint game = str.GetToken("::", 2, 2).ToInt();if ( game && m_iGame && m_iGame != game )return;int num = 0;CyString *tok = str.SplitToken("::", &num);if ( !num || !tok ) return;if ( num < 7 ) { CLEANSPLIT(tok, num); return; }SAvailablePackage *p = new SAvailablePackage;p->iType = tok[0].ToInt();p->bSigned = false;CyString gameCompat = tok[1];if ( gameCompat.IsIn("!") ) {int maxSplit = 0;CyString *games = gameCompat.SplitToken("!", &maxSplit);if ( games && maxSplit ) {for ( int i = 0; i < maxSplit; i++ ) {SGameCompat *gc = new SGameCompat;gc->iVersion = 0;gc->iGame = games[i].ToInt();p->lGames.push_back(gc);}}CLEANSPLIT(games, maxSplit);}else {SGameCompat *gc = new SGameCompat;gc->iVersion = 0;gc->iGame = gameCompat.ToInt();p->lGames.push_back(gc);}p->sName = tok[2];p->sAuthor = tok[3];p->sVersion = tok[4];p->sUpdated = tok[5];p->sFilename = tok[6];if ( !webaddress.Empty() )p->sFilename = webaddress + "/" + p->sFilename;p->iChanging = p->iEase = p->iPluginType = p->iRec = p->iScriptType = -1;if ( num >= 12 ){p->iEase = tok[7].ToInt();p->iChanging = tok[8].ToInt();p->iRec = tok[9].ToInt();p->iPluginType = tok[10].ToInt();p->iScriptType = tok[11].ToInt();if ( num > 12 ) {if ( num > 13 ) {p->sDesc = str.GetToken("::", 14);p->bSigned = str.GetToken("::", 13).ToBool();}elsep->sDesc = str.GetToken("::", 13);}}else if ( num > 7 )p->sDesc = str.GetToken("::", 8);if ( !p->sDesc.Empty() )p->sDesc.FindReplace("::newline::", "\\n");AddAvailablePackage(p);CLEANSPLIT(tok, num);}SAvailablePackage *CPackages::FindAvailablePackage(CyString &filename){for ( CListNode<SAvailablePackage> *node = m_lAvailablePackages.Front(); node; node = node->next() ){if ( node->Data()->sFilename.Compare(filename) )return node->Data();}return NULL;}bool CPackages::AddAvailablePackage(SAvailablePackage *package){if ( !package->lGames.empty() ) {bool found = false;for ( CListNode<SGameCompat> *node = package->lGames.Front(); node; node = node->next() ) {if ( !node->Data()->iGame || node->Data()->iGame == m_iGame ) {found = true;break;}}if ( !found )return false;}SAvailablePackage *p = FindAvailablePackage(package->sFilename);if ( p )m_lAvailablePackages.remove(p);m_lAvailablePackages.push_back(package);return true;}bool CPackages::AnyAvailablePackages(int type){if ( type == -1 ) return !m_lAvailablePackages.empty();for ( CListNode<SAvailablePackage> *node = m_lAvailablePackages.Front(); node; node = node->next() ){if ( node->Data()->iType == type )return true;}return false;}int CPackages::FindAllServers(CyStringList *list){for ( CListNode<CBaseFile> *node = m_lPackages.Front(); node; node = node->next() ){if ( !node->Data()->webAddress().empty() )list->PushBack(CyString(node->Data()->webAddress()), true);if ( node->Data()->AnyWebMirrors() ){for ( SStringList *str = node->Data()->GetWebMirrors()->Head(); str; str = str->next )list->PushBack(str->str, true);}}return list->Count();}void CPackages::ReadArchiveData(CyString filename, CBaseFile *archive){size_t size;char *data = CFileIO(filename).ReadToData(&size);if ( size && data )ReadArchiveData(data, size, archive);}void CPackages::ReadArchiveData(const char *buf, size_t len, CBaseFile *archive){CyString data(buf);int max;CyString *str = data.SplitToken("\n", &max);if ( str && max ){for ( int i = 0; i < max; i++ ){CyString line = str[i];if ( line.Empty() )continue;// filter out any spaces, tabs in frontline.RemoveChar('\t');line.RemoveChar('\r');CyString linenospace = line;linenospace.RemoveFirstSpace();if ( linenospace.Empty() )continue;// check for any commentsif ( linenospace.Left(2) == "//" )continue;if ( linenospace[0] == '#' )continue;// all commands start with a keyword followed by a colon, if one doesn't exist, it cant be a valid lineif ( !line.IsIn(':') )continue;CyString first = line.GetToken(":", 1, 1);CyString rest = line.GetToken(":", 2).RemoveFirstSpace();CyString checkType = first;bool shared = false;if ( checkType.Left(6).Compare("Shared") ){checkType = first.Right(-6);shared = true;}// now check type nameint filetype = GetFileTypeFromString(checkType);if ( filetype == -1 )archive->LoadPackageData(first.ToString(), rest.ToString());}}CLEANSPLIT(str, max)}CBaseFile *CPackages::_archive_fromRar(CyString filename, bool toInstall ){// make sure we can open the zip fileCBaseFile *archive = NULL;#ifdef _RARHANDLE hArcData;int RHCode,PFCode;char CmtBuf[16384];struct RARHeaderDataEx HeaderData;struct RAROpenArchiveDataEx OpenArchiveData;// find the pluginmanager text to covnert to spkfileif ( toInstall ) {memset(&OpenArchiveData,0,sizeof(OpenArchiveData));OpenArchiveData.ArcName=(char *)filename.c_str();OpenArchiveData.CmtBuf=CmtBuf;OpenArchiveData.CmtBufSize=sizeof(CmtBuf);OpenArchiveData.OpenMode=RAR_OM_LIST;hArcData=RAROpenArchiveEx(&OpenArchiveData);if (OpenArchiveData.OpenResult!=0) return NULL;HeaderData.CmtBuf=NULL;memset(&OpenArchiveData.Reserved,0,sizeof(OpenArchiveData.Reserved));while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0) {if ( CyString(HeaderData.FileName).Compare("pluginmanager.txt") ) {toInstall = false;break;}}RARCloseArchive(hArcData);}if ( toInstall )archive = new CArchiveFile(); // just installing an archive fileelsearchive = new CSpkFile(); // converting to a spk filememset(&OpenArchiveData,0,sizeof(OpenArchiveData));OpenArchiveData.ArcName=(char *)filename.c_str();OpenArchiveData.CmtBuf=CmtBuf;OpenArchiveData.CmtBufSize=sizeof(CmtBuf);OpenArchiveData.OpenMode=RAR_OM_EXTRACT;OpenArchiveData.UserData=EXTRACT;hArcData=RAROpenArchiveEx(&OpenArchiveData);if (OpenArchiveData.OpenResult!=0) return NULL;HeaderData.CmtBuf=NULL;memset(&OpenArchiveData.Reserved,0,sizeof(OpenArchiveData.Reserved));bool error = false;CyString extractedFile = CDirIO(m_sTempDir).File("extracted.tst").findreplace("/", "\\").findreplace("\\\\", "\\");while ((RHCode=RARReadHeaderEx(hArcData,&HeaderData))==0){CyString fileName = HeaderData.FileName;if ( HeaderData.FileAttr == 16 )continue;wchar_t wText[200];::MultiByteToWideChar(CP_ACP, NULL, (char *)extractedFile.c_str(), -1, wText, extractedFile.Length() + 1);PFCode=RARProcessFileW(hArcData, RAR_EXTRACT, NULL, NULL);if (PFCode!=0){error = true;break;}CFileIO File(fileName);if ( File.exists() ){if ( fileName.Compare("pluginmanager.txt") )this->ReadArchiveData(File.GetFullFilename(), archive);else{CyString extradir;int type = SPK::GetAutomaticFiletype(fileName, &extradir, true);// check for special file typesC_File *f = NULL;if ( type == FILETYPE_SCRIPT_UNINSTALL ) {f = archive->AddFile(CFileIO(fileName).GetFilename(), "", FILETYPE_SCRIPT);if ( f ) {f->ReadFromFile(File.GetFullFilename());}type = FILETYPE_UNINSTALL;}if ( type == -1 )f = archive->AddFile(CFileIO(fileName).GetFilename(), CFileIO(fileName).GetDir(), FILETYPE_EXTRA);elsef = archive->AddFile(CFileIO(fileName).GetFilename(), extradir, type);f->ReadFromFile(File.GetFullFilename());}File.remove();}}RARCloseArchive(hArcData);if ( error ){delete archive;archive = NULL;}#endifreturn archive;}CBaseFile *CPackages::_archive_fromZip(CyString filename, bool toInstall){CBaseFile *archive = NULL;TCHAR buf[5000];wsprintf(buf, L"%hs", filename.c_str());HZIP hz = OpenZip(buf, 0);if ( !hz )return NULL;int index;// move the files from the zip to the packageZIPENTRY ze;if ( FindZipItem(hz, L"pluginmanager.txt", true, &index, &ze) == Z_OK )toInstall = false;CloseZip(hz);hz = OpenZip(buf, 0);if ( !hz )return NULL;// create the correct packageif ( toInstall )archive = new CArchiveFile(); // just installing an archive fileelsearchive = new CSpkFile(); // converting to a spk fileGetZipItem(hz, -1, &ze);int numitems = ze.index;bool error = false;for ( int zi = 0; zi < numitems; zi++ ){ZIPENTRY ze;if ( GetZipItem(hz, zi, &ze) != Z_OK ){error = true;break;}if ( ze.attr & FILE_ATTRIBUTE_DIRECTORY )continue; // dont do directorieschar *iBuf = new char[ze.unc_size];UnzipItem(hz, zi, iBuf, ze.unc_size);CyString Name(ze.name);// if its the data file, dont add it, but extract to get settings fromif ( Name.Compare("pluginmanager.txt") ){this->ReadArchiveData(iBuf, ze.unc_size, archive);delete[] iBuf;}else{CyString extradir;int type = SPK::GetAutomaticFiletype(Name, &extradir, true);C_File *f = NULL;// check for special file typesif ( type == FILETYPE_SCRIPT_UNINSTALL ) {f = archive->AddFile(CFileIO(Name).GetFilename(), CFileIO(Name).GetDir(), FILETYPE_SCRIPT);if ( f ) {f->copyData((const unsigned char *)iBuf, ze.unc_size);}type = FILETYPE_UNINSTALL;}if ( type == -1 )f = archive->AddFile(CFileIO(Name).GetFilename(), CFileIO(Name).GetDir(), FILETYPE_EXTRA);elsef = archive->AddFile(CFileIO(Name).GetFilename(), extradir, type);if ( f )f->SetData((const unsigned char *)iBuf, ze.unc_size);elsedelete[] iBuf;}}CloseZip(hz);if ( error ){delete archive;archive = NULL;}return archive;}CBaseFile *CPackages::CreateFromArchive(CyString filename, bool toInstall ){// make sure we can open the zip fileCBaseFile *archive = NULL;if ( CFileIO(filename).CheckFileExtension("rar") )archive = this->_archive_fromRar(filename, toInstall);else if ( CFileIO(filename).CheckFileExtension("zip") )archive = this->_archive_fromZip(filename, toInstall);if ( archive ) {archive->setFilename(CFileIO(filename).ChangeFileExtension("spk").ToString());if ( toInstall )archive->setName(CFileIO(filename).filename());elsearchive->setName(CFileIO(filename).baseName());}return archive;}CyString CPackages::CreateFromPackagerScript(CyString filename){CyString curDir = CFileIO(filename).GetDir();CyStringList variables;variables.PushBack("$PATH", curDir);CPackages p;CBaseFile *package = p.LoadPackagerScript(filename, NULL, NULL, NULL, &variables);if ( !package )return NullString;CyString saveto = package->filename();saveto = saveto.FindReplace("$DEFAULTDIR", curDir + "/");saveto = saveto.FindReplace("$PATH", curDir);saveto = saveto.FindReplace("\\", "/");saveto = saveto.FindReplace("//", "/");if ( !saveto.Right(4).Compare(".spk") && package->GetType() != TYPE_XSP )saveto += ".spk";else if ( !saveto.Right(4).Compare(".xsp") && package->GetType() == TYPE_XSP )saveto += ".xsp";// write scriptif ( package->WriteFile(saveto) ){if ( package->AutoGenerateUpdateFile() )package->CreateUpdateFile(CFileIO(saveto).GetDir());return saveto;}return NullString;}int CPackages::GeneratePackageUpdateData(CyString dir, bool includeSingle){CyStringList filedata;CPackages packages;CDirIO Dir(dir);for ( int i = 0; i < 2; i++ ){CyString pattern;if ( i == 0 ) pattern = "*.spk";else if ( i == 1 ) pattern = ".xsp";else break;CyStringList *files = Dir.DirList("", pattern);if ( files ){for ( SStringList *node = files->Head(); node; node = node->next ){int error = 0;CBaseFile *p = packages.OpenPackage(Dir.File(node->str), &error, 0, SPKREAD_NODATA);if ( !p )continue;if ( includeSingle )p->CreateUpdateFile(dir);filedata.PushBack(CPackages::FormatAvailablePackageData(p));delete p;}delete files;}}if ( !filedata.Empty() ){CFileIO File(dir + "/xpackagedata.dat");if ( File.WriteFile(&filedata) )return filedata.Count();}return 0;}int CPackages::VerifyInstalledFiles(CyStringList *missingFiles, bool getPackages){int count = 0;for ( CListNode<C_File> *fn = m_lFiles.Front(); fn; fn = fn->next() ){C_File *f = fn->Data();bool exists = false;if ( f->GetFilePointer().IsIn("::") ) {CyString modFile = f->GetFilePointer().GetToken("::", 1, 1);CyString file = f->GetFilePointer().GetToken("::", 2, 2);if ( CFileIO(modFile).ExistsOld() ) {CCatFile catFile;if ( catFile.Open(modFile, "", CATREAD_CATDECRYPT, false) == CATERR_NONE ) {if ( catFile.FindData(file) )exists = true;}}}else {exists = CFileIO(f->GetFilePointer()).ExistsOld();}if ( !exists ){++count;if ( missingFiles ){CyString packages;if ( getPackages ){for ( CListNode<CBaseFile> *p = m_lPackages.Front(); p; p = p->next() ){CBaseFile *package = p->Data();if ( package->IsFileAdded(f) ){if ( !packages.Empty() )packages += "\n";packages += package->GetFullPackageName(m_iLanguage);}}}CyString filename = f->GetFilePointer();filename = filename.Remove(m_sCurrentDir);missingFiles->PushBack(filename, packages, false);}}}return count;}