Rev 143 | Rev 155 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
// SpkFile.cpp: implementation of the CSpkFile class.////////////////////////////////////////////////////////////////////////#include "BaseFile.h"//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////#include "spk.h"#include "DirIO.h"#include "File_IO.h"#include "CatFile.h"#include "Packages.h"#include "TextDB.h"#include <Package/InstallText.h>// remove these eventuallyusing namespace SPK;using namespace Package;CArchiveFile::~CArchiveFile(){Delete ();}CArchiveFile::CArchiveFile() : CBaseFile (){SetDefaults ();}void CBaseFile::SetDefaults (){_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;_changed();m_bUpdate = false;_bCombineFiles = false;ClearError();m_iLoadError = 0;m_bFullyLoaded = false;m_bSigned = false;m_bEnable = m_bGlobal = m_bProfile = m_bModifiedEnabled = true;m_bOverrideFiles = false;}CBaseFile::CBaseFile() : _pTextDB(NULL){SetDefaults ();}CBaseFile::~CBaseFile(){Delete();}void CBaseFile::Delete (){m_lFiles.clear(true);if ( m_pIconFile ){delete m_pIconFile;m_pIconFile = NULL;}if ( _pTextDB ) {delete _pTextDB;_pTextDB = NULL;}m_lNames.clear(true);}CyString CBaseFile::GetLanguageName ( int lang ) const{for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() ){SNames *n = node->Data();if ( n->iLanguage == lang )return n->sName;}return this->name();}/*############################################################################################################ Base Class Functions ############################################################################################################*/const CLinkList<C_File> *CBaseFile::fileList() const{return &m_lFiles;}CLinkList<C_File> *CBaseFile::fileList(int type) const{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) const{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) const{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) const{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 ){CFileIO File(filename);if ( !File.startRead() ) return 0;Utils::String line = File.readEndOfLine();Utils::String type = line.token(";", 1);File.close();// check for old versionif ( line.left(3) == "HiP" ) return SPKFILE_OLD;// check for formatif ( version ) *version = line.token(";", 2);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 ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() ){f->Data()->DeleteData();}}Utils::String CBaseFile::getNameValidFile() const{Utils::String name = this->name();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->fileType() != file->fileType() )continue;if ( f->name() != file->name () )continue;if ( f->GetDir() != file->GetDir() )continue;if ( f->game() != file->game() )continue;m_lFiles.remove(node, true);break;}_addFile(file);}C_File *CBaseFile::AddFile(CyString file, CyString dir, int type, int game){return addFile(file.ToString(), dir.ToString(), (FileType)type, game);}C_File *CBaseFile::addFile(const Utils::String &file, const Utils::String &dir, FileType 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->fileType() != newfile->fileType() )continue;if ( f->name() != newfile->name () )continue;if ( f->dir() != newfile->dir() )continue;if (f->game() != newfile->game()){//same file, for different game, check if they are the same and combine themif (_bCombineFiles){char *data = NULL;char *newData = NULL;size_t size = 0;size_t newSize = 0;if (f->GetData() && f->GetDataSize())data = (char *)f->UncompressData((long *)&size, NULL);else if(f->isExternalFile())data = CFileIO(f->filePointer()).ReadToData(&size);if (newfile->GetData() && newfile->GetDataSize())newData = (char *)f->UncompressData((long *)&newSize, NULL);elsenewData = CFileIO(newfile->filePointer()).ReadToData(&newSize);// compare bytesbool matched = false;if (size == newSize){matched = true;for (unsigned long i = 0; i < size; ++i){if (data[i] != newData[i]){matched = false;break;}}}if (data)delete data;if (newData)delete newData;if (matched){if(!f->game() || f->game() == GAME_ALLNEW)newfile->setGame(0);elsenewfile->setGame(newfile->game() | f->game());m_lFiles.remove(node, true);break;}}continue;}// must already exist, delete this onem_lFiles.remove(node, true);break;}_addFile(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->game() )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;_changed();return true;}void CBaseFile::removeAllFiles(FileType type, int game){if ( m_lFiles.empty() )return;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){if (game == 0 && node->Data()->game() && node->Data()->game() != GAME_ALLNEW)continue;if ( game > -1 ){unsigned int fileGame = node->Data()->game() & ~GAME_ALLNEW;if (fileGame != (1 << game)){// just remove the game from fileif (fileGame & (1 << game))node->Data()->setGame(node->Data()->game() & ~(1 << game));continue;}}if ( type == FILETYPE_UNKNOWN || node->Data()->GetFileType() == type )node->DeleteData();}m_lFiles.RemoveEmpty();_changed();}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, CProgressInfo *overallProgress, int level ){if ( overallProgress ) overallProgress->SetMax(m_lFiles.size());int iCount = 0;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 );if ( overallProgress ) overallProgress->SetDone(++iCount);}}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->isExternalFile()){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;_changed();}}}void CBaseFile::AddLanguageName ( int lang, const Utils::String &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 );_changed();}CyString CBaseFile::GetFullPackageName(CyString format, int lang){if ( format.Empty() )return GetFullPackageName(lang);CyString args[3] = { this->GetLanguageName(lang), this->version(), this->author() };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() + ":NULL:" + (long)file->game() + "\n");elseline += (command + ":" + (file->GetDataSize() + (long)4) + ":" + file->GetUncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->GetFilename() + ":" + file->GetDir() + ":" + (long)file->game() + "\n");if ( updateheader ){++m_SHeader2.iNumFiles;m_SHeader2.lFullSize += (file->GetDataSize() + 4);}}return line;}/*################################################################################################ Reading Functions ################################################################################################*/void CBaseFile::ReadAllFilesToMemory (){// no file to read fromif ( this->filename().empty() ) return;// now open the fileCFileIO File(this->filename());if ( !File.startRead() ) return;// read the headerFile.readEndOfLine();// skip past valuesFile.seek(4 + m_SHeader.lValueCompressSize);// read the next headerFile.readEndOfLine();// skip past filesFile.seek(4 + m_SHeader2.lSize);if ( m_pIconFile ){if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )m_pIconFile->readFromFile(File, m_pIconFile->GetDataSize());elseFile.seek(4 + m_pIconFile->GetDataSize());}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();if ( (!fit->GetData()) && (!fit->Skip()) )fit->readFromFile(File, fit->GetDataSize());elseFile.seek(4 + fit->GetDataSize());}File.close();}bool CBaseFile::ReadFileToMemory(C_File *f){if ( this->filename().empty() || !f ) return false; // no filename to load fromif ( f->GetData() && f->GetDataSize() ) return true; // already loaded the dataif ( !m_lFiles.FindData(f) ) return false; // unable to find file entry// now open the fileCFileIO *File = _startRead();if ( !File ) return false;if ( m_pIconFile ) File->seek(4 + m_pIconFile->GetDataSize());for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {C_File *fit = node->Data();if (fit == f ) {fit->readFromFile(*File, fit->GetDataSize());break;}else File->seek(4 + fit->GetDataSize());}delete File;return true;}CFileIO *CBaseFile::_startRead(){// no file to read fromif ( this->filename().empty() ) return NULL;// now open the fileCFileIO *File = new CFileIO(this->filename());if ( !File->startRead() ) return NULL;// read the headerFile->readEndOfLine();// skip past valuesFile->seek(4 + m_SHeader.lValueCompressSize);// read the next headerFile->readEndOfLine();// skip past filesFile->seek(4 + m_SHeader2.lSize);return File;}void CBaseFile::_addFile(C_File *file, bool dontChange){if ( !dontChange ) {file->UpdateSigned();_changed();}m_lFiles.push_back(file);_updateTextDB(file);}void CBaseFile::_updateTextDB(C_File *file){if ( !_pTextDB ) _pTextDB = new CTextDB();if ( file->GetFileType() == FILETYPE_TEXT ) {Utils::String baseFile = CFileIO(file->filePointer()).baseName();int lang = (baseFile.isin("-L")) ? baseFile.right(3) : baseFile.truncate(-4);// read in the text file to the database_pTextDB->parseTextFile(0, 0, file->filePointer(), lang);}}void CBaseFile::_resetTextDB(){if ( _pTextDB ) delete _pTextDB;_pTextDB = new CTextDB();for(CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next()) {_updateTextDB(node->Data());}}void CBaseFile::ReadIconFileToMemory (){if ( !m_pIconFile ) return;CFileIO *File = _startRead();if ( !File ) return;if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )m_pIconFile->readFromFile(*File, m_pIconFile->GetDataSize());elseFile->seek(4 + m_pIconFile->GetDataSize());delete File;}void CBaseFile::_install_adjustFakePatches(CPackages *pPackages){CyStringList lPatches;int startfake = pPackages->FindNextFakePatch();for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();// only do fake patchsif ( !fit->IsFakePatch() )continue;// we should only have cat and dat files, but lets check just incase they have been added incorrectlyif ( !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();CLog::logf(CLog::Log_Install, 2, "Adjusting fake patch number, %s => %s", fit->GetNameDirectory(this).c_str(), (newname + "." + fit->GetFileExt()).c_str());fit->SetName ( newname + "." + fit->GetFileExt() );// find the next gapif ( !opposite ) {startfake = pPackages->FindNextFakePatch(startfake + 1);}}}void CBaseFile::_install_renameText(CPackages *pPackages){int starttext = pPackages->findNextTextFile();for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {C_File *fit = node->Data();if ( !fit->isAutoTextFile() )continue;Utils::String newname = SPK::FormatTextName(starttext, pPackages->GetLanguage(), (pPackages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));fit->FixOriginalName();CLog::logf(CLog::Log_Install, 2, "Adjusting text file, %s => %s", fit->getNameDirectory(this).c_str(), (newname + "." + fit->fileExt()).c_str());fit->setName(newname + "." + fit->fileExt());++starttext;}}bool CBaseFile::_install_setEnabled(bool bEnable, C_File *fit){if ( !bEnable ){if ( (fit->GetFileType() == FILETYPE_UNINSTALL) || (fit->GetFileType() == FILETYPE_README) || (fit->GetFileType() == FILETYPE_ADVERT) )bEnable = true;else if ( (fit->GetFileType() == FILETYPE_EXTRA) && (fit->GetDir().Left(7).ToLower() == "Extras/") )bEnable = true;else if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) && (!fit->IsFakePatch()) )bEnable = true;if ( bEnable ) CLog::logf(CLog::Log_Install, 3, "Filetype(%d) is always enabled, setting enabled flag", fit->GetFileType());}return bEnable;}bool CBaseFile::_install_uncompress(C_File *fit, CProgressInfo *progress, CyStringList *errorStr, bool *uncomprToFile){*uncomprToFile = false;_sLastError = fit->getNameDirectory(this);_iLastError = SPKERR_UNCOMPRESS;if ( !fit->UncompressData ( progress ) ){CLog::log(CLog::Log_Install, 2, "Failed to uncompress data, attempting file decompression");if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP ){if ( fit->UncompressToFile ( NullString, this, false, progress ) )*uncomprToFile = true;}if ( !uncomprToFile ){if ( errorStr )errorStr->PushBack(CyString(_sLastError), ERRORLOG_OLD(SPKINSTALL_UNCOMPRESS_FAIL));CLog::log(CLog::Log_Install, 1, "Unable to decompress file, skipping");return false;}}ClearError ();return true;}bool CBaseFile::_install_checkVersion(C_File *pFile, const Utils::String &sDestination){// new check if we should install the file// first get the versionif ( !m_bOverrideFiles && pFile->ReadScriptVersion() ){CLog::log(CLog::Log_Install, 2, "Checking for existing file version");C_File checkfile;CyString checkfilename = sDestination;if ( !checkfilename.Empty() ) checkfilename += "/";checkfilename += pFile->GetNameDirectory(this);checkfile.SetFilename ( checkfilename );checkfile.setFileType(pFile->fileType());if ( checkfile.CheckValidFilePointer() ) {if ( checkfile.ReadScriptVersion() > pFile->GetVersion() ) {CLog::log(CLog::Log_Install, 1, "Newer version of the file found in directory, skipping");return false;}}}return true;}Utils::String CBaseFile::_install_adjustFilepointer(C_File *pFile, bool bEnabled, const Utils::String &sDestination){Utils::String filename = sDestination;if ( !filename.empty() ) filename += "/";if ( (IsPatch()) && (pFile->fileType() == FILETYPE_MOD) )pFile->SetDir ( CyString("Patch") );if ( pFile->IsInMod() ){if ( bEnabled )pFile->setFilename(filename + pFile->GetInMod().ToString() + "::" + pFile->getNameDirectory(this));elsepFile->setFilename(filename + "PluginManager/DisabledFiles.cat::" + pFile->getNameDirectory(this));}elsepFile->setFilename ( filename + pFile->getNameDirectory(this) );if ( !bEnabled ){if ( !pFile->IsInMod() ){if ( pFile->IsFakePatch() )pFile->setFilename ( filename + "PluginManager/Disabled/FakePatches/FakePatch_" + this->getNameValidFile() + "_" + this->author() + "_" + pFile->name() );else if ( pFile->isAutoTextFile() )pFile->setFilename ( filename + "PluginManager/Disabled/TextFiles/Text_" + this->getNameValidFile() + "_" + this->author() + "_" + pFile->name() );elsepFile->SetFullDir ( filename + "PluginManager/Disabled/" + pFile->getDirectory(this) );}pFile->SetDisabled(true);}CLog::logf(CLog::Log_Install, 2, "Adjusting the file pointer to correct install destintation, %s", pFile->filePointer().c_str());return filename;}C_File *CBaseFile::_install_checkFile(C_File *pFile, CyStringList *errorStr, bool *bDoFile, CLinkList<C_File> *pFileList){if ( !pFile->IsFakePatch() && pFile->GetFileType() != FILETYPE_README ){C_File *cFile;for ( cFile = pFileList->First(); cFile; cFile = pFileList->Next() ){if ( !cFile->MatchFile(pFile) ) continue;if ( !m_bOverrideFiles && !cFile->CompareNew(pFile) ) {if ( errorStr ) errorStr->PushBack(pFile->GetNameDirectory(this), ERRORLOG_OLD(SPKINSTALL_SKIPFILE));CLog::log(CLog::Log_Install, 1, "Newer version of the file already installed, skipping");*bDoFile = false;}break;}return cFile;}return NULL;}bool CBaseFile::_install_checkFileEnable(C_File *pCheckFile, C_File *fit, const Utils::String &sDestination, bool bEnabled, CyStringList *errorStr){// found a file, check if its in the disabled directoryUtils::String dir = CFileIO(pCheckFile->filePointer()).dir();Utils::String lastDir = CDirIO(dir).topDir().lower();// if its disabled, rename it so its enabledif ( ((pCheckFile->IsDisabled()) || (lastDir == "disabled") || (dir.lower().isin("/disabled/"))) && (bEnabled) ){CLog::logf(CLog::Log_Install, 2, "Existing file, %s, is disabled, re-enabling it", pCheckFile->filePointer().c_str());// first check if the directory existsif ( pCheckFile->IsInMod() ) {CyString tofile = pCheckFile->filePointer().token("::", 2);CCatFile tocat;int err = tocat.open(fit->filePointer().token("::", 1), "", CATREAD_CATDECRYPT, true);if ( (err == CATERR_NONE) || (err == CATERR_CREATED) ) {tocat.AppendFile(pCheckFile->filePointer(), tofile.ToString());CLog::logf(CLog::Log_Install, 2, "Adding existing file into new mod File, %s => %s", fit->filePointer().token("::", 1).c_str(), tofile.c_str());}CCatFile fromcat;err = fromcat.open(pCheckFile->filePointer().token("::", 1), "", CATREAD_CATDECRYPT, false);if ( err == CATERR_NONE ) {fromcat.removeFile(tofile.ToString());CLog::logf(CLog::Log_Install, 2, "Removing file from existing mod, %s::%s", pCheckFile->filePointer().token("::", 1).c_str(), tofile.c_str());}CLog::logf(CLog::Log_Install, 1, "Adjusting existing file name %s => %s", pCheckFile->filePointer().c_str(), fit->filePointer().c_str());pCheckFile->SetFilename ( fit->GetFilePointer() );CLog::logf(CLog::Log_Install, 2, "Adjusting In Mod setting, %s => %s", pCheckFile->GetInMod().c_str(), fit->GetInMod().c_str());pCheckFile->SetInMod(fit->GetInMod());}else {CyString to = pCheckFile->GetDirectory(this);CDirIO Dir(sDestination);if ( !Dir.exists(to.ToString()) ) {if ( !Dir.Create ( to ) ) {if ( errorStr ) errorStr->PushBack(to, ERRORLOG_OLD(SPKINSTALL_CREATEDIRECTORY_FAIL));return false;}if ( errorStr ) errorStr->PushBack(to, ERRORLOG_OLD(SPKINSTALL_CREATEDIRECTORY));}CyString destfile = CyString(sDestination) + "/" + pCheckFile->GetNameDirectory(this);if ( CFileIO(destfile).ExistsOld() ) CFileIO::Remove(destfile.ToString());CLog::logf(CLog::Log_Install, 1, "Adjusting existing filename, %s => %s", pCheckFile->GetFilePointer().c_str(), destfile.c_str());rename ( pCheckFile->GetFilePointer().c_str(), destfile.c_str() );pCheckFile->SetFilename ( CyString(sDestination) + "/" + pCheckFile->GetNameDirectory(this) );}pCheckFile->SetDisabled(false);if ( errorStr ) errorStr->PushBack(pCheckFile->GetNameDirectory(this), ERRORLOG_OLD(SPKINSTALL_ENABLEFILE));}return true;}bool CBaseFile::_install_createDirectory(CDirIO &Dir, const Utils::String &sTo, C_File *pFile, CyStringList *errorStr){_sLastError = sTo;if ( !sTo.contains( "::" ) ){if ( !Dir.exists(sTo) ){CLog::logf(CLog::Log_Install, 2, "Creating directory to install file into, %s", sTo.c_str());if ( !Dir.Create(sTo) ){if ( errorStr )errorStr->PushBack(CyString(sTo), ERRORLOG_OLD(SPKINSTALL_CREATEDIRECTORY_FAIL));return false;}if ( errorStr )errorStr->PushBack(CyString(sTo), ERRORLOG_OLD(SPKINSTALL_CREATEDIRECTORY));}}else {CLog::logf(CLog::Log_Install, 2, "Adjusting file extension for file in mod, %s => %s", pFile->filePointer().c_str(), CCatFile::PckChangeExtension(pFile->filePointer()).c_str());pFile->setFilename(CCatFile::PckChangeExtension(pFile->filePointer()));}return true;}void CBaseFile::_install_writeFile(C_File *pFile, const Utils::String &sDestination, CyStringList *errorStr){_iLastError = SPKERR_WRITEFILE;_sLastError = pFile->filePointer();Utils::String sInstalledFile = pFile->getNameDirectory(this);if ( pFile->IsDisabled() ){sInstalledFile = pFile->filePointer().findRemove(sDestination);if ( sInstalledFile[0] == '/' || sInstalledFile[0] == '\\' )sInstalledFile.erase(0, 1);}if ( !pFile->writeFilePointer() ){CLog::log(CLog::Log_Install, 1, "Failed to write the file");if ( errorStr )errorStr->PushBack(CyString(sInstalledFile), ERRORLOG_OLD(SPKINSTALL_WRITEFILE_FAIL));}else{CLog::log(CLog::Log_Install, 1, "File written successfully");CLog::log(CLog::Log_Install, 2, "Checking signed status of the file");pFile->UpdateSigned();if ( errorStr )errorStr->PushBack(CyString(sInstalledFile), ERRORLOG_OLD(SPKINSTALL_WRITEFILE));switch(pFile->GetFileType()){case FILETYPE_SCRIPT:case FILETYPE_UNINSTALL:CLog::log(CLog::Log_Install, 2, "Updating file signature");pFile->UpdateSignature();break;}}}bool CBaseFile::InstallFiles ( CyString destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, CyStringList *errorStr, bool enabled, CPackages *packages ){//TODO: add errorStr and progress as member variablesif ( enabled ) {this->_install_adjustFakePatches(packages);if ( packages ) this->_install_renameText(packages);}bool bFailed = false;CDirIO Dir(destdir);int fileCount = 0;for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *fit = node->Data();// start the install process, check if we need to the file enabled or disabledCLog::logf(CLog::Log_Install, 1, "Preparing to install file: %s", fit->GetNameDirectory(this).c_str());bool fileEnabled = _install_setEnabled(enabled, fit);// check if the file is for the correct game versionif (!fit->isForGame(packages->GetGame())){CLog::logf(CLog::Log_Install, 1, "File didn't match game version, skipping, %d != %d", fit->game(), packages->GetGame());continue;}// update the progress display to show we are processing this fileif ( progress ) {if ( progress->IsSecond() ) progress->SwitchSecond();progress->UpdateFile ( fit );progress->UpdateProgress(fileCount++, m_lFiles.size());progress->SwitchSecond();}// first uncompress the file//TODO: add this flag to C_Filebool uncomprToFile;if ( !this->_install_uncompress(fit, progress, errorStr, &uncomprToFile) ) {bFailed = true;continue;}bool dofile = _install_checkVersion(fit, destdir.ToString());// change file pointerUtils::String sInstallDir = _install_adjustFilepointer(fit, fileEnabled, destdir.ToString());C_File *adjustPointer = NULL;if ( filelist ) {C_File *cFile = _install_checkFile(fit, errorStr, &dofile, filelist);// 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 ) //_install_checkDisabled(cFile, destdir, errorStr);{//TODO: check what this is actually doingif ( !cFile->GetUsed() ){CFileIO rFile(cFile->GetFilePointer());if ( rFile.exists() ){if ( errorStr ){if ( rFile.remove() )errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG_OLD(SPKINSTALL_DELETEFILE));elseerrorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG_OLD(SPKINSTALL_DELETEFILE_FAIL));}}cFile->SetFilename(fit->GetFilePointer());cFile->SetDisabled(true);}else{fit->SetFullDir ( CyString(sInstallDir) + fit->GetDirectory(this) );fit->SetDisabled(false);}}// move it to enabledelse {if ( !this->_install_checkFileEnable(cFile, fit, destdir.ToString(), fileEnabled, errorStr) ) {bFailed = true;continue;}}adjustPointer = cFile;if ( dofile ) adjustPointer->SetCreationTime(fit->GetCreationTime());}}if ( dofile ){// uncompressed to file, rename and moveif ( uncomprToFile ){_iLastError = SPKERR_WRITEFILE;Utils::String to = fit->getDirectory(this);if ( !fileEnabled ) to = "PluginManager/Disabled/" + to;if ( !_install_createDirectory(Dir, to, fit, errorStr) ) {bFailed = true;continue;}int err = 1;_sLastError = to;if ( !fit->GetTempFile ().Empty() ) err = rename ( fit->GetTempFile().c_str(), to.c_str() );if ( err ) {bFailed = true;continue;}}//otherwise, just extract the fileelse{// old file is found in list, switch to using new oneif ( (filelist) && (adjustPointer) ) {adjustPointer->CopyData(fit, false);CLog::log(CLog::Log_Install, 2, "Copying data into existing file");}Utils::String fpointer = fit->filePointer();_iLastError = SPKERR_CREATEDIRECTORY;Utils::String dir = CFileIO(fit->filePointer()).dir();dir = dir.findRemove(destdir.ToString());if ( dir[0] == '/' || dir[0] == '\\' ) dir.erase(0, 1);if ( !_install_createDirectory(Dir, dir, fit, errorStr) ) {bFailed = true;continue;}_install_writeFile(fit, destdir.ToString(), errorStr);}ClearError ();}if ( adjustPointer ){CLog::log(CLog::Log_Install, 2, "Adjusting pointers to existing file and deleting new file pointer");node->ChangeData(adjustPointer);delete fit;}CLog::log(CLog::Log_Install, 1, "File installation completed");}// now clear or data memoryCLog::log(CLog::Log_Install, 2, "Delting temporary file data from memory");for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) node->Data()->DeleteData();return !bFailed;}/*######################################################################################################*//*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, ';' ).ToString()) )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 CBaseFile::CheckHeader(const Utils::String header) const{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(const Utils::String &sLine){Utils::String first = sLine.token(" ", 1);Utils::String rest = sLine.tokens(" ", 2);if ( first.Compare("Name:") ) this->setName(rest);else if ( first.Compare("Author:") ) this->setAuthor(rest);else if ( first.Compare("Version:") ) this->setVersion(rest);else if ( first.Compare("fGameVersion:") ) {if ( m_lGames.Back() ) {m_lGames.Back()->Data()->sVersion = rest;}}else if ( first.Compare("GameVersion:") ) {if ( m_lGames.Back() ) {m_lGames.Back()->Data()->iVersion = rest;}}else if ( first.Compare("Game:") )this->AddGameCompatability(rest, "");else if ( first.Compare("GameCompat:") )this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));else if ( first.Compare("GameCompatExact:") )this->AddGameCompatability(rest.token(" ", 1), rest.tokens(" ", 2));else if ( first.Compare("Date:") ) this->setCreationDate(rest);else if ( first.Compare("WebAddress:") ) this->setWebAddress(rest);else if ( first.Compare("WebSite:") ) this->setWebSite(rest);else if ( first.Compare("Email:") ) this->setEmail(rest);else if ( first.Compare("WebMirror1:") || first.Compare("Mirror1:") || first.Compare("WebMirror:") )this->AddWebMirror(rest);else if ( first.Compare("WebMirror2:") || first.Compare("Mirror2:") )this->AddWebMirror(rest);else if ( first.Compare("PluginType:") ) this->setPluginType(rest);else if ( first.Compare("Desc:") ) this->setDescription(rest);else if ( first.Compare("UninstallAfter:") ) this->addUninstallText(ParseLanguage(rest.token("|", 1)), false, rest.tokens("|", 2));else if ( first.Compare("UninstallBefore:") ) this->addUninstallText(ParseLanguage(rest.token("|", 1)), true, rest.tokens("|", 2));else if ( first.Compare("InstallAfter:") ) this->addInstallText(ParseLanguage(rest.token("|", 1)), false, rest.tokens("|", 2));else if ( first.Compare("InstallBefore:") ) this->addInstallText(ParseLanguage(rest.token("|", 1)), true, rest.tokens("|", 2));else if ( first.Compare("ScriptName:") )AddLanguageName(ParseLanguage(rest.token(":", 1)), rest.token(":", 2));else if ( first.Compare("GameChanging:") ) this->setGameChanging(rest);else if ( first.Compare("EaseOfUse:") ) this->setEaseOfUse(rest);else if ( first.Compare("Recommended:") ) this->setRecommended(rest);else if ( first.Compare("NeededLibrary:") )this->AddNeededLibrary(rest.token("||", 1), rest.token("||", 2), rest.token("||", 3));else if ( first.Compare("FakePatchBefore:") )this->AddFakePatchOrder(false, rest.token("||", 1), rest.token("||", 2));else if ( first.Compare("FakePatchAfter:") )this->AddFakePatchOrder(true, rest.token("||", 1), rest.token("||", 2));else if ( first.Compare("ForumLink:") ) this->setForumLink(rest);elsereturn false;return true;}int CBaseFile::ParseLanguage(const Utils::String &lang) const{int langID = lang;if ( !langID ) {if ( lang.Compare("english") ) return 44;else if ( lang.Compare("default") ) return 0;else if ( lang.Compare("german") ) return 49;else if ( lang.Compare("russian") ) return 7;else if ( lang.Compare("spanish") ) return 34;else if ( lang.Compare("french") ) return 33;}return langID;}/*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].ToString() );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 sLine ){Utils::String line = sLine.ToString();if ( !line.contains(":") )return false;Utils::String command = line.token(":", 1);long size = line.token(":", 2).toInt();long usize = line.token(":", 3).toInt ();long compression = line.token(":", 4).toInt ();if ( command == "Icon" ){m_sIconExt = line.token (":", 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.token(":", 5).toLong();bool compressToFile = (line.token(":", 6).toInt() == 1) ? true : false;Utils::String name = line.token(":", 7);Utils::String dir = line.token(":", 8);if ( name.empty() )return true;bool shared = false;if ( command.left(1) == "$" ){shared = true;command.erase(0, 1);}FileType type = FILETYPE_UNKNOWN;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 == FILETYPE_UNKNOWN)return false;C_File *file = new C_File();if (dir.left(5).Compare("GAME_")) {unsigned int iGame = dir.token("_", 2).toInt();if (!iGame)file->setGame(0);elsefile->setGame(1 << 31 | 1 << iGame);dir = Utils::String::Null();}else if ( line.countToken(":") >= 9 ){Utils::String game = line.token(":", 9);if (game.contains("_")){unsigned int iGame = game.token("_", 2).toInt();if (iGame)file->setGame(1 << 31 | 1 << iGame);elsefile->setGame(0);}else{int iGame = game.toInt();if (iGame & (1 << 31))file->setGame(iGame);else if (!iGame)file->setGame(0);elsefile->setGame(1 << 31 | 1 << iGame);}}if (dir.Compare("NULL")) {dir = Utils::String::Null();}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 );_addFile(file, true);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){return readFile(filename.ToString(), readtype, progress);}bool CBaseFile::readFile(const Utils::String &filename, int readtype, CProgressInfo *progress){CFileIO File(filename);if ( !File.startRead() ) return false;bool ret = this->readFile(File, readtype, progress);if ( ret ) this->setFilename(filename);File.close();return ret;}int CBaseFile::_read_Header(CFileIO &File, int iReadType, int iMaxProgress, CProgressInfo *pProgress){int doneLen = 0;// read data to memoryunsigned char *readData;try {readData = new unsigned char[m_SHeader.lValueCompressSize];}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_Header() unable to malloc [header], %d (%s)", m_SHeader.lValueCompressSize, e.what());return -1;}unsigned char size[4];File.read(size, 4);File.read(readData, m_SHeader.lValueCompressSize);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 datatry {unsigned char *uncompr = new unsigned char[uncomprLen];int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lValueCompressSize );// update the progress for each sectionif ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(2, iMaxProgress);if ( err == Z_OK ) this->ReadValues ( CyString ((char *)uncompr) );doneLen = uncomprLen;delete uncompr;}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_Header() unable to malloc [uncompr], %d (%s)", uncomprLen, e.what());delete []readData;return -1;}}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 ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(2, iMaxProgress);if ( compr ) ReadValues ( CyString ((char *)compr) );}// no compressionelseReadValues ( CyString ((char *)readData) );delete []readData;return doneLen;}int CBaseFile::_read_FileHeader(CFileIO &File, int iReadType, int iMaxProgress, int iDoneLen, CProgressInfo *pProgress){unsigned char *readData;try {readData = new unsigned char[m_SHeader2.lSize];}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_FileHeader() unable to malloc [header], %d (%s)", m_SHeader2.lSize, e.what());return -1;}unsigned char size[4];File.read(size, 4);File.read(readData, m_SHeader2.lSize);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)iDoneLen ) uncomprLen = iDoneLen;try {unsigned char *uncompr = new unsigned char[uncomprLen];int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader2.lSize );// update the progress for each sectionif ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(5, iMaxProgress);if ( err == Z_OK ) ReadFiles ( CyString ((char *)uncompr) );delete uncompr;}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, "CBaseFile::_read_FileHeader() unable to malloc [uncompr], %d (%s)", uncomprLen, e.what());delete []readData;return -1;}}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 ( iReadType != SPKREAD_ALL && pProgress ) pProgress->UpdateProgress(5, iMaxProgress);if ( compr ) ReadFiles ( CyString ((char *)compr) );}elseReadFiles ( CyString ((char *)readData) );delete []readData;return true;}bool CBaseFile::readFile(CFileIO &File, int readtype, CProgressInfo *progress){ClearError ();// first read the headerif ( !ParseHeader(File.readEndOfLine()) ) 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 ) doneLen = this->_read_Header(File, readtype, maxProgress, progress);// 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(File.readEndOfLine()) ) return false;// clear the current file listm_lFiles.clear(true);if ( _pTextDB ) {delete _pTextDB;_pTextDB = NULL;}// update the progress for each sectionif ( readtype != SPKREAD_ALL && progress ) progress->UpdateProgress(4, maxProgress);if ( m_SHeader2.lSize ) this->_read_FileHeader(File, readtype, maxProgress, doneLen, progress);// file mismatchlong numfiles = m_lFiles.size();if ( m_pIconFile ) ++numfiles;if ( m_SHeader2.iNumFiles != numfiles ) {_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(File, m_pIconFile->GetDataSize());// ok finally we need to read all the filefor ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {node->Data()->readFromFile(File, 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() const{// 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;}Utils::String CBaseFile::CreateValuesLine () const{Utils::String values("Name: ");values += this->name() + "\n";values += "Author: " + this->author() + "\n";values += "Version: " + this->version() + "\n";if ( !this->creationDate().empty() )values += "Date: " + this->creationDate() + "\n";if ( !this->webAddress().empty() ) values += "WebAddress: " + this->webAddress() + "\n";if ( !this->webSite().empty() ) values += "WebSite: " + this->webSite() + "\n";if ( !this->email().empty() ) values += "Email: " + this->email() + "\n";if ( !this->forumLink().empty() ) values += "ForumLink: " + this->forumLink() + "\n";for ( SStringList *str = m_lMirrors.Head(); str; str = str->next )values += Utils::String("WebMirror: ") + str->str.ToString() + "\n";if ( !this->description().empty() ) {Utils::String desc = this->description();desc = desc.findReplace("<newline>", "<br>");desc = desc.findReplace("\n", "<br>");desc.remove('\r');values += "Desc: " + desc + "\n";}for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {if ( !gc->Data()->sVersion.empty() )values += Utils::String("GameCompatExact: ") + (long)gc->Data()->iGame + " " + gc->Data()->sVersion + "\n";elsevalues += Utils::String("GameCompat: ") + (long)gc->Data()->iGame + " " + (long)gc->Data()->iVersion + "\n";}if ( m_bSigned )values += "Signed\n";for ( int j = 0; j < 2; j++ ) {const CInstallText *text;Utils::String textStart;switch(j) {case 0: textStart = "Uninstall"; text = this->uninstallText(); break;case 1: textStart = "Install"; text = this->installText(); break;}for ( unsigned int i = 0; i < text->count(); i++ ) {int iLang = text->language(i);if ( !text->getBefore(iLang).empty() ) values += textStart + "Before: " + (long)iLang + "|" + text->getBefore(iLang) + "\n";if ( !text->getAfter(iLang).empty() ) values += textStart + "After: " + (long)iLang + "|" + text->getAfter(iLang) + "\n";}}values += Utils::String("GameChanging: ") + (long)gameChanging() + "\n";values += Utils::String("EaseOfUse: ") + (long)easeOfUse() + "\n";values += Utils::String("Recommended: ") + (long)recommended() + "\n";for ( CListNode<SNames> *nNode = m_lNames.Front(); nNode; nNode = nNode->next() )values += Utils::String("ScriptName: ") + (long)nNode->Data()->iLanguage + ":" + nNode->Data()->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").ToString();}for ( SStringList *fpbNode = m_lFakePatchBefore.Head(); fpbNode; fpbNode = fpbNode->next )values += (CyString("FakePatchBefore: ") + fpbNode->str + "||" + fpbNode->data + "\n").ToString();for ( SStringList *fpaNode = m_lFakePatchAfter.Head(); fpaNode; fpaNode = fpaNode->next )values += (CyString("FakePatchAfter: ") + fpaNode->str + "||" + fpaNode->data + "\n").ToString();values += Utils::String("PluginType: ") + (long)this->pluginType() + "\n";return values;}/*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 ){CFileIO File(filename);if ( File.startWrite() ) return WriteData(File, progress);return false;}bool CBaseFile::WriteHeader(CFileIO &file, int valueheader, int valueComprLen){return file.write("BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);}bool CBaseFile::WriteData(CFileIO &file, 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(file, valueheader, valueComprLen) ) return false;// write the compressed data to filefile.put(static_cast<unsigned char>(valueUncomprLen >> 24));file.put(static_cast<unsigned char>(valueUncomprLen >> 16));file.put(static_cast<unsigned char>(valueUncomprLen >> 8));file.put(static_cast<unsigned char>(valueUncomprLen));file.write(valueCompr, valueComprLen);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;file.write("FileHeader;%d;%ld;%ld;%d;%d\n", m_SHeader2.iNumFiles, m_SHeader2.lSize, m_SHeader2.lFullSize, fileheader, m_SHeader2.iDataCompression);file.put(static_cast<unsigned char>(fileUncomprLen >> 24));file.put(static_cast<unsigned char>(fileUncomprLen >> 16));file.put(static_cast<unsigned char>(fileUncomprLen >> 8));file.put(static_cast<unsigned char>(fileUncomprLen));file.write(fileCompr, fileComprLen);free ( fileCompr );if ( progress ){progress->UpdateStatus(STATUS_WRITE);progress->SetDone(0);long max = 0;for ( CListNode<C_File> *file = m_lFiles.Front(); file; file = file->next() )max += file->Data()->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);file.writeSize(m_pIconFile->GetUncompressedDataSize());file.write(m_pIconFile->GetData(), m_pIconFile->GetDataSize());if ( progress ) progress->IncDone(m_pIconFile->GetDataSize());}for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *f = node->Data();if ( progress ) progress->UpdateFile(f);file.writeSize(f->GetUncompressedDataSize());unsigned char *data = f->GetData();size_t remaining = f->GetDataSize();while ( remaining ) {size_t writeSize = WRITECHUNK;if ( writeSize > remaining ) writeSize = remaining;if ( file.write(data, writeSize) ) {data += writeSize;remaining -= writeSize;}if ( progress ) progress->IncDone((int)writeSize);}}_changed();return true;}bool CBaseFile::ExtractFile(C_File *file, CyString dir, bool includedir, CProgressInfo *progress){return extractFile(file, dir.ToString(), includedir, progress);}bool CBaseFile::extractFile(C_File *file, const Utils::String &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, Utils::String::Null(), data, len))return false;return true;}elsereturn false;}bool CBaseFile::extractFile(C_File *file, const Utils::String &dir, unsigned int game, const Utils::CStringList &gameAddons, bool includedir, CProgressInfo *progress){if (ReadFileToMemory(file)){CDirIO Dir(dir);Utils::String addonDir;if (file->isFileInAddon()){int addonGame = file->getForSingleGame();if (!addonGame) addonGame = game;if (addonGame > 0)addonDir = gameAddons.findString(Utils::String::Number(addonGame));}if (!addonDir.empty())Dir.cd(addonDir);// create directory firstDir.create(file->getDirectory(this));// 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.dir(), this, includedir, progress))return true;}return false;}if (!file->writeToDir(Dir.dir(), this, includedir, Utils::String::Null(), 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.ToString(), includedir, progress);}bool CBaseFile::extractFile(int filenum, const Utils::String &dir, unsigned int game, const Utils::CStringList &gameAddons, 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, game, gameAddons, includedir, progress);}bool CBaseFile::extractFile(int filenum, const Utils::String &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(const Utils::String &dir, int game, const Utils::CStringList &gameAddons, bool includedir, CProgressInfo *progress){// no file to read fromif (this->filename().empty())return false;// now open the fileCFileIO *File = _startRead();if (!File) return false;// now were in the file section// skip past each oneif (m_pIconFile) File->seek(4 + m_pIconFile->GetDataSize());for (CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next()){C_File *fit = node->Data();if ((!fit->GetDataSize()) || (!fit->GetData())){if (!fit->readFromFile(*File, fit->GetDataSize()))return false;}elseFile->seek(fit->GetDataSize());if (game && !fit->isForGame(game))continue;if (progress)progress->UpdateFile(fit);CDirIO Dir(dir);Utils::String addonDir;if (fit->isFileInAddon()){int addonGame = fit->getForSingleGame();if (!addonGame) addonGame = game;if (addonGame > 0)addonDir = gameAddons.findString(Utils::String::Number(addonGame));}if (!addonDir.empty())Dir.cd(addonDir);// 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.dir(), this, includedir, progress)) return false;}else if ((!data) || (!fit->writeToDir(Dir.dir(), this, includedir, Utils::String::Null(), data, size))) return false;}delete File;return true;}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 CBaseFile::IsPackageNeeded(const Utils::String &scriptName, const Utils::String &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(const Utils::String &scriptName, const Utils::String &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(const Utils::String &scriptName, const Utils::String &author, const Utils::String &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(const Utils::String &scriptName, const Utils::String &author){SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);if ( l ){m_lNeededLibrarys.remove(l);delete l;}}void CBaseFile::ClearNeededPackages(){SNeededLibrary *ns = this->FindPackageNeeded("<package>", "<author>");Utils::String 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 CBaseFile::GeneratePackagerScript(bool wildcard, Utils::CStringList *list, int game, const Utils::CStringList &gameAddons, bool datafile){list->pushBack("#");list->pushBack("# Packager Script");list->pushBack("# -- Generated by SPK Libraries V" + Utils::String::FromFloat(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("Name: " + this->name());list->pushBack("");list->pushBack("# The author of the script, ie, you");list->pushBack("Author: " + this->author());list->pushBack("");list->pushBack("# The creation data, when it was created");if ( datafile )list->pushBack("Date: " + this->creationDate());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("Version: " + this->version());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() ) {if (game > 0 && g->iGame != game)continue;Utils::String game = CBaseFile::ConvertGameToString(g->iGame);if ( !g->sVersion.empty() ){game += " ";game += g->sVersion;}else{game += " ";game += (long)g->iVersion;}list->pushBack("Game: " + game);}list->pushBack("");}if ( !this->description().empty() ) {list->pushBack("# The description of the script, displays when installing");list->pushBack("Description: " + this->description());list->pushBack("");}if ( !this->webSite().empty() ) {list->pushBack("# A link to the website for the script, ie for an online help page");list->pushBack("WebSite: " + this->webSite());list->pushBack("");}if ( !this->forumLink().empty() ) {list->pushBack("# A direct link to the thread in the egosoft forum");list->pushBack("ForumLink: " + this->forumLink());list->pushBack("");}if ( !this->webAddress().empty() ) {list->pushBack("# A link to the address for the update file");list->pushBack("WebAddress: " + this->webAddress());list->pushBack("");}if ( !this->email().empty() ) {list->pushBack("# The email address of the author, to allow users to contract if needed");list->pushBack("Email: " + this->email());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(Utils::String("WebMirror: ") + node->str.ToString());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("Depend: " + node->Data()->sName + "|" + node->Data()->sMinVersion + "|" + node->Data()->sAuthor);list->pushBack("");}if ( !_noRatings() ){list->pushBack("# Ratings Values, 0 to 5, <ease> <changing> <recommended>");list->pushBack(Utils::String("Ratings: ") + (long)easeOfUse() + " " + (long)gameChanging() + " " + (long)recommended());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(Utils::String("ScriptName: ") + (long)node->Data()->iLanguage + " " + node->Data()->sName);list->pushBack("");}for ( int j = 0; j < 2; j++ ) {Utils::String installText = (j == 0) ? "Install" : "Uninstall";const CInstallText *pText = (j == 0) ? this->installText() : this->uninstallText();if ( pText->any() ){list->pushBack("# " + installText + " Texts, display text before and/or after " + installText + "ing to inform the use of special conditions");for ( unsigned int i = 0; i < pText->count(); i++ ) {long iLang = pText->language(i);if ( !pText->getBefore(iLang).empty() ) list->pushBack(installText + "Before: " + iLang + " " + pText->getBefore(iLang));if ( !pText->getAfter(iLang).empty() ) list->pushBack(installText + "After: " + iLang + " " + pText->getAfter(iLang));}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->pluginType() ){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, Utils::CStringList *list, int game, const Utils::CStringList &gameAddons){// now do files and wildcardsUtils::CStringList files;for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() ){if (game && !(f->Data()->game() & 1 << game))continue;Utils::String name = "$GAMEDIR/";// addon directory?unsigned int checkGame = f->Data()->game() & ~(1 << 31);unsigned int foundGame = 0;for (int i = 0; i < 31; ++i){if (checkGame == 1 << i){foundGame = i;break;}}if (foundGame){Utils::String str = gameAddons.findString(Utils::String::Number(foundGame));if(!str.empty())name += str + "/";}bool done = false;if ( wildcard ){Utils::String base = f->Data()->baseName();if ( f->Data()->fileType() == FILETYPE_SCRIPT ){if ( base.token(".", 1).Compare("plugin") || base.token(".", 1).Compare("lib") ){name += f->Data()->getDirectory(this) + "/" + base.tokens(".", 1, 2) + ".*";done = true;}else if ( base.token(".", 1).Compare("al") && !base.token(".", 2).Compare("plugin") ){name += f->Data()->getDirectory(this) + "/" + base.tokens(".", 1, 2) + ".*";done = true;}}else if ( f->Data()->fileType() == FILETYPE_TEXT ){if ( base.contains("-L") ){name += f->Data()->getDirectory(this) + "/" + base.token("-L", 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()->dir().empty() ){name += "|";name += f->Data()->dir();}Utils::String s = "GAME ";if (!f->Data()->game() || f->Data()->game() == GAME_ALLNEW)s += CBaseFile::ConvertGameToString(f->Data()->game());else{bool first = true;for (int i = 0; i < 31; ++i){if (f->Data()->game() & 1 << i){if (first)first = false;elses += "|";s += CBaseFile::ConvertGameToString(i);}}}s += " " + name;if(!files.contains(s))files.pushBack(s, f->Data()->GetFileTypeString().ToString());}if ( !files.empty() ){list->pushBack("# Files List, all the files to add, can include wild cards");for(auto itr = files.begin(); itr != files.end(); itr++)list->pushBack((*itr)->data + ": " + (*itr)->str);list->pushBack("");}return true;}Utils::String CBaseFile::GetAutosaveName(){return this->name() + "-V" + this->version() + "-" + this->creationDate().findReplace("/", ".");}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 ( CyString(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);_changed();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, const Utils::String &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 = "";if ( version.isin(".") || !version.isNumber() )Found->sVersion = version;elseFound->iVersion = version;_changed();}Utils::String CBaseFile::_replaceFilename(const Utils::String &fname){Utils::String filename = fname;Utils::String cdate = this->creationDate().findReplace("/", ".").remove(' ');if (filename.isin("$AUTOSAVE")){if (this->GetType() == TYPE_XSP)filename = filename.findReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.xsp");elsefilename = filename.findReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.spk");}filename = filename.findReplace("$NAME", this->name().remove(' '));filename = filename.findReplace("$AUTHOR", this->author().remove(' '));filename = filename.findReplace("$DATE", cdate);filename = filename.findReplace("$CDATE", cdate);filename = filename.findReplace("$VERSION", this->version());return filename;}bool CBaseFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames, Utils::CStringList &gameAddons, CProgressInfo *progress){if (sFirst.Compare("Name")) this->setName(sRest);else if (sFirst.Compare("Author")) this->setAuthor(sRest);else if (sFirst.Compare("ScriptName"))AddLanguageName(ParseLanguage(sRest.token(" ", 1)), sRest.tokens(" ", 2));else if (sFirst.Compare("UninstallBefore")) this->addUninstallText(ParseLanguage(sRest.token(" ", 1)), true, sRest.tokens(" ", 2));else if (sFirst.Compare("UninstallAfter")) this->addUninstallText(ParseLanguage(sRest.token(" ", 1)), false, sRest.tokens(" ", 2));else if (sFirst.Compare("InstallBefore")) this->addInstallText(ParseLanguage(sRest.token(" ", 1)), true, sRest.tokens(" ", 2));else if (sFirst.Compare("InstallAfter")) this->addInstallText(ParseLanguage(sRest.token(" ", 1)), false, sRest.tokens(" ", 2));else if (sFirst.Compare("Date")) this->setCreationDate(sRest);else if (sFirst.Compare("Version")) this->setVersion(sRest);else if (sFirst.Compare("GameVersion"))this->AddGameCompatability(-1, sRest);else if (sFirst.Compare("PluginType")) {if (sRest.isNumber()) this->setPluginType(sRest);else if (sRest.Compare("Normal")) this->setPluginType(PLUGIN_NORMAL);else if (sRest.Compare("Stable")) this->setPluginType(PLUGIN_STABLE);else if (sRest.Compare("Experimental")) this->setPluginType(PLUGIN_EXPERIMENTAL);else if (sRest.Compare("Cheat")) this->setPluginType(PLUGIN_CHEAT);else if (sRest.Compare("Mod")) this->setPluginType(PLUGIN_MOD);}// new versionelse if (sFirst.Compare("GenerateUpdateFile"))m_bAutoGenerateUpdateFile = true;else if (sFirst.Compare("Game")){Utils::String sGame = sRest.token(" ", 1);this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), sRest.token(" ", 2));}else if (sFirst.Compare("Description")) this->setDescription(sRest);else if (sFirst.Compare("AutoSave") || sFirst.Compare("AutoExport") || sFirst.Compare("AutoRarExport") || sFirst.Compare("AutoZipExport")){Utils::String filename = _replaceFilename(sRest);if (sFirst.Compare("AutoZipExport") || sFirst.Compare("AutoExport"))this->setExportFilename(CFileIO(filename).changeFileExtension("zip"));else if (sFirst.Compare("AutoRarExport"))this->setExportFilename(CFileIO(filename).changeFileExtension("rar"));elsethis->setFilename(filename);}else if (sFirst.Compare("WebSite")) this->setWebSite(sRest);else if (sFirst.Compare("ForumLink") || sFirst.Compare("Forum")) this->setForumLink(sRest);else if (sFirst.Compare("Email")) this->setEmail(sRest);else if (sFirst.Compare("WebAddress")) this->setWebAddress(sRest);else if (sFirst.Compare("WebMirror"))this->AddWebMirror(sRest);else if (sFirst.Compare("WebMirror1"))this->AddWebMirror(sRest);else if (sFirst.Compare("WebMirror2"))this->AddWebMirror(sRest);else if (sFirst.Compare("Ftp"))m_sFtpAddr = sRest;else if (sFirst.Compare("Ratings")) _setRatings(sRest.token(" ", 1), sRest.token(" ", 2), sRest.token(" ", 3));else if (sFirst.Compare("EaseOfUse")) setEaseOfUse(sRest);else if (sFirst.Compare("GameChanging")) setGameChanging(sRest);else if (sFirst.Compare("Recommended")) setRecommended(sRest);else if (sFirst.Compare("Depend")){Utils::String version = sRest.token("|", 2);Utils::String name = sRest.token("|", 1);Utils::String author = sRest.tokens("|", 3);this->AddNeededLibrary(name, author, version);}else if (sFirst.Compare("DependPackage")){CPackages p;CBaseFile *spk = p.OpenPackage(sRest, 0, 0, SPKREAD_VALUES);if (spk){this->AddNeededLibrary(spk->name(), spk->author(), spk->version());delete spk;}}else if (sFirst.Compare("Icon")){C_File *icon = new C_File(sRest.c_str());if (icon->ReadFromFile())this->SetIcon(icon, CFileIO(sRest).GetFileExtension());}else if (sFirst.Compare("CombineGameFiles"))_bCombineFiles = sRest.Compare("true") || sRest.Compare("yes") || sRest.toInt();else if (sFirst.Compare("UpdateFile"))this->createUpdateFile(sRest);else if (sFirst.Compare("ExportZip")){Utils::String ext = "zip";Utils::String game = sRest.word(1);Utils::String file = _replaceFilename(CFileIO(sRest.words(2)).fullFilename());if (game.contains("|")){int max;Utils::String *games = game.tokenise("|", &max);if (games){for (int i = 0; i < max; ++i){unsigned int g = CBaseFile::GetGameFromString(games[i]);Utils::String filename = CFileIO(file).dir() + "/" + CFileIO(file).baseName() + "_" + CBaseFile::ConvertGameToString(g) + "." + ext;this->addAutoExport(g, filename);}CLEANSPLIT(games, max);}}else{unsigned int g = CBaseFile::GetGameFromString(game);Utils::String filename = CFileIO(file).dir() + "/" + CFileIO(file).baseName() + "_" + CBaseFile::ConvertGameToString(g) + "." + ext;this->addAutoExport(g, filename);}}else if (sFirst.Compare("Extract")){Utils::String game = sRest.word(1);Utils::String dir = CDirIO(sRest.words(2)).dir();if (game.contains("|")){int max;Utils::String *games = game.tokenise("|", &max);if (games){for(int i = 0; i < max; ++i)this->addAutoExtract(CBaseFile::GetGameFromString(games[i]), dir);CLEANSPLIT(games, max);}}elsethis->addAutoExtract(CBaseFile::GetGameFromString(game), dir);}else{Utils::String checkType = sFirst;bool shared = false;if ( checkType.left(6).Compare("Shared") ){checkType = sFirst.right(-6);shared = true;}// now check type nameFileType filetype = GetFileTypeFromString(checkType);if (filetype != FILETYPE_UNKNOWN)this->AddFileScript(filetype, shared, sRest, sMainGame, otherGames, gameAddons, progress);else if ( !checkType.Compare("changelog") )return false;}return true;}void CBaseFile::AddFileScript(FileType filetype, bool shared, CyString sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames, Utils::CStringList &gameAddons, CProgressInfo *progress){Utils::String dir;Utils::String rest = sRest.ToString();unsigned int mainGame = CBaseFile::GetGameFromString(sMainGame);unsigned int game = 0;if ( rest.token(" ", 1).left(4).Compare("GAME") ) {Utils::String gameStr = rest.token(" ", 2);if (gameStr.contains("|")){int max = 0;Utils::String *games = gameStr.tokenise("|", &max);for (int i = 0; i < max; ++i){unsigned int g = CBaseFile::GetGameFromString(games[i]);if (g)game |= 1 << g;}CLEANSPLIT(games, max);}else{unsigned int g = CBaseFile::GetGameFromString(gameStr);if (g)game = 1 << g;}rest = rest.tokens(" ", 3);}if (game)game |= 1 << 31;if (rest.contains("|")){dir = rest.tokens("|", 2);rest = rest.token("|", 1);}rest = rest.findReplace("\\", "/");// wild cardsif ( rest.containsAny("*?") ){CDirIO Dir(CFileIO(rest).dir());CyStringList *dirList = Dir.DirList();if ( dirList ){for ( SStringList *strNode = dirList->Head(); strNode; strNode = strNode->next ){Utils::String file = Dir.file(strNode->str.ToString());if (file.match(rest)){int addGame = game;// check if the file exists in the subdirectory too, if it does, add for each gameif ( game == GAME_ALL && !sMainGame.empty() && !otherGames.empty() ) {CFileIO F(file);for(Utils::String g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {Utils::String checkDir = F.dir() + "/" + g;if ( CDirIO(checkDir).exists(F.filename()) ) {addGame = mainGame;C_File *newfile = this->AppendFile(CDirIO(checkDir).File(F.filename()), filetype, CBaseFile::GetGameFromString(g), dir);if (newfile && progress)progress->UpdateFile(newfile);if ( newfile ) newfile->SetShared(shared);}}}C_File *newfile = this->AppendFile(file, filetype, addGame, dir);if (newfile && progress)progress->UpdateFile(newfile);if ( newfile )newfile->SetShared(shared);}}delete dirList;}}else{unsigned int addGame = game;// check if the file exists in the subdirectory too, if it does, add for each gameif ( game == GAME_ALL && !sMainGame.empty() && !otherGames.empty() ) {CFileIO F(rest);for(Utils::String g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {Utils::String checkDir = F.dir() + "/" + g;if ( CDirIO(checkDir).exists(F.filename()) ) {addGame = mainGame;C_File *newfile = this->AppendFile(CDirIO(checkDir).file(F.filename()), filetype, CBaseFile::GetGameFromString(g), dir);if (newfile && progress)progress->UpdateFile(newfile);if ( newfile ) newfile->SetShared(shared);}}}unsigned int checkGame = addGame & ~(1 << 31);unsigned int foundGame = 0;for (int i = 0; i < 31; ++i){if (1 << i == checkGame){foundGame = i;break;}}C_File *file = NULL;if (foundGame){Utils::String addon = gameAddons.findString(Utils::String::Number(foundGame));if (!addon.empty()){Utils::String dir = C_File::GetDirectory(filetype, rest, this);Utils::String filename = rest;if (CCatFile::IsAddonDir(dir) && !filename.contains(addon)){filename = filename.findReplace(dir + "/", addon + "/" + dir + "/");file = this->AppendFile(filename, filetype, addGame, dir);}}}if(!file)file = this->AppendFile(rest, filetype, addGame, dir);if (file && progress)progress->UpdateFile(file);if (file)file->SetShared(shared);}}CyString CBaseFile::GetFullFileSizeString() { return SPK::GetSizeString ( this->GetFullFileSize() ); }// used for a multiple spk fileunsigned char *CBaseFile::CreateData(size_t *size, CProgressInfo *progress){if ( this->WriteFile("temp.dat", progress) ) {CFileIO File("temp.dat");File.setAutoDelete(true);return File.readAll(size);}return NULL;}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);}Utils::String CBaseFile::createUpdateFile(const Utils::String &dir) const{Utils::String file = this->getNameValidFile() + "_" + this->author() + ".dat";file.removeChar(' ');Utils::CStringList write;write.pushBack("Package: " + this->name());write.pushBack("Author: " + this->author());write.pushBack("Version: " + this->version());write.pushBack("File: " + CFileIO(this->filename()).filename());CFileIO File(dir + "/" + file);if (File.writeFile(&write))return File.fullFilename();return Utils::String::Null();}Utils::String CBaseFile::ErrorString(int error, const Utils::String &errorStr){if (error == SPKERR_NONE) return Utils::String::Null();Utils::String 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 Utils::String::Number((long)error);}bool CBaseFile::SaveToArchive(CyString filename, int game, const CGameExe *exes, CProgressInfo *progress){return saveToArchive(filename.ToString(), game, exes, progress);}bool CBaseFile::saveToArchive(const Utils::String &filename, int game, const CGameExe *exes, CProgressInfo *progress){CDirIO Dir(CFileIO(filename).dir());if (!Dir.exists())Dir.create();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()->game() & (1 << game)))continue;// extracting for all games, so ignore files that have a game setif (!game && node->Data()->game() && node->Data()->game() != GAME_ALLNEW)continue;}Utils::String fname = node->Data()->getNameDirectory(this);// use the addon directoryif (node->Data()->isFileInAddon() && exes){unsigned int whatGame = game;if (game == -1){unsigned int checkGame = node->Data()->game() & ~GAME_ALLNEW;whatGame = 0;for (int i = 0; i < 31; ++i){if (1 << i == checkGame){whatGame = i;break;}}}if (whatGame > 0){SGameExe *e = exes->GetGame(whatGame - 1);if (e){if (e->iFlags & EXEFLAG_ADDON)fname = e->sAddon + "/" + fname;}}}// create the directorywsprintf(buf, L"%hs", fname.c_str());if (node->Data()->isExternalFile()){CFileIO file(node->Data()->filePointer());size_t size = 0;unsigned char *data = file.readAll(&size);ZipAdd(hz, buf, data, size);delete data;}elseZipAdd(hz, buf, node->Data()->GetData(), node->Data()->GetDataSize());}// if its a ship, then add any generated filesthis->addGeneratedFiles(hz);// add the data fileUtils::CStringList list;Utils::CStringList addons;if ( this->GeneratePackagerScript(false, &list, game, addons, true) ){if ( CFileIO("test.tmp").writeFile(&list) ){ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");CFileIO::Remove("test.tmp");}}CloseZip(hz);return true;}int CBaseFile::GetGameFromString(const Utils::String &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("X3FL"))iGame = GAME_X3FL;else if ( sGame.isNumber() )iGame = sGame;return iGame;}Utils::String CBaseFile::ConvertGameToString(int iGame){Utils::String game = "ALL";switch(iGame) {case GAME_ALL:case GAME_ALLNEW: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_X3FL:game = "X3FL";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;}Utils::String builtInWares(){Utils::String str;str += "28;0;0;0;0;59;5753;0;35714;1;1;0;35714;-100000;0;0;SS_WARE_SW_NEW1;\n";str += "28;0;0;0;0;60;5763;0;33232;1;1;0;33232;0;1043;0;SS_WARE_SW_NEW2;\n";str += "28;0;0;0;0;61;5773;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW3;\n";str += "28;0;0;0;0;62;5783;0;56;1;1;0;56;-100000;0;0;SS_WARE_SW_NEW4;\n";str += "28;0;0;0;0;63;5793;0;88;1;1;0;88;-100000;0;0;SS_WARE_SW_NEW5;\n";str += "28;0;0;0;0;64;5803;0;283;1;1;0;283;-100000;0;0;SS_WARE_SW_NEW6;\n";str += "28;0;0;0;0;65;5813;0;383;1;1;0;383;-100000;0;0;SS_WARE_SW_NEW7;\n";str += "28;0;0;0;0;66;5823;0;1389;1;1;0;1389;-100000;1043;0;SS_WARE_SW_NEW8;\n";str += "28;0;0;0;0;67;5833;0;3396;1;1;0;3396;-100000;0;0;SS_WARE_SW_NEW9;\n";str += "28;0;0;0;0;68;5843;0;4215;1;1;0;4215;-100000;0;0;SS_WARE_SW_NEW10;\n";str += "28;0;0;0;0;69;5853;0;5635;1;1;0;5635;-100000;0;0;SS_WARE_SW_NEW11;\n";str += "28;0;0;0;0;70;5863;0;65735;1;1;0;65735;-100000;0;0;SS_WARE_SW_NEW12;\n";str += "28;0;0;0;0;71;5873;0;17857;1;1;0;17857;333;1043;0;SS_WARE_SW_NEW13;\n";str += "28;0;0;0;0;72;5883;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW14;\n";str += "28;0;0;0;0;73;5893;0;324515;1;1;0;324515;-100000;0;0;SS_WARE_SW_NEW15;\n";str += "28;0;0;0;0;74;5903;0;638508;1;1;0;638508;-100000;0;0;SS_WARE_SW_NEW16;\n";str += "28;0;0;0;0;75;5913;0;225755;1;1;0;225755;-100000;0;0;SS_WARE_SW_NEW17;\n";str += "28;0;0;0;0;76;5923;0;1931535;1;1;0;1931535;1000;0;0;SS_WARE_SW_NEW18;\n";str += "28;0;0;0;0;77;5933;0;2209150;1;1;0;2209150;-100000;0;0;SS_WARE_SW_NEW19;\n";str += "28;0;0;0;0;78;5943;0;6727565;1;1;0;6727565;-100000;0;0;SS_WARE_SW_NEW20;\n";str += "28;0;0;0;0;85;9999;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_1;\n";str += "28;0;0;0;0;86;15053;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_2;\n";str += "28;0;0;0;0;87;15063;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_3;\n";str += "28;0;0;0;0;88;15073;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_4;\n";str += "28;0;0;0;0;89;15083;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_5;\n";str += "28;0;0;0;0;90;15093;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_6;\n";return str;}void CBaseFile::_addWaresToList(int iLang, CLinkList<SWareEntry> &list, const Utils::String &wares, enum WareTypes eType){int totalWares = 0;Utils::String *w = wares.tokenise("\n", &totalWares);for(int i = 0; i < totalWares; i++) {int textId = w[i].token(";", 7).toLong();int useLang = iLang;if ( !_pTextDB->exists(useLang, 17, textId) )useLang = 44;if ( !_pTextDB->exists(useLang, 17, textId) )useLang = 49;if ( _pTextDB->exists(useLang, 17, textId) ) {SWareEntry *ware = new SWareEntry;ware->name = _pTextDB->get(useLang, 17, textId);ware->description = _pTextDB->get(useLang, 17, textId + 1);ware->id = w[i].token(";", -2);ware->relval = w[i].token(";", 9).toLong();ware->notority = w[i].token(";", 14).toLong();ware->type = eType;ware->position = i;ware->package = this;list.push_back(ware);}}CLEANSPLIT(w, totalWares);}bool CBaseFile::readWares(int iLang, CLinkList<SWareEntry> &list, const Utils::String &empWares){_pTextDB->setLanguage(iLang);// now go through all emp wares and get the ones we have text for_addWaresToList(iLang, list, empWares, Ware_EMP);_addWaresToList(iLang, list, builtInWares(), Ware_BuiltIn);return true;}bool CBaseFile::_readCommands(int iLang, int iStartID, CLinkList<SCommandSlot> &list){_pTextDB->setLanguage(iLang);for(int i = 2; i <= 13; i++) {for(int j = 0; j < 64; j++) {int id = (i * 100) + j;if ( _pTextDB->exists(iLang, iStartID + 2, id) ) {SCommandSlot *slot = new SCommandSlot;list.push_back(slot);slot->id = _pTextDB->get(iLang, iStartID, id);slot->name = _pTextDB->get(iLang, iStartID + 2, id);slot->shortName = _pTextDB->get(iLang, iStartID + 3, id);slot->info = _pTextDB->get(iLang, iStartID + 14, id);slot->slot = id;slot->package = this;}}}for(int i = 1400; i <= 2000; i++) {if ( _pTextDB->exists(iLang, iStartID + 2, i) ) {SCommandSlot *slot = new SCommandSlot;list.push_back(slot);slot->id = _pTextDB->get(iLang, iStartID, i);slot->name = _pTextDB->get(iLang, iStartID + 2, i);slot->shortName = _pTextDB->get(iLang, iStartID + 3, i);slot->info = _pTextDB->get(iLang, iStartID + 14, i);slot->slot = i;slot->package = this;}}for(int i = 6000; i <= 9999; i++) {if ( _pTextDB->exists(iLang, iStartID + 2, i) ) {SCommandSlot *slot = new SCommandSlot;list.push_back(slot);slot->id = _pTextDB->get(iLang, iStartID, i);slot->name = _pTextDB->get(iLang, iStartID + 2, i);slot->shortName = _pTextDB->get(iLang, iStartID + 3, i);slot->info = _pTextDB->get(iLang, iStartID + 14, i);slot->slot = i;slot->package = this;}}return true;}bool CBaseFile::readWingCommands(int iLang, CLinkList<SCommandSlot> &list){return _readCommands(iLang, 2028, list);}bool CBaseFile::readCommands(int iLang, CLinkList<SCommandSlot> &list){return _readCommands(iLang, 2008, list);}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;}