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 this
unsigned 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: SetDefaults
Desc: 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: ParseValueLine
Input: String - single line from a file to set
Return: Boolean - returns true if value exists
Desc: 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));
}
else
return CBaseFile::parseValueLine ( line );
return true;
}
/*
Func: CreateValuesLine
Return: String - returns the full string for values
Desc: 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 together
if ( (!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";
else
values += 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;
else
return 2;
}
bool CSpkFile::computeSigned(bool updateFiles) const
{
// check for any custom wares
// patch mods and custom starts are also not signed
if ((!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;
else
scriptType = 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 text
if (iLang)
{
CLanguages* langList = CLanguages::Instance();
// if the language is -1, then we use the default language
// otherwise, push the language onto the stack
if (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 default
if (iLang != -1)
langList->popLanguage();
return text;
}
// remember to pop the language if we pushed it to restore to default
if (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 TRANSLATED
switch ( 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 use
SWares *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 already
if ( 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);
else
wt->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;
else
return 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");
else
list->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);
else
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);
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 used
if ( 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 used
if ( 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 script
C_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 changes
if ( base->GetType() == TYPE_SPK )
{
CSpkFile *spk = (CSpkFile *)base;
m_bForceProfile = spk->IsForceProfile();
// add any new wares
if ( 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 settings
if ( 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);
else
this->AddGameCompatability(gNode->Data()->iGame, (long)gNode->Data()->iVersion);
}
// copy over needed librarys
for ( 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 ones
for(auto itr = base->webMirrors().begin(); itr != base->webMirrors().end(); itr++)
this->addWebMirror((*itr)->str);
// copy over package names
for(auto itr = base->namesList()->begin(); itr != base->namesList()->end(); itr++)
this->addName((*itr)->iLanguage, (*itr)->sName);
// finally do all the files
for ( CListNode<C_File> *node = base->fileList().Front(); node; node = node->next() )
{
C_File *f = node->Data();
// if it exists, remove the old
for ( 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 later
base->GetFileList()->clear();
}
unsigned char *CSpkFile::_convert_uncompressFile(const Utils::WString &sOldFilename, int *pLen)
{
// firstcheck if the file exists
FILE *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" compression
Utils::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 length
fseek ( id, 0, SEEK_END );
len = ftell ( id );
// move back to beginning
fseek ( id, 0, SEEK_SET );
// read the data from file into memory
uncomprData = 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 length
fseek ( id, 0, SEEK_END );
len = ftell ( id );
// move back to beginning
fseek ( id, 0, SEEK_SET );
// read the data from file into memory
data = 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 _INCLUDE7ZIP
uncomprData = LZMADecodeData ( data, len, newlen, progress );
#else
uncomprData = 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 );
else
this->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);
else
sFilename = 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 directory
Utils::WString dir, filename = _convert_parseFilename(sRest, fVersion, &dir);
// get the size and time
long 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 data
if ( 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 file
file->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 format
int 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 format
int ret = CBaseFile::CheckFile ( sOldFilename );
if ( ret != SPKFILE_INVALID && ret != SPKFILE_OLD ) {
return false;
}
//uncomress the data
int len;
unsigned char *uncomprData = this->_convert_uncompressFile(sOldFilename, &len);
// uncomressed failed
if ( !uncomprData ) {
CLog::log(CLog::Log_IO, 1, L"Error: Unable to uncompress the file");
return false;
}
// now we can read the data
unsigned 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 line
d = 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" );
CLEANUP
exit ( 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;
}