Rev 127 | Rev 160 | Go to most recent revision | 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"//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::String header) const{if ( header.Compare("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::String &line){Utils::String first = line.token(" ", 1);Utils::String rest = line.tokens(" ", 2);if ( first == "AnotherMod:" ){m_sOtherAuthor = rest.token("|", 1);m_sOtherName = rest.tokens("|", 2);}else if ( line == "CustomStart" )m_iPackageType = PACKAGETYPE_CUSTOMSTART;else if ( line == "PackageUpdate" )m_iPackageType = PACKAGETYPE_UPDATE;else if ( line == "Patch" )m_iPackageType = PACKAGETYPE_PATCH;else if ( line == "ForceProfile" )m_bForceProfile = true;else if ( line == "Signed" )m_bSigned = true;else if ( first == "ScriptType:" )m_sScriptType = rest;else if ( first == "ScriptTypeNew:" )m_iScriptType = rest;else if ( first == "PackageType:" )m_iPackageType = rest;else if ( first == "Ware:" )AddWare ( rest );else if ( (first == "WareText:") && (m_pLastWare) )AddWareText ( rest );else if ( first == "Setting:" ){SSettingType *t = AddSetting ( rest.token("|", 2), rest.token("|", 1) );ConvertSetting ( t, rest.tokens("|", 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::String CSpkFile::CreateValuesLine () const{Utils::String values = CBaseFile::CreateValuesLine ();// combine all values togetherif ( (!m_sOtherAuthor.empty()) && (!m_sOtherName.empty()) )values += "AnotherMod: " + m_sOtherAuthor + "|" + m_sOtherName + "\n";if ( m_bForceProfile )values += "ForceProfile\n";if ( !m_sScriptType.empty() )values += "ScriptType: " + m_sScriptType + "\n";values += Utils::String("PackageType: ") + (long)m_iPackageType + "\n";values += Utils::String("ScriptTypeNew: ") + (long)m_iScriptType + "\n";for ( CListNode<SSettingType> *node = m_lSettings.Front(); node; node = node->next() )values += Utils::String("Setting: ") + (long)node->Data()->iType + "|" + node->Data()->sKey + "|" + GetSetting(node->Data()) + "\n";for ( CListNode<SWares> *wNode = m_lWares.Front(); wNode; wNode = wNode->next() ) {SWares *ware = wNode->Data();if ( wNode->Data()->iTextID > 0 )values += Utils::String("Ware: ") + ware->cType + ":" + ware->iPrice + ":" + (long)ware->iSize + ":" + (long)ware->iVolumn + ":" + ware->sID + ":" + (long)ware->iNotority + ":" + (long)ware->iTextID + "," + (long)ware->iTextPage + "\n";elsevalues += Utils::String("Ware: ") + ware->cType + ":" + ware->iPrice + ":" + (long)ware->iSize + ":" + (long)ware->iVolumn + ":" + ware->sID + ":" + (long)ware->iNotority + "\n";for ( CListNode<SWaresText> *wtNode = ware->lText.Front(); wtNode; wtNode = wtNode->next() )values += Utils::String("WareText: ") + (long)wtNode->Data()->iLang + " " + wtNode->Data()->sName + "|" + wtNode->Data()->sDesc + "\n";}return values;}Utils::String CSpkFile::GetCustomScriptType (int lang) const{if ( !m_sScriptType.empty() ){int max;Utils::String *split = m_sScriptType.tokenise("<br>", &max);if ( max && split ){for ( int i = 1; i < max; i++ ){Utils::String str = split[i];int num = str.token(":", 1);Utils::String name = str.tokens(":", 2);if ( num == lang ){CLEANSPLIT(split, max)return name;}}Utils::String ret = split[0];CLEANSPLIT(split, max)return ret;}CLEANSPLIT(split, max)}return m_sScriptType;}bool CSpkFile::readWares(int iLang, CLinkList<SWareEntry> &list, const Utils::String &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){return file.write("SPKCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen);}void CSpkFile::AddWareText(const Utils::String &sData){if ( !m_pLastWare )return;SWaresText *wt = new SWaresText;wt->iLang = sData.token(" ", 1);wt->sName = sData.tokens(" ", 2).token("|", 1);wt->sDesc = sData.tokens(" ", 2).tokens("|", 2);m_pLastWare->lText.push_back ( wt );_changed();}void CSpkFile::AddWare(const Utils::String &sData){SWares *ware = new SWares;ware->iTextID = -1;ware->iTextPage = 0;ware->cType = sData.token(":", 1)[0];ware->iPrice = sData.token(":", 2);ware->iSize = sData.token(":", 3);ware->iVolumn = sData.token(":", 4);ware->sID = sData.token(":", 5);ware->iNotority = sData.token(":", 6);if ( !sData.token(":", 7).empty() ){Utils::String r = sData.token(":", 7);ware->iTextID = r.token(",", 1);ware->iTextPage = r.token(",", 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::String &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::String &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::String &sName, const Utils::String &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::String &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::String &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::String basename = file->GetName().GetToken ( 1, file->GetName().NumToken('.') - 1, '.' ).ToString();if ( basename.right(15).Compare(".initplayership") )return 0;}if ( !IsAnotherMod() )return 1;elsereturn 2;}bool CSpkFile::UpdateSigned (bool updateFiles){// check for any custom wares// patch mods and custom starts are also not signedif ( (!m_lWares.empty()) || (this->IsPatch()) || (this->IsCustomStart()) ){m_bSigned = false;return false;}return CBaseFile::UpdateSigned(updateFiles);}SSettingType *CSpkFile::AddSetting(const Utils::String &key, int type ){Utils::String 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::String &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::String CSpkFile::GetSetting ( SSettingType *t ) const{if ( !t )return "";switch ( t->iType ){case SETTING_STRING:return ((SSettingString *)t)->sValue;case SETTING_INTEGER:return Utils::String::Number(((SSettingInteger *)t)->iValue);case SETTING_CHECK:return (((SSettingInteger *)t)->iValue) ? "1" : "0";}return "";}void CSpkFile::ClearSettings (){m_lSettings.clear(true);_changed();}bool CSpkFile::IsMatchingMod(const Utils::String &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::String filename = file->GetBaseName().ToString();if ( filename.Compare(mod) )return true;}return false;}Utils::String CSpkFile::GetScriptTypeString(int lang) const{int iType = m_iScriptType;if ( this->IsLibrary() )return "Library";else if ( this->IsPackageUpdate() )return "Package Update";else if ( this->IsCustomStart() )return "Custom Start";else if ( this->IsPatch() )return "Patch";else if ( m_iScriptType == SCRIPTTYPE_CUSTOM ){Utils::String type = this->GetCustomScriptType(lang);if ( !type.empty() )return type;iType = -1;}if (iType == -1) // no script type{if ( this->IsFakePatch() )return "Fake Patch";}Utils::String sType = CSpkFile::GetScriptTypeStringStatic(m_iScriptType);if ( sType.empty() )return "Other";return sType;}int CSpkFile::ConvertScriptType(const Utils::String &sType){for ( int i = 0; i < SCRIPTTYPE_MAX; i++ ){if ( sType.Compare(CSpkFile::GetScriptTypeStringStatic(i)) )return i;}return -1;}Utils::String CSpkFile::GetScriptTypeStringStatic(int type){switch ( type ){case SCRIPTTYPE_CUSTOM:return "Custom";case SCRIPTTYPE_NAVIGATION:return "Navigation";case SCRIPTTYPE_COMBAT:return "Combat";case SCRIPTTYPE_MISSION:return "Mission";case SCRIPTTYPE_ALPLUGIN:return "AL Plugin";case SCRIPTTYPE_HOTKEY:return "Hotkey";case SCRIPTTYPE_SHIPUPGRADE:return "Ship Upgrade";case SCRIPTTYPE_SHIPCOMMAND:return "Ship Command";case SCRIPTTYPE_STATIONCOMMAND:return "Station Command";case SCRIPTTYPE_FLEET:return "Fleet Management";case SCRIPTTYPE_TRADE:return "Trade";case SCRIPTTYPE_PIRACY:return "Piracy";case SCRIPTTYPE_CHEAT:return "Cheat";case SCRIPTTYPE_EXTENSION:return "Extension Mods";case SCRIPTTYPE_REBALANCE:return "Rebalance";case SCRIPTTYPE_FIX:return "Vanilla Fix";case SCRIPTTYPE_GENERALMOD:return "General Mod";case SCRIPTTYPE_TOTAL:return "Totel Conversion";case SCRIPTTYPE_WINGCOMMAND:return "Wing Command";}return "Other";}bool CSpkFile::LoadPackageData(const Utils::String &sFirst, const Utils::String &sRest, const Utils::String &sMainGame, Utils::CStringList &otherGames, Utils::CStringList &gameAddons, CProgressInfo *progress){if ( sFirst.Compare("ScriptType") ){if ( sRest.Compare("Library") || sRest.Compare("Library Script") )this->SetLibrary();else if ( sRest.Compare("Update") || sRest.Compare("Package Update") || sRest.Compare("Mod Update") )this->SetPackageUpdate();else if ( sRest.Compare("Start") || sRest.Compare("Custom Start") )this->SetCustomStart();else if ( sRest.Compare("Patch") || sRest.Compare("Patch Mod") )this->SetPatch();else{int check = sRest;if ( check || sRest == "0" )m_iScriptType = check;else{m_iScriptType = CSpkFile::ConvertScriptType(sRest);if ( m_iScriptType == -1 )m_sScriptType = sRest;}}}else if ( sFirst.Compare("AnotherMod") ){m_sOtherName = sRest.token("|", 1);m_sOtherAuthor = sRest.tokens("|", 2);}else if ( sFirst.Compare("WareName") || sFirst.Compare("WareDesc") ){// find the ware to useSWares *useWare = m_pLastWare;Utils::String id = sRest.token(" ", 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(" ", 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("WareName") )wt->sName = sRest.tokens(" ", 3);elsewt->sDesc = sRest.tokens(" ", 3);}}else if ( sFirst.left(4).Compare("Ware") ){SWares *ware = new SWares;ware->iTextID = -1;ware->iTextPage = 0;ware->cType = sFirst[4];ware->iPrice = sRest.token(" ", 2);ware->iSize = sRest.token(" ", 3);ware->iVolumn = sRest.token(" ", 4);ware->sID = sRest.token(" ", 1);ware->iNotority = sRest.token(" ", 5);if ( !sRest.token(" ", 6).empty() ){ware->iTextID = sRest.token(" ", 6).token(",", 2);ware->iTextPage = sRest.token(" ", 6).token(",", 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::CStringList *list, int game, const Utils::CStringList &gameAddons, bool datafile){if ( !CBaseFile::GeneratePackagerScript(wildcard, list, game, gameAddons, datafile) )return false;list->pushBack("# File Type, Script or Ship");list->pushBack("FileType: Script");list->pushBack("");list->pushBack("# Script Type, the type of package file, some are special types, others are just for show");if ( this->IsLibrary() )list->pushBack("ScriptType: Library");else if ( this->IsPackageUpdate() )list->pushBack("ScriptType: Package Update");else if ( this->IsCustomStart() )list->pushBack("ScriptType: Custom Start");else if ( this->IsPatch() )list->pushBack("ScriptType: Patch");elselist->pushBack("ScriptType: " + this->GetScriptTypeString(44));list->pushBack("");if ( this->IsAnotherMod() ){list->pushBack("# For another mod/package, this is a child package");list->pushBack("AnotherMod: " + m_sOtherName + "|" + m_sOtherAuthor);list->pushBack("");}if ( !m_lWares.empty() ){list->pushBack("# Custom Wares, Ware<type>: <id> <price> <size> <volumn> <notority>");for ( CListNode<SWares> *node = m_lWares.Front(); node; node = node->next() ){SWares *w = node->Data();if ( w->iTextID > 0 )list->pushBack(Utils::String("Ware") + (char)w->cType + ": " + w->sID + " " + (long)w->iPrice + " " + (long)w->iSize + " " + (long)w->iVolumn + " " + (long)w->iNotority + " " + (long)w->iTextPage + "," + (long)w->iTextID);elselist->pushBack(Utils::String("Ware") + (char)w->cType + ": " + w->sID + " " + (long)w->iPrice + " " + (long)w->iSize + " " + (long)w->iVolumn + " " + (long)w->iNotority);for ( CListNode<SWaresText> *wNode = w->lText.Front(); wNode; wNode = wNode->next() ){SWaresText *wt = wNode->Data();if ( !wt->sName.empty() )list->pushBack("WareName: " + w->sID + " " + (long)wt->iLang + " " + wt->sName);if ( !wt->sDesc.empty() )list->pushBack("WareDesc: " + w->sID + " " + (long)wt->iLang + " " + wt->sDesc);}list->pushBack("");}}if ( !datafile ){if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list, game, gameAddons) )return false;}return true;}Utils::String CSpkFile::GetWareText(SWares *w, int lang){// return the text page if being usedif ( w->iTextID > 0 && w->iTextPage > 0 )return Utils::String("{") + (long)w->iTextPage + "," + (long)w->iTextID + "}";Utils::String 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::String CSpkFile::GetWareDesc(SWares *w, int lang){// return the text page if being usedif ( w->iTextID > 0 && w->iTextPage > 0 )return Utils::String("{") + (long)w->iTextPage + "," + ((long)w->iTextID + 1) + "}";Utils::String 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::String CSpkFile::GetCustomStartName() const{if ( !this->IsCustomStart() )return "";// else find the custom start scriptC_File *file = NULL;for ( file = this->GetFirstFile(FILETYPE_SCRIPT); file; file = this->GetNextFile(file) ){if ( file->GetFilename().IsIn("initplayership") && file->GetFilename().GetToken(".", 1, 1).Compare("galaxy") )break;}if ( !file )return "";return file->GetFilename().GetToken(".", 2, 2).ToString();}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->GetSettingsList()->Front(); node; node = node->next() )this->AddSetting(node->Data()->sKey, node->Data()->iType);}if ( !spk->GetOtherName().empty() ){m_sOtherName = spk->GetOtherName();m_sOtherAuthor = spk->GetOtherAuthor();}}// copy settings from base 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 ( SStringList *str = base->GetWebMirrors()->Head(); str; str = str->next )this->AddWebMirror(str->str);// copy over package namesfor ( CListNode<SNames> *nNode = base->GetNamesList()->Front(); nNode; nNode = nNode->next() )this->AddLanguageName(nNode->Data()->iLanguage, nNode->Data()->sName);// finally do all the filesfor ( CListNode<C_File> *node = base->GetFileList()->Front(); node; node = node->next() ){C_File *f = node->Data();// if it exists, remove the oldfor ( CListNode<C_File> *thisNode = m_lFiles.Front(); thisNode; thisNode = thisNode->next() ){if ( thisNode->Data()->GetFileType() == f->GetFileType() && thisNode->Data()->GetFilename().Compare(f->GetFilename()) && thisNode->Data()->GetDir().Compare(f->GetDir()) ){m_lFiles.remove(thisNode);break;}}m_lFiles.push_back(f);}// clear the files so we dont delete them laterbase->GetFileList()->clear();}unsigned char *CSpkFile::_convert_uncompressFile(const Utils::String &sOldFilename, int *pLen){// firstcheck if the file existsFILE *id = fopen(sOldFilename.c_str(), "rb" );if ( !id ) {CLog::logf(CLog::Log_IO, 1, "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, "Unable to uncompress file, exiting...");return false;}CLog::log(CLog::Log_IO, 1, "* 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, "* 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, "* 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::String CSpkFile::_convert_fileEndString(const Utils::String &sFile){if ( sFile.Compare("Text") )return "-- End of Script --";else if ( sFile.Compare("Uninstall") )return "-- End of Uninstall --";else if ( sFile.Compare("Readme") )return "-- End of Readme --";else if ( sFile.Compare("Map") )return "-- End of Map --";else if ( sFile.Compare("Mod") || sFile.Compare("Extra") || sFile.Compare("Screen") || sFile.Compare("Sound") )return "";return "-- End of Script --";}FileType CSpkFile::_convert_fileType(const Utils::String &sFile){if ( sFile.Compare("Text") )return FILETYPE_TEXT;else if ( sFile.Compare("Uninstall") )return FILETYPE_UNINSTALL;else if ( sFile.Compare("Readme") )return FILETYPE_README;else if ( sFile.Compare("Map") )return FILETYPE_MAP;else if ( sFile.Compare("Mod") )return FILETYPE_MOD;else if ( sFile.Compare("Extra") )return FILETYPE_EXTRA;else if ( sFile.Compare("Screen") )return FILETYPE_SCREEN;else if ( sFile.Compare("Sound") )return FILETYPE_SOUND;return FILETYPE_SCRIPT;}void CSpkFile::_convert_parse(const Utils::String &sCmd, const Utils::String &sRest){if ( sCmd == "Name:" ){this->setName ( sRest );CLog::logf(CLog::Log_EditPackage, 3, "\tScript Name: %s", sRest.c_str() );}else if ( sCmd == "Author:" ){this->setAuthor(sRest);CLog::logf(CLog::Log_EditPackage, 3, "\tScript Author: %s", sRest.c_str() );}else if ( sCmd == "CustomStart" ){this->SetCustomStart();CLog::logf(CLog::Log_EditPackage, 3, "\tPackage is a custom start!!" );}else if ( sCmd == "AnotherMod:" ){this->SetAnotherMod(sRest.token("|", 1), sRest.tokens("|", 2));CLog::logf(CLog::Log_EditPackage, 3, "\tFor another Mod, Name: %s, Author: %s", this->GetOtherName().c_str(), this->GetOtherAuthor().c_str() );}else if ( sCmd == "PATCH" ){this->SetPatch();CLog::logf(CLog::Log_EditPackage, 3, "\tPackage is a Patch Mod!!" );}else if ( sCmd == "Version:" ){this->setVersion(sRest);CLog::logf(CLog::Log_EditPackage, 3,"\tScript Version: %s", sRest.c_str() );}else if ( sCmd == "Date:" ){this->setCreationDate ( sRest );CLog::logf(CLog::Log_EditPackage, 3,"\tScript Creation Date: %s", sRest.c_str() );}else if ( sCmd == "Desc:" ) {this->setDescription(sRest.findReplace("<br>", "\n") );CLog::logf(CLog::Log_EditPackage, 3,"\tScript Description: %s", this->description().c_str() );}else if ( sCmd == "WebAddress:" ) {this->setWebAddress(sRest);CLog::logf(CLog::Log_EditPackage, 3, "\tWeb Address: %s", sRest.c_str() );}else if ( sCmd == "WebMirror1:" ){this->AddWebMirror(sRest);CLog::logf(CLog::Log_EditPackage, 3, "\tWeb Mirror Address: %s", sRest.c_str() );}else if ( sCmd == "WebMirror2:" ){this->AddWebMirror(sRest);CLog::logf(CLog::Log_EditPackage, 3, "\tWeb Mirror Address: %s", sRest.c_str() );}else if ( sCmd == "ScriptType:" )this->SetScriptType (sRest);else if ( sCmd == "WebSite:" ) {this->setWebSite ( sRest );CLog::logf(CLog::Log_EditPackage, 3, "\tWeb Site: %s", sRest.c_str() );}else if ( sCmd == "Email:" ) {this->setEmail(sRest);CLog::logf(CLog::Log_EditPackage, 3, "\tAuthor Email Address: %s", sRest.c_str() );}else if ( sCmd == "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 == "Ware:" ){this->AddWare ( sRest );CLog::logf(CLog::Log_EditPackage, 3, "\tAdding Custom Ware" );}else if ( sCmd == "WareText:" )this->AddWareText ( sRest );else if ( sCmd == "UninstallAfter:" ) this->addUninstallText(sRest.token(" ", 1).toLong(), false, sRest.tokens(" ", 2));else if ( sCmd == "UninstallBefore:" ) this->addUninstallText(sRest.token(" ", 1).toLong(), true, sRest.tokens(" ", 2));else if ( sCmd == "InstallAfter:" ) this->addInstallText(sRest.token(" ", 1).toLong(), false, sRest.tokens(" ", 2));else if ( sCmd == "InstallBefore:" ) this->addInstallText(sRest.token(" ", 1).toLong(), true, sRest.tokens(" ", 2));else if ( sCmd == "ScriptName:" ){Utils::String lang = sRest.token(":", 1);Utils::String name = sRest.tokens(":", 2);this->AddLanguageName(lang.toLong(), name);CLog::logf(CLog::Log_EditPackage, 3, "\tScript Name Language (%s) %s", lang.c_str(), name.c_str() );}}Utils::String CSpkFile::_convert_parseFilename(const Utils::String &sRest, float fVersion, Utils::String *pDir){Utils::String sFilename;if ( fVersion >= 3.00f )sFilename = sRest.tokens(" ", 3);else if ( fVersion >= 2.00f )sFilename = sRest.tokens(" ", 2);elsesFilename = sRest;if ( sFilename.isin("<br>") ) {sFilename = sFilename.findReplace("<br>", "|");if ( sFilename[0] == '|' ) {sFilename = sFilename.token("|", 1);}else {*pDir = sFilename.token("|", 1);sFilename = sFilename.tokens("|", 2);}}return sFilename;}unsigned char *CSpkFile::_convert_parseFile(const Utils::String &sCmd, const Utils::String &sRest, float fVersion, unsigned char *d){bool bShared = (sCmd.left(9) == "$$$Shared") ? true : false;Utils::String sFile = sCmd.right(-3).left(-1);Utils::String sEnd = this->_convert_fileEndString(sFile);FileType iType = this->_convert_fileType(sFile);// convert the filename and directoryUtils::String dir, filename = _convert_parseFilename(sRest, fVersion, &dir);// get the size and timelong time = 0, size = 0;if ( fVersion >= 2.00f ) time = sRest.token(" ", 1).toLong();if ( fVersion >= 3.00f ) size = sRest.token(" ", 2).toLong();bool binaryRead = (CFileIO(filename).CheckFileExtension("PCK")) ? true : false;if ( sEnd.empty() ) binaryRead = true;C_File *file = new C_File ();if ( bShared ) CLog::logf(CLog::Log_File, 2, "\tFound %s File (Shared): %s, Reading...", sFile.c_str(), filename.c_str() );else CLog::logf(CLog::Log_File, 2, "\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, &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, "Size: %s", file->dataSizeString().c_str() );return d;}CSpkFile *CSpkFile::convertFromOld(const Utils::String &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::String &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, "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, "* 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, "\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, "\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, "* Reading spk data..." );return true;}