Rev 299 | Blame | Compare with Previous | Last modification | View Log | RSS feed
//header#include "SpkFile.h"// debug logging#include "Logging/Log.h"// old style compression (needed to convert old formats)#include "../../HiP/HiP.h"#include "TextDB.h"#include <Languages.h>//TODO: remove thisunsigned char *LineByLineRead ( unsigned char *data, const Utils::String &end, Utils::String *readData ){Utils::String line;while ( true ){data = line.readToEndOfLine(data);if ( (*readData).empty() && line.empty() ) continue;if ( line == end )break;*readData += (line + "\r\n");}return data;}CSpkFile::CSpkFile() : CBaseFile (){SetDefaults ();}CSpkFile::~CSpkFile(){Delete ();}/*Func: SetDefaultsDesc: Sets the default values when class is created*/void CSpkFile::SetDefaults (){m_pLastWare = NULL;m_iPackageType = PACKAGETYPE_NORMAL;m_bForceProfile = false;m_iScriptType = SCRIPTTYPE_CUSTOM;CBaseFile::SetDefaults ();}void CSpkFile::Delete (){m_lWares.clear(true);m_lSettings.clear(true);CBaseFile::Delete ();}bool CSpkFile::_checkHeader(const Utils::WString &header) const{if ( header.Compare(L"SPKCycrow") )return true;return false;}/*Func: ParseValueLineInput: String - single line from a file to setReturn: Boolean - returns true if value existsDesc: Reads the line and assigns the parameters for the file*/bool CSpkFile::parseValueLine(const Utils::WString &line){Utils::WString first = line.token(L" ", 1);Utils::WString rest = line.tokens(L" ", 2);if ( first == L"AnotherMod:" ){m_sOtherAuthor = rest.token(L"|", 1);m_sOtherName = rest.tokens(L"|", 2);}else if ( line == L"CustomStart" )m_iPackageType = PACKAGETYPE_CUSTOMSTART;else if ( line == L"PackageUpdate" )m_iPackageType = PACKAGETYPE_UPDATE;else if ( line == L"Patch" )m_iPackageType = PACKAGETYPE_PATCH;else if ( line == L"ForceProfile" )m_bForceProfile = true;else if ( line == L"Signed" )m_bSigned = true;else if ( first == L"ScriptType:" )m_sScriptType = rest;else if ( first == L"ScriptTypeNew:" )m_iScriptType = rest;else if ( first == L"PackageType:" )m_iPackageType = rest;else if ( first == L"Ware:" )addWare(rest);else if ( (first == L"WareText:") && (m_pLastWare) )addWareText(rest);else if ( first == L"Setting:" ){SSettingType *t = addSetting(rest.token(L"|", 2), rest.token(L"|", 1));convertSetting(t, rest.tokens(L"|", 3));}elsereturn CBaseFile::parseValueLine ( line );return true;}/*Func: CreateValuesLineReturn: String - returns the full string for valuesDesc: Creates a single string for all values, this is used when compressing to write to the spk file*/Utils::WString CSpkFile::createValuesLine () const{Utils::WString values = CBaseFile::createValuesLine ();// combine all values togetherif ( (!m_sOtherAuthor.empty()) && (!m_sOtherName.empty()) )values += L"AnotherMod: " + m_sOtherAuthor + L"|" + m_sOtherName + L"\n";if ( m_bForceProfile )values += L"ForceProfile\n";if ( !m_sScriptType.empty() )values += L"ScriptType: " + m_sScriptType + L"\n";values += Utils::WString(L"PackageType: ") + (long)m_iPackageType + L"\n";values += Utils::WString(L"ScriptTypeNew: ") + Utils::WString::Number(m_iScriptType) + L"\n";for ( CListNode<SSettingType> *node = m_lSettings.Front(); node; node = node->next() )values += Utils::WString(L"Setting: ") + (long)node->Data()->iType + L"|" + node->Data()->sKey + L"|" + getSetting(node->Data()) + L"\n";for ( CListNode<SWares> *wNode = m_lWares.Front(); wNode; wNode = wNode->next() ) {SWares *ware = wNode->Data();if ( wNode->Data()->iTextID > 0 )values += Utils::WString(L"Ware: ") + Utils::WString(ware->cType) + L":" + ware->iPrice + L":" + (long)ware->iSize + L":" + (long)ware->iVolumn + L":" + ware->sID + L":" + (long)ware->iNotority + L":" + (long)ware->iTextID + L"," + (long)ware->iTextPage + L"\n";elsevalues += Utils::WString(L"Ware: ") + Utils::WString(ware->cType) + L":" + ware->iPrice + L":" + (long)ware->iSize + ":" + (long)ware->iVolumn + L":" + ware->sID + L":" + (long)ware->iNotority + L"\n";for ( CListNode<SWaresText> *wtNode = ware->lText.Front(); wtNode; wtNode = wtNode->next() )values += Utils::WString(L"WareText: ") + (long)wtNode->Data()->iLang + L" " + wtNode->Data()->sName + L"|" + wtNode->Data()->sDesc + L"\n";}return values;}Utils::WString CSpkFile::customScriptType(int lang) const{if ( !m_sScriptType.empty() ){std::vector<Utils::WString> split;if(m_sScriptType.tokenise(L"<br>", split)){for (size_t i = 1; i < split.size(); i++){Utils::WString str = split[i];int num = str.token(L":", 1);Utils::WString name = str.tokens(L":", 2);if ( num == lang )return name;}return split[0];}}return m_sScriptType;}bool CSpkFile::readWares(int iLang, CLinkList<SWareEntry> &list, const Utils::WString &empWares){if ( CBaseFile::readWares(iLang, list, empWares) ) {for(CListNode<SWares> *node = m_lWares.Front(); node; node = node->next()) {SWareEntry *ware = new SWareEntry;for(CListNode<SWaresText> *textNode = node->Data()->lText.Front(); textNode; textNode = textNode->next()) {ware->name = textNode->Data()->sName;ware->description = textNode->Data()->sDesc;if ( textNode->Data()->iLang == iLang ) {break;}}if ( ware->name.empty() ) {ware->name = _pTextDB->get(iLang, node->Data()->iTextPage, node->Data()->iTextID);}if ( ware->description.empty() ) {ware->description = _pTextDB->get(iLang, node->Data()->iTextPage, node->Data()->iDescID);}ware->id = node->Data()->sID;ware->relval = node->Data()->iPrice;ware->position = node->Data()->iPosID;ware->type = Ware_Custom;ware->notority = node->Data()->iNotority;ware->position = 0;ware->package = this;list.push_back(ware);}return true;}return false;}bool CSpkFile::writeHeader(CFileIO &file, int valueheader, int valueComprLen) const{return file.write("SPKCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);}void CSpkFile::addWareText(const Utils::WString &sData){if ( !m_pLastWare )return;SWaresText *wt = new SWaresText;wt->iLang = sData.token(L" ", 1);wt->sName = sData.tokens(L" ", 2).token(L"|", 1);wt->sDesc = sData.tokens(L" ", 2).tokens(L"|", 2);m_pLastWare->lText.push_back ( wt );_changed();}void CSpkFile::addWare(const Utils::WString &sData){SWares *ware = new SWares;ware->iTextID = -1;ware->iTextPage = 0;ware->cType = sData.token(L":", 1)[0];ware->iPrice = sData.token(L":", 2);ware->iSize = sData.token(L":", 3);ware->iVolumn = sData.token(L":", 4);ware->sID = sData.token(L":", 5);ware->iNotority = sData.token(L":", 6);if ( !sData.token(L":", 7).empty() ){Utils::WString r = sData.token(L":", 7);ware->iTextID = r.token(L",", 1);ware->iTextPage = r.token(L",", 2);}m_lWares.push_back ( ware );m_pLastWare = ware;_changed();}bool CSpkFile::CheckValidReadmes () const{for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != FILETYPE_README )continue;if ( !file->CheckValidFilePointer() )continue;return true;}return false;}void CSpkFile::clearWares(){for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() ) {node->Data()->lText.clear(true);node->DeleteData();}_changed();m_lWares.clear(true);}SWares *CSpkFile::findWare(const Utils::WString &id) const{for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() ) {SWares *w = node->Data();if ( w->sID.Compare(id) ) {return w;}}return NULL;}void CSpkFile::removeWare(const Utils::WString &id ){for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() ) {SWares *w = node->Data();if ( w->sID.Compare(id) ) {m_lWares.RemoveCurrent ();delete w;_changed();return;}}}void CSpkFile::addWare(SWares *ware){ware->sID.remove(' ');SWares *newware = this->findWare(ware->sID);if ( newware ) {m_lWares.remove(newware);}m_lWares.push_back(ware);_changed();}void CSpkFile::addWareText(SWares *pWare, int iLang, const Utils::WString &sName, const Utils::WString &sDesc){SWaresText *wt;for ( CListNode<SWaresText> *node = pWare->lText.Front(); node; node = node->next() ) {wt = node->Data();if ( wt->iLang == iLang ) {wt->sDesc = sDesc;wt->sName = sName;return;}}wt = new SWaresText;wt->iLang = iLang;wt->sName = sName;wt->sDesc = sDesc;pWare->lText.push_back(wt);_changed();}void CSpkFile::clearWareText(const Utils::WString &id){SWares *w = findWare(id);clearWareText(w);}void CSpkFile::clearWareText(SWares *w){if ( !w ) return;w->lText.clear(true);_changed();}void CSpkFile::removeWareText(const Utils::WString &wid, int lang){SWares *w = findWare(wid);if ( w ){for ( CListNode<SWaresText> *node = w->lText.Front(); node; node = node->next() ) {SWaresText *wt = node->Data();if ( wt->iLang == lang ) {w->lText.RemoveCurrent();_changed();delete wt;break;}}}}int CSpkFile::CheckValidCustomStart () const{for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != FILETYPE_SCRIPT )continue;Utils::WString basename = file->baseName();if ( basename.right(15).Compare(L".initplayership") )return 0;}if ( !IsAnotherMod() )return 1;elsereturn 2;}bool CSpkFile::computeSigned(bool updateFiles) const{// check for any custom wares// patch mods and custom starts are also not signedif ((!m_lWares.empty()) || (this->IsPatch()) || (this->IsCustomStart()))return false;return CBaseFile::computeSigned(updateFiles);}SSettingType *CSpkFile::addSetting(const Utils::WString &key, int type){Utils::WString sKey = key.remove('|');SSettingType *t;for ( t = m_lSettings.First(); t; t = m_lSettings.Next() ){if ( t->sKey.Compare(sKey) )return NULL;}switch ( type ){case SETTING_STRING:t = new SSettingString;break;case SETTING_INTEGER:t = new SSettingInteger;break;case SETTING_CHECK:t = new SSettingCheck;break;}if ( !t )return NULL;t->sKey = sKey;t->iType = type;m_lSettings.push_back ( t );_changed();return t;}void CSpkFile::convertSetting(SSettingType *t, const Utils::WString &set) const{if ( !t )return;switch ( t->iType ){case SETTING_STRING:((SSettingString *)t)->sValue = set;break;case SETTING_INTEGER:((SSettingInteger *)t)->iValue = set;break;case SETTING_CHECK:((SSettingCheck *)t)->bValue = set;break;}}Utils::WString CSpkFile::getSetting(SSettingType *t) const{if ( !t )return L"";switch ( t->iType ){case SETTING_STRING:return ((SSettingString *)t)->sValue;case SETTING_INTEGER:return Utils::WString::Number(((SSettingInteger *)t)->iValue);case SETTING_CHECK:return (((SSettingInteger *)t)->iValue) ? L"1" : L"0";}return L"";}void CSpkFile::clearSettings (){m_lSettings.clear(true);_changed();}bool CSpkFile::isMatchingMod(const Utils::WString &mod) const{for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ){C_File *file = node->Data();if ( file->GetFileType() != FILETYPE_MOD )continue;if ( file->IsFakePatch() )continue;Utils::WString filename = file->baseName();if ( filename.Compare(mod) )return true;}return false;}Utils::WString CSpkFile::scriptTypeString(int lang) const{int scriptType = -1;if (this->IsLibrary())scriptType = SCRIPTTYPE_LIBRARY;else if (this->IsPackageUpdate())scriptType = SCRIPTTYPE_UPDATE;else if (this->IsCustomStart())scriptType = SCRIPTTYPE_CUSTOMSTART;else if (this->IsPatch())scriptType = SCRIPTTYPE_PATCH;else if (m_iScriptType == SCRIPTTYPE_CUSTOM){Utils::WString type = this->customScriptType(lang);if (!type.empty())return type;}if (scriptType == -1){if (this->IsFakePatch())scriptType = SCRIPTTYPE_FAKEPATCH;elsescriptType = m_iScriptType;}Utils::WString sType = CSpkFile::GetScriptTypeStringStatic(scriptType, lang);return (sType.empty()) ? L"Other" : sType;}int CSpkFile::ConvertScriptType(const Utils::WString &sType){for ( int i = 0; i < SCRIPTTYPE_MAX; i++ ){if ( sType.Compare(CSpkFile::GetScriptTypeStringStatic(i, 0)) )return i;}return -1;}Utils::WString CSpkFile::GetScriptTypeStringStatic(int type, int iLang){// if we have a language, use the language list to find the textif (iLang){CLanguages* langList = CLanguages::Instance();// if the language is -1, then we use the default language// otherwise, push the language onto the stackif (iLang != -1)langList->pushLanguage(iLang);Utils::WString text = langList->findText(LS_SCRIPTTYPE, type);if (!text.empty()){// remember to pop the language if we pushed it to restore to defaultif (iLang != -1)langList->popLanguage();return text;}// remember to pop the language if we pushed it to restore to defaultif (iLang != -1)langList->popLanguage();// fallback to static strings if not found}// otherwise we need to get the static string (this is used for data files)// MUST NOT BE TRANSLATEDswitch ( type ){case SCRIPTTYPE_LIBRARY:return L"Library";case SCRIPTTYPE_UPDATE:return L"Package Update";case SCRIPTTYPE_CUSTOMSTART:return L"Custom Start";case SCRIPTTYPE_PATCH:return L"Patch";case SCRIPTTYPE_FAKEPATCH:return L"Fake Patch";case SCRIPTTYPE_CUSTOM:return L"Custom";case SCRIPTTYPE_NAVIGATION:return L"Navigation";case SCRIPTTYPE_COMBAT:return L"Combat";case SCRIPTTYPE_MISSION:return L"Mission";case SCRIPTTYPE_ALPLUGIN:return L"AL Plugin";case SCRIPTTYPE_HOTKEY:return L"Hotkey";case SCRIPTTYPE_SHIPUPGRADE:return L"Ship Upgrade";case SCRIPTTYPE_SHIPCOMMAND:return L"Ship Command";case SCRIPTTYPE_STATIONCOMMAND:return L"Station Command";case SCRIPTTYPE_FLEET:return L"Fleet Management";case SCRIPTTYPE_TRADE:return L"Trade";case SCRIPTTYPE_PIRACY:return L"Piracy";case SCRIPTTYPE_CHEAT:return L"Cheat";case SCRIPTTYPE_EXTENSION:return L"Extension Mods";case SCRIPTTYPE_REBALANCE:return L"Rebalance";case SCRIPTTYPE_FIX:return L"Vanilla Fix";case SCRIPTTYPE_GENERALMOD:return L"General Mod";case SCRIPTTYPE_TOTAL:return L"Totel Conversion";case SCRIPTTYPE_WINGCOMMAND:return L"Wing Command";case SCRIPTTYPE_OTHER:return L"Other";}return L"Other";}bool CSpkFile::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"ScriptType") ){if ( sRest.Compare(L"Library") || sRest.Compare(L"Library Script") )this->SetLibrary();else if ( sRest.Compare(L"Update") || sRest.Compare(L"Package Update") || sRest.Compare(L"Mod Update") )this->SetPackageUpdate();else if ( sRest.Compare(L"Start") || sRest.Compare(L"Custom Start") )this->SetCustomStart();else if ( sRest.Compare(L"Patch") || sRest.Compare(L"Patch Mod") )this->SetPatch();else{int check = sRest;if ( check || sRest == L"0" )m_iScriptType = check;else{m_iScriptType = CSpkFile::ConvertScriptType(sRest);if (m_iScriptType == -1){m_sScriptType = sRest;m_iScriptType = SCRIPTTYPE_CUSTOM;}}}}else if (sFirst.Compare(L"AnotherMod")){m_sOtherName = sRest.token(L"|", 1);m_sOtherAuthor = sRest.tokens(L"|", 2);}else if ( sFirst.Compare(L"WareName") || sFirst.Compare(L"WareDesc") ){// find the ware to useSWares *useWare = m_pLastWare;Utils::WString id = sRest.token(L" ", 1);for ( CListNode<SWares> *wNode = m_lWares.Front(); wNode; wNode = wNode->next() ){if ( wNode->Data()->sID.Compare(id.c_str()) ){useWare = wNode->Data();break;}}// check if we have the id alreadyif ( useWare ){int lang = sRest.token(L" ", 2);SWaresText *wt = NULL;for ( CListNode<SWaresText> *tNode = useWare->lText.Front(); tNode; tNode = tNode->next() ){if ( tNode->Data()->iLang == lang ){wt = tNode->Data();break;}}if ( !wt ){wt = new SWaresText;wt->iLang = lang;useWare->lText.push_back(wt);}if ( sFirst.Compare(L"WareName") )wt->sName = sRest.tokens(L" ", 3);elsewt->sDesc = sRest.tokens(L" ", 3);}}else if ( sFirst.left(4).Compare(L"Ware") ){SWares *ware = new SWares;ware->iTextID = -1;ware->iTextPage = 0;ware->cType = sFirst[4];ware->iPrice = sRest.token(L" ", 2);ware->iSize = sRest.token(L" ", 3);ware->iVolumn = sRest.token(L" ", 4);ware->sID = sRest.token(L" ", 1);ware->iNotority = sRest.token(L" ", 5);if ( !sRest.token(L" ", 6).empty() ){ware->iTextID = sRest.token(L" ", 6).token(L",", 2);ware->iTextPage = sRest.token(L" ", 6).token(L",", 1);}m_lWares.push_back ( ware );m_pLastWare = ware;}else if ( CBaseFile::loadPackageData(sFirst, sRest, sMainGame, otherGames, gameAddons, progress) )return true;elsereturn false;return true;}bool CSpkFile::GeneratePackagerScript(bool wildcard, Utils::WStringList *list, int game, const Utils::WStringList &gameAddons, bool datafile){if ( !CBaseFile::GeneratePackagerScript(wildcard, list, game, gameAddons, datafile) )return false;list->pushBack(L"# File Type, Script or Ship");list->pushBack(L"FileType: Script");list->pushBack(L"");list->pushBack(L"# Script Type, the type of package file, some are special types, others are just for show");if ( this->IsLibrary() )list->pushBack(L"ScriptType: Library");else if ( this->IsPackageUpdate() )list->pushBack(L"ScriptType: Package Update");else if ( this->IsCustomStart() )list->pushBack(L"ScriptType: Custom Start");else if ( this->IsPatch() )list->pushBack(L"ScriptType: Patch");elselist->pushBack(L"ScriptType: " + this->scriptTypeString(44));list->pushBack(L"");if ( this->IsAnotherMod() ){list->pushBack(L"# For another mod/package, this is a child package");list->pushBack(L"AnotherMod: " + m_sOtherName + L"|" + m_sOtherAuthor);list->pushBack(L"");}if ( !m_lWares.empty() ){list->pushBack(L"# Custom Wares, Ware<type>: <id> <price> <size> <volumn> <notority>");for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() ){SWares *w = node->Data();if ( w->iTextID > 0 )list->pushBack(Utils::WString(L"Ware") + Utils::WString(w->cType) + L": " + w->sID + L" " + (long)w->iPrice + L" " + (long)w->iSize + L" " + (long)w->iVolumn + L" " + (long)w->iNotority + L" " + (long)w->iTextPage + L"," + (long)w->iTextID);elselist->pushBack(Utils::WString(L"Ware") + Utils::WString(w->cType) + L": " + w->sID + L" " + (long)w->iPrice + L" " + (long)w->iSize + L" " + (long)w->iVolumn + L" " + (long)w->iNotority);for ( CListNode<SWaresText> *wNode = w->lText.Front(); wNode; wNode = wNode->next() ){SWaresText *wt = wNode->Data();if ( !wt->sName.empty() )list->pushBack(L"WareName: " + w->sID + L" " + (long)wt->iLang + L" " + wt->sName);if ( !wt->sDesc.empty() )list->pushBack(L"WareDesc: " + w->sID + L" " + (long)wt->iLang + L" " + wt->sDesc);}list->pushBack(L"");}}if ( !datafile ){if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list, game, gameAddons) )return false;}return true;}Utils::WString CSpkFile::GetWareText(SWares *w, int lang){// return the text page if being usedif ( w->iTextID > 0 && w->iTextPage > 0 )return Utils::WString(L"{") + (long)w->iTextPage + L"," + (long)w->iTextID + L"}";Utils::WString name;for ( CListNode<SWaresText> *wt = w->lText.Front(); wt; wt = wt->next() ){if ( wt->Data()->sName.empty() )continue;if ( wt->Data()->iLang == lang )name = wt->Data()->sName;else if ( name.empty() && wt->Data()->iLang == 44 )name = wt->Data()->sName;else if ( name.empty() )name = wt->Data()->sName;}return name;}Utils::WString CSpkFile::GetWareDesc(SWares *w, int lang){// return the text page if being usedif ( w->iTextID > 0 && w->iTextPage > 0 )return Utils::WString(L"{") + (long)w->iTextPage + L"," + ((long)w->iTextID + 1) + L"}";Utils::WString name;for ( CListNode<SWaresText> *wt = w->lText.Front(); wt; wt = wt->next() ){if ( wt->Data()->sDesc.empty() )continue;if ( wt->Data()->iLang == lang )name = wt->Data()->sDesc;else if ( name.empty() && wt->Data()->iLang == 44 )name = wt->Data()->sDesc;else if ( name.empty() )name = wt->Data()->sDesc;}return name;}Utils::WString CSpkFile::customStartName() const{if ( !this->IsCustomStart() )return L"";// else find the custom start scriptC_File *file = NULL;for ( file = this->GetFirstFile(FILETYPE_SCRIPT); file; file = this->GetNextFile(file) ){if ( file->filename().contains(L"initplayership") && file->filename().token(L".", 1).Compare(L"galaxy") )break;}if ( !file )return L"";return file->filename().token(L".", 2);}void CSpkFile::MergePackage(CBaseFile *base){// update possible changesif ( base->GetType() == TYPE_SPK ){CSpkFile *spk = (CSpkFile *)base;m_bForceProfile = spk->IsForceProfile();// add any new waresif ( spk->anyWares() ){for ( CListNode<SWares> *node = spk->GetWaresList()->Front(); node; node = node->next() )this->addWare(node->Data());spk->GetWaresList()->clear(); // remove wares so they aren't deleted}// add any settingsif ( spk->anySettings() ){for ( CListNode<SSettingType> *node = spk->settingsList()->Front(); node; node = node->next() )this->addSetting(node->Data()->sKey, node->Data()->iType);}if ( !spk->otherName().empty() ){m_sOtherName = spk->otherName();m_sOtherAuthor = spk->otherAuthor();}}// copy settings from base class_merge(base);for ( CListNode<SGameCompat> *gNode = base->GetGameCompatabilityList()->Front(); gNode; gNode = gNode->next() ) {if ( !gNode->Data()->sVersion.empty() )this->AddGameCompatability(gNode->Data()->iGame, gNode->Data()->sVersion);elsethis->AddGameCompatability(gNode->Data()->iGame, (long)gNode->Data()->iVersion);}// copy over needed librarysfor ( CListNode<SNeededLibrary> *lNode = base->GetNeededLibraries()->Front(); lNode; lNode = lNode->next() )this->addNeededLibrary(lNode->Data()->sName, lNode->Data()->sAuthor, lNode->Data()->sMinVersion);// web mirror address, add any new onesfor(auto itr = base->webMirrors().begin(); itr != base->webMirrors().end(); itr++)this->addWebMirror((*itr)->str);// copy over package namesfor(auto itr = base->namesList()->begin(); itr != base->namesList()->end(); itr++)this->addName((*itr)->iLanguage, (*itr)->sName);// finally do all the filesfor ( CListNode<C_File> *node = base->fileList().Front(); node; node = node->next() ){C_File *f = node->Data();// if it exists, remove the oldfor ( CListNode<C_File> *thisNode = m_lFiles.Front(); thisNode; thisNode = thisNode->next() ){if ( thisNode->Data()->GetFileType() == f->GetFileType() && thisNode->Data()->filename().Compare(f->filename()) && thisNode->Data()->dir().Compare(f->dir()) ){m_lFiles.remove(thisNode);break;}}m_lFiles.push_back(f);}// clear the files so we dont delete them laterbase->GetFileList()->clear();}unsigned char *CSpkFile::_convert_uncompressFile(const Utils::WString &sOldFilename, int *pLen){// firstcheck if the file existsFILE *id = _wfopen(sOldFilename.c_str(), L"rb" );if ( !id ) {CLog::logf(CLog::Log_IO, 1, L"Unable to open file: %s", sOldFilename.c_str());return false;}// read the first 3 charaters to check if its using the original "HiP" compressionUtils::String check((char)fgetc(id));check += (char)fgetc ( id );check += (char)fgetc ( id );Utils::String removeFile;unsigned char *uncomprData = NULL;unsigned char *data = NULL;long len = 0, newlen = 0;if ( check == "HiP" ) {fclose ( id );bool opened = false;if ( DecompressFile ( (char *)sOldFilename.c_str(), "uncompr.tmp" ) ) {removeFile = "uncompr.tmp";id = fopen ( "uncompr.tmp", "r" );if ( id )opened = true;}if ( !opened ) {CLog::log(CLog::Log_IO, 1, L"Unable to uncompress file, exiting...");return false;}CLog::log(CLog::Log_IO, 1, L"* Reading file into memory...");// get file lengthfseek ( id, 0, SEEK_END );len = ftell ( id );// move back to beginningfseek ( id, 0, SEEK_SET );// read the data from file into memoryuncomprData = new unsigned char[len + 1];fread ( uncomprData, sizeof(unsigned char), len, id );newlen = len;}else{CLog::log(CLog::Log_IO, 1, L"* Reading file into memory...");// get file lengthfseek ( id, 0, SEEK_END );len = ftell ( id );// move back to beginningfseek ( id, 0, SEEK_SET );// read the data from file into memorydata = new unsigned char[len + 1];fread ( data, sizeof(unsigned char), len, id );// uncompress the file (currently only 7zip compression)CLog::log(CLog::Log_IO, 1, L"* Uncompressing file...");newlen = len;#ifdef _INCLUDE7ZIPuncomprData = LZMADecodeData ( data, len, newlen, progress );#elseuncomprData = LZMADecode_C ( (unsigned char *)data, len, (size_t*)&newlen, NULL );#endif}*pLen = newlen;if ( !removeFile.empty() ) {CFileIO::Remove(removeFile);}return uncomprData;}Utils::WString CSpkFile::_convert_fileEndString(const Utils::WString &sFile){if ( sFile.Compare(L"Text") )return L"-- End of Script --";else if ( sFile.Compare(L"Uninstall") )return L"-- End of Uninstall --";else if ( sFile.Compare(L"Readme") )return L"-- End of Readme --";else if ( sFile.Compare(L"Map") )return L"-- End of Map --";else if ( sFile.Compare(L"Mod") || sFile.Compare(L"Extra") || sFile.Compare(L"Screen") || sFile.Compare(L"Sound") )return L"";return L"-- End of Script --";}FileType CSpkFile::_convert_fileType(const Utils::WString &sFile){if ( sFile.Compare(L"Text") )return FILETYPE_TEXT;else if ( sFile.Compare(L"Uninstall") )return FILETYPE_UNINSTALL;else if ( sFile.Compare(L"Readme") )return FILETYPE_README;else if ( sFile.Compare(L"Map") )return FILETYPE_MAP;else if ( sFile.Compare(L"Mod") )return FILETYPE_MOD;else if ( sFile.Compare(L"Extra") )return FILETYPE_EXTRA;else if ( sFile.Compare(L"Screen") )return FILETYPE_SCREEN;else if ( sFile.Compare(L"Sound") )return FILETYPE_SOUND;return FILETYPE_SCRIPT;}void CSpkFile::_convert_parse(const Utils::WString &sCmd, const Utils::WString &sRest){if ( sCmd == L"Name:" ){this->setName(sRest);CLog::logf(CLog::Log_EditPackage, 3, L"\tScript Name: %s", sRest.c_str() );}else if ( sCmd == L"Author:" ){this->setAuthor(sRest);CLog::logf(CLog::Log_EditPackage, 3, L"\tScript Author: %s", sRest.c_str() );}else if ( sCmd == L"CustomStart" ){this->SetCustomStart();CLog::logf(CLog::Log_EditPackage, 3, L"\tPackage is a custom start!!" );}else if ( sCmd == L"AnotherMod:" ){this->setAnotherMod(sRest.token(L"|", 1), sRest.tokens(L"|", 2));CLog::logf(CLog::Log_EditPackage, 3, L"\tFor another Mod, Name: %s, Author: %s", this->otherName().c_str(), this->otherAuthor().c_str() );}else if ( sCmd == L"PATCH" ){this->SetPatch();CLog::logf(CLog::Log_EditPackage, 3, L"\tPackage is a Patch Mod!!" );}else if ( sCmd == L"Version:" ){this->setVersion(sRest);CLog::logf(CLog::Log_EditPackage, 3, L"\tScript Version: %s", sRest.c_str() );}else if ( sCmd == L"Date:" ){this->setCreationDate ( sRest );CLog::logf(CLog::Log_EditPackage, 3, L"\tScript Creation Date: %s", sRest.c_str() );}else if ( sCmd == L"Desc:" ) {this->setDescription(sRest.findReplace(L"<br>", L"\n") );CLog::logf(CLog::Log_EditPackage, 3, L"\tScript Description: %s", this->description().c_str() );}else if ( sCmd == L"WebAddress:" ) {this->setWebAddress(sRest);CLog::logf(CLog::Log_EditPackage, 3, L"\tWeb Address: %s", sRest.c_str() );}else if ( sCmd == L"WebMirror1:" ){this->addWebMirror(sRest);CLog::logf(CLog::Log_EditPackage, 3, L"\tWeb Mirror Address: %s", sRest.c_str() );}else if ( sCmd == L"WebMirror2:" ){this->addWebMirror(sRest);CLog::logf(CLog::Log_EditPackage, 3, L"\tWeb Mirror Address: %s", sRest.c_str() );}else if ( sCmd == L"ScriptType:" )this->setScriptType (sRest);else if ( sCmd == L"WebSite:" ) {this->setWebSite ( sRest );CLog::logf(CLog::Log_EditPackage, 3, L"\tWeb Site: %s", sRest.c_str() );}else if ( sCmd == L"Email:" ) {this->setEmail(sRest);CLog::logf(CLog::Log_EditPackage, 3, L"\tAuthor Email Address: %s", sRest.c_str() );}else if ( sCmd == L"GameVersion:" ){//TODO: fix this for new game version/*int version = sRest.ToInt();if ( version == 0 )this->SetGameVersion ( 1 );else if (version == 1 )this->SetGameVersion ( 0 );elsethis->SetGameVersion ( version );CLog::logf(CLog::Log_EditPackage, "\tGame Version: %d", this->GetGameVersion () );*/}else if ( sCmd == L"Ware:" ){this->addWare ( sRest );CLog::logf(CLog::Log_EditPackage, 3, L"\tAdding Custom Ware" );}else if ( sCmd == L"WareText:" )this->addWareText ( sRest );else if ( sCmd == L"UninstallAfter:" ) this->addUninstallText(sRest.token(L" ", 1).toLong(), false, sRest.tokens(L" ", 2));else if ( sCmd == L"UninstallBefore:" ) this->addUninstallText(sRest.token(L" ", 1).toLong(), true, sRest.tokens(L" ", 2));else if ( sCmd == L"InstallAfter:" ) this->addInstallText(sRest.token(L" ", 1).toLong(), false, sRest.tokens(L" ", 2));else if ( sCmd == L"InstallBefore:" ) this->addInstallText(sRest.token(L" ", 1).toLong(), true, sRest.tokens(L" ", 2));else if ( sCmd == L"ScriptName:" ){Utils::WString lang = sRest.token(L":", 1);Utils::WString name = sRest.tokens(L":", 2);this->addName(lang.toLong(), name);CLog::logf(CLog::Log_EditPackage, 3, L"\tScript Name Language (%s) %s", lang.c_str(), name.c_str() );}}Utils::WString CSpkFile::_convert_parseFilename(const Utils::WString &sRest, float fVersion, Utils::WString *pDir){Utils::WString sFilename;if ( fVersion >= 3.00f )sFilename = sRest.tokens(L" ", 3);else if ( fVersion >= 2.00f )sFilename = sRest.tokens(L" ", 2);elsesFilename = sRest;if ( sFilename.contains(L"<br>") ) {sFilename = sFilename.findReplace(L"<br>", L"|");if ( sFilename[0] == L'|' ) {sFilename = sFilename.token(L"|", 1);}else {*pDir = sFilename.token(L"|", 1);sFilename = sFilename.tokens(L"|", 2);}}return sFilename;}unsigned char *CSpkFile::_convert_parseFile(const Utils::WString &sCmd, const Utils::WString &sRest, float fVersion, unsigned char *d){bool bShared = (sCmd.left(9) == L"$$$Shared") ? true : false;Utils::WString sFile = sCmd.right(-3).left(-1);Utils::WString sEnd = this->_convert_fileEndString(sFile);FileType iType = this->_convert_fileType(sFile);// convert the filename and directoryUtils::WString dir, filename = _convert_parseFilename(sRest, fVersion, &dir);// get the size and timelong time = 0, size = 0;if ( fVersion >= 2.00f ) time = sRest.token(L" ", 1).toLong();if ( fVersion >= 3.00f ) size = sRest.token(L" ", 2).toLong();bool binaryRead = (CFileIO(filename).isFileExtension(L"PCK")) ? true : false;if ( sEnd.empty() ) binaryRead = true;C_File *file = new C_File ();if ( bShared ) CLog::logf(CLog::Log_File, 2, L"\tFound %s File (Shared): %s, Reading...", sFile.c_str(), filename.c_str() );else CLog::logf(CLog::Log_File, 2, L"\tFound %s File: %s, Reading...", sFile.c_str(), filename.c_str() );// read the dataif ( binaryRead ){file->ReadFromData ( (char *)d, size );d += size;}else{Utils::String readData;d = LineByLineRead ( d, sEnd.toString(), &readData);file->ReadFromData ( (char *)readData.c_str(), (long)readData.length() );}// setup the filefile->setName ( filename );file->setFileType(iType);file->SetShared ( bShared );file->SetCreationTime ( time );if ( !dir.empty() )file->setDir ( dir );this->AddFile ( file );CLog::logf(CLog::Log_File, 3, L"Size: %s", file->dataSizeString().c_str() );return d;}CSpkFile *CSpkFile::convertFromOld(const Utils::WString &sOldFilename){// check if the old file is actually in an old formatint ret = CBaseFile::CheckFile ( sOldFilename );if ( ret != SPKFILE_INVALID && ret != SPKFILE_OLD ) {return NULL;}CSpkFile *pSpkFile = new CSpkFile();if ( !pSpkFile->convertOld(sOldFilename) ) {delete pSpkFile;return NULL;}return pSpkFile;}bool CSpkFile::convertOld(const Utils::WString &sOldFilename){// check if the old file is actually in an old formatint ret = CBaseFile::CheckFile ( sOldFilename );if ( ret != SPKFILE_INVALID && ret != SPKFILE_OLD ) {return false;}//uncomress the dataint len;unsigned char *uncomprData = this->_convert_uncompressFile(sOldFilename, &len);// uncomressed failedif ( !uncomprData ) {CLog::log(CLog::Log_IO, 1, L"Error: Unable to uncompress the file");return false;}// now we can read the dataunsigned char *d = uncomprData;Utils::String str;// CMultiSpkFile *mspk = NULL;//SMultiSpkFile *cur_mspk = NULL;int numscripts = 0, curscript = 0;float fVersion = 1;CLog::log(CLog::Log_IO, 1, L"* Reading spk data...");while ( d ){// read the next lined = str.readToEndOfLine(d);if ( !d || d[0] == 0 ) {break;}if ( str.empty() ) {continue;}Utils::String sCmd = str.token(" ", 1);//TODO: split this into CMultiSpkFile/*if ( first == "MultiPackage:" )mspk = new CMultiSpkFile;else if ( (first == "SelectScript:") && (mspk) ){mspk->AddFileEntry ( rest.GetToken ( 2, -1, ' ' ) + ".spk" );++numscripts;}else if ( (str == "AllowSelection") && (mspk) )mspk->SetSelection ( true );else if ( str == "-- Start New Script --" ){if ( !mspk ){printf ( "Invalid file format, seems to be multi package file but isn't\n" );CLEANUPexit ( 0 );}cur_mspk = mspk->GetFileList()->Get ( curscript );++curscript;cur_mspk->pFile = new CSpkFile;spkfile = (CSpkFile *)cur_mspk->pFile;}*/Utils::String sRest = str.tokens(" ", 2);if ( sCmd == "Packager:" ) {fVersion = sRest;CLog::logf(CLog::Log_Read, 3, L"\tPackager Version: %.2f", fVersion );}else if ( sCmd == "Icon:" ){long size = sRest.token(" ", 1);Utils::String ext = sRest.token(" ", 2);C_File *file = new C_File ();file->ReadFromData ( (char *)d, size );d += size;this->setIcon(file, ext);CLog::logf(CLog::Log_File, 3, L"\tIcon (%s) Size: %s", ext.c_str(), file->dataSizeString ().c_str() );}else if ( sCmd.left(3) == "$$$" )d = _convert_parseFile(sCmd, sRest, fVersion, d);else {this->_convert_parse(sCmd, sRest);}}CLog::logf(CLog::Log_IO, 1, L"* Reading spk data..." );return true;}