Rev 254 | 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();}Utils::WString CBaseFile::getFullPackageName(int language, const Utils::WString &byString) const{return getFullPackageName(language, true, byString);}Utils::WString CBaseFile::getFullPackageName(int language, bool includeVersion, const Utils::WString &byString) const{Utils::WString p = this->name(language);if (includeVersion){p += L" V";p += this->version();}p += L" ";p += byString + L" " + this->author();return p;}Utils::WString CBaseFile::getFullPackageName(const Utils::WString &format, int lang) const{if (format.empty())return getFullPackageName(lang);Utils::WString args[3] = { this->name(lang), this->version(), this->author() };return format.args(args, 3);}void CBaseFile::Delete (){m_lTempFiles.clear();m_lFiles.clear(true);if ( m_pIconFile ){delete m_pIconFile;m_pIconFile = NULL;}if ( _pTextDB ) {delete _pTextDB;_pTextDB = NULL;}}/*############################################################################################################ Base Class Functions ############################################################################################################*/const CLinkList<C_File> &CBaseFile::fileList() const{return m_lFiles;}CLinkList<C_File> &CBaseFile::fileList(FileType type, CLinkList<C_File>& list) const{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;}CLinkList<C_File> &CBaseFile::fileList(FileType type){m_lTempFiles.clear();return fileList(type, m_lTempFiles);}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(const Utils::WString &filename, float *version ){CFileIO File(filename);if ( !File.startRead() ) return 0;Utils::WString line = File.readEndOfLine();Utils::WString type = line.token(L";", 1);File.close();// check for old versionif ( line.left(3) == L"HiP" ) return SPKFILE_OLD;// check for formatif ( version ) *version = line.token(L";", 2);if ( type == L"BaseCycrow" ) return SPKFILE_BASE;if ( type == L"SPKCycrow" ) return SPKFILE_SINGLE;if ( type == L"XSPCycrow" ) return SPKFILE_SINGLESHIP;if ( type == L"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::WString CBaseFile::getNameValidFile() const{Utils::WString 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->dir() != file->dir() )continue;if ( f->game() != file->game() )continue;m_lFiles.remove(node, true);break;}_addFile(file);}C_File *CBaseFile::addFile(const Utils::WString &file, const Utils::WString &dir, FileType type, int game, bool packed){C_File *newfile = new C_File(file);newfile->setDir(dir);newfile->setFileType(type);newfile->setGame(game);if (packed){if (newfile->PCKFile())newfile->setFilename(CFileIO(newfile->filePointer()).changeFileExtension(L"pck"));}// 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(const Utils::WString &file, const Utils::WString &dir, FileType 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(const Utils::WString &file, int type, int game, bool packed, const Utils::WString &dir, CProgressInfo *progress ){C_File *newfile = addFile(file, dir, static_cast<FileType>(type), game, packed);if ( !newfile )return NULL;// read the file into memoryif (newfile->GetData() && newfile->GetDataSize()){// now compress the fileif (newfile->CompressData(m_SHeader2.iDataCompression, progress))return newfile;}if ( 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(FileType filetype, size_t pos) const{size_t 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(const Utils::WString &filename, FileType type, const Utils::WString &dir, int game) const{Utils::WString lfile = CFileIO(filename.lower()).filename();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->dir())continue;if (game && (game != f->game()))continue;if (f->name().lower() == lfile)return f;}return NULL;}bool CBaseFile::removeFile(const Utils::WString& file, FileType type, const Utils::WString& dir, int game){C_File* f = findFile(file, type, dir, game);if (!f)return false;return removeFile(f);}bool CBaseFile::removeFile(C_File *file){size_t 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(size_t pos){if (pos >= static_cast<size_t>(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(L"temp", this, false, progress))return false;else{uncomprToFile = true;fit->setFullDir(L"temp");}}if (!uncomprToFile)return false;}}if ( progress )progress->SwitchSecond();}return true;}size_t CBaseFile::fileSize() const{size_t fullsize = 1000;for (CListNode<C_File>* node = m_lFiles.Front(); node; node = node->next())fullsize += node->Data()->uncompressedDataSize();if (m_pIconFile)fullsize += m_pIconFile->uncompressedDataSize();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*/Utils::String CBaseFile::GetEndOfLine ( FILE *id, int *line, bool upper ){Utils::String 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.upper();return word;}size_t CBaseFile::countFiles(FileType filetype) const{size_t 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;}/*Func: CreateFilesLineReturn: String - returns the full string for files listDesc: Creates a signle line list of all the files*/Utils::WString CBaseFile::createFilesLine(SSPKHeader2 *header, CProgressInfo* progress) const{Utils::WString line;if (progress){progress->SetDone(0);progress->UpdateStatus(STATUS_COMPRESS);}if (header){header->iDataCompression = m_SHeader2.iDataCompression;header->iFileCompression = m_SHeader2.iFileCompression;header->lSize = m_SHeader2.lSize;header->iNumFiles = 0;header->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 += L"Icon:" + Utils::WString::Number(m_pIconFile->GetDataSize() + (long)4) + L":" + m_pIconFile->uncompressedDataSize() + L":" + (long)m_pIconFile->GetCompressionType() + L":" + _sIconExt + L"\n";if (header){++header->iNumFiles;header->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());}Utils::WString command = GetFileTypeString(file->GetFileType());if (command.empty())continue;if (file->IsShared())command = L"$" + command;if (file->dir().empty())line += command + L":" + (file->GetDataSize() + (long)4) + L":" + file->uncompressedDataSize() + L":" + (long)file->GetCompressionType() + L":" + (long)file->GetCreationTime() + L":" + ((file->IsCompressedToFile()) ? L"1" : L"0") + L":" + file->filename() + L":NULL:" + (long)file->game() + L"\n";elseline += command + L":" + (file->GetDataSize() + (long)4) + L":" + file->uncompressedDataSize() + L":" + (long)file->GetCompressionType() + L":" + (long)file->GetCreationTime() + L":" + ((file->IsCompressedToFile()) ? L"1" : L"0") + L":" + file->filename() + L":" + file->dir() + L":" + (long)file->game() + L"\n";if (header){++header->iNumFiles;header->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.readEndOfLineStr();// skip past valuesFile.seek(4 + m_SHeader.lValueCompressSize);// read the next headerFile.readEndOfLineStr();// 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->readEndOfLineStr();// skip past valuesFile->seek(4 + m_SHeader.lValueCompressSize);// read the next headerFile->readEndOfLineStr();// 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::WString baseFile = CFileIO(file->filePointer()).baseName();int lang = (baseFile.contains(L"-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){Utils::WStringList lPatches;int startfake = pPackages->findNextFakePatch();std::vector<C_File*> fakepatches;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(L"cat"))continue;if (fakepatches.empty())fakepatches.push_back(fit);else{bool added = false;int num = fit->baseName().toInt();for (auto itr = fakepatches.begin(); itr != fakepatches.end(); itr++){int checkNum = (*itr)->baseName().toInt();if (num < checkNum){fakepatches.insert(itr, fit);added = true;break;}}if(!added)fakepatches.push_back(fit);}}// rename all the cat filesfor (auto itr = fakepatches.begin(); itr != fakepatches.end(); itr++){Utils::WString newname = Utils::WString::PadNumber((long)startfake, 2);lPatches.pushBack((*itr)->baseName(), newname);// rename the file(*itr)->FixOriginalName();CLog::logf(CLog::Log_Install, 2, L"Adjusting fake patch number, %s => %s", (*itr)->getNameDirectory(this).c_str(), (newname + L"." + (*itr)->fileExt()).c_str());(*itr)->setName(newname + L"." + (*itr)->fileExt());// find the next gapstartfake = pPackages->findNextFakePatch(startfake);}// now rename all the matching dat filesfor ( 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(L"dat") )continue;// search for the name on the listif (lPatches.contains(fit->baseName())){Utils::WString newname = lPatches.findString(fit->baseName());// rename the filefit->FixOriginalName();CLog::logf(CLog::Log_Install, 2, L"Adjusting fake patch number, %s => %s", fit->getNameDirectory(this).c_str(), (newname + L"." + fit->fileExt()).c_str());fit->setName(newname + L"." + fit->fileExt());}}}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::WString newname = SPK::FormatTextName(starttext, pPackages->GetLanguage(), (pPackages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));fit->FixOriginalName();CLog::logf(CLog::Log_Install, 2, L"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->dir().left(7).lower() == L"Extras/") )bEnable = true;else if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) && (!fit->IsFakePatch()) )bEnable = true;if ( bEnable ) CLog::logf(CLog::Log_Install, 3, L"Filetype(%d) is always enabled, setting enabled flag", fit->GetFileType());}return bEnable;}bool CBaseFile::_install_uncompress(C_File *fit, CProgressInfo *progress, Utils::WStringList *errorStr, bool *uncomprToFile){*uncomprToFile = false;_sLastError = fit->getNameDirectory(this);_iLastError = SPKERR_UNCOMPRESS;if ( !fit->UncompressData ( progress ) ){CLog::log(CLog::Log_Install, 2, L"Failed to uncompress data, attempting file decompression");if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP ){if ( fit->uncompressToFile(Utils::WString::Null(), this, false, progress ) )*uncomprToFile = true;}if ( !uncomprToFile ){if ( errorStr )errorStr->pushBack(_sLastError, ERRORLOG(SPKINSTALL_UNCOMPRESS_FAIL));CLog::log(CLog::Log_Install, 1, L"Unable to decompress file, skipping");return false;}}ClearError ();return true;}bool CBaseFile::_install_checkVersion(C_File *pFile, const Utils::WString &sDestination){// new check if we should install the file// first get the versionif ( !m_bOverrideFiles && pFile->ReadScriptVersion() ){CLog::log(CLog::Log_Install, 2, L"Checking for existing file version");C_File checkfile;Utils::WString checkfilename = sDestination;if ( !checkfilename.empty() ) checkfilename += L"/";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, L"Newer version of the file found in directory, skipping");return false;}}}return true;}Utils::WString CBaseFile::_install_adjustFilepointer(C_File *pFile, bool bEnabled, const Utils::WString &sDestination){Utils::WString filename = sDestination;if ( !filename.empty() ) filename += L"/";if ( (IsPatch()) && (pFile->fileType() == FILETYPE_MOD) )pFile->setDir(L"Patch");if ( pFile->isInMod() ){if ( bEnabled )pFile->setFilename(filename + pFile->getInMod() + L"::" + pFile->getNameDirectory(this));elsepFile->setFilename(filename + L"PluginManager/DisabledFiles.cat::" + pFile->getNameDirectory(this));}elsepFile->setFilename ( filename + pFile->getNameDirectory(this) );if ( !bEnabled ){if ( !pFile->isInMod() ){if ( pFile->IsFakePatch() )pFile->setFilename ( filename + L"PluginManager/Disabled/FakePatches/FakePatch_" + this->getNameValidFile() + L"_" + this->author() + L"_" + pFile->name());else if ( pFile->isAutoTextFile() )pFile->setFilename ( filename + L"PluginManager/Disabled/TextFiles/Text_" + this->getNameValidFile() + L"_" + this->author() + L"_" + pFile->name());elsepFile->setFullDir ( filename + L"PluginManager/Disabled/" + pFile->getDirectory(this) );}pFile->SetDisabled(true);}CLog::logf(CLog::Log_Install, 2, L"Adjusting the file pointer to correct install destintation, %s", pFile->filePointer().c_str());return filename;}C_File *CBaseFile::_install_checkFile(C_File *pFile, Utils::WStringList *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(SPKINSTALL_SKIPFILE));CLog::log(CLog::Log_Install, 1, L"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::WString &sDestination, bool bEnabled, Utils::WStringList *errorStr){// found a file, check if its in the disabled directoryUtils::WString dir = CFileIO(pCheckFile->filePointer()).dir();Utils::WString lastDir = CDirIO(dir).topDir().lower();// if its disabled, rename it so its enabledif ( ((pCheckFile->IsDisabled()) || (lastDir == L"disabled") || (dir.lower().contains(L"/disabled/"))) && (bEnabled) ){CLog::logf(CLog::Log_Install, 2, L"Existing file, %s, is disabled, re-enabling it", pCheckFile->filePointer().c_str());// first check if the directory existsif ( pCheckFile->isInMod() ) {Utils::WString tofile = pCheckFile->filePointer().token(L"::", 2);CCatFile tocat;int err = tocat.open(fit->filePointer().token(L"::", 1), L"", CATREAD_CATDECRYPT, true);if ( (err == CATERR_NONE) || (err == CATERR_CREATED) ) {tocat.appendFile(pCheckFile->filePointer(), tofile);CLog::logf(CLog::Log_Install, 2, L"Adding existing file into new mod File, %s => %s", fit->filePointer().token(L"::", 1).c_str(), tofile.c_str());}CCatFile fromcat;err = fromcat.open(pCheckFile->filePointer().token(L"::", 1), L"", CATREAD_CATDECRYPT, false);if ( err == CATERR_NONE ) {fromcat.removeFile(tofile);CLog::logf(CLog::Log_Install, 2, L"Removing file from existing mod, %s::%s", pCheckFile->filePointer().token(L"::", 1).c_str(), tofile.c_str());}CLog::logf(CLog::Log_Install, 1, L"Adjusting existing file name %s => %s", pCheckFile->filePointer().c_str(), fit->filePointer().c_str());pCheckFile->setFilename(fit->filePointer());CLog::logf(CLog::Log_Install, 2, L"Adjusting In Mod setting, %s => %s", pCheckFile->getInMod().c_str(), fit->getInMod().c_str());pCheckFile->setInMod(fit->getInMod());}else {Utils::WString to = pCheckFile->getDirectory(this);CDirIO Dir(sDestination);if ( !Dir.exists(to) ) {if ( !Dir.create ( to ) ) {if ( errorStr ) errorStr->pushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));return false;}if ( errorStr ) errorStr->pushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));}Utils::WString destfile = sDestination + L"/" + pCheckFile->getNameDirectory(this);if ( CFileIO::Exists(destfile) ) CFileIO::Remove(destfile);CLog::logf(CLog::Log_Install, 1, L"Adjusting existing filename, %s => %s", pCheckFile->filePointer().c_str(), destfile.c_str());CFileIO::Rename(pCheckFile->filePointer(), destfile);pCheckFile->setFilename (sDestination + L"/" + pCheckFile->getNameDirectory(this) );}pCheckFile->SetDisabled(false);if ( errorStr ) errorStr->pushBack(pCheckFile->getNameDirectory(this), ERRORLOG(SPKINSTALL_ENABLEFILE));}return true;}bool CBaseFile::_install_createDirectory(CDirIO &Dir, const Utils::WString &sTo, C_File *pFile, Utils::WStringList *errorStr){_sLastError = sTo;if ( !sTo.contains(L"::")){if ( !Dir.exists(sTo) ){CLog::logf(CLog::Log_Install, 2, L"Creating directory to install file into, %s", sTo.c_str());if ( !Dir.create(sTo) ){if ( errorStr )errorStr->pushBack(sTo, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));return false;}if ( errorStr )errorStr->pushBack(sTo, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));}}else {CLog::logf(CLog::Log_Install, 2, L"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::WString &sDestination, Utils::WStringList *errorStr){_iLastError = SPKERR_WRITEFILE;_sLastError = pFile->filePointer();Utils::WString 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, L"Failed to write the file");if ( errorStr )errorStr->pushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE_FAIL));}else{CLog::log(CLog::Log_Install, 1, L"File written successfully");CLog::log(CLog::Log_Install, 2, L"Checking signed status of the file");pFile->UpdateSigned();if ( errorStr )errorStr->pushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE));switch(pFile->GetFileType()){case FILETYPE_SCRIPT:case FILETYPE_UNINSTALL:CLog::log(CLog::Log_Install, 2, L"Updating file signature");pFile->updateSignature();break;}}}bool CBaseFile::installFiles(const Utils::WString &destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, Utils::WStringList *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, L"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, L"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);// change file pointerUtils::WString sInstallDir = _install_adjustFilepointer(fit, fileEnabled, destdir);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->filePointer());if ( rFile.exists() ){if ( errorStr ){if ( rFile.remove() )errorStr->pushBack(cFile->filePointer().findRemove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE));elseerrorStr->pushBack(cFile->filePointer().findRemove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE_FAIL));}}cFile->setFilename(fit->filePointer());cFile->SetDisabled(true);}else{fit->setFullDir(sInstallDir + fit->getDirectory(this));fit->SetDisabled(false);}}// move it to enabledelse {if ( !this->_install_checkFileEnable(cFile, fit, destdir, 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::WString to = fit->getDirectory(this);if ( !fileEnabled ) to = L"PluginManager/Disabled/" + to;if ( !_install_createDirectory(Dir, to, fit, errorStr) ) {bFailed = true;continue;}bool err = true;_sLastError = to;if ( !fit->getTempFile().empty())err = CFileIO::Rename(fit->getTempFile(), to);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, L"Copying data into existing file");}Utils::WString fpointer = fit->filePointer();_iLastError = SPKERR_CREATEDIRECTORY;Utils::WString dir = CFileIO(fit->filePointer()).dir();dir = dir.findRemove(destdir);if (!dir.empty() && (dir[0] == '/' || dir[0] == '\\'))dir.erase(0, 1);if ( !_install_createDirectory(Dir, dir, fit, errorStr) ) {bFailed = true;continue;}_install_writeFile(fit, destdir, errorStr);}ClearError ();}if ( adjustPointer ){CLog::log(CLog::Log_Install, 2, L"Adjusting pointers to existing file and deleting new file pointer");node->ChangeData(adjustPointer);delete fit;}CLog::log(CLog::Log_Install, 1, L"File installation completed");}// now clear or data memoryCLog::log(CLog::Log_Install, 2, L"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(const Utils::WString &header){if ( !this->_checkHeader(header.token(L";", 1)))return false;m_SHeader.fVersion = header.token(L";", 2).toFloat();if ( m_SHeader.fVersion > FILEVERSION )return false;m_SHeader.iValueCompression = header.token(L";", 3).toInt();m_SHeader.lValueCompressSize = header.token(L";", 4).toLong();return true;}bool CBaseFile::_checkHeader(const Utils::WString &header) const{if ( header.Compare(L"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(const Utils::WString &header){if (header.token(L";", 1) != L"FileHeader")return false;m_SHeader2.iNumFiles = header.token(L";", 2).toInt();m_SHeader2.lSize = header.token(L";", 3).toInt();m_SHeader2.lFullSize = header.token(L";", 4).toInt();m_SHeader2.iFileCompression = header.token(L";", 5).toInt();m_SHeader2.iDataCompression = header.token(L";", 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::WString &sLine){Utils::WString first = sLine.token(L" ", 1);Utils::WString rest = sLine.tokens(L" ", 2);if ( first.Compare(L"Name:") ) this->setName(rest);else if ( first.Compare(L"Author:") ) this->setAuthor(rest);else if ( first.Compare(L"Version:") ) this->setVersion(rest);else if ( first.Compare(L"fGameVersion:") ) {if ( m_lGames.Back() ) {m_lGames.Back()->Data()->sVersion = rest;}}else if ( first.Compare(L"GameVersion:") ) {if ( m_lGames.Back() ) {m_lGames.Back()->Data()->iVersion = rest.toInt();}}else if ( first.Compare(L"Game:") )this->AddGameCompatability(rest, L"");else if ( first.Compare(L"GameCompat:") )this->AddGameCompatability(rest.token(L" ", 1), rest.tokens(L" ", 2));else if ( first.Compare(L"GameCompatExact:") )this->AddGameCompatability(rest.token(L" ", 1), rest.tokens(L" ", 2));else if ( first.Compare(L"Date:") ) this->setCreationDate(rest);else if ( first.Compare(L"WebAddress:") ) this->setWebAddress(rest);else if ( first.Compare(L"WebSite:") ) this->setWebSite(rest);else if ( first.Compare(L"Email:") ) this->setEmail(rest);else if ( first.Compare(L"WebMirror1:") || first.Compare(L"Mirror1:") || first.Compare(L"WebMirror:") )this->addWebMirror(rest);else if ( first.Compare(L"WebMirror2:") || first.Compare(L"Mirror2:") )this->addWebMirror(rest);else if ( first.Compare(L"PluginType:") ) this->setPluginType(rest);else if ( first.Compare(L"Desc:") ) this->setDescription(rest);else if ( first.Compare(L"UninstallAfter:") ) this->addUninstallText(parseLanguage(rest.token(L"|", 1)), false, rest.tokens(L"|", 2));else if ( first.Compare(L"UninstallBefore:") ) this->addUninstallText(parseLanguage(rest.token(L"|", 1)), true, rest.tokens(L"|", 2));else if ( first.Compare(L"InstallAfter:") ) this->addInstallText(parseLanguage(rest.token(L"|", 1)), false, rest.tokens(L"|", 2));else if ( first.Compare(L"InstallBefore:") ) this->addInstallText(parseLanguage(rest.token(L"|", 1)), true, rest.tokens(L"|", 2));else if ( first.Compare(L"ScriptName:") ) addName(parseLanguage(rest.token(L":", 1)), rest.token(L":", 2));else if ( first.Compare(L"GameChanging:") ) this->setGameChanging(rest);else if ( first.Compare(L"EaseOfUse:") ) this->setEaseOfUse(rest);else if ( first.Compare(L"Recommended:") ) this->setRecommended(rest);else if ( first.Compare(L"NeededLibrary:") )this->addNeededLibrary(rest.token(L"||", 1), rest.token(L"||", 2), rest.token(L"||", 3));else if ( first.Compare(L"FakePatchBefore:") )this->addFakePatchOrder(false, rest.token(L"||", 1), rest.token(L"||", 2));else if (first.Compare(L"FakePatchAfter:"))this->addFakePatchOrder(true, rest.token(L"||", 1), rest.token(L"||", 2));else if (first.Compare(L"Globals:"))this->addGlobal(rest.token(L";", 1), rest.tokens(L";", 2));else if ( first.Compare(L"ForumLink:") ) this->setForumLink(rest);elsereturn false;return true;}int CBaseFile::parseLanguage(const Utils::WString &lang) const{int langID = lang;if ( !langID ) {if (lang.Compare(L"english")) return 44;else if (lang.Compare(L"default")) return 0;else if (lang.Compare(L"german")) return 49;else if (lang.Compare(L"russian")) return 7;else if (lang.Compare(L"spanish")) return 34;else if (lang.Compare(L"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(const Utils::WString &values){std::vector<Utils::WString> lines;values.tokenise(L"\n", lines);for (size_t i = 0; i < lines.size(); i++)parseValueLine(lines[i]);}/*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(const Utils::WString &line){if ( !line.contains(L":") )return false;Utils::WString command = line.token(L":", 1);long size = line.token(L":", 2).toInt();long usize = line.token(L":", 3).toInt ();long compression = line.token(L":", 4).toInt ();if ( command == L"Icon" ){_sIconExt = line.token(L":", 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(L":", 5).toLong();bool compressToFile = (line.token(L":", 6).toInt() == 1) ? true : false;Utils::WString name = line.token(L":", 7);Utils::WString dir = line.token(L":", 8);if ( name.empty() )return true;bool shared = false;if ( command.left(1) == L"$" ){shared = true;command.erase(0, 1);}FileType type = FILETYPE_UNKNOWN;if ( command == L"Script" )type = FILETYPE_SCRIPT;else if ( command == L"Text" )type = FILETYPE_TEXT;else if ( command == L"Readme" )type = FILETYPE_README;else if ( command == L"Map" )type = FILETYPE_MAP;else if ( command == L"Mod" )type = FILETYPE_MOD;else if ( command == L"Uninstall" )type = FILETYPE_UNINSTALL;else if ( command == L"Sound" )type = FILETYPE_SOUND;else if ( command == L"Mission" )type = FILETYPE_MISSION;else if ( command == L"Extra" )type = FILETYPE_EXTRA;else if ( command == L"Screen" )type = FILETYPE_SCREEN;else if ( command == L"Backup" )type = FILETYPE_BACKUP;else if ( command == L"Advert" )type = FILETYPE_ADVERT;else if ( command == L"ShipScene" )type = FILETYPE_SHIPSCENE;else if ( command == L"CockpitScene" )type = FILETYPE_COCKPITSCENE;else if ( command == L"ShipOther" )type = FILETYPE_SHIPOTHER;else if ( command == L"ShipModel" )type = FILETYPE_SHIPMODEL;if (type == FILETYPE_UNKNOWN)return false;C_File *file = new C_File();if (dir.left(5).Compare(L"GAME_")) {unsigned int iGame = dir.token(L"_", 2).toInt();if (!iGame)file->setGame(0);elsefile->setGame(1 << 31 | 1 << iGame);dir = Utils::WString::Null();}else if ( line.countToken(L":") >= 9 ){Utils::WString game = line.token(L":", 9);if (game.contains(L"_")){unsigned int iGame = game.token(L"_", 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(L"NULL")) {dir = Utils::WString::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(const Utils::WString &values){std::vector<Utils::WString> lines;values.tokenise(L"\n", lines);for (size_t i = 0; i < lines.size(); i++)_parseFilesLine(lines[i]);}/*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(const Utils::WString &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 = 0;try {readData = new unsigned char[m_SHeader.lValueCompressSize];}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, L"CBaseFile::_read_Header() unable to malloc [header], %d (%hs)", m_SHeader.lValueCompressSize, e.what());return -1;}if (!readData)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){if (m_SHeader.fVersion < 4.4f){std::string data((const char*)uncompr);_readValues(std::wstring(data.begin(), data.end()));}else{const wchar_t* data = (const wchar_t*)uncompr;_readValues(Utils::WString(data));}}doneLen = uncomprLen;delete []uncompr;}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, L"CBaseFile::_read_Header() unable to malloc [uncompr], %d (%hs)", 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){if (m_SHeader.fVersion <= 4.4f){std::string data((const char*)compr);_readValues(std::wstring(data.begin(), data.end()));}else{const wchar_t* data = (const wchar_t*)compr;_readValues(Utils::WString(data));}}}// no compressionelse{if (m_SHeader.fVersion <= 4.4f){std::string data((const char*)readData);_readValues(std::wstring(data.begin(), data.end()));}else{const wchar_t* data = (const wchar_t*)readData;_readValues(Utils::WString(data));}}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, L"CBaseFile::_read_FileHeader() unable to malloc [header], %d (%hs)", 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){//#pragma warning(disable:4244)if (m_SHeader.fVersion < 4.4f){std::string data((char*)uncompr);_readFiles(std::wstring(data.begin(), data.end()));}else{std::wstring data((wchar_t*)uncompr);_readFiles(data);}//#pragma warning(enable:4244)}delete[] uncompr;}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, L"CBaseFile::_read_FileHeader() unable to malloc [uncompr], %d (%hs)", 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){if (m_SHeader.fVersion < 4.4f){std::string data((char*)compr);_readFiles(std::wstring(data.begin(), data.end()));}else{std::wstring data((wchar_t*)compr);_readFiles(data);}}}else{if (m_SHeader.fVersion < 4.4f){std::string data((char*)readData);_readFiles(std::wstring(data.begin(), data.end()));}else{std::wstring data((wchar_t*)readData);_readFiles(data);}}delete []readData;return true;}bool CBaseFile::readFile(CFileIO &File, int readtype, CProgressInfo *progress){ClearError ();// first read the headerif ( !_parseHeader(File.readEndOfLineStr()) ) 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.readEndOfLineStr()) ) 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::WString CBaseFile::createValuesLine () const{Utils::WString values(L"Name: ");values += this->name() + L"\n";values += L"Author: " + this->author() + L"\n";values += L"Version: " + this->version() + L"\n";if ( !this->creationDate().empty() )values += L"Date: " + this->creationDate() + L"\n";if ( !this->webAddress().empty() ) values += L"WebAddress: " + this->webAddress() + L"\n";if ( !this->webSite().empty() ) values += L"WebSite: " + this->webSite() + L"\n";if ( !this->email().empty() ) values += L"Email: " + this->email() + L"\n";if ( !this->forumLink().empty() ) values += L"ForumLink: " + this->forumLink() + L"\n";for(auto itr = webMirrors().begin(); itr != webMirrors().end(); itr++)values += Utils::WString(L"WebMirror: ") + (*itr)->str + L"\n";if ( !this->description().empty() ) {Utils::WString desc = this->description();desc = desc.findReplace(L"<newline>", L"<br>");desc = desc.findReplace(L"\n", L"<br>");desc.remove(L'\r');values += L"Desc: " + desc + L"\n";}for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {if ( !gc->Data()->sVersion.empty() )values += Utils::WString(L"GameCompatExact: ") + (long)gc->Data()->iGame + L" " + gc->Data()->sVersion + L"\n";elsevalues += Utils::WString(L"GameCompat: ") + (long)gc->Data()->iGame + L" " + (long)gc->Data()->iVersion + L"\n";}if (computeSigned(true))values += L"Signed\n";for ( int j = 0; j < 2; j++ ) {const CInstallText *text;Utils::WString textStart;switch(j) {case 0: textStart = L"Uninstall"; text = this->uninstallText(); break;case 1: textStart = L"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 + L"Before: " + (long)iLang + L"|" + text->getBefore(iLang) + L"\n";if ( !text->getAfter(iLang).empty() ) values += textStart + L"After: " + (long)iLang + L"|" + text->getAfter(iLang) + L"\n";}}values += Utils::WString(L"GameChanging: ") + (long)gameChanging() + L"\n";values += Utils::WString(L"EaseOfUse: ") + (long)easeOfUse() + L"\n";values += Utils::WString(L"Recommended: ") + (long)recommended() + L"\n";for(auto itr = namesList()->begin(); itr != namesList()->end(); itr++)values += Utils::WString(L"ScriptName: ") + (long)(*itr)->iLanguage + L":" + (*itr)->sName + L"\n";for ( CListNode<SNeededLibrary> *libNode = m_lNeededLibrarys.Front(); libNode; libNode = libNode->next() ) {SNeededLibrary *l = libNode->Data();values += L"NeededLibrary: " + l->sName + L"||" + l->sAuthor + L"||" + l->sMinVersion + L"\n";}for (auto itr = _lFakePatchBefore.begin(); itr != _lFakePatchBefore.end(); itr++)values += L"FakePatchBefore: " + (*itr)->str + L"||" + (*itr)->data + L"\n";for (auto itr = _lFakePatchAfter.begin(); itr != _lFakePatchAfter.end(); itr++)values += L"FakePatchAfter: " + (*itr)->str + L"||" + (*itr)->data + L"\n";values += Utils::WString(L"PluginType: ") + (long)this->pluginType() + L"\n";for (auto itr = _lGlobals.begin(); itr != _lGlobals.end(); itr++)values += L"Globals: " + (*itr)->str + L";" + (*itr)->data + L"\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(const Utils::WString &filename, CProgressInfo *progress) const{CFileIO File(filename);if ( File.startWrite() ) return writeData(File, progress);return false;}bool CBaseFile::writeHeader(CFileIO &file, int valueheader, int valueComprLen) const{return file.write("BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);}bool CBaseFile::writeData(CFileIO &file, CProgressInfo *progress ) const{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 valuesUtils::WString values = this->createValuesLine();const char* data = (const char*)values.c_str();// compress the valuesint valueUncomprLen = (int)(wcslen(values.c_str()) * sizeof(wchar_t)) / sizeof(char);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 *)data, (unsigned long)valueUncomprLen, 0 );if ( err == Z_OK )compressed = true;}if ( !compressed ){valueComprLen = valueUncomprLen;valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);memcpy ( valueCompr, (const unsigned char *)data, 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 valuesSSPKHeader2 header;Utils::WString files = createFilesLine(&header, progress);// compress the files valueslong fileUncomprLen = (long)((wcslen(files.c_str()) * sizeof(wchar_t)) / sizeof(char)), 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)fileUncomprLen, 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, (const unsigned char *)files.c_str(), fileComprLen );fileheader = SPKCOMPRESS_NONE;}// now write the file headerheader.lSize = fileComprLen;file.write("FileHeader;%d;%ld;%ld;%d;%d\n", header.iNumFiles, header.lSize, header.lFullSize, fileheader, header.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->uncompressedDataSize());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->uncompressedDataSize());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);}}return true;}bool CBaseFile::extractFile(C_File *file, const Utils::WString &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::WString::Null(), data, len))return false;return true;}elsereturn false;}bool CBaseFile::extractFile(C_File *file, const Utils::WString &dir, unsigned int game, const Utils::WStringList &gameAddons, bool includedir, CProgressInfo *progress){if (ReadFileToMemory(file)){CDirIO Dir(dir);Utils::WString addonDir;if (file->isFileInAddon()){int addonGame = file->getForSingleGame();if (!addonGame) addonGame = game;if (addonGame > 0)addonDir = gameAddons.findString(Utils::WString::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::WString::Null(), data, len))return false;return true;}elsereturn false;}bool CBaseFile::extractFile(int filenum, const Utils::WString &dir, unsigned int game, const Utils::WStringList &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::WString &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::WString &dir, int game, const Utils::WStringList &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::WString addonDir;if (fit->isFileInAddon()){int addonGame = fit->getForSingleGame();if (!addonGame) addonGame = game;if (addonGame > 0)addonDir = gameAddons.findString(Utils::WString::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::WString::Null(), data, size))) return false;}delete File;return true;}bool CBaseFile::computeSigned(bool updateFiles) const{// any globals?if (!_lGlobals.empty())return false;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))return false;// 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())return false;}return true;}bool CBaseFile::updateSigned(bool updateFiles){m_bSigned = computeSigned(updateFiles);return m_bSigned;}bool CBaseFile::isPackageNeeded(const Utils::WString &scriptName, const Utils::WString &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::WString &scriptName, const Utils::WString &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(const Utils::WString &scriptName, const Utils::WString &author){removeFakePatchOrder(true, scriptName, author);removeFakePatchOrder(false, scriptName, author);}void CBaseFile::removeFakePatchOrder(bool after, const Utils::WString &scriptName, const Utils::WString &author){Utils::WStringList *list;if ( after )list = &_lFakePatchAfter;elselist = &_lFakePatchBefore;int found = list->findStringAndData(scriptName, author);while (found != -1){list->removeAt(found);found = list->findStringAndData(scriptName, author);}}void CBaseFile::addFakePatchOrder(bool after, const Utils::WString &scriptName, const Utils::WString &author){Utils::WStringList *list;if ( after )list = &_lFakePatchAfter;elselist = &_lFakePatchBefore;// check if the package already existsif (!list->containsStringAndData(scriptName, author)){// cant have it on both listremoveFakePatchOrder(!after, scriptName, author);list->pushBack(scriptName, author);}}void CBaseFile::addNeededLibrary(const Utils::WString &scriptName, const Utils::WString &author, const Utils::WString &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::WString &scriptName, const Utils::WString &author){SNeededLibrary *l = this->findPackageNeeded(scriptName, author);if ( l ){m_lNeededLibrarys.remove(l);delete l;}}void CBaseFile::ClearNeededPackages(){SNeededLibrary *ns = this->findPackageNeeded(L"<package>", L"<author>");Utils::WString 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(L"<package>", L"<author>", version);}bool CBaseFile::GeneratePackagerScript(bool wildcard, Utils::WStringList *list, int game, const Utils::WStringList &gameAddons, bool datafile){list->pushBack(L"#");list->pushBack(L"# Packager Script");list->pushBack(L"# -- Generated by SPK Libraries V" + Utils::WString::FromFloat(GetLibraryVersion(), 2) + L" --");list->pushBack(L"#");list->pushBack(L"");if ( !datafile ){list->pushBack(L"# Variable for your game directory, where to get files from");list->pushBack(L"# $PATH variable is used to get the current path");list->pushBack(L"Variable: $GAMEDIR $PATH");list->pushBack(L"");}list->pushBack(L"# The name of the script");list->pushBack(L"Name: " + this->name());list->pushBack(L"");list->pushBack(L"# The author of the script, ie, you");list->pushBack(L"Author: " + this->author());list->pushBack(L"");list->pushBack(L"# The creation data, when it was created");if ( datafile )list->pushBack(L"Date: " + this->creationDate());else {list->pushBack(L"# $DATE variable is used to get the current date");list->pushBack(L"Date: $DATE");}list->pushBack(L"");list->pushBack(L"# The version of script");if ( datafile )list->pushBack(L"Version: " + this->version());else{list->pushBack(L"# $ASK variable is used to get an input when creating");list->pushBack(L"Version: $ASK");}list->pushBack(L"");if ( !m_lGames.empty() ) {list->pushBack(L"# 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::WString game = CBaseFile::ConvertGameToString(g->iGame);if ( !g->sVersion.empty() ){game += L" ";game += g->sVersion;}else{game += L" ";game += (long)g->iVersion;}list->pushBack(L"Game: " + game);}list->pushBack(L"");}if ( !this->description().empty() ) {list->pushBack(L"# The description of the script, displays when installing");list->pushBack(L"Description: " + this->description());list->pushBack(L"");}if ( !this->webSite().empty() ) {list->pushBack(L"# A link to the website for the script, ie for an online help page");list->pushBack(L"WebSite: " + this->webSite());list->pushBack(L"");}if ( !this->forumLink().empty() ) {list->pushBack(L"# A direct link to the thread in the egosoft forum");list->pushBack(L"ForumLink: " + this->forumLink());list->pushBack(L"");}if ( !this->webAddress().empty() ) {list->pushBack(L"# A link to the address for the update file");list->pushBack(L"WebAddress: " + this->webAddress());list->pushBack(L"");}if ( !this->email().empty() ) {list->pushBack(L"# The email address of the author, to allow users to contract if needed");list->pushBack(L"Email: " + this->email());list->pushBack(L"");}if (webMirrors().size()){list->pushBack(L"# A link to the mirror address for the update file, can have many of these");for(auto itr = webMirrors().begin(); itr != webMirrors().end(); itr++)list->pushBack(Utils::WString(L"WebMirror: ") + (*itr)->str);list->pushBack(L"");}if ( m_bAutoGenerateUpdateFile ){list->pushBack(L"# Auto generate the package update file when created");list->pushBack(L"GenerateUpdateFile");}if ( m_lNeededLibrarys.size() ){list->pushBack(L"# Needed Library dependacies, require these to be installed");for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )list->pushBack(L"Depend: " + node->Data()->sName + L"|" + node->Data()->sMinVersion + L"|" + node->Data()->sAuthor);list->pushBack(L"");}if ( !_noRatings() ){list->pushBack(L"# Ratings Values, 0 to 5, <ease> <changing> <recommended>");list->pushBack(Utils::WString(L"Ratings: ") + (long)easeOfUse() + L" " + (long)gameChanging() + L" " + (long)recommended());list->pushBack(L"");}if (namesList()->size()){list->pushBack(L"# Package names, uses different names for different languages");for(auto itr = namesList()->begin(); itr != namesList()->end(); itr++)list->pushBack(Utils::WString("ScriptName: ") + (long)(*itr)->iLanguage + L" " + (*itr)->sName);list->pushBack(L"");}for ( int j = 0; j < 2; j++ ) {Utils::WString installText = (j == 0) ? L"Install" : L"Uninstall";const CInstallText *pText = (j == 0) ? this->installText() : this->uninstallText();if ( pText->any() ){list->pushBack(L"# " + installText + L" Texts, display text before and/or after " + installText + L"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 + L" " + pText->getBefore(iLang));if ( !pText->getAfter(iLang).empty() ) list->pushBack(installText + "After: " + iLang + L" " + pText->getAfter(iLang));}list->pushBack(L"");}}list->pushBack(L"# 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(L"PluginType: Normal");break;case PLUGIN_STABLE:list->pushBack(L"PluginType: Stable");break;case PLUGIN_EXPERIMENTAL:list->pushBack(L"PluginType: Experimental");break;case PLUGIN_CHEAT:list->pushBack(L"PluginType: Cheat");break;case PLUGIN_MOD:list->pushBack(L"PluginType: Mod");break;}list->pushBack(L"");if (!_lGlobals.empty()){list->pushBack(L"# Globals, add global overrides to a package when generating the globals file, to override game settings");for (auto itr = _lGlobals.begin(); itr != _lGlobals.end(); itr++)list->pushBack(L"Global: " + (*itr)->str + L";" + (*itr)->data);list->pushBack(L"");}return true;}bool CBaseFile::GeneratePackagerScriptFile(bool wildcard, Utils::WStringList *list, int game, const Utils::WStringList &gameAddons){// now do files and wildcardsUtils::WStringList files;for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() ){if (game && !(f->Data()->game() & 1 << game))continue;Utils::WString name = L"$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::WString str = gameAddons.findString(Utils::WString::Number(foundGame));if(!str.empty())name += str + L"/";}bool done = false;if ( wildcard ){Utils::WString base = f->Data()->baseName();if ( f->Data()->fileType() == FILETYPE_SCRIPT ){if ( base.token(L".", 1).Compare(L"plugin") || base.token(L".", 1).Compare(L"lib") ){name += f->Data()->getDirectory(this) + "/" + base.tokens(L".", 1, 2) + L".*";done = true;}else if ( base.token(L".", 1).Compare(L"al") && !base.token(L".", 2).Compare(L"plugin") ){name += f->Data()->getDirectory(this) + L"/" + base.tokens(L".", 1, 2) + L".*";done = true;}}else if ( f->Data()->fileType() == FILETYPE_TEXT ){if ( base.contains(L"-L") ){name += f->Data()->getDirectory(this) + L"/" + base.token(L"-L", 1) + L"-L*";done = true;}else{name += f->Data()->getDirectory(this) + L"/*" + base.right(4) + L".*";done = true;}}}if ( !done )name += f->Data()->getNameDirectory(this);if ( !f->Data()->dir().empty() ){name += L"|";name += f->Data()->dir();}Utils::WString s = L"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 += L"|";s += CBaseFile::ConvertGameToString(i);}}}s += L" " + name;if(!files.contains(s))files.pushBack(s, f->Data()->fileTypeString());}if ( !files.empty() ){list->pushBack(L"# Files List, all the files to add, can include wild cards");for(auto itr = files.begin(); itr != files.end(); itr++)list->pushBack((*itr)->data + L": " + (*itr)->str);list->pushBack(L"");}return true;}Utils::WString CBaseFile::getAutosaveName() const{return this->name() + L"-V" + this->version() + L"-" + this->creationDate().findReplace(L"/", L".");}void CBaseFile::addGlobal(const Utils::WString& global, const Utils::WString& setting){if (!_lGlobals.changeData(global, setting))_lGlobals.pushBack(global, setting);}void CBaseFile::removeGlobal(const Utils::WString& global){_lGlobals.remove(global);}void CBaseFile::clearGlobals(){_lGlobals.clear();}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, const Utils::WString &sVersion, int iVersion) const{if (m_lGames.empty())return true; // no game compatability added, assume its ok for allbool foundAll = false;for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {if ( node->Data()->iGame == 0 )foundAll = true;else if ( node->Data()->iGame == game ) { // now check the versionif ( node->Data()->sVersion.empty() ) {if (node->Data()->sVersion.compareVersion(sVersion) == COMPARE_OLDER)return false;return true;}else {if ( node->Data()->iVersion > iVersion )return false;return true;}}}return foundAll;}bool CBaseFile::RemoveGameCompatability(int game){for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {if ( node->Data()->iGame == game ) {m_lGames.remove(node);_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::WString &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 = L"";if ( version.contains(L".") || !version.isNumber() )Found->sVersion = version;elseFound->iVersion = version;_changed();}Utils::WString CBaseFile::_replaceFilename(const Utils::WString &fname){Utils::WString filename = fname;Utils::WString cdate = this->creationDate().findReplace(L"/", L".").remove(' ');if (filename.contains(L"$AUTOSAVE")){if (this->GetType() == TYPE_XSP)filename = filename.findReplace(L"$AUTOSAVE", L"$NAME-V$VERSION-$CDATE.xsp");elsefilename = filename.findReplace(L"$AUTOSAVE", L"$NAME-V$VERSION-$CDATE.spk");}filename = filename.findReplace(L"$NAME", this->name().remove(L' '));filename = filename.findReplace(L"$AUTHOR", this->author().remove(L' '));filename = filename.findReplace(L"$DATE", cdate);filename = filename.findReplace(L"$CDATE", cdate);filename = filename.findReplace(L"$VERSION", this->version());return filename;}bool CBaseFile::loadPackageData(const Utils::WString &sFirst, const Utils::WString &sRest, const Utils::WString &sMainGame, Utils::WStringList &otherGames, Utils::WStringList &gameAddons, CProgressInfo *progress){if (sFirst.Compare(L"Name")) this->setName(sRest);else if (sFirst.Compare(L"Author")) this->setAuthor(sRest);else if (sFirst.Compare(L"ScriptName")) addName(parseLanguage(sRest.token(L" ", 1)), sRest.tokens(L" ", 2));else if (sFirst.Compare(L"UninstallBefore")) this->addUninstallText(parseLanguage(sRest.token(L" ", 1)), true, sRest.tokens(L" ", 2));else if (sFirst.Compare(L"UninstallAfter")) this->addUninstallText(parseLanguage(sRest.token(L" ", 1)), false, sRest.tokens(L" ", 2));else if (sFirst.Compare(L"InstallBefore")) this->addInstallText(parseLanguage(sRest.token(L" ", 1)), true, sRest.tokens(L" ", 2));else if (sFirst.Compare(L"InstallAfter")) this->addInstallText(parseLanguage(sRest.token(L" ", 1)), false, sRest.tokens(L" ", 2));else if (sFirst.Compare(L"Date")) this->setCreationDate(sRest);else if (sFirst.Compare(L"Version")) this->setVersion(sRest);else if (sFirst.Compare(L"GameVersion"))this->AddGameCompatability(-1, sRest);else if (sFirst.Compare(L"PluginType")) {if (sRest.isNumber()) this->setPluginType(sRest);else if (sRest.Compare(L"Normal")) this->setPluginType(PLUGIN_NORMAL);else if (sRest.Compare(L"Stable")) this->setPluginType(PLUGIN_STABLE);else if (sRest.Compare(L"Experimental")) this->setPluginType(PLUGIN_EXPERIMENTAL);else if (sRest.Compare(L"Cheat")) this->setPluginType(PLUGIN_CHEAT);else if (sRest.Compare(L"Mod")) this->setPluginType(PLUGIN_MOD);}// new versionelse if (sFirst.Compare(L"GenerateUpdateFile"))m_bAutoGenerateUpdateFile = true;else if (sFirst.Compare(L"Game")){Utils::WString sGame = sRest.token(L" ", 1);this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), sRest.token(L" ", 2));}else if (sFirst.Compare(L"Description")) this->setDescription(sRest);else if (sFirst.Compare(L"AutoSave") || sFirst.Compare(L"AutoExport") || sFirst.Compare(L"AutoRarExport") || sFirst.Compare(L"AutoZipExport")){Utils::WString filename = _replaceFilename(sRest);if (sFirst.Compare(L"AutoZipExport") || sFirst.Compare(L"AutoExport"))this->setExportFilename(CFileIO(filename).changeFileExtension(L"zip"));else if (sFirst.Compare(L"AutoRarExport"))this->setExportFilename(CFileIO(filename).changeFileExtension(L"rar"));elsethis->setFilename(filename);}else if (sFirst.Compare(L"WebSite")) this->setWebSite(sRest);else if (sFirst.Compare(L"ForumLink") || sFirst.Compare(L"Forum")) this->setForumLink(sRest);else if (sFirst.Compare(L"Email")) this->setEmail(sRest);else if (sFirst.Compare(L"WebAddress")) this->setWebAddress(sRest);else if (sFirst.Compare(L"WebMirror"))this->addWebMirror(sRest);else if (sFirst.Compare(L"WebMirror1"))this->addWebMirror(sRest);else if (sFirst.Compare(L"WebMirror2"))this->addWebMirror(sRest);else if (sFirst.Compare(L"Ftp"))_sFtpAddr = sRest;else if (sFirst.Compare(L"Ratings")) _setRatings(sRest.token(L" ", 1), sRest.token(L" ", 2), sRest.token(L" ", 3));else if (sFirst.Compare(L"EaseOfUse")) setEaseOfUse(sRest);else if (sFirst.Compare(L"GameChanging")) setGameChanging(sRest);else if (sFirst.Compare(L"Recommended")) setRecommended(sRest);else if (sFirst.Compare(L"Depend")){Utils::WString version = sRest.token(L"|", 2);Utils::WString name = sRest.token(L"|", 1);Utils::WString author = sRest.tokens(L"|", 3);this->addNeededLibrary(name, author, version);}else if (sFirst.Compare(L"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(L"Icon")){C_File *icon = new C_File(sRest);if (icon->ReadFromFile())this->setIcon(icon, CFileIO(sRest).extension());}else if (sFirst.Compare(L"CombineGameFiles"))_bCombineFiles = sRest.Compare(L"true") || sRest.Compare(L"yes") || sRest.toInt();else if (sFirst.Compare(L"UpdateFile"))this->createUpdateFile(sRest);else if (sFirst.Compare(L"ExportZip")){Utils::WString ext = L"zip";Utils::WString game = sRest.word(1);Utils::WString file = _replaceFilename(CFileIO(sRest.words(2)).fullFilename());if (game.contains(L"|")){std::vector<Utils::WString> games;if(game.tokenise(L"|", games)){for (size_t i = 0; i < games.size(); ++i){unsigned int g = CBaseFile::GetGameFromString(games[i]);Utils::WString filename = CFileIO(file).dir() + L"/" + CFileIO(file).baseName() + L"_" + CBaseFile::ConvertGameToString(g) + L"." + ext;this->addAutoExport(g, filename);}}}else{unsigned int g = CBaseFile::GetGameFromString(game);Utils::WString filename = CFileIO(file).dir() + L"/" + CFileIO(file).baseName() + L"_" + CBaseFile::ConvertGameToString(g) + L"." + ext;this->addAutoExport(g, filename);}}else if (sFirst.Compare(L"Extract")){Utils::WString game = sRest.word(1);Utils::WString dir = CDirIO(sRest.words(2)).dir();if (game.contains(L"|")){std::vector<Utils::WString> games;if (game.tokenise(L"|", games)){for(size_t i = 0; i < games.size(); ++i)this->addAutoExtract(CBaseFile::GetGameFromString(games[i]), dir);}}elsethis->addAutoExtract(CBaseFile::GetGameFromString(game), dir);}else if (sFirst.Compare(L"Global"))this->addGlobal(sRest.token(L";", 1), sRest.token(L";", 2));else{Utils::WString checkType = sFirst;bool shared = false;if (checkType.left(6).Compare(L"Shared")){checkType = sFirst.right(-6);shared = true;}bool packed = false;if (checkType.right(3).Compare(L"PCK")){checkType = sFirst.left(-3);packed = true;}// now check type nameFileType filetype = GetFileTypeFromString(checkType);if (filetype != FILETYPE_UNKNOWN)this->addFileScript(filetype, shared, packed, sRest, sMainGame, otherGames, gameAddons, progress);else if ( !checkType.Compare(L"changelog") )return false;}return true;}void CBaseFile::addFileScript(FileType filetype, bool shared, bool packed, const Utils::WString &sRest, const Utils::WString &sMainGame, Utils::WStringList &otherGames, Utils::WStringList &gameAddons, CProgressInfo *progress){Utils::WString dir;Utils::WString rest = sRest;unsigned int mainGame = CBaseFile::GetGameFromString(sMainGame);unsigned int game = 0;if ( rest.token(L" ", 1).left(4).Compare(L"GAME") ) {Utils::WString gameStr = rest.token(L" ", 2);if (gameStr.contains(L"|")){std::vector<Utils::WString> games;gameStr.tokenise(L"|", games);for (size_t i = 0; i < games.size(); ++i){unsigned int g = CBaseFile::GetGameFromString(games[i]);if (g)game |= 1 << g;}}else{unsigned int g = CBaseFile::GetGameFromString(gameStr);if (g)game = 1 << g;}rest = rest.tokens(L" ", 3);}if (game)game |= 1 << 31;if (rest.contains(L"|")){dir = rest.tokens(L"|", 2);rest = rest.token(L"|", 1);}rest = rest.findReplace(L"\\", L"/");// wild cardsif ( rest.containsAny(L"*?") ){CDirIO Dir(CFileIO(rest).dir());Utils::WStringList dirList;if(Dir.dirList(dirList)){for(auto itr = dirList.begin(); itr != dirList.end(); itr++){Utils::WString file = Dir.file((*itr)->str);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::WString g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {Utils::WString checkDir = F.dir() + L"/" + g;if ( CDirIO(checkDir).exists(F.filename()) ) {addGame = mainGame;C_File *newfile = this->appendFile(CDirIO(checkDir).file(F.filename()), filetype, CBaseFile::GetGameFromString(g), packed, dir);if (newfile && progress)progress->UpdateFile(newfile);if ( newfile ) newfile->SetShared(shared);}}}C_File *newfile = this->appendFile(file, filetype, addGame, packed, dir);if (newfile && progress)progress->UpdateFile(newfile);if ( newfile )newfile->SetShared(shared);}}}}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::WString g = otherGames.firstString(); !g.empty(); g = otherGames.nextString()) {Utils::WString checkDir = F.dir() + L"/" + g;if ( CDirIO(checkDir).exists(F.filename()) ) {addGame = mainGame;C_File *newfile = this->appendFile(CDirIO(checkDir).file(F.filename()), filetype, CBaseFile::GetGameFromString(g), packed, 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::WString addon = gameAddons.findString(Utils::WString::Number(foundGame));if (!addon.empty()){Utils::WString dir = C_File::GetDirectory(filetype, rest, this);Utils::WString filename = rest;if (CCatFile::IsAddonDir(dir) && !filename.contains(addon)){filename = filename.findReplace(dir + L"/", addon + L"/" + dir + L"/");file = this->appendFile(filename, filetype, addGame, packed, dir);}}}if(!file)file = this->appendFile(rest, filetype, addGame, packed, dir);if (file && progress)progress->UpdateFile(file);if (file)file->SetShared(shared);}}Utils::WString CBaseFile::fileSizeString() const { return SPK::GetSizeString ( this->fileSize() ); }// used for a multiple spk fileunsigned char *CBaseFile::createData(size_t *size, CProgressInfo *progress){if ( this->writeFile(L"temp.dat", progress) ) {CFileIO File(L"temp.dat");File.setAutoDelete(true);return File.readAll(size);}return NULL;}void CBaseFile::convertNormalMod(C_File *f, const Utils::WString &to) const{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) const{Utils::WString to;if ( f->baseName().contains(L"-L") )to = L"0000-L" + f->baseName().token(L"-L", 2);else if ( f->baseName().contains(L"-l") )to = L"0000-L" + f->baseName().token(L"-l", 2);elseto = f->baseName().left(-4) + L"0000";// file linkif ( !f->GetData() )f->ReadFromFile();f->changeBaseName(to);}void CBaseFile::convertFakePatch(C_File *f) const{// find next available fake patchint num = 0;bool found = true;while ( found ){++num;found = false;Utils::WString find = Utils::WString::PadNumber(num, 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()->baseName().Compare(find) ){found = true;break;}}}Utils::WString to = Utils::WString::PadNumber(num, 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) const{for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){if ( node->Data()->GetFileType() != FILETYPE_MOD )continue;if ( f->fileExt().Compare(node->Data()->fileExt()) )continue;if ( f->baseName().Compare(node->Data()->baseName()) )return node->Data();}return NULL;}void CBaseFile::renameFile(C_File *f, const Utils::WString &baseName) const{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::WString CBaseFile::createUpdateFile(const Utils::WString &dir) const{Utils::WString file = this->getNameValidFile() + L"_" + this->author() + L".dat";file.removeChar(' ');Utils::WStringList write;write.pushBack(L"Package: " + this->name());write.pushBack(L"Author: " + this->author());write.pushBack(L"Version: " + this->version());write.pushBack(L"File: " + CFileIO(this->filename()).filename());CFileIO File(dir + L"/" + file);if (File.writeFile(&write))return File.fullFilename();return Utils::WString::Null();}Utils::WString CBaseFile::ErrorString(int error, const Utils::WString &errorStr){if (error == SPKERR_NONE) return Utils::WString::Null();Utils::WString err;switch (error){case SPKERR_MALLOC:err = L"Memory Failed";break;case SPKERR_FILEOPEN:err = L"Failed to open file";break;case SPKERR_FILEREAD:err = L"Failed to read file";break;case SPKERR_UNCOMPRESS:err = L"Failed to Uncompress";break;case SPKERR_WRITEFILE:err = L"Failed to write file";break;case SPKERR_CREATEDIRECTORY:err = L"Failed to create directory";break;case SPKERR_FILEMISMATCH:err = L"File count mismatch";break;}if (!err.empty()){if (!errorStr.empty()){err += L" (";err += errorStr + L")";}return err;}return Utils::WString::Number((long)error);}bool CBaseFile::saveToArchive(const Utils::WString &filename, int game, const CGameExe *exes, CProgressInfo *progress){CDirIO Dir(CFileIO(filename).dir());if (!Dir.exists())Dir.create();HZIP hz = CreateZip(filename.c_str(), 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::WString 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->game(whatGame - 1);if (e){if (e->iFlags & EXEFLAG_ADDON)fname = e->sAddon + L"/" + fname;}}}// create the directory//wsprintf(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, fname.c_str(), data, size);delete data;}elseZipAdd(hz, fname.c_str(), node->Data()->GetData(), node->Data()->GetDataSize());}// if its a ship, then add any generated filesthis->addGeneratedFiles(hz);// add the data fileUtils::WStringList list;Utils::WStringList addons;if ( this->GeneratePackagerScript(false, &list, game, addons, true) ){if ( CFileIO(L"test.tmp").writeFile(&list) ){ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");CFileIO::Remove(L"test.tmp");}}CloseZip(hz);return true;}int CBaseFile::GetGameFromString(const Utils::WString &sGame){int iGame = GAME_ALL;if ( sGame.Compare(L"ALL") )iGame = GAME_ALL;else if ( sGame.Compare(L"X3") )iGame = GAME_X3;else if ( sGame.Compare(L"X2") )iGame = GAME_X2;else if ( sGame.Compare(L"X3TC") )iGame = GAME_X3TC;else if (sGame.Compare(L"X3AP"))iGame = GAME_X3AP;else if (sGame.Compare(L"X3FL"))iGame = GAME_X3FL;else if ( sGame.isNumber() )iGame = sGame;return iGame;}Utils::WString CBaseFile::ConvertGameToString(int iGame){Utils::WString game = L"ALL";switch(iGame) {case GAME_ALL:case GAME_ALLNEW:game = L"ALL";break;case GAME_X2:game = L"X2";break;case GAME_X3:game = L"X3";break;case GAME_X3TC:game = L"X3TC";break;case GAME_X3AP:game = L"X3AP";break;case GAME_X3FL:game = L"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::WString builtInWares(){Utils::WString str;str += L"28;0;0;0;0;59;5753;0;35714;1;1;0;35714;-100000;0;0;SS_WARE_SW_NEW1;\n";str += L"28;0;0;0;0;60;5763;0;33232;1;1;0;33232;0;1043;0;SS_WARE_SW_NEW2;\n";str += L"28;0;0;0;0;61;5773;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW3;\n";str += L"28;0;0;0;0;62;5783;0;56;1;1;0;56;-100000;0;0;SS_WARE_SW_NEW4;\n";str += L"28;0;0;0;0;63;5793;0;88;1;1;0;88;-100000;0;0;SS_WARE_SW_NEW5;\n";str += L"28;0;0;0;0;64;5803;0;283;1;1;0;283;-100000;0;0;SS_WARE_SW_NEW6;\n";str += L"28;0;0;0;0;65;5813;0;383;1;1;0;383;-100000;0;0;SS_WARE_SW_NEW7;\n";str += L"28;0;0;0;0;66;5823;0;1389;1;1;0;1389;-100000;1043;0;SS_WARE_SW_NEW8;\n";str += L"28;0;0;0;0;67;5833;0;3396;1;1;0;3396;-100000;0;0;SS_WARE_SW_NEW9;\n";str += L"28;0;0;0;0;68;5843;0;4215;1;1;0;4215;-100000;0;0;SS_WARE_SW_NEW10;\n";str += L"28;0;0;0;0;69;5853;0;5635;1;1;0;5635;-100000;0;0;SS_WARE_SW_NEW11;\n";str += L"28;0;0;0;0;70;5863;0;65735;1;1;0;65735;-100000;0;0;SS_WARE_SW_NEW12;\n";str += L"28;0;0;0;0;71;5873;0;17857;1;1;0;17857;333;1043;0;SS_WARE_SW_NEW13;\n";str += L"28;0;0;0;0;72;5883;0;21428;1;1;0;21428;0;1043;0;SS_WARE_SW_NEW14;\n";str += L"28;0;0;0;0;73;5893;0;324515;1;1;0;324515;-100000;0;0;SS_WARE_SW_NEW15;\n";str += L"28;0;0;0;0;74;5903;0;638508;1;1;0;638508;-100000;0;0;SS_WARE_SW_NEW16;\n";str += L"28;0;0;0;0;75;5913;0;225755;1;1;0;225755;-100000;0;0;SS_WARE_SW_NEW17;\n";str += L"28;0;0;0;0;76;5923;0;1931535;1;1;0;1931535;1000;0;0;SS_WARE_SW_NEW18;\n";str += L"28;0;0;0;0;77;5933;0;2209150;1;1;0;2209150;-100000;0;0;SS_WARE_SW_NEW19;\n";str += L"28;0;0;0;0;78;5943;0;6727565;1;1;0;6727565;-100000;0;0;SS_WARE_SW_NEW20;\n";str += L"28;0;0;0;0;85;9999;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_1;\n";str += L"28;0;0;0;0;86;15053;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_2;\n";str += L"28;0;0;0;0;87;15063;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_3;\n";str += L"28;0;0;0;0;88;15073;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_4;\n";str += L"28;0;0;0;0;89;15083;0;105;1;5;0;105;0;1043;0;SS_WARE_SW_X3TC_5;\n";str += L"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::WString &wares, enum WareTypes eType){if (_pTextDB){std::vector<Utils::WString> w;wares.tokenise(L"\n", w);for (size_t i = 0; i < w.size(); i++) {int textId = w[i].token(L";", 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(L";", -2);ware->relval = w[i].token(L";", 9).toLong();ware->notority = w[i].token(L";", 14).toLong();ware->type = eType;ware->position = i;ware->package = this;list.push_back(ware);}}}}bool CBaseFile::readWares(int iLang, CLinkList<SWareEntry> &list, const Utils::WString &empWares){if (_pTextDB){_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;}return false;}bool CBaseFile::_readCommands(int iLang, int iStartID, CLinkList<SCommandSlot> &list){if (_pTextDB){_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;}return false;}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;}