Rev 6 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
// SpkFile.cpp: implementation of the CSpkFile class.////////////////////////////////////////////////////////////////////////#include "SpkFile.h"//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////#include "spk.h"#include "DirIO.h"#include "File_IO.h"#include "CatFile.h"#include "archive/zip.h"#include "Packages.h"CSpkFile::CSpkFile() : CBaseFile (){SetDefaults ();m_iType = TYPE_SPK;}CSpkFile::~CSpkFile(){Delete ();}CArchiveFile::~CArchiveFile(){Delete ();}CArchiveFile::CArchiveFile() : CBaseFile (){SetDefaults ();m_iType = TYPE_ARCHIVE;}/*Func: SetDefaultsDesc: Sets the default values when class is created*/void CSpkFile::SetDefaults (){m_pLastWare = NULL;m_iPackageType = PACKAGETYPE_NORMAL;m_bForceProfile = false;m_iScriptType = SCRIPTTYPE_CUSTOM;CBaseFile::SetDefaults ();}void CBaseFile::SetDefaults (){m_pIconFile = NULL;m_bAutoGenerateUpdateFile = false;m_SHeader.iValueCompression = SPKCOMPRESS_ZLIB;m_SHeader2.iFileCompression = SPKCOMPRESS_ZLIB;m_SHeader2.iDataCompression = SPKCOMPRESS_LZMA;m_pParent = NULL;m_bChanged = false;m_bUpdate = false;m_iPluginType = PLUGIN_NORMAL;ClearError();m_iLoadError = 0;m_bFullyLoaded = false;m_bSigned = false;m_bEnable = m_bGlobal = m_bProfile = m_bModifiedEnabled = true;m_bOverrideFiles = false;m_iRecommended = m_iEaseOfUse = m_iGameChanging = -1;}CBaseFile::CBaseFile(){SetDefaults ();m_iType = TYPE_BASE;}CBaseFile::~CBaseFile(){Delete();}void CSpkFile::Delete (){m_lWares.clear(true);m_lSettings.clear(true);CBaseFile::Delete ();}void CBaseFile::Delete (){m_lFiles.clear(true);if ( m_pIconFile ){delete m_pIconFile;m_pIconFile = NULL;}m_lInstallText.clear(true);m_lUninstallText.clear(true);m_lNames.clear(true);}CyString CBaseFile::GetLanguageName ( int lang ){for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() ){SNames *n = node->Data();if ( n->iLanguage == lang )return n->sName;}return m_sName;}/*############################################################################################################ Base Class Functions ############################################################################################################*/CLinkList<C_File> *CBaseFile::GetFileList(int type){CLinkList<C_File> *list = new CLinkList<C_File>;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f->GetFileType() == type )list->push_back(f);}return list;}C_File *CBaseFile::GetNextFile(C_File *prev){int type = -1;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( type == -1 ){if ( f == prev )type = f->GetFileType();}else{if ( f->GetFileType() == type )return f;}}return NULL;}C_File *CBaseFile::GetPrevFile(C_File *next){if ( !next )return NULL;int type = -1;for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() ){C_File *f = node->Data();if ( type == -1 ){if ( f == next )type = f->GetFileType();}else{if ( f->GetFileType() == type )return f;}}return NULL;}C_File *CBaseFile::GetFirstFile(int type){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f->GetFileType() == type )return f;}return NULL;}int CBaseFile::CheckFile ( CyString filename, float *version ){FILE *id = fopen ( filename.c_str(), "rb" );if ( !id )return false;CyString line = GetEndOfLine ( id, NULL, false );CyString type = line.GetToken ( 1, ';' );fclose ( id );// check for old versionif ( line.Left(3) == "HiP" )return SPKFILE_OLD;// check for formatif ( version )*version = line.GetToken ( 2, ';' ).ToFloat();if ( type == "BaseCycrow" )return SPKFILE_BASE;if ( type == "SPKCycrow" )return SPKFILE_SINGLE;if ( type == "XSPCycrow" )return SPKFILE_SINGLESHIP;if ( type == "MSPKCycrow" )return SPKFILE_MULTI;return SPKFILE_INVALID;}void CBaseFile::ClearFileData(){for ( C_File *f = m_lFiles.First(); f; f = m_lFiles.Next() ){f->DeleteData();}}CyString CBaseFile::GetNameValidFile (){CyString name = m_sName;name.RemoveChar ( ':' );name.RemoveChar ( '/' );name.RemoveChar ( '\\' );name.RemoveChar ( '*' );name.RemoveChar ( '?' );name.RemoveChar ( '"' );name.RemoveChar ( '<' );name.RemoveChar ( '>' );name.RemoveChar ( '|' );return name;}void CBaseFile::SwitchFilePointer(C_File *oldFile, C_File *newFile){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f == oldFile ){node->ChangeData(newFile);break;}}}bool CBaseFile::AnyFileType ( int type ){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f->GetFileType() == type )return true;}return false;}void CBaseFile::AddFile ( C_File *file ){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f->GetFileType() != file->GetFileType() )continue;if ( f->GetName() != file->GetName () )continue;if ( f->GetDir() != file->GetDir() )continue;if ( f->GetGame() != file->GetGame() )continue;m_lFiles.remove(node, true);break;}file->UpdateSigned();m_bChanged = true;m_lFiles.push_back ( file );}C_File *CBaseFile::AddFile ( CyString file, CyString dir, int type, int game ){C_File *newfile = new C_File ( file );newfile->SetDir ( dir );newfile->SetFileType ( type );newfile->SetGame(game);// first check if the file already existsfor ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f->GetFileType() != newfile->GetFileType() )continue;if ( f->GetName() != newfile->GetName () )continue;if ( f->GetDir() != newfile->GetDir() )continue;if ( f->GetGame() != newfile->GetGame() )continue;// must already exist, delete this onem_lFiles.remove(node, true);break;}m_bChanged = true;newfile->UpdateSigned();m_lFiles.push_back ( newfile );return newfile;}bool CBaseFile::AddFileNow ( CyString file, CyString dir, int type, CProgressInfo *progress ){C_File *f = AddFile ( file, dir, type );if ( !f->ReadFromFile () )return false;// compress the filereturn f->CompressData ( m_SHeader2.iDataCompression, progress );}C_File *CBaseFile::AppendFile ( CyString file, int type, int game, CyString dir, CProgressInfo *progress ){C_File *newfile = AddFile ( file, dir, type, game );if ( !newfile )return NULL;// read the file into memoryif ( newfile->ReadFromFile () ){// now compress the fileif ( newfile->CompressData ( m_SHeader2.iDataCompression, progress ) )return newfile;}else if ( newfile->GetLastError() == SPKERR_MALLOC ){if ( newfile->CompressFile ( progress ) )return newfile;}m_lFiles.pop_back ();delete newfile;return NULL;}C_File *CBaseFile::FindFileAt ( int filetype, int pos ){int count = 0;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != filetype )continue;if ( count == pos )return file;++count;}return NULL;}C_File *CBaseFile::FindFile ( CyString filename, int type, CyString dir, int game ){CyString lfile = filename.ToLower();lfile = lfile.FindReplace ( "\\", "/" );lfile = lfile.GetToken ( lfile.NumToken('/'), '/' );CListNode<C_File> *node = m_lFiles.Front();while ( node ){C_File *f = node->Data();node = node->next();if ( type != f->GetFileType() )continue;if ( dir != f->GetDir() )continue;if ( game != f->GetGame() )continue;if ( f->GetName().ToLower() == lfile )return f;}return NULL;}bool CBaseFile::RemoveFile ( CyString file, int type, CyString dir, int game ){C_File *f = FindFile (file, type, dir, game);if ( !f )return false;return RemoveFile ( f );}bool CBaseFile::RemoveFile ( C_File *file ){int count = 0;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( f == file )return RemoveFile ( count );++count;}return false;}bool CBaseFile::RemoveFile ( int pos ){if ( (pos < 0) || (pos >= m_lFiles.size()) )return false;C_File *file = m_lFiles.Get ( pos );m_lFiles.erase ( pos + 1 );if ( file )delete file;m_bChanged = true;return true;}void CBaseFile::RemoveAllFiles ( int type, int game ){if ( m_lFiles.empty() )return;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){if ( game > -1 ) {if ( node->Data()->GetGame() != game )continue;}if ( type == -1 || node->Data()->GetFileType() == type )node->DeleteData();}m_lFiles.RemoveEmpty();m_bChanged = true;}void CBaseFile::RecompressAllFiles ( int type, CProgressInfo *progress ){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( progress )progress->UpdateFile(file);if ( file->GetCompressionType() == type )continue;if ( !file->GetData() )file->ReadFromFile();file->ChangeCompression ( type, progress );}}void CBaseFile::CompressAllFiles ( int type, CProgressInfo *progress, int level ){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( progress )progress->UpdateFile(file);if ( !file->GetData() )file->ReadFromFile();file->CompressData ( type, progress, level );}}bool CBaseFile::UncompressAllFiles ( CProgressInfo *progress ){int countFile = 0;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();if ( progress ){progress->UpdateFile ( fit );progress->UpdateProgress(countFile++, m_lFiles.size());}bool uncomprToFile = false;if ( progress )progress->SwitchSecond();if ( !fit->UncompressData ( progress ) ){if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP ){if ( !fit->UncompressToFile ( "temp", this, false, progress ) )return false;else{uncomprToFile = true;fit->SetFullDir ( "temp" );}}if ( !uncomprToFile )return false;}if ( progress )progress->SwitchSecond();}return true;}long CBaseFile::GetFullFileSize(){long fullsize = 1000;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )fullsize += node->Data()->GetUncompressedDataSize();if ( m_pIconFile )fullsize += m_pIconFile->GetUncompressedDataSize();return fullsize;}/*Func: GetEndOfLineInput: id - The file id for the current file to read fromline - Pointed to hold the line number thats readupper - true if it converts to uppercaseReturn: String - the string it has readDesc: Reads a string from a file, simlar to readLine() classes, reads to the end of the line in a file*/CyString CBaseFile::GetEndOfLine ( FILE *id, int *line, bool upper ){CyString word;char c = fgetc ( id );if ( c == -1 )return "";while ( (c != 13) && (!feof(id)) && (c != '\n') ){word += c;c = fgetc ( id );}if ( line )++(*line);if ( upper )return word.ToUpper();return word;}int CBaseFile::CountFiles ( int filetype ){int i = 0;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != filetype )continue;++i;}return i;}void CBaseFile::ClearNames (){m_lNames.clear(true);}void CBaseFile::RemoveLanguageName ( int lang ){SNames *n;for ( n = m_lNames.First(); n; n = m_lNames.Next() ){if ( n->iLanguage == lang ){m_lNames.RemoveCurrent();delete n;m_bChanged = true;}}}void CBaseFile::AddLanguageName ( int lang, CyString name ){// first check for an existing languageSNames *n;for ( n = m_lNames.First(); n; n = m_lNames.Next() ){if ( n->iLanguage == lang ){n->sName = name;return;}}// not found, add a new entryn = new SNames;n->iLanguage = lang;n->sName = name;m_lNames.push_back ( n );m_bChanged = true;}/*Func: AddInstallTextInput: before - true for before text, false for after textinstall - true to add to install text list, false for unisntall text listlang - string containing the language to usedata - The text to add for the languageReturn: install text - Returns the text struct that it used to addDesc: Adds the text to list, adds either install or uninstall textIf language already exists, then its overwrittenAllows adding before and after seperatly to the same entry*/SInstallText *CBaseFile::AddInstallText ( bool before, bool install, int lang, CyString data ){CLinkList<SInstallText> *list = NULL;if ( install )list = &m_lInstallText;elselist = &m_lUninstallText;SInstallText *unist = NULL;// check if language already exists and overright if neededfor ( SInstallText *u = list->First(); u; u = list->Next() ){if ( u->iLanguage == lang ){unist = u;break;}}if ( !unist ){unist = new SInstallText;unist->iLanguage = lang;if ( lang == 0 )list->push_front ( unist );elselist->push_back ( unist );}if ( !before )unist->sAfter = data;elseunist->sBefore = data;m_bChanged = true;return unist;}SInstallText *CBaseFile::FindInstallText ( bool install, int lang ){CLinkList<SInstallText> *list = NULL;if ( install )list = &m_lInstallText;elselist = &m_lUninstallText;for ( SInstallText *it = list->First(); it; it = list->Next() ){if ( it->iLanguage == lang )return it;}return NULL;}void CBaseFile::AddInstallText ( SInstallText *add ){SInstallText *it = FindInstallText ( true, add->iLanguage );if ( it == add )return;if ( it ){m_lInstallText.remove ( it );delete it;}m_bChanged = true;m_lInstallText.push_back ( add );}void CBaseFile::AddUninstallText ( SInstallText *add ){SInstallText *it = FindInstallText ( false, add->iLanguage );if ( it == add )return;if ( it ){m_lUninstallText.remove ( it );delete it;}m_bChanged = true;m_lUninstallText.push_back ( add );}void CBaseFile::RemoveInstallText ( bool install, int lang ){SInstallText *it = FindInstallText ( install, lang );if ( it ){if ( install )m_lInstallText.remove ( it );elsem_lUninstallText.remove ( it );delete it;m_bChanged = true;}}bool CBaseFile::IsThereInstallText ( bool install ){CLinkList<SInstallText> *list = NULL;if ( install )list = &m_lInstallText;elselist = &m_lUninstallText;if ( list->size() > 1 )return true;if ( list->size() <= 0 )return false;SInstallText *it = list->First();if ( !it->sAfter.Empty() )return true;if ( !it->sBefore.Empty() )return true;return false;}CyString CBaseFile::GetBeforeText ( CLinkList<SInstallText> *list, int lang, bool noDefault ){CyString beforetext;for ( SInstallText *u = list->First(); u; u = list->Next() ){if ( !noDefault ){if ( (beforetext.Empty()) && (u->iLanguage == 0) )beforetext = u->sBefore;}if ( (u->iLanguage == lang) && (!u->sBefore.Empty()) )beforetext = u->sBefore;}return beforetext;}CyString CBaseFile::GetAfterText ( CLinkList<SInstallText> *list, int lang, bool noDefault ){CyString text;for ( SInstallText *u = list->First(); u; u = list->Next() ){if ( (u->iLanguage == lang) && (!u->sAfter.Empty()) )text = u->sAfter;if ( !noDefault ){if ( (text.Empty()) && (u->iLanguage == 0) )text = u->sAfter;}}return text;}CyString CBaseFile::GetFullPackageName(CyString format, int lang){if ( format.Empty() )return GetFullPackageName(lang);CyString args[3] = { this->GetLanguageName(lang), this->GetVersion(), this->GetAuthor() };return format.Args(args, 3);}/*Func: CreateFilesLineReturn: String - returns the full string for files listDesc: Creates a signle line list of all the files*/CyString CBaseFile::CreateFilesLine ( bool updateheader, CProgressInfo *progress ){CyString line;if ( progress ){progress->SetDone(0);progress->UpdateStatus(STATUS_COMPRESS);}if ( updateheader ){m_SHeader2.iNumFiles = 0;m_SHeader2.lFullSize = 0;}if ( m_pIconFile ){// no data, read it from fileif ( !m_pIconFile->GetData() )m_pIconFile->ReadFromFile ();// compress the fileif ( !m_pIconFile->CompressData ( m_SHeader2.iDataCompression, progress ) )m_pIconFile->SetDataCompression(SPKCOMPRESS_NONE);line += CyString("Icon:") + (m_pIconFile->GetDataSize() + (long)4) + ":" + m_pIconFile->GetUncompressedDataSize() + ":" + (long)m_pIconFile->GetCompressionType() + ":" + m_sIconExt + "\n";if ( updateheader ){++m_SHeader2.iNumFiles;m_SHeader2.lFullSize += (m_pIconFile->GetDataSize() + 4);}}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( progress )progress->UpdateFile ( file );// no data, read it from fileif ( !file->GetData() ){if ( !file->ReadFromFile () ){if ( file->GetLastError() == SPKERR_MALLOC ){if ( !file->CompressFile ( progress ) )continue;}}}if ( !file->GetData() )continue;// compress the fileif ( !file->CompressData ( m_SHeader2.iDataCompression, progress ) ){file->SetDataCompression(SPKCOMPRESS_NONE);file->SetUncompressedDataSize(file->GetDataSize());}CyString command = GetFileTypeString ( file->GetFileType() );if ( command.Empty() )continue;if ( file->IsShared() )command = CyString("$") + command;if ( file->GetDir().Empty() )line += (command + ":" + (file->GetDataSize() + (long)4) + ":" + file->GetUncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->GetFilename() + ":GAME_" + (long)file->GetGame() + "\n");elseline += (command + ":" + (file->GetDataSize() + (long)4) + ":" + file->GetUncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->GetFilename() + ":" + file->GetDir() + ":GAME_" + (long)file->GetGame() + "\n");if ( updateheader ){++m_SHeader2.iNumFiles;m_SHeader2.lFullSize += (file->GetDataSize() + 4);}}return line;}/*################################################################################################ Reading Functions ################################################################################################*/void CBaseFile::ReadAllFilesToMemory (){// no file to read fromif ( m_sFilename.Empty() )return;// now open the fileFILE *id = fopen ( m_sFilename.c_str(), "rb" );if ( !id )return;// read the headerGetEndOfLine ( id, NULL, false );// skip past valuesfseek ( id, 4, SEEK_CUR );fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );// read the next headerGetEndOfLine ( id, NULL, false );// skip past filesfseek ( id, 4, SEEK_CUR );fseek ( id, m_SHeader2.lSize, SEEK_CUR );if ( m_pIconFile ){if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );else{fseek ( id, 4, SEEK_CUR );fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );}}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();if ( (!fit->GetData()) && (!fit->Skip()) )fit->ReadFromFile ( id, fit->GetDataSize() );else{fseek ( id, 4, SEEK_CUR );fseek ( id, fit->GetDataSize(), SEEK_CUR );}}fclose ( id );}bool CBaseFile::ReadFileToMemory(C_File *f){if ( f->GetData() && f->GetDataSize() )return true;// no file to read fromif ( m_sFilename.Empty() || !f )return false;// check the file is part of the packageif ( !m_lFiles.FindData(f) )return false;// now open the fileFILE *id = fopen ( m_sFilename.c_str(), "rb" );if ( !id )return false;// read the headerGetEndOfLine ( id, NULL, false );// skip past valuesfseek ( id, 4, SEEK_CUR );fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );// read the next headerGetEndOfLine ( id, NULL, false );// skip past filesfseek ( id, 4, SEEK_CUR );fseek ( id, m_SHeader2.lSize, SEEK_CUR );if ( m_pIconFile ){fseek ( id, 4, SEEK_CUR );fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();if (fit == f ){fit->ReadFromFile ( id, fit->GetDataSize() );break;}else{fseek ( id, 4, SEEK_CUR );fseek ( id, fit->GetDataSize(), SEEK_CUR );}}fclose(id);return true;}void CBaseFile::ReadIconFileToMemory (){// no file to read fromif ( m_sFilename.Empty() )return;if ( !m_pIconFile )return;// now open the fileFILE *id = fopen ( m_sFilename.c_str(), "rb" );if ( !id )return;// read the headerGetEndOfLine ( id, NULL, false );// skip past valuesfseek ( id, 4, SEEK_CUR );fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );// read the next headerGetEndOfLine ( id, NULL, false );// skip past filesfseek ( id, 4, SEEK_CUR );fseek ( id, m_SHeader2.lSize, SEEK_CUR );if ( m_pIconFile ){if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );else{fseek ( id, 4, SEEK_CUR );fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );}}fclose ( id );}bool CBaseFile::InstallFiles ( CyString destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, CyStringList *errorStr, bool enabled, CPackages *packages ){// first rename any fake patchesCyStringList lPatches;if ( enabled ){int startfake = 1;while ( startfake < 99 ){CyString filename = destdir;if ( !filename.Empty() )filename += "/";filename += CyString::Number((long)startfake).PadNumber(2);if ( !CFileIO(filename + ".cat").Exists() ){if ( !CFileIO(filename + ".dat").Exists() )break;}startfake++;}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();// only do fake patchsif ( !fit->IsFakePatch() )continue;if ( !fit->CheckFileExt ("cat") && !fit->CheckFileExt("dat") )continue;// search for the name on the listSStringList *opposite = lPatches.FindString(fit->GetBaseName());CyString newname;if ( opposite )newname = opposite->data;else{newname = CyString::Number((long)startfake).PadNumber(2);lPatches.PushBack(fit->GetBaseName(), newname);}// rename the filefit->FixOriginalName();fit->SetName ( newname + "." + fit->GetFileExt() );// find the next gapif ( !opposite ){startfake++; // make sure we moved past the one we've just usedwhile ( startfake < 99 ){CyString filename = destdir;if ( !filename.Empty() )filename += "/";filename += CyString::Number((long)startfake).PadNumber(2);if ( !CFileIO(filename + ".cat").Exists() ){if ( !CFileIO(filename + ".dat").Exists() )break;}startfake++;}}}// find renable text fileif ( packages ){int starttext = 3;while ( starttext < 9999 ){CyString filename = destdir;if ( !filename.Empty() )filename += "/t/";filename += SPK::FormatTextName(starttext, packages->GetLanguage(), (packages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));if ( !CFileIO(filename + ".xml").Exists() ){if ( !CFileIO(filename + ".pck").Exists() )break;}starttext++;}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();if ( !fit->IsAutoTextFile() )continue;CyString newname = SPK::FormatTextName(starttext, packages->GetLanguage(), (packages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));fit->FixOriginalName();fit->SetName ( newname + "." + fit->GetFileExt() );++starttext;}}}CDirIO Dir(destdir);int fileCount = 0;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();bool fileEnabled = enabled;if ( !fileEnabled ){if ( (fit->GetFileType() == FILETYPE_UNINSTALL) || (fit->GetFileType() == FILETYPE_README) || (fit->GetFileType() == FILETYPE_ADVERT) )fileEnabled = true;else if ( (fit->GetFileType() == FILETYPE_EXTRA) && (fit->GetDir().Left(7).ToLower() == "Extras/") )fileEnabled = true;else if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) && (!fit->IsFakePatch()) )fileEnabled = true;}if ( fit->GetGame() && packages->GetGame() ) {if ( fit->GetGame() != packages->GetGame() )continue;}if ( progress ){if ( progress->IsSecond() )progress->SwitchSecond();progress->UpdateFile ( fit );progress->UpdateProgress(fileCount++, m_lFiles.size());progress->SwitchSecond();}// first uncompress the filebool uncomprToFile = false;m_sLastError = fit->GetNameDirectory(this);m_iLastError = SPKERR_UNCOMPRESS;if ( !fit->UncompressData ( progress ) ){if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP ){if ( fit->UncompressToFile ( NullString, this, false, progress ) )uncomprToFile = true;}if ( !uncomprToFile ){if ( errorStr )errorStr->PushBack(m_sLastError, ERRORLOG(SPKINSTALL_UNCOMPRESS_FAIL));return false;}}ClearError ();bool dofile = true;// new check if we should install the file// first get the versionif ( fit->ReadScriptVersion () && !m_bOverrideFiles ){C_File checkfile;CyString checkfilename = destdir;if ( !checkfilename.Empty() )checkfilename += "/";checkfilename += fit->GetNameDirectory(this);checkfile.SetFilename ( checkfilename );checkfile.SetFileType ( fit->GetFileType() );if ( checkfile.CheckValidFilePointer() ){if ( checkfile.ReadScriptVersion() > fit->GetVersion() )dofile = false;}}// change file pointerCyString filename = destdir;if ( !filename.Empty() )filename += "/";if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) )fit->SetDir ( CyString("Patch") );if ( fit->IsInMod() ){if ( fileEnabled )fit->SetFilename(filename + fit->GetInMod() + "::" + fit->GetNameDirectory(this));elsefit->SetFilename(filename + "PluginManager/DisabledFiles.cat::" + fit->GetNameDirectory(this));}elsefit->SetFilename ( filename + fit->GetNameDirectory(this) );if ( !fileEnabled ){if ( !fit->IsInMod() ){if ( fit->IsFakePatch() )fit->SetFilename ( filename + "PluginManager/Disabled/FakePatches/FakePatch_" + this->GetNameValidFile() + "_" + m_sAuthor + "_" + fit->GetName() );else if ( fit->IsAutoTextFile() )fit->SetFilename ( filename + "PluginManager/Disabled/TextFiles/Text_" + this->GetNameValidFile() + "_" + m_sAuthor + "_" + fit->GetName() );elsefit->SetFullDir ( filename + "PluginManager/Disabled/" + fit->GetDirectory(this) );}fit->SetDisabled(true);}C_File *adjustPointer = NULL;bool checkFile = dofile;if ( filelist ){C_File *cFile = NULL;if ( checkFile ){if ( !fit->IsFakePatch() && fit->GetFileType() != FILETYPE_README ){for ( cFile = filelist->First(); cFile; cFile = filelist->Next() ){if ( !cFile->MatchFile ( fit ) )continue;if ( !m_bOverrideFiles && !cFile->CompareNew ( fit ) ){if ( errorStr )errorStr->PushBack(fit->GetNameDirectory(this), ERRORLOG(SPKINSTALL_SKIPFILE));dofile = false;}break;}}}// no matching file found, adding to main listif ( !cFile )filelist->push_back ( fit );else{// if the file is not enabled, we need to check for any that might be enabledif ( !fileEnabled ){if ( !cFile->GetUsed() ){CFileIO rFile(cFile->GetFilePointer());if ( rFile.Exists() ){if ( errorStr ){if ( rFile.Remove() )errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE));elseerrorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE_FAIL));}}cFile->SetFilename(fit->GetFilePointer());cFile->SetDisabled(true);}else{fit->SetFullDir ( filename + fit->GetDirectory(this) );fit->SetDisabled(false);}}else// move it to enabled{// found a file, check if its in the disabled directoryCyString dir = cFile->GetFilePointer();dir = dir.GetToken ( 1, dir.NumToken ('/') - 1, '/' );CyString lastDir = dir.GetToken ( dir.NumToken('/'), '/' ).ToLower();// if its disabled, rename it so its enabledif ( ((cFile->IsDisabled()) || (lastDir == "disabled") || (dir.ToLower().IsIn ("/disabled/"))) && (enabled) ){// first check if the directory existsif ( cFile->IsInMod() ){CyString tofile = cFile->GetFilePointer().GetToken("::", 2, 2);CCatFile tocat;int err = tocat.Open ( fit->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, true );if ( (err == CATERR_NONE) || (err == CATERR_CREATED) ){tocat.AppendFile ( cFile->GetFilePointer(), tofile );}CCatFile fromcat;err = fromcat.Open ( cFile->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, false );if ( err == CATERR_NONE ){fromcat.RemoveFile(tofile);}cFile->SetFilename ( fit->GetFilePointer() );cFile->SetInMod(fit->GetInMod());}else{CyString to = cFile->GetDirectory(this);CDirIO Dir(destdir);if ( !Dir.Exists(to) ){if ( !Dir.Create ( to ) ){if ( errorStr )errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));return false;}if ( errorStr )errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));}CyString destfile = destdir + "/" + cFile->GetNameDirectory(this);if ( CFileIO(destfile).Exists() )CFileIO(destfile).Remove();rename ( cFile->GetFilePointer().c_str(), destfile.c_str() );cFile->SetFilename ( destdir + "/" + cFile->GetNameDirectory(this) );}cFile->SetDisabled(false);if ( !dofile && errorStr )errorStr->PushBack(cFile->GetNameDirectory(this), ERRORLOG(SPKINSTALL_ENABLEFILE));}}adjustPointer = cFile;if ( dofile )adjustPointer->SetCreationTime ( fit->GetCreationTime() );}}if ( dofile ){// uncompressed to file, rename and moveif ( uncomprToFile ){m_iLastError = SPKERR_WRITEFILE;CyString to = fit->GetDirectory(this);//to = to.GetToken ( 1, to.NumToken ('/') - 1, '/' );if ( !fileEnabled )to = CyString("PluginManager/Disabled/") + to;CDirIO Dir(destdir);if ( !Dir.Exists(to) ){if ( !Dir.Create ( to ) ){if ( errorStr )errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));return false;}if ( errorStr )errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));}int err = 1;m_sLastError = to;if ( !fit->GetTempFile ().Empty() )err = rename ( fit->GetTempFile().c_str(), to.c_str() );if ( err )return false;}//otherwise, just extract the fileelse{// old file is found in list, switch to using new oneif ( (filelist) && (adjustPointer) )adjustPointer->CopyData(fit, false);CyString fpointer = fit->GetFilePointer();m_iLastError = SPKERR_CREATEDIRECTORY;CyString dir = fit->GetFilePointer().GetToken ( "/", 1, fit->GetFilePointer().NumToken("/") - 1 );dir = dir.Remove(destdir);if ( dir[0] == '/' || dir[0] == '\\' )dir.Erase(0, 1);m_sLastError = dir;if ( !dir.IsIn ( "::" ) ){if ( !Dir.Exists(dir) ){if ( !Dir.Create(dir) ){if ( errorStr )errorStr->PushBack(dir, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));return false;}if ( errorStr )errorStr->PushBack(dir, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));}}elsefit->SetFilename(CCatFile::PckChangeExtension(fit->GetFilePointer()));m_iLastError = SPKERR_WRITEFILE;m_sLastError = fit->GetFilePointer();CyString sInstalledFile = fit->GetNameDirectory(this);if ( fit->IsDisabled() ){sInstalledFile = fit->GetFilePointer().Remove(destdir);if ( sInstalledFile[0] == '/' || sInstalledFile[0] == '\\' )sInstalledFile.Erase(0, 1);}if ( !fit->WriteFilePointer() ){if ( errorStr )errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE_FAIL));}else{fit->UpdateSigned();if ( errorStr )errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE));switch(fit->GetFileType()){case FILETYPE_SCRIPT:case FILETYPE_UNINSTALL:fit->UpdateSignature();break;}}}ClearError ();}if ( adjustPointer ){node->ChangeData(adjustPointer);delete fit;}}// now clear or data memoryfor ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){// add plugin manager file to identify fake patches/*if ( fit->IsFakePatch() && fit->CheckFileExt ("cat") ){CFileIO plugin("pluginmanager.txt");std::vector<CyString> lines;CyString version;version.FromFloat(GetLibraryVersion(), 2);SStringList *strList = lPatches.FindData(fit->GetBaseName());CyString baseName;if ( strList )baseName = strList->str;elsebaseName = fit->GetBaseName();lines.push_back(CyString("FakePatch:") + baseName);lines.push_back(CyString("spklibrary:") + version);lines.push_back(CyString("Package:") + m_sName);lines.push_back(CyString("Author:") + m_sAuthor);lines.push_back(CyString("OriginalFile:") + fit->GetOriginalName());if ( plugin.WriteFile(&lines) ){CCatFile cat;if ( cat.Open(fit->GetFilePointer(), CATREAD_DAT, false) == CATERR_NONE ){cat.AppendFile(plugin.GetFilename(), plugin.GetFilename(), true);cat.WriteCatFile();}plugin.Remove();}}*/node->Data()->DeleteData();}return true;}/*######################################################################################################*//*Func: ParseHeaderInput: Header String - string formated directly from the fileReturn: Boolean - If string is a valid headerDesc: Splits up the main header string to get all required settings*/bool CBaseFile::ParseHeader ( CyString header ){if ( !this->CheckHeader(header.GetToken ( 1, ';' )) )return false;m_SHeader.fVersion = header.GetToken ( 2, ';' ).ToFloat();if ( m_SHeader.fVersion > FILEVERSION )return false;m_SHeader.iValueCompression = header.GetToken ( 3, ';' ).ToInt();m_SHeader.lValueCompressSize = header.GetToken ( 4, ';' ).ToLong();return true;}bool CSpkFile::CheckHeader ( CyString header ){if ( header.Compare("SPKCycrow") )return true;return false;}bool CBaseFile::CheckHeader ( CyString header ){if ( header.Compare("BaseCycrow") )return true;return false;}/*Func: ParseFileHeaderInput: Header String - string formated directly from the fileReturn: Boolean - If string is a valid headerDesc: Splits up the file header string to get all required settings*/bool CBaseFile::ParseFileHeader ( CyString header ){if ( header.GetToken ( 1, ';' ) != "FileHeader" )return false;m_SHeader2.iNumFiles = header.GetToken ( 2, ';' ).ToInt();m_SHeader2.lSize = header.GetToken ( 3, ';' ).ToInt();m_SHeader2.lFullSize = header.GetToken ( 4, ';' ).ToInt();m_SHeader2.iFileCompression = header.GetToken ( 5, ';' ).ToInt();m_SHeader2.iDataCompression = header.GetToken ( 6, ';' ).ToInt();return true;}/*Func: ParseValueLineInput: String - single line from a file to setReturn: Boolean - returns true if value existsDesc: Reads the line and assigns the parameters for the file*/bool CBaseFile::ParseValueLine ( CyString line ){CyString first = line.GetToken ( 1, ' ' );CyString rest = line.GetToken ( 2, -1, ' ' );if ( first == "Name:" )m_sName = rest;else if ( first == "Author:" )m_sAuthor = rest;else if ( first == "Version:" )m_sVersion = rest;else if ( first == "fGameVersion:" ) {if ( m_lGames.Back() ) {m_lGames.Back()->Data()->sVersion = rest;}}else if ( first == "GameVersion:" ) {if ( m_lGames.Back() ) {m_lGames.Back()->Data()->iVersion = rest.ToInt();}}else if ( first == "Game:" )this->AddGameCompatability(rest.ToInt(), NullString);else if ( first == "GameCompat:" )this->AddGameCompatability(rest.GetToken(" ", 1, 1).ToInt(), rest.GetToken(" ", 2, 2));else if ( first == "GameCompatExact:" )this->AddGameCompatability(rest.GetToken(" ", 1, 1).ToInt(), rest.GetToken(" ", 2));else if ( first == "Date:" )m_sCreationDate = rest;else if ( first == "WebAddress:" )m_sWebAddress = rest;else if ( first == "WebSite:" )m_sWebSite = rest;else if ( first == "Email:" )m_sEmail = rest;else if ( first == "WebMirror1:" || first == "Mirror1:" || first == "WebMirror:" )this->AddWebMirror(rest);else if ( first == "WebMirror2:" || first == "Mirror2:" )this->AddWebMirror(rest);else if ( first == "PluginType:" )m_iPluginType = rest.ToInt();else if ( first == "Desc:" ){m_sDescription = rest;m_sDescription.RemoveFirstChar('\n');m_sDescription.RemoveFirstChar('\r');m_sDescription.RemoveFirstSpace();m_sDescription = m_sDescription.FindReplace(""", "\"");m_sDescription = m_sDescription.FindReplace(">", ">");m_sDescription = m_sDescription.FindReplace("<", "<");m_sDescription = m_sDescription.FindReplace("&", "&");m_sDescription = m_sDescription.FindReplace("<newline>", "\n");m_sDescription = m_sDescription.FindReplace("<br>", "\n");if ( m_sDescription.Left(6).lower() == "<html>" ){int foundFirst = -1;int pos = 0;while ( foundFirst == -1 ){pos = m_sDescription.FindPos(">", pos);pos++;if ( pos >= (int)m_sDescription.Length() )break;char c = m_sDescription[pos];if ( c != '<' )foundFirst = pos;}if ( foundFirst == -1 )m_sDescription = "";else{CyString firstStr = m_sDescription.Left(foundFirst);firstStr.FindRemove("<br />");firstStr.FindRemove("<br/>");CyString lastStr = m_sDescription.Right(m_sDescription.Length() - foundFirst);m_sDescription = firstStr + lastStr;}}}else if ( first == "UninstallAfter:" )AddUninstallAfterText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );else if ( first == "UninstallBefore:" )AddUninstallBeforeText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );else if ( first == "InstallAfter:" )AddInstallAfterText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );else if ( first == "InstallBefore:" )AddInstallBeforeText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );else if ( first == "ScriptName:" )AddLanguageName ( ParseLanguage(rest.GetToken ( 1, ':' )), rest.GetToken ( 2, -1, ':' ) );else if ( first == "GameChanging:" )m_iGameChanging = rest.ToInt();else if ( first == "EaseOfUse:" )m_iEaseOfUse = rest.ToInt();else if ( first == "Recommended:" )m_iRecommended = rest.ToInt();else if ( first == "NeededLibrary:" )this->AddNeededLibrary(rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2), rest.GetToken("||", 3, 3));else if ( first == "FakePatchBefore:" )this->AddFakePatchOrder(false, rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2));else if ( first == "FakePatchAfter:" )this->AddFakePatchOrder(true, rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2));else if ( first == "ForumLink:" )m_sForumLink = rest;elsereturn false;return true;}int CBaseFile::ParseLanguage(CyString lang){int langID = lang.ToInt();if ( !langID ){lang = lang.ToLower();if ( lang == "english" )return 44;else if ( lang == "default" )return 0;else if ( lang == "german" )return 49;else if ( lang == "russian" )return 7;else if ( lang == "spanish" )return 34;else if ( lang == "french" )return 33;}return langID;}int CBaseFile::ParseInstallText(CyString lang){return this->ParseLanguage(lang);}/*Func: ParseValueLineInput: String - single line from a file to setReturn: Boolean - returns true if value existsDesc: Reads the line and assigns the parameters for the file*/bool CSpkFile::ParseValueLine ( CyString line ){CyString first = line.GetToken ( 1, ' ' );CyString rest = line.GetToken ( 2, -1, ' ' );if ( first == "AnotherMod:" ){m_sOtherAuthor = rest.GetToken ( 1, '|' );m_sOtherName = rest.GetToken ( 2, -1, '|' );}else if ( line == "CustomStart" )m_iPackageType = PACKAGETYPE_CUSTOMSTART;else if ( line == "PackageUpdate" )m_iPackageType = PACKAGETYPE_UPDATE;else if ( line == "Patch" )m_iPackageType = PACKAGETYPE_PATCH;else if ( line == "ForceProfile" )m_bForceProfile = true;else if ( line == "Signed" )m_bSigned = true;else if ( first == "ScriptType:" )m_sScriptType = rest;else if ( first == "ScriptTypeNew:" )m_iScriptType = rest.ToInt();else if ( first == "PackageType:" )m_iPackageType = rest.ToInt();else if ( first == "Ware:" )AddWare ( rest );else if ( (first == "WareText:") && (m_pLastWare) )AddWareText ( rest );else if ( first == "Setting:" ){SSettingType *t = AddSetting ( rest.GetToken ( 2, '|' ), rest.GetToken ( 1, '|' ).ToInt() );ConvertSetting ( t, rest.GetToken ( 3, -1, '|' ) );}elsereturn CBaseFile::ParseValueLine ( line );return true;}/*Func: ReadValuesInput: String - values in one long lineDesc: splits the values data into each line to read the data*/void CBaseFile::ReadValues ( CyString values ){int num = 0;CyString *lines = values.SplitToken ( '\n', &num );for ( int i = 0; i < num; i++ )ParseValueLine ( lines[i] );CLEANSPLIT(lines, num)}/*Func: ParseFilesLineInput: String - single line from a file to setReturn: Boolean - returns true if value existsDesc: Reads the line and assigns the parameters for the file*/bool CBaseFile::ParseFilesLine ( CyString line ){if ( !line.IsIn(":") )return false;CyString command = line.GetToken ( 1, ':' );long size = line.GetToken ( 2, ':').ToInt ();long usize = line.GetToken ( 3, ':').ToInt ();long compression = line.GetToken ( 4, ':').ToInt ();if ( command == "Icon" ){m_sIconExt = line.GetToken ( 5, ':' );m_pIconFile = new C_File ();m_pIconFile->SetDataSize ( size - 4 );m_pIconFile->SetDataCompression ( compression );m_pIconFile->SetUncompressedDataSize ( usize );return true;}time_t time = line.GetToken ( 5,':' ).ToLong();bool compressToFile = (line.GetToken ( 6, ':').ToInt() == 1) ? true : false;CyString name = line.GetToken ( 7, ':' );CyString dir = line.GetToken ( 8, ':' );if ( name.Empty() )return true;bool shared = false;if ( command.Left(1) == "$" ){shared = true;command.Erase ( 0, 1 );}int type = -1;if ( command == "Script" )type = FILETYPE_SCRIPT;else if ( command == "Text" )type = FILETYPE_TEXT;else if ( command == "Readme" )type = FILETYPE_README;else if ( command == "Map" )type = FILETYPE_MAP;else if ( command == "Mod" )type = FILETYPE_MOD;else if ( command == "Uninstall" )type = FILETYPE_UNINSTALL;else if ( command == "Sound" )type = FILETYPE_SOUND;else if ( command == "Mission" )type = FILETYPE_MISSION;else if ( command == "Extra" )type = FILETYPE_EXTRA;else if ( command == "Screen" )type = FILETYPE_SCREEN;else if ( command == "Backup" )type = FILETYPE_BACKUP;else if ( command == "Advert" )type = FILETYPE_ADVERT;else if ( command == "ShipScene" )type = FILETYPE_SHIPSCENE;else if ( command == "CockpitScene" )type = FILETYPE_COCKPITSCENE;else if ( command == "ShipOther" )type = FILETYPE_SHIPOTHER;else if ( command == "ShipModel" )type = FILETYPE_SHIPMODEL;if ( type == -1 )return false;C_File *file = new C_File ();if ( dir.Left(5).Compare("GAME_") ) {file->SetGame(dir.GetToken("_", 2, 2).ToInt());dir = NullString;}else if ( line.NumToken(":") >= 9 ) {file->SetGame(line.GetToken(":", 9, 9).GetToken("_", 2, 2).ToInt());}file->SetFileType ( type );file->SetCreationTime ( time );file->SetName ( name );file->SetDir ( dir );file->SetDataSize ( size - 4 );file->SetDataCompression ( compression );file->SetUncompressedDataSize ( usize );file->SetShared ( shared );file->SetCompressedToFile ( compressToFile );m_lFiles.push_back ( file );return true;}/*Func: ParseFilesInput: String - values in one long lineDesc: splits the files data into each line to read the data*/void CBaseFile::ReadFiles ( CyString values ){int num = 0;CyString *lines = values.SplitToken ( '\n', &num );for ( int i = 0; i < num; i++ )ParseFilesLine ( lines[i] );CLEANSPLIT(lines, num)}/*Func: ReadFileInput: filename - the name of the file to open and readreaddata - If falses, dont read the files to memory, just read the headers and valuesReturn: boolean - return ture if acceptable formatDesc: Opens and reads the spk file and loads all data into class*/bool CBaseFile::ReadFile ( CyString filename, int readtype, CProgressInfo *progress ){FILE *id = fopen ( filename.c_str(), "rb" );if ( !id )return false;bool ret = ReadFile ( id, readtype, progress );if ( ret )m_sFilename = filename;fclose ( id );return ret;}bool CBaseFile::ReadFile ( FILE *id, int readtype, CProgressInfo *progress ){ClearError ();// first read the headerif ( !ParseHeader ( GetEndOfLine ( id, NULL, false ) ) )return false;if ( readtype == SPKREAD_HEADER )return true;// update the progress for each sectionint maxProgress = (readtype == SPKREAD_VALUES) ? 3 : 6;if ( readtype != SPKREAD_ALL && progress )progress->UpdateProgress(1, maxProgress);long doneLen = 0;// next read the data values for the spk filesif ( m_SHeader.lValueCompressSize ){// read data to memoryunsigned char *readData = new unsigned char[m_SHeader.lValueCompressSize];unsigned char size[4];fread ( size, 4, 1, id );fread ( readData, sizeof(unsigned char), m_SHeader.lValueCompressSize, id );unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];// check for zlib compressionif ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB ){// uncomress the dataunsigned char *uncompr = new unsigned char[uncomprLen];int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lValueCompressSize );// update the progress for each sectionif ( readtype != SPKREAD_ALL && progress )progress->UpdateProgress(2, maxProgress);if ( err == Z_OK )ReadValues ( CyString ((char *)uncompr) );doneLen = uncomprLen;delete uncompr;}else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP ){long len = uncomprLen;unsigned char *compr = LZMADecode_C ( readData, m_SHeader.lValueCompressSize, (size_t*)&len, NULL );// update the progress for each sectionif ( readtype != SPKREAD_ALL && progress )progress->UpdateProgress(2, maxProgress);if ( compr )ReadValues ( CyString ((char *)compr) );}// no compressionelseReadValues ( CyString ((char *)readData) );delete readData;}// update the progress for each sectionif ( readtype != SPKREAD_ALL && progress )progress->UpdateProgress(3, maxProgress);if ( readtype == SPKREAD_VALUES )return true;// next should be the next headerif ( !ParseFileHeader ( GetEndOfLine (id, NULL, false) ) )return false;// clear the current file listm_lFiles.clear(true);// update the progress for each sectionif ( readtype != SPKREAD_ALL && progress )progress->UpdateProgress(4, maxProgress);if ( m_SHeader2.lSize ){unsigned char *readData = new unsigned char[m_SHeader2.lSize];unsigned char size[4];fread ( size, 4, 1, id );fread ( readData, sizeof(char), m_SHeader2.lSize, id );unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];// check for zlib compressionif ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB ){if ( uncomprLen < (unsigned long)doneLen )uncomprLen = doneLen;unsigned char *uncompr = new unsigned char[uncomprLen];int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader2.lSize );// update the progress for each sectionif ( readtype != SPKREAD_ALL && progress )progress->UpdateProgress(5, maxProgress);if ( err == Z_OK )ReadFiles ( CyString ((char *)uncompr) );delete uncompr;}else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP ){long len = uncomprLen;unsigned char *compr = LZMADecode_C ( readData, m_SHeader2.lSize, (size_t*)&len, NULL );// update the progress for each sectionif ( readtype != SPKREAD_ALL && progress )progress->UpdateProgress(5, maxProgress);if ( compr )ReadFiles ( CyString ((char *)compr) );}elseReadFiles ( CyString ((char *)readData) );delete readData;}// file mismatchlong numfiles = m_lFiles.size();if ( m_pIconFile )++numfiles;if ( m_SHeader2.iNumFiles != numfiles ){m_iLastError = SPKERR_FILEMISMATCH;return false;}// update the progress for each sectionif ( readtype != SPKREAD_ALL && progress )progress->UpdateProgress(6, maxProgress);if ( readtype == SPKREAD_ALL ){int fileCount = 2;if ( m_pIconFile )m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );// ok finally we need to read all the filesfor ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){node->Data()->ReadFromFile ( id, node->Data()->GetDataSize() );if ( progress )progress->UpdateProgress(fileCount++, m_lFiles.size() + 2);}m_bFullyLoaded = true;}return true;}bool CBaseFile::IsMod(){// check for any mod files that are not fake patchsfor ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() ){C_File *f = fNode->Data();if ( f->GetFileType() != FILETYPE_MOD )continue;if ( !f->IsFakePatch() )return true;}return false;}bool CBaseFile::IsFakePatch(){// check for any mod files that are not fake patchsfor ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() ){C_File *f = fNode->Data();if ( f->GetFileType() != FILETYPE_MOD )continue;if ( f->IsFakePatch() )return true;}return false;}CyString CBaseFile::CreateValuesLine (){CyString values ( "Name: " );values += (m_sName + "\n");values += (CyString("Author: ") + m_sAuthor + "\n");values += (CyString("Version: ") + m_sVersion + "\n");if ( !m_sCreationDate.Empty() )values += (CyString("Date: ") + m_sCreationDate + "\n");if ( !m_sWebAddress.Empty() )values += (CyString("WebAddress: ") + m_sWebAddress + "\n");if ( !m_sWebSite.Empty() )values += (CyString("WebSite: ") + m_sWebSite + "\n");if ( !m_sEmail.Empty() )values += (CyString("Email: ") + m_sEmail + "\n");for ( SStringList *str = m_lMirrors.Head(); str; str = str->next )values += (CyString("WebMirror: ") + str->str + "\n");if ( !m_sDescription.Empty() ){CyString desc = m_sDescription;desc = desc.FindReplace("<newline>", "<br>");desc = desc.FindReplace("\n", "<br>");desc.RemoveChar("\r");values += (CyString("Desc: ") + desc + "\n");}for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {if ( !gc->Data()->sVersion.Empty() )values += CyString("GameCompatExact: ") + (long)gc->Data()->iGame + " " + gc->Data()->sVersion + "\n";elsevalues += CyString("GameCompat: ") + (long)gc->Data()->iGame + " " + (long)gc->Data()->iVersion + "\n";}if ( !m_sForumLink.Empty() )values += (CyString("ForumLink: ") + m_sForumLink + "\n");if ( m_bSigned )values += "Signed\n";SInstallText *it;for ( it = m_lUninstallText.First(); it; it = m_lUninstallText.Next() ){if ( !it->sAfter.Empty() )values += (CyString("UninstallAfter: ") + CyString::Number(it->iLanguage) + "|" + it->sAfter + "\n");if ( !it->sBefore.Empty() )values += (CyString("UninstallBefore: ") + CyString::Number(it->iLanguage) + "|" + it->sBefore + "\n");}for ( it = m_lInstallText.First(); it; it = m_lInstallText.Next() ){if ( !it->sAfter.Empty() )values += (CyString("InstallAfter: ") + CyString::Number(it->iLanguage) + "|" + it->sAfter + "\n");if ( !it->sBefore.Empty() )values += (CyString("InstallBefore: ") + CyString::Number(it->iLanguage) + "|" + it->sBefore + "\n");}values += CyString("GameChanging: ") + CyString::Number(m_iGameChanging) + "\n";values += CyString("EaseOfUse: ") + CyString::Number(m_iEaseOfUse) + "\n";values += CyString("Recommended: ") + CyString::Number(m_iRecommended) + "\n";for ( SNames *sn = m_lNames.First(); sn; sn = m_lNames.Next() )values += CyString("ScriptName: ") + CyString::Number(sn->iLanguage) + ":" + sn->sName + "\n";for ( CListNode<SNeededLibrary> *libNode = m_lNeededLibrarys.Front(); libNode; libNode = libNode->next() ){SNeededLibrary *l = libNode->Data();values += (CyString("NeededLibrary: ") + l->sName + "||" + l->sAuthor + "||" + l->sMinVersion + "\n");}for ( SStringList *fpbNode = m_lFakePatchBefore.Head(); fpbNode; fpbNode = fpbNode->next )values += (CyString("FakePatchBefore: ") + fpbNode->str + "||" + fpbNode->data + "\n");for ( SStringList *fpaNode = m_lFakePatchAfter.Head(); fpaNode; fpaNode = fpaNode->next )values += (CyString("FakePatchAfter: ") + fpaNode->str + "||" + fpaNode->data + "\n");values += (CyString("PluginType: ") + (long)m_iPluginType + "\n");return values;}/*Func: CreateValuesLineReturn: String - returns the full string for valuesDesc: Creates a single string for all values, this is used when compressing to write to the spk file*/CyString CSpkFile::CreateValuesLine (){CyString values = CBaseFile::CreateValuesLine ();// combine all values togetherif ( (!m_sOtherAuthor.Empty()) && (!m_sOtherName.Empty()) )values += (CyString("AnotherMod: ") + m_sOtherAuthor + "|" + m_sOtherName + "\n");if ( m_bForceProfile )values += "ForceProfile\n";if ( !m_sScriptType.Empty() )values += (CyString("ScriptType: ") + m_sScriptType + "\n");values += (CyString("PackageType: ") + (long)m_iPackageType + "\n");values += (CyString("ScriptTypeNew: ") + (long)m_iScriptType + "\n");for ( SSettingType *st = m_lSettings.First(); st; st = m_lSettings.Next() )values += (CyString("Setting: ") + CyString::Number(st->iType) + "|" + st->sKey + "|" + GetSetting(st) + "\n");for ( SWares *ware = m_lWares.First(); ware; ware = m_lWares.Next() ){if ( ware->iTextID > 0 )values += CyString("Ware: ") + ware->cType + ":" + ware->iPrice + ":" + (long)ware->iSize + ":" + (long)ware->iVolumn + ":" + ware->sID + ":" + (long)ware->iNotority + ":" + (long)ware->iTextID + "," + (long)ware->iTextPage + "\n";elsevalues += CyString("Ware: ") + ware->cType + ":" + ware->iPrice + ":" + (long)ware->iSize + ":" + (long)ware->iVolumn + ":" + ware->sID + ":" + (long)ware->iNotority + "\n";for ( SWaresText *wt = ware->lText.First(); wt; wt = ware->lText.Next() )values += CyString("WareText: ") + (long)wt->iLang + " " + wt->sName + "|" + wt->sDesc + "\n";}return values;}CyString CSpkFile::GetCustomScriptType (int lang){if ( !m_sScriptType.Empty() ){int max;CyString *split = m_sScriptType.SplitToken("<br>", &max);if ( max && split ){for ( int i = 1; i < max; i++ ){CyString str = split[i];int num = str.GetToken(":", 1, 1).ToInt();CyString name = str.GetToken(":", 2);if ( num == lang ){CLEANSPLIT(split, max)return name;}}CyString ret = split[0];CLEANSPLIT(split, max)return ret;}CLEANSPLIT(split, max)}return m_sScriptType;}/*Func: WriteFileInput: filename - The filename of the spk file to write toDesc: Writes the data to an spk file*/bool CBaseFile::WriteFile ( CyString filename, CProgressInfo *progress ){FILE *id = fopen ( filename.c_str(), "wb" );if ( !id )return false;bool ret = WriteData ( id, progress );fclose ( id );return ret;}bool CSpkFile::WriteHeader(FILE *id, int valueheader, int valueComprLen){fprintf ( id, "SPKCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );if ( ferror(id) )return false;return true;}bool CBaseFile::WriteHeader(FILE *id, int valueheader, int valueComprLen){fprintf ( id, "BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );if ( ferror(id) )return false;return true;}bool CBaseFile::WriteData ( FILE *id, CProgressInfo *progress ){int valueheader = m_SHeader.iValueCompression, fileheader = m_SHeader.iValueCompression;if ( valueheader == SPKCOMPRESS_7ZIP )valueheader = SPKCOMPRESS_ZLIB;if ( fileheader == SPKCOMPRESS_7ZIP )fileheader = SPKCOMPRESS_ZLIB;// get the script valuesthis->UpdateSigned(true);CyString values = this->CreateValuesLine();// compress the valuesint valueUncomprLen = (int)values.Length();unsigned long valueComprLen = 0;unsigned char *valueCompr = NULL;bool compressed = false;if ( valueheader == SPKCOMPRESS_ZLIB ){valueComprLen = valueUncomprLen;if ( valueComprLen < 100 )valueComprLen = 200;else if ( valueComprLen < 1000 )valueComprLen *= 2;valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);int err = compress ( (unsigned char *)valueCompr, &valueComprLen, (const unsigned char *)values.c_str(), (unsigned long)values.Length(), 0 );if ( err == Z_OK )compressed = true;}if ( !compressed ){valueComprLen = valueUncomprLen;valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);memcpy ( valueCompr, values.c_str(), valueComprLen );valueheader = SPKCOMPRESS_NONE;}// write the main header to the fileif ( !this->WriteHeader(id, valueheader, valueComprLen) )return false;// write the compressed data to filefputc ( (unsigned char)(valueUncomprLen >> 24), id );fputc ( (unsigned char)(valueUncomprLen >> 16), id );fputc ( (unsigned char)(valueUncomprLen >> 8), id );fputc ( (unsigned char)valueUncomprLen, id );fwrite ( valueCompr, sizeof(char), valueComprLen, id );free ( valueCompr );// now compress the files header// create the files valuesCyString files = CreateFilesLine ( true, progress );// compress the files valueslong fileUncomprLen = (long)files.Length(), fileComprLen = fileUncomprLen;unsigned char *fileCompr = NULL;compressed = false;if ( fileUncomprLen ){if ( fileheader == SPKCOMPRESS_ZLIB ){if ( fileComprLen < 100 )fileComprLen = 200;else if ( fileComprLen < 1000 )fileComprLen *= 2;fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);int err = compress ( (unsigned char *)fileCompr, (unsigned long *)&fileComprLen, (const unsigned char *)files.c_str(), (unsigned long)files.Length(), 0 );if ( err == Z_OK )compressed = true;}}// if unable to compress, store it as plain textif ( !compressed ){fileComprLen = fileUncomprLen;fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);memcpy ( fileCompr, files.c_str(), fileComprLen );fileheader = SPKCOMPRESS_NONE;}// now write the file headerm_SHeader2.lSize = fileComprLen;fprintf ( id, "FileHeader;%d;%ld;%ld;%d;%d\n", m_SHeader2.iNumFiles, m_SHeader2.lSize, m_SHeader2.lFullSize, fileheader, m_SHeader2.iDataCompression );fputc ( (unsigned char)(fileUncomprLen >> 24), id );fputc ( (unsigned char)(fileUncomprLen >> 16), id );fputc ( (unsigned char)(fileUncomprLen >> 8), id );fputc ( (unsigned char)fileUncomprLen, id );fwrite ( fileCompr, sizeof(char), fileComprLen, id );free ( fileCompr );if ( progress ){progress->UpdateStatus(STATUS_WRITE);progress->SetDone(0);long max = 0;for ( C_File *file = m_lFiles.First(); file; file = m_lFiles.Next() )max += file->GetDataSize();if ( m_pIconFile )max += m_pIconFile->GetDataSize();progress->SetMax(max);}// now finally, write all the file dataif ( m_pIconFile ){if ( progress )progress->UpdateFile(m_pIconFile);fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 24), id );fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 16), id );fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 8), id );fputc ( (unsigned char)m_pIconFile->GetUncompressedDataSize(), id );fwrite ( m_pIconFile->GetData(), sizeof(char), m_pIconFile->GetDataSize(), id );if ( progress )progress->IncDone(m_pIconFile->GetDataSize());}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( progress )progress->UpdateFile(file);fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 24), id );fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 16), id );fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 8), id );fputc ( (unsigned char)file->GetUncompressedDataSize(), id );unsigned char *data = file->GetData();size_t remaining = file->GetDataSize();while ( remaining ){size_t writeSize = WRITECHUNK;if ( writeSize > remaining )writeSize = remaining;size_t written = fwrite ( data, sizeof(char), writeSize, id );data += written;remaining -= written;if ( progress )progress->IncDone((int)written);}}m_bChanged = false;return true;}void CSpkFile::AddWareText ( CyString rest ){if ( !m_pLastWare )return;SWaresText *wt = new SWaresText;wt->iLang = rest.GetToken ( 1, ' ' ).ToInt();wt->sName = rest.GetToken ( 2, -1, ' ' ).GetToken ( 1, '|' );wt->sDesc = rest.GetToken ( 2, -1, ' ' ).GetToken ( 2, -1, '|' );m_pLastWare->lText.push_back ( wt );m_bChanged = true;}void CSpkFile::AddWare ( CyString rest ){SWares *ware = new SWares;ware->iTextID = -1;ware->iTextPage = 0;ware->cType = rest.GetToken ( 1, ':' )[0];ware->iPrice = rest.GetToken ( 2, ':' ).ToLong();ware->iSize = rest.GetToken ( 3, ':' ).ToInt();ware->iVolumn = rest.GetToken ( 4, ':' ).ToInt();ware->sID = rest.GetToken ( 5, ':' );ware->iNotority = rest.GetToken ( 6, ':' ).ToInt();if ( !rest.GetToken( 7, ':' ).Empty() ){CyString r = rest.GetToken ( 7, ':' );ware->iTextID = r.GetToken(",", 1, 1).ToInt();ware->iTextPage = r.GetToken(",", 2, 2).ToInt();}m_lWares.push_back ( ware );m_pLastWare = ware;m_bChanged = true;}bool CSpkFile::ReadFileToMemory ( C_File *file ){if ( !file )return false;// check if data is already extractedif ( (file->GetDataSize ()) && (file->GetData()) )return true;// no file to read fromif ( m_sFilename.Empty() )return false;// now open the fileFILE *id = fopen ( m_sFilename.c_str(), "rb" );if ( !id )return false;// read the headerGetEndOfLine ( id, NULL, false );// skip past valuesfseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );// read the next headerGetEndOfLine ( id, NULL, false );// skip past filesfseek ( id, 4, SEEK_CUR );fseek ( id, m_SHeader2.lSize, SEEK_CUR );// skip the icon fileif ( m_pIconFile ){fseek ( id, 4, SEEK_CUR );fseek ( id, m_pIconFile->GetDataSize (), SEEK_CUR );}// now were in the file section// skip past each onefor ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();if ( fit == file )break;fseek ( id, 4, SEEK_CUR );fseek ( id, fit->GetDataSize(), SEEK_CUR );}// now we should be at the start of the file// read the data into memoryif ( !file->ReadFromFile ( id, file->GetDataSize() ) ){fclose ( id );return false;}fclose ( id );return true;}bool CBaseFile::ExtractFile ( C_File *file, CyString dir, bool includedir, CProgressInfo *progress ){if ( ReadFileToMemory ( file ) ){// now finally, uncompress the filelong len = 0;unsigned char *data = file->UncompressData ( &len, progress );if ( !data ){// attempt a file decompressif ( file->GetCompressionType() == SPKCOMPRESS_7ZIP ){if ( file->UncompressToFile ( dir, this, includedir, progress ) )return true;}return false;}if ( !file->WriteToDir ( dir, this, includedir, NullString, data, len ) )return false;return true;}elsereturn false;}bool CBaseFile::ExtractFile ( int filenum, CyString dir, bool includedir, CProgressInfo *progress ){// invalid valusif ( filenum < 0 )return false;// out of rangeif ( filenum > m_lFiles.size() )return false;// get the file pointerC_File *file = m_lFiles.Get ( filenum );return ExtractFile ( file, dir, includedir, progress );}bool CBaseFile::ExtractAll ( CyString dir, int game, bool includedir, CProgressInfo *progress ){// no file to read fromif ( m_sFilename.Empty() )return false;// now open the fileFILE *id = fopen ( m_sFilename.c_str(), "rb" );if ( !id )return false;fseek ( id, 0, SEEK_SET );// read the headerGetEndOfLine ( id, NULL, false );// skip past valuesfseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );// read the next headerGetEndOfLine ( id, NULL, false );// skip past filesfseek ( id, 4, SEEK_CUR );fseek ( id, m_SHeader2.lSize, SEEK_CUR );// now were in the file section// skip past each oneif ( m_pIconFile ){fseek ( id, 4, SEEK_CUR );fseek ( id, m_pIconFile->GetDataSize (), SEEK_CUR );}CDirIO Dir(dir);for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();if ( progress )progress->UpdateFile ( fit );if ( (!fit->GetDataSize ()) || (!fit->GetData()) ){if ( !fit->ReadFromFile ( id, fit->GetDataSize() ) ){fclose ( id );return false;}}elsefseek ( id, fit->GetDataSize(), SEEK_CUR );if ( game ) {if ( fit->GetGame() && fit->GetGame() != game )continue;}// create directory firstDir.Create(fit->GetDirectory(this));long size = 0;unsigned char *data = fit->UncompressData (&size, progress);if ( (!data) && (fit->GetCompressionType() == SPKCOMPRESS_7ZIP) ){if ( !fit->UncompressToFile ( dir, this, includedir, progress ) ){fclose ( id );return false;}}else if ( (!data) || (!fit->WriteToDir ( dir, this, includedir, NullString, data, size )) ){fclose ( id );return false;}}fclose ( id );return true;}bool CSpkFile::CheckValidReadmes (){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != FILETYPE_README )continue;if ( !file->CheckValidFilePointer() )continue;return true;}return false;}void CSpkFile::ClearWares(){for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() ){node->Data()->lText.clear(true);node->DeleteData();}m_bChanged = true;m_lWares.clear(true);}SWares *CSpkFile::FindWare ( CyString id ){for ( SWares *w = m_lWares.First(); w; w = m_lWares.Next() ){if ( w->sID.ToUpper() == id.ToUpper() )return w;}return NULL;}void CSpkFile::RemoveWare ( CyString id ){for ( SWares *w = m_lWares.First(); w; w = m_lWares.Next() ){if ( w->sID.ToUpper() == id.ToUpper() ){m_lWares.RemoveCurrent ();delete w;m_bChanged = true;return;}}}void CSpkFile::AddWare ( SWares *ware ){ware->sID.RemoveChar ( ' ' );ware->sID = ware->sID.ToUpper();SWares *newware = FindWare ( ware->sID );if ( newware )m_lWares.remove ( newware );m_lWares.push_back ( ware );m_bChanged = true;}void CSpkFile::AddWareText ( SWares *w, int lang, CyString name, CyString desc ){SWaresText *wt;for ( wt = w->lText.First(); wt; wt = w->lText.Next() ){if ( wt->iLang == lang ){wt->sDesc = desc;wt->sName = name;return;}}wt = new SWaresText;wt->iLang = lang;wt->sName = name;wt->sDesc = desc;w->lText.push_back ( wt );m_bChanged = true;}void CSpkFile::ClearWareText ( CyString id ){SWares *w = FindWare ( id );ClearWareText ( w );}void CSpkFile::ClearWareText ( SWares *w ){if ( !w ) return;w->lText.clear(true);m_bChanged = true;}void CSpkFile::RemoveWareText ( CyString wid, int lang ){SWares *w = FindWare ( wid );if ( w ){for ( SWaresText *wt = w->lText.First(); wt; wt = w->lText.Next() ){if ( wt->iLang == lang ){w->lText.RemoveCurrent();m_bChanged = true;delete wt;break;}}}}int CSpkFile::CheckValidCustomStart (){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != FILETYPE_SCRIPT )continue;CyString basename = file->GetName().GetToken ( 1, file->GetName().NumToken('.') - 1, '.' );if ( basename.ToLower().Right(15) == ".initplayership" )return 0;}if ( !IsAnotherMod() )return 1;elsereturn 2;}bool CBaseFile::UpdateSigned (bool updateFiles){m_bSigned = true;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( updateFiles )file->UpdateSigned();// extra, text, soundtrack, readmes and screen files do not require a modified game directlyif ( (file->GetFileType() == FILETYPE_EXTRA) || (file->GetFileType() == FILETYPE_TEXT) || (file->GetFileType() == FILETYPE_SOUND) || (file->GetFileType() == FILETYPE_SCREEN) || (file->GetFileType() == FILETYPE_README) )continue;// mods and maps always need modified gameelse if ( (file->GetFileType() == FILETYPE_MOD) || (file->GetFileType() == FILETYPE_MAP) ){m_bSigned = false;break;}// else should be a script file, script or uninstall type// all scripts must be signed, if any are not, then no signed statusif ( !file->IsSigned () ){m_bSigned = false;break;}}return m_bSigned;}bool CSpkFile::UpdateSigned (bool updateFiles){// check for any custom wares// patch mods and custom starts are also not signedif ( (!m_lWares.empty()) || (this->IsPatch()) || (this->IsCustomStart()) ){m_bSigned = false;return false;}return CBaseFile::UpdateSigned(updateFiles);}SSettingType *CSpkFile::AddSetting ( CyString key, int type ){key.RemoveChar ( '|' );SSettingType *t;for ( t = m_lSettings.First(); t; t = m_lSettings.Next() ){if ( t->sKey.upper() == key.lower() )return NULL;}switch ( type ){case SETTING_STRING:t = new SSettingString;break;case SETTING_INTEGER:t = new SSettingInteger;break;case SETTING_CHECK:t = new SSettingCheck;break;}if ( !t )return NULL;t->sKey = key;t->iType = type;m_lSettings.push_back ( t );m_bChanged = true;return t;}void CSpkFile::ConvertSetting ( SSettingType *t, CyString set ){if ( !t )return;switch ( t->iType ){case SETTING_STRING:((SSettingString *)t)->sValue = set;break;case SETTING_INTEGER:((SSettingInteger *)t)->iValue = set.ToInt();break;case SETTING_CHECK:((SSettingCheck *)t)->bValue = set.ToBool();break;}}CyString CSpkFile::GetSetting ( SSettingType *t ){if ( !t )return "";switch ( t->iType ){case SETTING_STRING:return ((SSettingString *)t)->sValue;case SETTING_INTEGER:return CyString::Number(((SSettingInteger *)t)->iValue);case SETTING_CHECK:return (((SSettingInteger *)t)->iValue) ? "1" : "0";}return "";}void CSpkFile::ClearSettings (){m_lSettings.clear(true);m_bChanged = true;}bool CSpkFile::IsMatchingMod ( CyString mod ){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != FILETYPE_MOD )continue;if ( file->IsFakePatch() )continue;CyString filename = file->GetBaseName();if ( filename.lower() == mod.lower() )return true;}return false;}CyString CSpkFile::GetScriptTypeString(int lang){int iType = m_iScriptType;if ( this->IsLibrary() )return "Library";else if ( this->IsPackageUpdate() )return "Package Update";else if ( this->IsCustomStart() )return "Custom Start";else if ( this->IsPatch() )return "Patch";else if ( m_iScriptType == SCRIPTTYPE_CUSTOM ){CyString type = this->GetCustomScriptType(lang);if ( !type.Empty() )return type;iType = -1;}if (iType == -1) // no script type{if ( this->IsFakePatch() )return "Fake Patch";}CyString sType = CSpkFile::GetScriptTypeStringStatic(m_iScriptType);if ( sType.Empty() )return "Other";return sType;}int CSpkFile::ConvertScriptType(CyString sType){for ( int i = 0; i < SCRIPTTYPE_MAX; i++ ){if ( sType.Compare(CSpkFile::GetScriptTypeStringStatic(i)) )return i;}return -1;}CyString CSpkFile::GetScriptTypeStringStatic(int type){switch ( type ){case SCRIPTTYPE_CUSTOM:return "Custom";case SCRIPTTYPE_NAVIGATION:return "Navigation";case SCRIPTTYPE_COMBAT:return "Combat";case SCRIPTTYPE_MISSION:return "Mission";case SCRIPTTYPE_ALPLUGIN:return "AL Plugin";case SCRIPTTYPE_HOTKEY:return "Hotkey";case SCRIPTTYPE_SHIPUPGRADE:return "Ship Upgrade";case SCRIPTTYPE_SHIPCOMMAND:return "Ship Command";case SCRIPTTYPE_STATIONCOMMAND:return "Station Command";case SCRIPTTYPE_FLEET:return "Fleet Management";case SCRIPTTYPE_TRADE:return "Trade";case SCRIPTTYPE_PIRACY:return "Piracy";case SCRIPTTYPE_CHEAT:return "Cheat";case SCRIPTTYPE_EXTENSION:return "Extension Mods";case SCRIPTTYPE_REBALANCE:return "Rebalance";case SCRIPTTYPE_FIX:return "Vanilla Fix";case SCRIPTTYPE_GENERALMOD:return "General Mod";case SCRIPTTYPE_TOTAL:return "Totel Conversion";case SCRIPTTYPE_WINGCOMMAND:return "Wing Command";}return "Other";}bool CBaseFile::IsPackageNeeded(CyString scriptName, CyString author){for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() ){SNeededLibrary *l = node->Data();if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )return true;}return false;}SNeededLibrary *CBaseFile::FindPackageNeeded(CyString scriptName, CyString author){for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() ){SNeededLibrary *l = node->Data();if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )return l;}return NULL;}void CBaseFile::RemoveFakePatchOrder(CyString scriptName, CyString author){RemoveFakePatchOrder(true, scriptName, author);RemoveFakePatchOrder(false, scriptName, author);}void CBaseFile::RemoveFakePatchOrder(bool after, CyString scriptName, CyString author){CyStringList *list;if ( after )list = &m_lFakePatchAfter;elselist = &m_lFakePatchBefore;for ( SStringList *str = list->Head(); str; str = str->next ){// already addedif ( str->str.Compare(scriptName) && str->data.Compare(author) )str->remove = true;}list->RemoveMarked();}void CBaseFile::AddFakePatchOrder(bool after, CyString scriptName, CyString author){CyStringList *list;if ( after )list = &m_lFakePatchAfter;elselist = &m_lFakePatchBefore;// check if the package already existsfor ( SStringList *str = list->Head(); str; str = str->next ){// already addedif ( str->str.Compare(scriptName) && str->data.Compare(author) )return;}// cant have it on both listRemoveFakePatchOrder(!after, scriptName, author);list->PushBack(scriptName, author);}void CBaseFile::AddNeededLibrary(CyString scriptName, CyString author, CyString minVersion){SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);if ( !l ){l = new SNeededLibrary;l->sName = scriptName;l->sAuthor = author;m_lNeededLibrarys.push_back(l);}l->sMinVersion = minVersion;}void CBaseFile::RemovePackageNeeded(CyString scriptName, CyString author){SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);if ( l ){m_lNeededLibrarys.remove(l);delete l;}}void CBaseFile::ClearNeededPackages(){SNeededLibrary *ns = this->FindPackageNeeded("<package>", "<author>");CyString version;if ( ns )version = ns->sMinVersion;for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )node->DeleteData();m_lNeededLibrarys.clear();if ( !version.Empty() )this->AddNeededLibrary("<package>", "<author>", version);}bool CSpkFile::LoadPackageData(CyString first, CyString rest){if ( first.Compare("ScriptType") ){if ( rest.Compare("Library") || rest.Compare("Library Script") )this->SetLibrary();else if ( rest.Compare("Update") || rest.Compare("Package Update") || rest.Compare("Mod Update") )this->SetPackageUpdate();else if ( rest.Compare("Start") || rest.Compare("Custom Start") )this->SetCustomStart();else if ( rest.Compare("Patch") || rest.Compare("Patch Mod") )this->SetPatch();else{int check = rest.ToInt();if ( check || rest == "0" )m_iScriptType = check;else{m_iScriptType = CSpkFile::ConvertScriptType(rest);if ( m_iScriptType == -1 )m_sScriptType = rest;}}}else if ( first.Compare("AnotherMod") ){m_sOtherName = rest.GetToken("|", 1, 1);m_sOtherAuthor = rest.GetToken("|", 2);}else if ( first.Compare("WareName") || first.Compare("WareDesc") ){// find the ware to useSWares *useWare = m_pLastWare;CyString id = rest.GetToken(" ", 1, 1);for ( CListNode<SWares> *wNode = m_lWares.Front(); wNode; wNode = wNode->next() ){if ( wNode->Data()->sID.Compare(id) ){useWare = wNode->Data();break;}}// check if we have the id alreadyif ( useWare ){int lang = rest.GetToken(" ", 2, 2).ToInt();SWaresText *wt = NULL;for ( CListNode<SWaresText> *tNode = useWare->lText.Front(); tNode; tNode = tNode->next() ){if ( tNode->Data()->iLang == lang ){wt = tNode->Data();break;}}if ( !wt ){wt = new SWaresText;wt->iLang = lang;useWare->lText.push_back(wt);}if ( first.Compare("WareName") )wt->sName = rest.GetToken(" ", 3);elsewt->sDesc = rest.GetToken(" ", 3);}}else if ( first.Left(4).Compare("Ware") ){SWares *ware = new SWares;ware->iTextID = -1;ware->iTextPage = 0;ware->cType = first[4];ware->iPrice = rest.GetToken ( " ", 2, 2 ).ToLong();ware->iSize = rest.GetToken ( " ", 3, 3 ).ToInt();ware->iVolumn = rest.GetToken ( " ", 4, 4 ).ToInt();ware->sID = rest.GetToken ( " ", 1, 1 );ware->iNotority = rest.GetToken ( " ", 5, 5 ).ToInt();if ( !rest.GetToken(" ", 6, 6).Empty() ){ware->iTextID = rest.GetToken ( " ", 6, 6 ).GetToken(",", 2, 2).ToInt();ware->iTextPage = rest.GetToken ( " ", 6, 6 ).GetToken(",", 1, 1).ToInt();}m_lWares.push_back ( ware );m_pLastWare = ware;}else if ( CBaseFile::LoadPackageData(first, rest) )return true;elsereturn false;return true;}bool CSpkFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile){if ( !CBaseFile::GeneratePackagerScript(wildcard, list, datafile) )return false;list->PushBack("# Script Type, the type of package file, some are special types, others are just for show");if ( this->IsLibrary() )list->PushBack("ScriptType: Library");else if ( this->IsPackageUpdate() )list->PushBack("ScriptType: Package Update");else if ( this->IsCustomStart() )list->PushBack("ScriptType: Custom Start");else if ( this->IsPatch() )list->PushBack("ScriptType: Patch");elselist->PushBack(CyString("ScriptType: ") + this->GetScriptTypeString(44));list->PushBack("");if ( this->IsAnotherMod() ){list->PushBack("# For another mod/package, this is a child package");list->PushBack(CyString("AnotherMod: ") + m_sOtherName + "|" + m_sOtherAuthor);list->PushBack("");}if ( !m_lWares.empty() ){list->PushBack("# Custom Wares, Ware<type>: <id> <price> <size> <volumn> <notority>");for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() ){SWares *w = node->Data();if ( w->iTextID > 0 )list->PushBack(CyString("Ware") + (char)w->cType + ": " + w->sID + " " + (long)w->iPrice + " " + (long)w->iSize + " " + (long)w->iVolumn + " " + (long)w->iNotority + " " + (long)w->iTextPage + "," + (long)w->iTextID);elselist->PushBack(CyString("Ware") + (char)w->cType + ": " + w->sID + " " + (long)w->iPrice + " " + (long)w->iSize + " " + (long)w->iVolumn + " " + (long)w->iNotority);for ( CListNode<SWaresText> *wNode = w->lText.Front(); wNode; wNode = wNode->next() ){SWaresText *wt = wNode->Data();if ( !wt->sName.Empty() )list->PushBack(CyString("WareName: ") + w->sID + " " + (long)wt->iLang + " " + wt->sName);if ( !wt->sDesc.Empty() )list->PushBack(CyString("WareDesc: ") + w->sID + " " + (long)wt->iLang + " " + wt->sDesc);}list->PushBack("");}}if ( !datafile ){if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list) )return false;}return true;}bool CBaseFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile){list->PushBack("#");list->PushBack(CyString("# Packager Script"));list->PushBack(CyString("# -- Generated by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2) + " --");list->PushBack("#");list->PushBack("");if ( !datafile ){list->PushBack("# Variable for your game directory, where to get files from");list->PushBack("# $PATH variable is used to get the current path");list->PushBack("Variable: $GAMEDIR $PATH");list->PushBack("");}list->PushBack("# The name of the script");list->PushBack(CyString("Name: ") + m_sName);list->PushBack("");list->PushBack("# The author of the script, ie, you");list->PushBack(CyString("Author: ") + m_sAuthor);list->PushBack("");list->PushBack("# The creation data, when it was created");if ( datafile )list->PushBack(CyString("Date: ") + m_sCreationDate);else{list->PushBack("# $DATE variable is used to get the current date");list->PushBack("Date: $DATE");}list->PushBack("");list->PushBack("# The version of script");if ( datafile )list->PushBack(CyString("Version: ") + m_sVersion);else{list->PushBack("# $ASK variable is used to get an input when creating");list->PushBack("Version: $ASK");}list->PushBack("");if ( !m_lGames.empty() ) {list->PushBack("# The game version the script is for <game> <version> (can have multiple games)");for ( SGameCompat *g = m_lGames.First(); g; g = m_lGames.Next() ) {CyString game = CBaseFile::ConvertGameToString(g->iGame);if ( !g->sVersion.Empty() ){game += " ";game += g->sVersion;}else{game += " ";game += (long)g->iVersion;}list->PushBack(CyString("Game: ") + game);}list->PushBack("");}if ( !m_sDescription.Empty() ){list->PushBack("# The description of the script, displays when installing");list->PushBack(CyString("Description: ") + m_sDescription);list->PushBack("");}if ( !m_sWebSite.Empty() ){list->PushBack("# A link to the website for the script, ie for an online help page");list->PushBack(CyString("WebSite: ") + m_sWebSite);list->PushBack("");}if ( !m_sForumLink.Empty() ){list->PushBack("# A direct link to the thread in the egosoft forum");list->PushBack(CyString("ForumLink: ") + m_sForumLink);list->PushBack("");}if ( !m_sWebAddress.Empty() ){list->PushBack("# A link to the address for the update file");list->PushBack(CyString("WebAddress: ") + m_sWebAddress);list->PushBack("");}if ( !m_sEmail.Empty() ){list->PushBack("# The email address of the author, to allow users to contract if needed");list->PushBack(CyString("Email: ") + m_sEmail);list->PushBack("");}if ( m_lMirrors.Count() ){list->PushBack("# A link to the mirror address for the update file, can have many of these");for ( SStringList *node = m_lMirrors.Head(); node; node = node->next )list->PushBack(CyString("WebMirror: ") + node->str);list->PushBack("");}if ( m_bAutoGenerateUpdateFile ){list->PushBack("# Auto generate the package update file when created");list->PushBack("GenerateUpdateFile");}if ( m_lNeededLibrarys.size() ){list->PushBack("# Needed Library dependacies, require these to be installed");for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )list->PushBack(CyString("Depend: ") + node->Data()->sName + "|" + node->Data()->sMinVersion + "|" + node->Data()->sAuthor);list->PushBack("");}if ( m_iEaseOfUse != -1 && m_iRecommended != -1 && m_iGameChanging != -1 ){list->PushBack("# Ratings Values, 0 to 5, <ease> <changing> <recommended>");list->PushBack(CyString("Ratings: ") + (long)m_iEaseOfUse + " " + (long)m_iGameChanging + " " + (long)m_iRecommended);list->PushBack("");}if ( m_lNames.size() ){list->PushBack("# Package names, uses different names for different languages");for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )list->PushBack(CyString("ScriptName: ") + (long)node->Data()->iLanguage + " " + node->Data()->sName);list->PushBack("");}if ( m_lInstallText.size() ){list->PushBack("# Install Texts, display text before and/or after installing to inform the use of special conditions");for ( CListNode<SInstallText> *node = m_lInstallText.Front(); node; node = node->next() ){if ( !node->Data()->sBefore.Empty() )list->PushBack(CyString("InstallBefore: ") + (long)node->Data()->iLanguage + " " + node->Data()->sBefore);if ( !node->Data()->sAfter.Empty() )list->PushBack(CyString("InstallAfter: ") + (long)node->Data()->iLanguage + " " + node->Data()->sAfter);}list->PushBack("");}if ( m_lUninstallText.size() ){list->PushBack("# Uninstall Texts, display text before and/or after uninstalling to inform the use of special conditions");for ( CListNode<SInstallText> *node = m_lUninstallText.Front(); node; node = node->next() ){if ( !node->Data()->sBefore.Empty() )list->PushBack(CyString("UninstallBefore: ") + (long)node->Data()->iLanguage + " " + node->Data()->sBefore);if ( !node->Data()->sAfter.Empty() )list->PushBack(CyString("UninstallAfter: ") + (long)node->Data()->iLanguage + " " + node->Data()->sAfter);}list->PushBack("");}list->PushBack("# Plugin Type, the type the plugin is, mainly used to show users the type, types include: Normal, Stable, Experimental, Cheat, Mod");switch ( this->GetPluginType() ){case PLUGIN_NORMAL:list->PushBack("PluginType: Normal");break;case PLUGIN_STABLE:list->PushBack("PluginType: Stable");break;case PLUGIN_EXPERIMENTAL:list->PushBack("PluginType: Experimental");break;case PLUGIN_CHEAT:list->PushBack("PluginType: Cheat");break;case PLUGIN_MOD:list->PushBack("PluginType: Mod");break;}list->PushBack("");return true;}bool CBaseFile::GeneratePackagerScriptFile(bool wildcard, CyStringList *list){// now do files and wildcardsCyStringList files;for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() ){CyString name = "$GAMEDIR/";bool done = false;if ( wildcard ){CyString base = f->Data()->GetBaseName();if ( f->Data()->GetFileType() == FILETYPE_SCRIPT ){if ( base.GetToken(".", 1, 1).Compare("plugin") || base.GetToken(".", 1, 1).Compare("lib") ){name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";done = true;}else if ( base.GetToken(".", 1, 1).Compare("al") && !base.GetToken(".", 2, 2).Compare("plugin") ){name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";done = true;}}else if ( f->Data()->GetFileType() == FILETYPE_TEXT ){if ( base.IsIn("-L") ){name += f->Data()->GetDirectory(this) + "/" + base.GetToken("-L", 1, 1) + "-L*";done = true;}else{name += f->Data()->GetDirectory(this) + "/*" + base.Right(4) + ".*";done = true;}}}if ( !done )name += f->Data()->GetNameDirectory(this);if ( !f->Data()->GetDir().Empty() ){name += "|";name += f->Data()->GetDir();}files.PushBack(CyString("GAME ") + CBaseFile::ConvertGameToString(f->Data()->GetGame()) + " " + name, f->Data()->GetFileTypeString(), true);}if ( !files.Empty() ){list->PushBack("# Files List, all the files to add, can include wild cards");for ( SStringList *node = files.Head(); node; node = node->next )list->PushBack(node->data + ": " + node->str);list->PushBack("");}return true;}CyString CBaseFile::GetAutosaveName(){CyString cdate = m_sCreationDate;cdate = cdate.FindReplace("/", ".");CyString name = m_sName + "-V" + m_sVersion + "-" + cdate;return name;}bool CBaseFile::CheckGameCompatability(int game){if ( m_lGames.empty() )return true; // no game compatability added, assume its ok for allfor ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {if ( node->Data()->iGame == 0 || node->Data()->iGame == game )return true;}return false;}bool CBaseFile::CheckGameVersionCompatability(int game, CyString sVersion, int iVersion){if ( m_lGames.empty() )return true; // no game compatability added, assume its ok for allbool foundAll = false;for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {if ( node->Data()->iGame == 0 )foundAll = true;else if ( node->Data()->iGame == game ) { // now check the versionif ( node->Data()->sVersion.Empty() ) {if ( node->Data()->sVersion.CompareVersion(sVersion) == COMPARE_OLDER )return false;return true;}else {if ( node->Data()->iVersion > iVersion )return false;return true;}}}return foundAll;}bool CBaseFile::RemoveGameCompatability(int game){for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {if ( node->Data()->iGame == game ) {m_lGames.remove(node);m_bChanged = true;return true;}}return false;}SGameCompat *CBaseFile::GetGameCompatability(int game){for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {if ( node->Data()->iGame == game ) {return node->Data();}}return NULL;}void CBaseFile::AddGameCompatability(int game, CyString version){// first check if we already have it on the listSGameCompat *Found = this->GetGameCompatability(game);if ( !Found ) {Found = new SGameCompat;m_lGames.push_back(Found);}Found->iGame = game;Found->iVersion = -1;Found->sVersion = NullString;if ( version.IsIn(".") || !version.IsNumber() )Found->sVersion = version;elseFound->iVersion = version.ToInt();m_bChanged = true;}bool CBaseFile::LoadPackageData(CyString first, CyString rest){if ( first.Compare("Name") )m_sName = rest;else if ( first.Compare("Author") )m_sAuthor = rest;else if ( first.Compare("ScriptName") )AddLanguageName(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));else if ( first.Compare("UninstallBefore") )this->AddUninstallBeforeText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));else if ( first.Compare("UninstallAfter") )this->AddUninstallAfterText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));else if ( first.Compare("InstallBefore") )this->AddInstallBeforeText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));else if ( first.Compare("InstallAfter") )this->AddInstallAfterText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));else if ( first.Compare("Date") )m_sCreationDate = rest;else if ( first.Compare("Version") )m_sVersion = rest;// old versionelse if ( first.Compare("GameVersion") )this->AddGameCompatability(-1, rest);else if ( first.Compare("PluginType") ){if ( rest.IsNumber() )this->SetPluginType(rest.ToInt());else if ( rest.Compare("Normal") )this->SetPluginType(PLUGIN_NORMAL);else if ( rest.Compare("Stable") )this->SetPluginType(PLUGIN_STABLE);else if ( rest.Compare("Experimental") )this->SetPluginType(PLUGIN_EXPERIMENTAL);else if ( rest.Compare("Cheat") )this->SetPluginType(PLUGIN_CHEAT);else if ( rest.Compare("Mod") )this->SetPluginType(PLUGIN_MOD);}// new versionelse if ( first.Compare("GenerateUpdateFile") )m_bAutoGenerateUpdateFile = true;else if ( first.Compare("Game") ){CyString sGame = rest.GetToken(" ", 1, 1);this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), rest.GetToken(" ", 2, 2));}else if ( first.Compare("Description") )m_sDescription = rest;else if ( first.Compare("AutoSave") || first.Compare("AutoExport") || first.Compare("AutoRarExport") || first.Compare("AutoZipExport") ){CyString filename = rest;CyString name = m_sName;CyString author = m_sAuthor;CyString cdate = m_sCreationDate;cdate = cdate.FindReplace("/", ".").Remove(" ");if ( filename.IsIn("$AUTOSAVE") ){if ( m_iType == TYPE_XSP )filename.FindReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.xsp");elsefilename.FindReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.spk");}if ( filename.IsIn("$NAME") )filename.FindReplace("$NAME", name.Remove(" "));if ( filename.IsIn("$AUTHOR") )filename.FindReplace("$AUTHOR", author.Remove(" "));if ( filename.IsIn("$DATE") )filename.FindReplace("$DATE", cdate);if ( filename.IsIn("$CDATE") )filename.FindReplace("$CDATE", cdate);if ( filename.IsIn("$VERSION") )filename.FindReplace("$VERSION", m_sVersion);if ( first.Compare("AutoZipExport") || first.Compare("AutoExport") )m_sExportFilename = CFileIO(filename).ChangeFileExtension("zip");else if ( first.Compare("AutoRarExport") )m_sExportFilename = CFileIO(filename).ChangeFileExtension("rar");elsem_sFilename = filename;}else if ( first.Compare("WebSite") )m_sWebSite = rest;else if ( first.Compare("ForumLink") || first.Compare("Forum") )m_sForumLink = rest;else if ( first.Compare("Email") )m_sEmail = rest;else if ( first.Compare("WebAddress") )m_sWebAddress = rest;else if ( first.Compare("WebMirror") )this->AddWebMirror(rest);else if ( first.Compare("WebMirror1") )this->AddWebMirror(rest);else if ( first.Compare("WebMirror2") )this->AddWebMirror(rest);else if ( first.Compare("Ftp") )m_sFtpAddr = rest;else if ( first.Compare("Ratings") ){m_iEaseOfUse = rest.GetToken(" ", 1, 1).ToInt();m_iGameChanging = rest.GetToken(" ", 2, 2).ToInt();m_iRecommended = rest.GetToken(" ", 3, 3).ToInt();}else if ( first.Compare("EaseOfUse") )m_iEaseOfUse = rest.ToInt();else if ( first.Compare("GameChanging") )m_iGameChanging = rest.ToInt();else if ( first.Compare("Recommended") )m_iRecommended = rest.ToInt();else if ( first.Compare("Depend") ){CyString version = rest.GetToken("|", 2, 2);CyString name = rest.GetToken("|", 1, 1);CyString author = rest.GetToken("|", 3);this->AddNeededLibrary(name, author, version);}else if ( first.Compare("DependPackage") ){CPackages p;CBaseFile *spk = p.OpenPackage(rest, 0, 0, SPKREAD_VALUES);if ( spk ){this->AddNeededLibrary(spk->GetName(), spk->GetAuthor(), spk->GetVersion());delete spk;}}else if ( first.Compare("Icon") ){C_File *icon = new C_File(rest);if ( icon->ReadFromFile() )this->SetIcon(icon, CFileIO(rest).GetFileExtension());}else{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 )this->AddFileScript(filetype, shared, rest);else if ( !checkType.Compare("changelog") )return false;}return true;}void CBaseFile::AddFileScript(int filetype, bool shared, CyString rest){CyString dir;if ( rest.IsIn("|") ){dir = rest.GetToken("|", 2);rest = rest.GetToken("|", 1, 1);}int game = 0;if ( rest.GetToken(" ", 1, 1).Left(4).Compare("GAME") ) {game = CBaseFile::GetGameFromString(rest.GetToken(" ", 2, 2));rest = rest.GetToken(" ", 3);}rest = rest.FindReplace("\\", "/");// wild cardsif ( rest.IsAnyIn("*?") ){CDirIO Dir(CFileIO(rest).GetDir());CyStringList *dirList = Dir.DirList();if ( dirList ){for ( SStringList *strNode = dirList->Head(); strNode; strNode = strNode->next ){CyString file = Dir.File(strNode->str);if ( file.WildMatch(rest) ){C_File *newfile = this->AppendFile(file, filetype, game, dir);if ( newfile )newfile->SetShared(shared);}}delete dirList;}}else{C_File *file = this->AppendFile(rest, filetype, game, dir);if ( file )file->SetShared(shared);}}CyString CSpkFile::GetWareText(SWares *w, int lang){// return the text page if being usedif ( w->iTextID > 0 && w->iTextPage > 0 )return CyString("{") + (long)w->iTextPage + "," + (long)w->iTextID + "}";CyString name;for ( CListNode<SWaresText> *wt = w->lText.Front(); wt; wt = wt->next() ){if ( wt->Data()->sName.Empty() )continue;if ( wt->Data()->iLang == lang )name = wt->Data()->sName;else if ( name.Empty() && wt->Data()->iLang == 44 )name = wt->Data()->sName;else if ( name.Empty() )name = wt->Data()->sName;}return name;}CyString CSpkFile::GetWareDesc(SWares *w, int lang){// return the text page if being usedif ( w->iTextID > 0 && w->iTextPage > 0 )return CyString("{") + (long)w->iTextPage + "," + ((long)w->iTextID + 1) + "}";CyString name;for ( CListNode<SWaresText> *wt = w->lText.Front(); wt; wt = wt->next() ){if ( wt->Data()->sDesc.Empty() )continue;if ( wt->Data()->iLang == lang )name = wt->Data()->sDesc;else if ( name.Empty() && wt->Data()->iLang == 44 )name = wt->Data()->sDesc;else if ( name.Empty() )name = wt->Data()->sDesc;}return name;}CyString CSpkFile::GetCustomStartName(){if ( !this->IsCustomStart() )return NullString;// else find the custom start scriptC_File *file = NULL;for ( file = this->GetFirstFile(FILETYPE_SCRIPT); file; file = this->GetNextFile(file) ){if ( file->GetFilename().IsIn("initplayership") && file->GetFilename().GetToken(".", 1, 1).Compare("galaxy") )break;}if ( !file )return NullString;return file->GetFilename().GetToken(".", 2, 2);}CyString CBaseFile::GetFullFileSizeString() { return SPK::GetSizeString ( this->GetFullFileSize() ); }unsigned char *CBaseFile::CreateData(size_t *size, CProgressInfo *progress){if ( this->WriteFile("temp.dat", progress) ){FILE *id = fopen("temp.dat", "rb");if ( id ){fseek(id, 0, SEEK_END);*size = ftell(id);fseek(id, 0, SEEK_SET);unsigned char *data = new unsigned char[*size];fread(data, sizeof(unsigned char), *size, id);fclose(id);remove("temp.dat");return data;}}remove("temp.dat");return NULL;}void CSpkFile::MergePackage(CBaseFile *base){// update version informationm_sVersion = base->GetVersion();m_sCreationDate = base->GetCreationDate();m_iPluginType = base->GetPluginType();// update possible changesif ( base->GetType() == TYPE_SPK ){CSpkFile *spk = (CSpkFile *)base;m_bForceProfile = spk->IsForceProfile();// add any new waresif ( spk->AnyWares() ){for ( CListNode<SWares> *node = spk->GetWaresList()->Front(); node; node = node->next() )this->AddWare(node->Data());spk->GetWaresList()->clear(); // remove wares so they aren't deleted}// add any settingsif ( spk->AnySettings() ){for ( CListNode<SSettingType> *node = spk->GetSettingsList()->Front(); node; node = node->next() )this->AddSetting(node->Data()->sKey, node->Data()->iType);}if ( !spk->GetOtherName().Empty() ){m_sOtherName = spk->GetOtherName();m_sOtherAuthor = spk->GetOtherAuthor();}}// copy settings from base classm_iGameChanging = base->GetGameChanging();m_iRecommended = base->GetRecommended();m_iEaseOfUse = base->GetEaseOfUse();for ( CListNode<SGameCompat> *gNode = base->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {if ( !gNode->Data()->sVersion.Empty() )this->AddGameCompatability(gNode->Data()->iGame, gNode->Data()->sVersion);elsethis->AddGameCompatability(gNode->Data()->iGame, CyString::Number(gNode->Data()->iVersion));}if ( !base->GetWebAddress().Empty() )m_sWebAddress = base->GetWebAddress();if ( !base->GetWebSite().Empty() )m_sWebSite = base->GetWebSite();if ( !base->GetEmail().Empty() )m_sEmail = base->GetEmail();if ( !base->GetForumLink().Empty() )m_sForumLink = base->GetForumLink();m_sDescription = base->GetDescription();// copy over needed librarysfor ( CListNode<SNeededLibrary> *lNode = base->GetNeededLibraries()->Front(); lNode; lNode = lNode->next() )this->AddNeededLibrary(lNode->Data()->sName, lNode->Data()->sAuthor, lNode->Data()->sMinVersion);// web mirror address, add any new onesfor ( SStringList *str = base->GetWebMirrors()->Head(); str; str = str->next )this->AddWebMirror(str->str);// copy over any install textfor ( CListNode<SInstallText> *iNode = base->GetInstallTextList()->Front(); iNode; iNode = iNode->next() ){if ( !iNode->Data()->sAfter.Empty() )this->AddInstallAfterText(iNode->Data()->iLanguage, iNode->Data()->sAfter);if ( !iNode->Data()->sBefore.Empty() )this->AddInstallBeforeText(iNode->Data()->iLanguage, iNode->Data()->sBefore);}for ( CListNode<SInstallText> *iNode = base->GetUninstallTextList()->Front(); iNode; iNode = iNode->next() ){if ( !iNode->Data()->sAfter.Empty() )this->AddUninstallAfterText(iNode->Data()->iLanguage, iNode->Data()->sAfter);if ( !iNode->Data()->sBefore.Empty() )this->AddUninstallBeforeText(iNode->Data()->iLanguage, iNode->Data()->sBefore);}// copy over package namesfor ( CListNode<SNames> *nNode = base->GetNamesList()->Front(); nNode; nNode = nNode->next() )this->AddLanguageName(nNode->Data()->iLanguage, nNode->Data()->sName);// finally do all the filesfor ( CListNode<C_File> *node = base->GetFileList()->Front(); node; node = node->next() ){C_File *f = node->Data();// if it exists, remove the oldfor ( CListNode<C_File> *thisNode = m_lFiles.Front(); thisNode; thisNode = thisNode->next() ){if ( thisNode->Data()->GetFileType() == f->GetFileType() && thisNode->Data()->GetFilename().Compare(f->GetFilename()) && thisNode->Data()->GetDir().Compare(f->GetDir()) ){m_lFiles.remove(thisNode);break;}}m_lFiles.push_back(f);}// clear the files so we dont delete them laterbase->GetFileList()->clear();}void CBaseFile::ConvertNormalMod(C_File *f, CyString to){C_File *match = this->FindMatchingMod(f);if ( match ){// file linkif ( !match->GetData() )match->ReadFromFile();match->ChangeBaseName(to);}// file linkif ( !f->GetData() )f->ReadFromFile();f->ChangeBaseName(to);}void CBaseFile::ConvertAutoText(C_File *f){CyString to;if ( f->GetBaseName().IsIn("-L") )to = CyString("0000-L") + f->GetBaseName().GetToken("-L", 2, 2);else if ( f->GetBaseName().IsIn("-l") )to = CyString("0000-L") + f->GetBaseName().GetToken("-l", 2, 2);elseto = f->GetBaseName().Left(-4) + "0000";// file linkif ( !f->GetData() )f->ReadFromFile();f->ChangeBaseName(to);}void CBaseFile::ConvertFakePatch(C_File *f){// find next available fake patchint num = 0;bool found = true;while ( found ){++num;found = false;CyString find = CyString::Number(num).PadNumber(2);for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){if ( node->Data()->GetFileType() != FILETYPE_MOD )continue;if ( !node->Data()->IsFakePatch() )continue;if ( node->Data()->GetBaseName().Compare(find) ){found = true;break;}}}CyString to = CyString::Number(num).PadNumber(2);C_File *match = this->FindMatchingMod(f);// file linkif ( !f->GetData() )f->ReadFromFile();f->ChangeBaseName(to);if ( match ){// file linkif ( !match->GetData() )match->ReadFromFile();match->ChangeBaseName(to);}}C_File *CBaseFile::FindMatchingMod(C_File *f){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){if ( node->Data()->GetFileType() != FILETYPE_MOD )continue;if ( f->GetFileExt().Compare(node->Data()->GetFileExt()) )continue;if ( f->GetBaseName().Compare(node->Data()->GetBaseName()) )return node->Data();}return NULL;}void CBaseFile::RenameFile(C_File *f, CyString baseName){if ( f->GetFileType() == FILETYPE_MOD ){C_File *match = this->FindMatchingMod(f);if ( match )match->ChangeBaseName(baseName);}// need to edit the fileif ( f->GetFileType() == FILETYPE_SCRIPT || f->GetFileType() == FILETYPE_UNINSTALL )f->RenameScript(baseName);f->ChangeBaseName(baseName);}CyString CBaseFile::CreateUpdateFile(CyString dir){CyString file = this->GetNameValidFile() + "_" + m_sAuthor + ".dat";file.RemoveChar(' ');CyStringList write;write.PushBack(CyString("Package: ") + m_sName);write.PushBack(CyString("Author: ") + m_sAuthor);write.PushBack(CyString("Version: ") + m_sVersion);write.PushBack(CyString("File: ") + CFileIO(m_sFilename).GetFilename());CFileIO File(dir + "/" + file);if ( File.WriteFile(&write) )return File.GetFullFilename();return NullString;}CyString CBaseFile::ErrorString(int error, CyString errorStr){if ( error == SPKERR_NONE ) return NullString;CyString err;switch(error){case SPKERR_MALLOC:err = "Memory Failed";break;case SPKERR_FILEOPEN:err = "Failed to open file";break;case SPKERR_FILEREAD:err = "Failed to read file";break;case SPKERR_UNCOMPRESS:err = "Failed to Uncompress";break;case SPKERR_WRITEFILE:err = "Failed to write file";break;case SPKERR_CREATEDIRECTORY:err = "Failed to create directory";break;case SPKERR_FILEMISMATCH:err = "File count mismatch";break;}if ( !err.Empty() ){if ( !errorStr.Empty() ){err += " (";err += errorStr + ")";}return err;}return CyString((long)error);}bool CBaseFile::SaveToArchive(CyString filename, int game, CProgressInfo *progress){TCHAR buf[5000];wsprintf(buf, L"%hs", filename.c_str());HZIP hz = CreateZip(buf, 0);if ( !hz ) return false;// read files and compressReadAllFilesToMemory();if ( !UncompressAllFiles(progress) ){CloseZip(hz);return false;}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){if ( game != -1 ) {if ( game && node->Data()->GetGame() && node->Data()->GetGame() != game )continue;if ( !game && node->Data()->GetGame() )continue;}CyString fname = node->Data()->GetNameDirectory(this);// create the directorywsprintf(buf, L"%hs", fname.c_str());ZipAdd(hz, buf, node->Data()->GetData(), node->Data()->GetDataSize());}// add the data fileCyStringList list;if ( this->GeneratePackagerScript(false, &list, true) ){if ( CFileIO("test.tmp").WriteFile(&list) ){ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");CFileIO("test.tmp").Remove();}}CloseZip(hz);return true;}int CBaseFile::GetGameFromString(CyString sGame){int iGame = GAME_ALL;if ( sGame.Compare("ALL") )iGame = GAME_ALL;else if ( sGame.Compare("X3") )iGame = GAME_X3;else if ( sGame.Compare("X2") )iGame = GAME_X2;else if ( sGame.Compare("X3TC") )iGame = GAME_X3TC;else if ( sGame.Compare("X3AP") )iGame = GAME_X3AP;else if ( sGame.Compare("XREBIRTH") )iGame = GAME_XREBIRTH;else if ( sGame.IsNumber() )iGame = sGame.ToInt();return iGame;}CyString CBaseFile::ConvertGameToString(int iGame){CyString game = "ALL";switch(iGame) {case GAME_ALL:game = "ALL";break;case GAME_X2:game = "X2";break;case GAME_X3:game = "X3";break;case GAME_X3TC:game = "X3TC";break;case GAME_X3AP:game = "X3AP";break;case GAME_XREBIRTH:game = "XREBIRTH";break;default:game = (long)iGame;}return game;}bool CBaseFile::IsGameInPackage(int game){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {if ( node->Data()->GetGame() == game )return true;}return false;}bool CBaseFile::IsAnyGameInPackage(){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {if ( node->Data()->GetGame() )return true;}return false;}int CBaseFile::FindFirstGameInPackage(){for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {if ( node->Data()->GetGame() )return node->Data()->GetGame();}return 0;}bool CBaseFile::IsMultipleGamesInPackage(){int game = 0;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {if ( node->Data()->GetGame() ) {if ( game != node->Data()->GetGame() )return true;game = node->Data()->GetGame();}}return false;}