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 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::String header) const
{
if ( header.Compare("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::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));
}
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::String CSpkFile::CreateValuesLine () const
{
Utils::String values = CBaseFile::CreateValuesLine ();
// combine all values together
if ( (!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";
else
values += 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;
else
return 2;
}
bool CSpkFile::UpdateSigned (bool updateFiles)
{
// check for any custom wares
// patch mods and custom starts are also not signed
if ( (!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 use
SWares *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 already
if ( 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);
else
wt->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;
else
return 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");
else
list->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);
else
list->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 used
if ( 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 used
if ( 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 script
C_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 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->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);
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 ( SStringList *str = base->GetWebMirrors()->Head(); str; str = str->next )
this->AddWebMirror(str->str);
// copy over package names
for ( CListNode<SNames> *nNode = base->GetNamesList()->Front(); nNode; nNode = nNode->next() )
this->AddLanguageName(nNode->Data()->iLanguage, nNode->Data()->sName);
// finally do all the files
for ( CListNode<C_File> *node = base->GetFileList()->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()->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 later
base->GetFileList()->clear();
}
unsigned char *CSpkFile::_convert_uncompressFile(const Utils::String &sOldFilename, int *pLen)
{
// firstcheck if the file exists
FILE *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" 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, "Unable to uncompress file, exiting...");
return false;
}
CLog::log(CLog::Log_IO, 1, "* 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, "* 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, "* 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::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 );
else
this->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);
else
sFilename = 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 directory
Utils::String dir, filename = _convert_parseFilename(sRest, fVersion, &dir);
// get the size and time
long 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 data
if ( 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 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, "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 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::String &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, "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, "* 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, "\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;
}