Rev 6 | Rev 8 | 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"
//TODO: remove this
unsigned char *LineByLineRead ( unsigned char *data, CyString end, CyString *readData )
{
CyString line;
while ( true )
{
data = line.GetEndOfLine(data);
//data = ReadNextLine ( data, len, &line );
if ( (*readData).Empty() && line.Empty() ) continue;
if ( line == end )
break;
*readData += (line + "\r\n");
}
return data;
}
CSpkFile::CSpkFile() : CBaseFile ()
{
SetDefaults ();
m_iType = TYPE_SPK;
}
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 ( CyString header )
{
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 ( CyString line )
{
CyString first = line.GetToken ( 1, ' ' );
CyString rest = line.GetToken ( 2, -1, ' ' );
if ( first == "AnotherMod:" )
{
m_sOtherAuthor = rest.GetToken ( 1, '|' );
m_sOtherName = rest.GetToken ( 2, -1, '|' );
}
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.ToInt();
else if ( first == "PackageType:" )
m_iPackageType = rest.ToInt();
else if ( first == "Ware:" )
AddWare ( rest );
else if ( (first == "WareText:") && (m_pLastWare) )
AddWareText ( rest );
else if ( first == "Setting:" )
{
SSettingType *t = AddSetting ( rest.GetToken ( 2, '|' ), rest.GetToken ( 1, '|' ).ToInt() );
ConvertSetting ( t, rest.GetToken ( 3, -1, '|' ) );
}
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
*/
CyString CSpkFile::CreateValuesLine ()
{
CyString values = CBaseFile::CreateValuesLine ();
// combine all values together
if ( (!m_sOtherAuthor.Empty()) && (!m_sOtherName.Empty()) )
values += (CyString("AnotherMod: ") + m_sOtherAuthor + "|" + m_sOtherName + "\n");
if ( m_bForceProfile )
values += "ForceProfile\n";
if ( !m_sScriptType.Empty() )
values += (CyString("ScriptType: ") + m_sScriptType + "\n");
values += (CyString("PackageType: ") + (long)m_iPackageType + "\n");
values += (CyString("ScriptTypeNew: ") + (long)m_iScriptType + "\n");
for ( SSettingType *st = m_lSettings.First(); st; st = m_lSettings.Next() )
values += (CyString("Setting: ") + CyString::Number(st->iType) + "|" + st->sKey + "|" + GetSetting(st) + "\n");
for ( SWares *ware = m_lWares.First(); ware; ware = m_lWares.Next() )
{
if ( ware->iTextID > 0 )
values += CyString("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 += CyString("Ware: ") + ware->cType + ":" + ware->iPrice + ":" + (long)ware->iSize + ":" + (long)ware->iVolumn + ":" + ware->sID + ":" + (long)ware->iNotority + "\n";
for ( SWaresText *wt = ware->lText.First(); wt; wt = ware->lText.Next() )
values += CyString("WareText: ") + (long)wt->iLang + " " + wt->sName + "|" + wt->sDesc + "\n";
}
return values;
}
CyString CSpkFile::GetCustomScriptType (int lang)
{
if ( !m_sScriptType.Empty() )
{
int max;
CyString *split = m_sScriptType.SplitToken("<br>", &max);
if ( max && split )
{
for ( int i = 1; i < max; i++ )
{
CyString str = split[i];
int num = str.GetToken(":", 1, 1).ToInt();
CyString name = str.GetToken(":", 2);
if ( num == lang )
{
CLEANSPLIT(split, max)
return name;
}
}
CyString ret = split[0];
CLEANSPLIT(split, max)
return ret;
}
CLEANSPLIT(split, max)
}
return m_sScriptType;
}
bool CSpkFile::WriteHeader(FILE *id, int valueheader, int valueComprLen)
{
fprintf ( id, "SPKCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );
if ( ferror(id) )
return false;
return true;
}
void CSpkFile::AddWareText ( CyString rest )
{
if ( !m_pLastWare )
return;
SWaresText *wt = new SWaresText;
wt->iLang = rest.GetToken ( 1, ' ' ).ToInt();
wt->sName = rest.GetToken ( 2, -1, ' ' ).GetToken ( 1, '|' );
wt->sDesc = rest.GetToken ( 2, -1, ' ' ).GetToken ( 2, -1, '|' );
m_pLastWare->lText.push_back ( wt );
m_bChanged = true;
}
void CSpkFile::AddWare ( CyString rest )
{
SWares *ware = new SWares;
ware->iTextID = -1;
ware->iTextPage = 0;
ware->cType = rest.GetToken ( 1, ':' )[0];
ware->iPrice = rest.GetToken ( 2, ':' ).ToLong();
ware->iSize = rest.GetToken ( 3, ':' ).ToInt();
ware->iVolumn = rest.GetToken ( 4, ':' ).ToInt();
ware->sID = rest.GetToken ( 5, ':' );
ware->iNotority = rest.GetToken ( 6, ':' ).ToInt();
if ( !rest.GetToken( 7, ':' ).Empty() )
{
CyString r = rest.GetToken ( 7, ':' );
ware->iTextID = r.GetToken(",", 1, 1).ToInt();
ware->iTextPage = r.GetToken(",", 2, 2).ToInt();
}
m_lWares.push_back ( ware );
m_pLastWare = ware;
m_bChanged = true;
}
bool CSpkFile::ReadFileToMemory ( C_File *file )
{
if ( !file )
return false;
// check if data is already extracted
if ( (file->GetDataSize ()) && (file->GetData()) )
return true;
// no file to read from
if ( m_sFilename.Empty() )
return false;
// now open the file
FILE *id = fopen ( m_sFilename.c_str(), "rb" );
if ( !id )
return false;
// read the header
GetEndOfLine ( id, NULL, false );
// skip past values
fseek ( id, m_SHeader.lValueCompressSize, SEEK_CUR );
// read the next header
GetEndOfLine ( id, NULL, false );
// skip past files
fseek ( id, 4, SEEK_CUR );
fseek ( id, m_SHeader2.lSize, SEEK_CUR );
// skip the icon file
if ( m_pIconFile )
{
fseek ( id, 4, SEEK_CUR );
fseek ( id, m_pIconFile->GetDataSize (), SEEK_CUR );
}
// now were in the file section
// skip past each one
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *fit = node->Data();
if ( fit == file )
break;
fseek ( id, 4, SEEK_CUR );
fseek ( id, fit->GetDataSize(), SEEK_CUR );
}
// now we should be at the start of the file
// read the data into memory
if ( !file->ReadFromFile ( id, file->GetDataSize() ) )
{
fclose ( id );
return false;
}
fclose ( id );
return true;
}
bool CSpkFile::CheckValidReadmes ()
{
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();
}
m_bChanged = true;
m_lWares.clear(true);
}
SWares *CSpkFile::FindWare ( CyString id )
{
for ( SWares *w = m_lWares.First(); w; w = m_lWares.Next() )
{
if ( w->sID.ToUpper() == id.ToUpper() )
return w;
}
return NULL;
}
void CSpkFile::RemoveWare ( CyString id )
{
for ( SWares *w = m_lWares.First(); w; w = m_lWares.Next() )
{
if ( w->sID.ToUpper() == id.ToUpper() )
{
m_lWares.RemoveCurrent ();
delete w;
m_bChanged = true;
return;
}
}
}
void CSpkFile::AddWare ( SWares *ware )
{
ware->sID.RemoveChar ( ' ' );
ware->sID = ware->sID.ToUpper();
SWares *newware = FindWare ( ware->sID );
if ( newware )
m_lWares.remove ( newware );
m_lWares.push_back ( ware );
m_bChanged = true;
}
void CSpkFile::AddWareText ( SWares *w, int lang, CyString name, CyString desc )
{
SWaresText *wt;
for ( wt = w->lText.First(); wt; wt = w->lText.Next() )
{
if ( wt->iLang == lang )
{
wt->sDesc = desc;
wt->sName = name;
return;
}
}
wt = new SWaresText;
wt->iLang = lang;
wt->sName = name;
wt->sDesc = desc;
w->lText.push_back ( wt );
m_bChanged = true;
}
void CSpkFile::ClearWareText ( CyString id )
{
SWares *w = FindWare ( id );
ClearWareText ( w );
}
void CSpkFile::ClearWareText ( SWares *w )
{
if ( !w ) return;
w->lText.clear(true);
m_bChanged = true;
}
void CSpkFile::RemoveWareText ( CyString wid, int lang )
{
SWares *w = FindWare ( wid );
if ( w )
{
for ( SWaresText *wt = w->lText.First(); wt; wt = w->lText.Next() )
{
if ( wt->iLang == lang )
{
w->lText.RemoveCurrent();
m_bChanged = true;
delete wt;
break;
}
}
}
}
int CSpkFile::CheckValidCustomStart ()
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *file = node->Data();
if ( file->GetFileType() != FILETYPE_SCRIPT )
continue;
CyString basename = file->GetName().GetToken ( 1, file->GetName().NumToken('.') - 1, '.' );
if ( basename.ToLower().Right(15) == ".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 ( CyString key, int type )
{
key.RemoveChar ( '|' );
SSettingType *t;
for ( t = m_lSettings.First(); t; t = m_lSettings.Next() )
{
if ( t->sKey.upper() == key.lower() )
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 = key;
t->iType = type;
m_lSettings.push_back ( t );
m_bChanged = true;
return t;
}
void CSpkFile::ConvertSetting ( SSettingType *t, CyString set )
{
if ( !t )
return;
switch ( t->iType )
{
case SETTING_STRING:
((SSettingString *)t)->sValue = set;
break;
case SETTING_INTEGER:
((SSettingInteger *)t)->iValue = set.ToInt();
break;
case SETTING_CHECK:
((SSettingCheck *)t)->bValue = set.ToBool();
break;
}
}
CyString CSpkFile::GetSetting ( SSettingType *t )
{
if ( !t )
return "";
switch ( t->iType )
{
case SETTING_STRING:
return ((SSettingString *)t)->sValue;
case SETTING_INTEGER:
return CyString::Number(((SSettingInteger *)t)->iValue);
case SETTING_CHECK:
return (((SSettingInteger *)t)->iValue) ? "1" : "0";
}
return "";
}
void CSpkFile::ClearSettings ()
{
m_lSettings.clear(true);
m_bChanged = true;
}
bool CSpkFile::IsMatchingMod ( CyString mod )
{
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;
CyString filename = file->GetBaseName();
if ( filename.lower() == mod.lower() )
return true;
}
return false;
}
CyString CSpkFile::GetScriptTypeString(int lang)
{
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 )
{
CyString type = this->GetCustomScriptType(lang);
if ( !type.Empty() )
return type;
iType = -1;
}
if (iType == -1) // no script type
{
if ( this->IsFakePatch() )
return "Fake Patch";
}
CyString sType = CSpkFile::GetScriptTypeStringStatic(m_iScriptType);
if ( sType.Empty() )
return "Other";
return sType;
}
int CSpkFile::ConvertScriptType(CyString sType)
{
for ( int i = 0; i < SCRIPTTYPE_MAX; i++ )
{
if ( sType.Compare(CSpkFile::GetScriptTypeStringStatic(i)) )
return i;
}
return -1;
}
CyString 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(CyString first, CyString rest)
{
if ( first.Compare("ScriptType") )
{
if ( rest.Compare("Library") || rest.Compare("Library Script") )
this->SetLibrary();
else if ( rest.Compare("Update") || rest.Compare("Package Update") || rest.Compare("Mod Update") )
this->SetPackageUpdate();
else if ( rest.Compare("Start") || rest.Compare("Custom Start") )
this->SetCustomStart();
else if ( rest.Compare("Patch") || rest.Compare("Patch Mod") )
this->SetPatch();
else
{
int check = rest.ToInt();
if ( check || rest == "0" )
m_iScriptType = check;
else
{
m_iScriptType = CSpkFile::ConvertScriptType(rest);
if ( m_iScriptType == -1 )
m_sScriptType = rest;
}
}
}
else if ( first.Compare("AnotherMod") )
{
m_sOtherName = rest.GetToken("|", 1, 1);
m_sOtherAuthor = rest.GetToken("|", 2);
}
else if ( first.Compare("WareName") || first.Compare("WareDesc") )
{
// find the ware to use
SWares *useWare = m_pLastWare;
CyString id = rest.GetToken(" ", 1, 1);
for ( CListNode<SWares> *wNode = m_lWares.Front(); wNode; wNode = wNode->next() )
{
if ( wNode->Data()->sID.Compare(id) )
{
useWare = wNode->Data();
break;
}
}
// check if we have the id already
if ( useWare )
{
int lang = rest.GetToken(" ", 2, 2).ToInt();
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 ( first.Compare("WareName") )
wt->sName = rest.GetToken(" ", 3);
else
wt->sDesc = rest.GetToken(" ", 3);
}
}
else if ( first.Left(4).Compare("Ware") )
{
SWares *ware = new SWares;
ware->iTextID = -1;
ware->iTextPage = 0;
ware->cType = first[4];
ware->iPrice = rest.GetToken ( " ", 2, 2 ).ToLong();
ware->iSize = rest.GetToken ( " ", 3, 3 ).ToInt();
ware->iVolumn = rest.GetToken ( " ", 4, 4 ).ToInt();
ware->sID = rest.GetToken ( " ", 1, 1 );
ware->iNotority = rest.GetToken ( " ", 5, 5 ).ToInt();
if ( !rest.GetToken(" ", 6, 6).Empty() )
{
ware->iTextID = rest.GetToken ( " ", 6, 6 ).GetToken(",", 2, 2).ToInt();
ware->iTextPage = rest.GetToken ( " ", 6, 6 ).GetToken(",", 1, 1).ToInt();
}
m_lWares.push_back ( ware );
m_pLastWare = ware;
}
else if ( CBaseFile::LoadPackageData(first, rest) )
return true;
else
return false;
return true;
}
bool CSpkFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
{
if ( !CBaseFile::GeneratePackagerScript(wildcard, list, datafile) )
return false;
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(CyString("ScriptType: ") + this->GetScriptTypeString(44));
list->PushBack("");
if ( this->IsAnotherMod() )
{
list->PushBack("# For another mod/package, this is a child package");
list->PushBack(CyString("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(CyString("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(CyString("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(CyString("WareName: ") + w->sID + " " + (long)wt->iLang + " " + wt->sName);
if ( !wt->sDesc.Empty() )
list->PushBack(CyString("WareDesc: ") + w->sID + " " + (long)wt->iLang + " " + wt->sDesc);
}
list->PushBack("");
}
}
if ( !datafile )
{
if ( !CBaseFile::GeneratePackagerScriptFile(wildcard, list) )
return false;
}
return true;
}
CyString CSpkFile::GetWareText(SWares *w, int lang)
{
// return the text page if being used
if ( w->iTextID > 0 && w->iTextPage > 0 )
return CyString("{") + (long)w->iTextPage + "," + (long)w->iTextID + "}";
CyString 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;
}
CyString CSpkFile::GetWareDesc(SWares *w, int lang)
{
// return the text page if being used
if ( w->iTextID > 0 && w->iTextPage > 0 )
return CyString("{") + (long)w->iTextPage + "," + ((long)w->iTextID + 1) + "}";
CyString 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;
}
CyString CSpkFile::GetCustomStartName()
{
if ( !this->IsCustomStart() )
return NullString;
// 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 NullString;
return file->GetFilename().GetToken(".", 2, 2);
}
void CSpkFile::MergePackage(CBaseFile *base)
{
// update version information
m_sVersion = base->GetVersion();
m_sCreationDate = base->GetCreationDate();
m_iPluginType = base->GetPluginType();
// 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
m_iGameChanging = base->GetGameChanging();
m_iRecommended = base->GetRecommended();
m_iEaseOfUse = base->GetEaseOfUse();
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, CyString::Number(gNode->Data()->iVersion));
}
if ( !base->GetWebAddress().Empty() )
m_sWebAddress = base->GetWebAddress();
if ( !base->GetWebSite().Empty() )
m_sWebSite = base->GetWebSite();
if ( !base->GetEmail().Empty() )
m_sEmail = base->GetEmail();
if ( !base->GetForumLink().Empty() )
m_sForumLink = base->GetForumLink();
m_sDescription = base->GetDescription();
// 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 any install text
for ( CListNode<SInstallText> *iNode = base->GetInstallTextList()->Front(); iNode; iNode = iNode->next() )
{
if ( !iNode->Data()->sAfter.Empty() )
this->AddInstallAfterText(iNode->Data()->iLanguage, iNode->Data()->sAfter);
if ( !iNode->Data()->sBefore.Empty() )
this->AddInstallBeforeText(iNode->Data()->iLanguage, iNode->Data()->sBefore);
}
for ( CListNode<SInstallText> *iNode = base->GetUninstallTextList()->Front(); iNode; iNode = iNode->next() )
{
if ( !iNode->Data()->sAfter.Empty() )
this->AddUninstallAfterText(iNode->Data()->iLanguage, iNode->Data()->sAfter);
if ( !iNode->Data()->sBefore.Empty() )
this->AddUninstallBeforeText(iNode->Data()->iLanguage, iNode->Data()->sBefore);
}
// 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::uncompressOldFile(const CyString &sOldFilename, int *pLen)
{
// firstcheck if the file exists
FILE *id = fopen ( ((CyString)sOldFilename).c_str(), "rb" );
if ( !id ) {
CLog::logf("Unable to open file: %s\n", ((CyString)sOldFilename).c_str());
return false;
}
// read the first 3 charaters to check if its using the original "HiP" compression
CyString check = (char)fgetc ( id );
check += (char)fgetc ( id );
check += (char)fgetc ( id );
CyString 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 *)((CyString)sOldFilename).c_str(), "uncompr.tmp" ) ) {
removeFile = "uncompr.tmp";
id = fopen ( "uncompr.tmp", "r" );
if ( id )
opened = true;
}
if ( !opened ) {
CLog::log("Unable to uncompress file, exiting...\n");
return false;
}
CLog::log("* Reading file into memory...\n");
// 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("* Reading file into memory...\n");
// 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("* Uncompressing file...\n");
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;
return uncomprData;
}
CyString CSpkFile::_convert_fileEndString(const CyString &sFile)
{
CyString temp = sFile;
if ( temp.Compare("Text") )
return "-- End of Script --";
else if ( temp.Compare("Uninstall") )
return "-- End of Uninstall --";
else if ( temp.Compare("Readme") )
return "-- End of Readme --";
else if ( temp.Compare("Map") )
return "-- End of Map --";
else if ( temp.Compare("Mod") || temp.Compare("Extra") || temp.Compare("Screen") || temp.Compare("Sound") )
return "";
return "-- End of Script --";
}
int CSpkFile::_convert_fileType(const CyString &sFile)
{
CyString temp = sFile;
if ( temp.Compare("Text") )
return FILETYPE_TEXT;
else if ( temp.Compare("Uninstall") )
return FILETYPE_UNINSTALL;
else if ( temp.Compare("Readme") )
return FILETYPE_README;
else if ( temp.Compare("Map") )
return FILETYPE_MAP;
else if ( temp.Compare("Mod") )
return FILETYPE_MOD;
else if ( temp.Compare("Extra") )
return FILETYPE_EXTRA;
else if ( temp.Compare("Screen") )
return FILETYPE_SCREEN;
else if ( temp.Compare("Sound") )
return FILETYPE_SOUND;
return FILETYPE_SCRIPT;
}
void CSpkFile::_convert_parse(const CyString &s_Cmd, const CyString &s_Rest, bool bVerbose)
{
CyString sCmd = s_Cmd;
CyString sRest = s_Rest;
if ( sCmd == "Name:" )
{
this->SetName ( sRest );
if ( bVerbose ) CLog::logf( "\tScript Name: %s\n", sRest.c_str() );
}
else if ( sCmd == "Author:" )
{
this->SetAuthor ( sRest );
if ( bVerbose ) CLog::logf( "\tScript Author: %s\n", sRest.c_str() );
}
else if ( sCmd == "CustomStart" )
{
this->SetCustomStart();
if ( bVerbose ) CLog::logf( "\tPackage is a custom start!!\n" );
}
else if ( sCmd == "AnotherMod:" )
{
this->SetAnotherMod ( sRest.GetToken ( 1, '|' ), sRest.GetToken ( 2, -1, '|' ) );
if ( bVerbose ) CLog::logf( "\tFor another Mod, Name: %s, Author: %s\n", this->GetOtherName().c_str(), this->GetOtherAuthor().c_str() );
}
else if ( sCmd == "PATCH" )
{
this->SetPatch();
if ( bVerbose ) CLog::logf("\tPackage is a Patch Mod!!\n" );
}
else if ( sCmd == "Version:" )
{
this->SetVersion ( sRest );
if ( bVerbose ) CLog::logf("\tScript Version: %s\n", sRest.c_str() );
}
else if ( sCmd == "Date:" )
{
this->SetCreationDate ( sRest );
if ( bVerbose ) CLog::logf("\tScript Creation Date: %s\n", sRest.c_str() );
}
else if ( sCmd == "Desc:" )
{
this->SetDescription ( sRest.FindReplace ( "<br>", "\n" ) );
if ( bVerbose ) CLog::logf("\tScript Description: %s\n", this->GetDescription().c_str() );
}
else if ( sCmd == "WebAddress:" )
{
this->SetWebAddress ( sRest );
if ( bVerbose ) CLog::logf("\tWeb Address: %s\n", sRest.c_str() );
}
else if ( sCmd == "WebMirror1:" )
{
this->AddWebMirror(sRest);
if ( bVerbose ) CLog::logf("\tWeb Mirror Address: %s\n", sRest.c_str() );
}
else if ( sCmd == "WebMirror2:" )
{
this->AddWebMirror(sRest);
if ( bVerbose ) CLog::logf("\tWeb Mirror Address: %s\n", sRest.c_str() );
}
else if ( sCmd == "ScriptType:" )
this->SetScriptType ( sRest );
else if ( sCmd == "WebSite:" )
{
this->SetWebSite ( sRest );
if ( bVerbose ) CLog::logf("\tWeb Site: %s\n", sRest.c_str() );
}
else if ( sCmd == "Email:" )
{
this->SetEmail ( sRest );
if ( bVerbose ) CLog::logf("\tAuthor Email Address: %s\n", 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 );
if ( bVerbose ) CLog::logf( "\tGame Version: %d\n", this->GetGameVersion () );
*/
}
else if ( sCmd == "Ware:" )
{
this->AddWare ( sRest );
if ( bVerbose ) CLog::logf( "\tAdding Custom Ware\n" );
}
else if ( sCmd == "WareText:" )
this->AddWareText ( sRest );
else if ( sCmd == "UninstallAfter:" )
this->AddUninstallAfterText ( sRest.GetToken ( 1, ' ' ).ToInt(), sRest.GetToken ( 2, -1, ' ' ) );
else if ( sCmd == "UninstallBefore:" )
this->AddUninstallBeforeText ( sRest.GetToken ( 1, ' ' ).ToInt(), sRest.GetToken ( 2, -1, ' ' ) );
else if ( sCmd == "InstallAfter:" )
this->AddInstallAfterText ( sRest.GetToken ( 1, ' ' ).ToInt(), sRest.GetToken ( 2, -1, ' ' ) );
else if ( sCmd == "InstallBefore:" )
this->AddInstallBeforeText ( sRest.GetToken ( 1, ' ' ).ToInt(), sRest.GetToken ( 2, -1, ' ' ) );
else if ( sCmd == "ScriptName:" )
{
CyString lang = sRest.GetToken ( 1, ':' );
CyString name = sRest.GetToken ( 2, -1, ':' );
this->AddLanguageName ( lang.ToInt(), name );
if ( bVerbose ) CLog::logf( "\tScript Name Language (%s) %s\n", lang.c_str(), name.c_str() );
}
}
CyString CSpkFile::_convert_parseFilename(const CyString &s_Rest, float fVersion, CyString *pDir)
{
CyString sFilename;
CyString sRest = s_Rest;
if ( fVersion >= 3.00f )
sFilename = sRest.GetToken ( 3, -1, ' ' );
else if ( fVersion >= 2.00f )
sFilename = sRest.GetToken ( 2, -1, ' ' );
else
sFilename = sRest;
if ( sFilename.IsIn ( "<br>" ) )
{
sFilename = sFilename.FindReplace ( "<br>", "|" );
if ( sFilename[0] == '|' ) {
sFilename = sFilename.GetToken ( 1, '|' );
}
else {
*pDir = sFilename.GetToken ( 1, '|' );
sFilename = sFilename.GetToken ( 2, -1, '|' );
}
}
return sFilename;
}
unsigned char *CSpkFile::_convert_parseFile(const CyString &s_Cmd, const CyString &s_Rest, float fVersion, unsigned char *d, bool bVerbose )
{
CyString sCmd = s_Cmd;
CyString sRest = s_Rest;
bool bShared = (sCmd.Left (9) == "$$$Shared") ? true : false;
CyString sFile = sCmd.Right(-3).Left(-1);
CyString sEnd = this->_convert_fileEndString(sFile);
int iType = this->_convert_fileType(sFile);
// convert the filename and directory
CyString dir, filename = _convert_parseFilename(sRest, fVersion, &dir);
// get the size and time
long time = 0, size = 0;
if ( fVersion >= 2.00f ) time = sRest.GetToken ( 1, ' ' ).ToLong();
if ( fVersion >= 3.00f ) size = sRest.GetToken ( 2, ' ' ).ToLong();
bool binaryRead = (CFileIO(filename).CheckFileExtension("PCK")) ? true : false;
if ( sEnd.Empty() ) binaryRead = true;
C_File *file = new C_File ();
if ( bVerbose )
{
if ( bShared )
CLog::logf( "\tFound %s File (Shared): %s, Reading...", sFile.c_str(), filename.c_str() );
else
CLog::logf( "\tFound %s File: %s, Reading...", sFile.c_str(), filename.c_str() );
}
// read the data
if ( binaryRead )
{
file->ReadFromData ( (char *)d, size );
d += size;
}
else
{
CyString 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( "(Done) Size: %s\n", file->GetDataSizeString().c_str() );
return d;
}
bool CSpkFile::convertOld(CyString &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->uncompressOldFile(sOldFilename, &len);
// uncomressed failed
if ( !uncomprData ) {
CLog::log("Error: Unable to uncompress the file\n");
return false;
}
// now we can read the data
unsigned char *d = uncomprData;
CyString str;
// CMultiSpkFile *mspk = NULL;
//SMultiSpkFile *cur_mspk = NULL;
int numscripts = 0, curscript = 0;
bool bVerbose = true;
float fVersion = 1;
CLog::log("* Reading spk data...\n");
while ( d )
{
// read the next line
d = str.GetEndOfLine(d);
if ( !d || d[0] == 0 ) {
break;
}
if ( str.Empty() ) {
continue;
}
CyString sCmd = str.GetToken ( 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;
}
*/
CyString sRest = str.GetToken ( 2, -1, ' ' );
if ( sCmd == "Packager:" ) {
fVersion = sRest.ToFloat ();
if ( bVerbose ) CLog::logf( "\tPackager Version: %.2f\n", fVersion );
}
else if ( sCmd == "Icon:" )
{
long size = sRest.GetToken ( 1, ' ' ).ToLong ();
C_File *file = new C_File ();
file->ReadFromData ( (char *)d, size );
d += size;
this->SetIcon(file, sRest.GetToken ( 2, ' ' ));
if ( bVerbose ) CLog::logf( "\tIcon (%s) Size: %s\n", ext.c_str(), file->GetDataSizeString ().c_str() );
}
else if ( sCmd.Left(3) == "$$$" )
d = _convert_parseFile(sCmd, sRest, fVersion, d, bVerbose);
else {
this->_convert_parse(sCmd, sRest, bVerbose);
}
}
if ( bVerbose ) CLog::logf( "* Reading spk data...\n" );
return true;
}