Rev 6 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
// SpkFile.cpp: implementation of the CSpkFile class.
//
//////////////////////////////////////////////////////////////////////
#include "SpkFile.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#include "spk.h"
#include "DirIO.h"
#include "File_IO.h"
#include "CatFile.h"
#include "archive/zip.h"
#include "Packages.h"
CSpkFile::CSpkFile() : CBaseFile ()
{
SetDefaults ();
m_iType = TYPE_SPK;
}
CSpkFile::~CSpkFile()
{
Delete ();
}
CArchiveFile::~CArchiveFile()
{
Delete ();
}
CArchiveFile::CArchiveFile() : CBaseFile ()
{
SetDefaults ();
m_iType = TYPE_ARCHIVE;
}
/*
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 CBaseFile::SetDefaults ()
{
m_pIconFile = NULL;
m_bAutoGenerateUpdateFile = false;
m_SHeader.iValueCompression = SPKCOMPRESS_ZLIB;
m_SHeader2.iFileCompression = SPKCOMPRESS_ZLIB;
m_SHeader2.iDataCompression = SPKCOMPRESS_LZMA;
m_pParent = NULL;
m_bChanged = false;
m_bUpdate = false;
m_iPluginType = PLUGIN_NORMAL;
ClearError();
m_iLoadError = 0;
m_bFullyLoaded = false;
m_bSigned = false;
m_bEnable = m_bGlobal = m_bProfile = m_bModifiedEnabled = true;
m_bOverrideFiles = false;
m_iRecommended = m_iEaseOfUse = m_iGameChanging = -1;
}
CBaseFile::CBaseFile()
{
SetDefaults ();
m_iType = TYPE_BASE;
}
CBaseFile::~CBaseFile()
{
Delete();
}
void CSpkFile::Delete ()
{
m_lWares.clear(true);
m_lSettings.clear(true);
CBaseFile::Delete ();
}
void CBaseFile::Delete ()
{
m_lFiles.clear(true);
if ( m_pIconFile )
{
delete m_pIconFile;
m_pIconFile = NULL;
}
m_lInstallText.clear(true);
m_lUninstallText.clear(true);
m_lNames.clear(true);
}
CyString CBaseFile::GetLanguageName ( int lang )
{
for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )
{
SNames *n = node->Data();
if ( n->iLanguage == lang )
return n->sName;
}
return m_sName;
}
/*
##########################################################################################
################## Base Class Functions ##################
##########################################################################################
*/
CLinkList<C_File> *CBaseFile::GetFileList(int type)
{
CLinkList<C_File> *list = new CLinkList<C_File>;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f->GetFileType() == type )
list->push_back(f);
}
return list;
}
C_File *CBaseFile::GetNextFile(C_File *prev)
{
int type = -1;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( type == -1 )
{
if ( f == prev )
type = f->GetFileType();
}
else
{
if ( f->GetFileType() == type )
return f;
}
}
return NULL;
}
C_File *CBaseFile::GetPrevFile(C_File *next)
{
if ( !next )
return NULL;
int type = -1;
for ( CListNode<C_File> *node = m_lFiles.Back(); node; node = node->prev() )
{
C_File *f = node->Data();
if ( type == -1 )
{
if ( f == next )
type = f->GetFileType();
}
else
{
if ( f->GetFileType() == type )
return f;
}
}
return NULL;
}
C_File *CBaseFile::GetFirstFile(int type)
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f->GetFileType() == type )
return f;
}
return NULL;
}
int CBaseFile::CheckFile ( CyString filename, float *version )
{
FILE *id = fopen ( filename.c_str(), "rb" );
if ( !id )
return false;
CyString line = GetEndOfLine ( id, NULL, false );
CyString type = line.GetToken ( 1, ';' );
fclose ( id );
// check for old version
if ( line.Left(3) == "HiP" )
return SPKFILE_OLD;
// check for format
if ( version )
*version = line.GetToken ( 2, ';' ).ToFloat();
if ( type == "BaseCycrow" )
return SPKFILE_BASE;
if ( type == "SPKCycrow" )
return SPKFILE_SINGLE;
if ( type == "XSPCycrow" )
return SPKFILE_SINGLESHIP;
if ( type == "MSPKCycrow" )
return SPKFILE_MULTI;
return SPKFILE_INVALID;
}
void CBaseFile::ClearFileData()
{
for ( C_File *f = m_lFiles.First(); f; f = m_lFiles.Next() )
{
f->DeleteData();
}
}
CyString CBaseFile::GetNameValidFile ()
{
CyString name = m_sName;
name.RemoveChar ( ':' );
name.RemoveChar ( '/' );
name.RemoveChar ( '\\' );
name.RemoveChar ( '*' );
name.RemoveChar ( '?' );
name.RemoveChar ( '"' );
name.RemoveChar ( '<' );
name.RemoveChar ( '>' );
name.RemoveChar ( '|' );
return name;
}
void CBaseFile::SwitchFilePointer(C_File *oldFile, C_File *newFile)
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f == oldFile )
{
node->ChangeData(newFile);
break;
}
}
}
bool CBaseFile::AnyFileType ( int type )
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f->GetFileType() == type )
return true;
}
return false;
}
void CBaseFile::AddFile ( C_File *file )
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f->GetFileType() != file->GetFileType() )
continue;
if ( f->GetName() != file->GetName () )
continue;
if ( f->GetDir() != file->GetDir() )
continue;
if ( f->GetGame() != file->GetGame() )
continue;
m_lFiles.remove(node, true);
break;
}
file->UpdateSigned();
m_bChanged = true;
m_lFiles.push_back ( file );
}
C_File *CBaseFile::AddFile ( CyString file, CyString dir, int type, int game )
{
C_File *newfile = new C_File ( file );
newfile->SetDir ( dir );
newfile->SetFileType ( type );
newfile->SetGame(game);
// first check if the file already exists
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f->GetFileType() != newfile->GetFileType() )
continue;
if ( f->GetName() != newfile->GetName () )
continue;
if ( f->GetDir() != newfile->GetDir() )
continue;
if ( f->GetGame() != newfile->GetGame() )
continue;
// must already exist, delete this one
m_lFiles.remove(node, true);
break;
}
m_bChanged = true;
newfile->UpdateSigned();
m_lFiles.push_back ( newfile );
return newfile;
}
bool CBaseFile::AddFileNow ( CyString file, CyString dir, int type, CProgressInfo *progress )
{
C_File *f = AddFile ( file, dir, type );
if ( !f->ReadFromFile () )
return false;
// compress the file
return f->CompressData ( m_SHeader2.iDataCompression, progress );
}
C_File *CBaseFile::AppendFile ( CyString file, int type, int game, CyString dir, CProgressInfo *progress )
{
C_File *newfile = AddFile ( file, dir, type, game );
if ( !newfile )
return NULL;
// read the file into memory
if ( newfile->ReadFromFile () )
{
// now compress the file
if ( newfile->CompressData ( m_SHeader2.iDataCompression, progress ) )
return newfile;
}
else if ( newfile->GetLastError() == SPKERR_MALLOC )
{
if ( newfile->CompressFile ( progress ) )
return newfile;
}
m_lFiles.pop_back ();
delete newfile;
return NULL;
}
C_File *CBaseFile::FindFileAt ( int filetype, int pos )
{
int count = 0;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *file = node->Data();
if ( file->GetFileType() != filetype )
continue;
if ( count == pos )
return file;
++count;
}
return NULL;
}
C_File *CBaseFile::FindFile ( CyString filename, int type, CyString dir, int game )
{
CyString lfile = filename.ToLower();
lfile = lfile.FindReplace ( "\\", "/" );
lfile = lfile.GetToken ( lfile.NumToken('/'), '/' );
CListNode<C_File> *node = m_lFiles.Front();
while ( node )
{
C_File *f = node->Data();
node = node->next();
if ( type != f->GetFileType() )
continue;
if ( dir != f->GetDir() )
continue;
if ( game != f->GetGame() )
continue;
if ( f->GetName().ToLower() == lfile )
return f;
}
return NULL;
}
bool CBaseFile::RemoveFile ( CyString file, int type, CyString dir, int game )
{
C_File *f = FindFile (file, type, dir, game);
if ( !f )
return false;
return RemoveFile ( f );
}
bool CBaseFile::RemoveFile ( C_File *file )
{
int count = 0;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *f = node->Data();
if ( f == file )
return RemoveFile ( count );
++count;
}
return false;
}
bool CBaseFile::RemoveFile ( int pos )
{
if ( (pos < 0) || (pos >= m_lFiles.size()) )
return false;
C_File *file = m_lFiles.Get ( pos );
m_lFiles.erase ( pos + 1 );
if ( file )
delete file;
m_bChanged = true;
return true;
}
void CBaseFile::RemoveAllFiles ( int type, int game )
{
if ( m_lFiles.empty() )
return;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
if ( game > -1 ) {
if ( node->Data()->GetGame() != game )
continue;
}
if ( type == -1 || node->Data()->GetFileType() == type )
node->DeleteData();
}
m_lFiles.RemoveEmpty();
m_bChanged = true;
}
void CBaseFile::RecompressAllFiles ( int type, CProgressInfo *progress )
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *file = node->Data();
if ( progress )
progress->UpdateFile(file);
if ( file->GetCompressionType() == type )
continue;
if ( !file->GetData() )
file->ReadFromFile();
file->ChangeCompression ( type, progress );
}
}
void CBaseFile::CompressAllFiles ( int type, CProgressInfo *progress, int level )
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *file = node->Data();
if ( progress )
progress->UpdateFile(file);
if ( !file->GetData() )
file->ReadFromFile();
file->CompressData ( type, progress, level );
}
}
bool CBaseFile::UncompressAllFiles ( CProgressInfo *progress )
{
int countFile = 0;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *fit = node->Data();
if ( progress )
{
progress->UpdateFile ( fit );
progress->UpdateProgress(countFile++, m_lFiles.size());
}
bool uncomprToFile = false;
if ( progress )
progress->SwitchSecond();
if ( !fit->UncompressData ( progress ) )
{
if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP )
{
if ( !fit->UncompressToFile ( "temp", this, false, progress ) )
return false;
else
{
uncomprToFile = true;
fit->SetFullDir ( "temp" );
}
}
if ( !uncomprToFile )
return false;
}
if ( progress )
progress->SwitchSecond();
}
return true;
}
long CBaseFile::GetFullFileSize()
{
long fullsize = 1000;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
fullsize += node->Data()->GetUncompressedDataSize();
if ( m_pIconFile )
fullsize += m_pIconFile->GetUncompressedDataSize();
return fullsize;
}
/*
Func: GetEndOfLine
Input: id - The file id for the current file to read from
line - Pointed to hold the line number thats read
upper - true if it converts to uppercase
Return: String - the string it has read
Desc: Reads a string from a file, simlar to readLine() classes, reads to the end of the line in a file
*/
CyString CBaseFile::GetEndOfLine ( FILE *id, int *line, bool upper )
{
CyString word;
char c = fgetc ( id );
if ( c == -1 )
return "";
while ( (c != 13) && (!feof(id)) && (c != '\n') )
{
word += c;
c = fgetc ( id );
}
if ( line )
++(*line);
if ( upper )
return word.ToUpper();
return word;
}
int CBaseFile::CountFiles ( int filetype )
{
int i = 0;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *file = node->Data();
if ( file->GetFileType() != filetype )
continue;
++i;
}
return i;
}
void CBaseFile::ClearNames ()
{
m_lNames.clear(true);
}
void CBaseFile::RemoveLanguageName ( int lang )
{
SNames *n;
for ( n = m_lNames.First(); n; n = m_lNames.Next() )
{
if ( n->iLanguage == lang )
{
m_lNames.RemoveCurrent();
delete n;
m_bChanged = true;
}
}
}
void CBaseFile::AddLanguageName ( int lang, CyString name )
{
// first check for an existing language
SNames *n;
for ( n = m_lNames.First(); n; n = m_lNames.Next() )
{
if ( n->iLanguage == lang )
{
n->sName = name;
return;
}
}
// not found, add a new entry
n = new SNames;
n->iLanguage = lang;
n->sName = name;
m_lNames.push_back ( n );
m_bChanged = true;
}
/*
Func: AddInstallText
Input: before - true for before text, false for after text
install - true to add to install text list, false for unisntall text list
lang - string containing the language to use
data - The text to add for the language
Return: install text - Returns the text struct that it used to add
Desc: Adds the text to list, adds either install or uninstall text
If language already exists, then its overwritten
Allows adding before and after seperatly to the same entry
*/
SInstallText *CBaseFile::AddInstallText ( bool before, bool install, int lang, CyString data )
{
CLinkList<SInstallText> *list = NULL;
if ( install )
list = &m_lInstallText;
else
list = &m_lUninstallText;
SInstallText *unist = NULL;
// check if language already exists and overright if needed
for ( SInstallText *u = list->First(); u; u = list->Next() )
{
if ( u->iLanguage == lang )
{
unist = u;
break;
}
}
if ( !unist )
{
unist = new SInstallText;
unist->iLanguage = lang;
if ( lang == 0 )
list->push_front ( unist );
else
list->push_back ( unist );
}
if ( !before )
unist->sAfter = data;
else
unist->sBefore = data;
m_bChanged = true;
return unist;
}
SInstallText *CBaseFile::FindInstallText ( bool install, int lang )
{
CLinkList<SInstallText> *list = NULL;
if ( install )
list = &m_lInstallText;
else
list = &m_lUninstallText;
for ( SInstallText *it = list->First(); it; it = list->Next() )
{
if ( it->iLanguage == lang )
return it;
}
return NULL;
}
void CBaseFile::AddInstallText ( SInstallText *add )
{
SInstallText *it = FindInstallText ( true, add->iLanguage );
if ( it == add )
return;
if ( it )
{
m_lInstallText.remove ( it );
delete it;
}
m_bChanged = true;
m_lInstallText.push_back ( add );
}
void CBaseFile::AddUninstallText ( SInstallText *add )
{
SInstallText *it = FindInstallText ( false, add->iLanguage );
if ( it == add )
return;
if ( it )
{
m_lUninstallText.remove ( it );
delete it;
}
m_bChanged = true;
m_lUninstallText.push_back ( add );
}
void CBaseFile::RemoveInstallText ( bool install, int lang )
{
SInstallText *it = FindInstallText ( install, lang );
if ( it )
{
if ( install )
m_lInstallText.remove ( it );
else
m_lUninstallText.remove ( it );
delete it;
m_bChanged = true;
}
}
bool CBaseFile::IsThereInstallText ( bool install )
{
CLinkList<SInstallText> *list = NULL;
if ( install )
list = &m_lInstallText;
else
list = &m_lUninstallText;
if ( list->size() > 1 )
return true;
if ( list->size() <= 0 )
return false;
SInstallText *it = list->First();
if ( !it->sAfter.Empty() )
return true;
if ( !it->sBefore.Empty() )
return true;
return false;
}
CyString CBaseFile::GetBeforeText ( CLinkList<SInstallText> *list, int lang, bool noDefault )
{
CyString beforetext;
for ( SInstallText *u = list->First(); u; u = list->Next() )
{
if ( !noDefault )
{
if ( (beforetext.Empty()) && (u->iLanguage == 0) )
beforetext = u->sBefore;
}
if ( (u->iLanguage == lang) && (!u->sBefore.Empty()) )
beforetext = u->sBefore;
}
return beforetext;
}
CyString CBaseFile::GetAfterText ( CLinkList<SInstallText> *list, int lang, bool noDefault )
{
CyString text;
for ( SInstallText *u = list->First(); u; u = list->Next() )
{
if ( (u->iLanguage == lang) && (!u->sAfter.Empty()) )
text = u->sAfter;
if ( !noDefault )
{
if ( (text.Empty()) && (u->iLanguage == 0) )
text = u->sAfter;
}
}
return text;
}
CyString CBaseFile::GetFullPackageName(CyString format, int lang)
{
if ( format.Empty() )
return GetFullPackageName(lang);
CyString args[3] = { this->GetLanguageName(lang), this->GetVersion(), this->GetAuthor() };
return format.Args(args, 3);
}
/*
Func: CreateFilesLine
Return: String - returns the full string for files list
Desc: Creates a signle line list of all the files
*/
CyString CBaseFile::CreateFilesLine ( bool updateheader, CProgressInfo *progress )
{
CyString line;
if ( progress )
{
progress->SetDone(0);
progress->UpdateStatus(STATUS_COMPRESS);
}
if ( updateheader )
{
m_SHeader2.iNumFiles = 0;
m_SHeader2.lFullSize = 0;
}
if ( m_pIconFile )
{
// no data, read it from file
if ( !m_pIconFile->GetData() )
m_pIconFile->ReadFromFile ();
// compress the file
if ( !m_pIconFile->CompressData ( m_SHeader2.iDataCompression, progress ) )
m_pIconFile->SetDataCompression(SPKCOMPRESS_NONE);
line += CyString("Icon:") + (m_pIconFile->GetDataSize() + (long)4) + ":" + m_pIconFile->GetUncompressedDataSize() + ":" + (long)m_pIconFile->GetCompressionType() + ":" + m_sIconExt + "\n";
if ( updateheader )
{
++m_SHeader2.iNumFiles;
m_SHeader2.lFullSize += (m_pIconFile->GetDataSize() + 4);
}
}
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *file = node->Data();
if ( progress )
progress->UpdateFile ( file );
// no data, read it from file
if ( !file->GetData() )
{
if ( !file->ReadFromFile () )
{
if ( file->GetLastError() == SPKERR_MALLOC )
{
if ( !file->CompressFile ( progress ) )
continue;
}
}
}
if ( !file->GetData() )
continue;
// compress the file
if ( !file->CompressData ( m_SHeader2.iDataCompression, progress ) )
{
file->SetDataCompression(SPKCOMPRESS_NONE);
file->SetUncompressedDataSize(file->GetDataSize());
}
CyString command = GetFileTypeString ( file->GetFileType() );
if ( command.Empty() )
continue;
if ( file->IsShared() )
command = CyString("$") + command;
if ( file->GetDir().Empty() )
line += (command + ":" + (file->GetDataSize() + (long)4) + ":" + file->GetUncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->GetFilename() + ":GAME_" + (long)file->GetGame() + "\n");
else
line += (command + ":" + (file->GetDataSize() + (long)4) + ":" + file->GetUncompressedDataSize() + ":" + (long)file->GetCompressionType() + ":" + (long)file->GetCreationTime() + ":" + ((file->IsCompressedToFile()) ? "1" : "0") + ":" + file->GetFilename() + ":" + file->GetDir() + ":GAME_" + (long)file->GetGame() + "\n");
if ( updateheader )
{
++m_SHeader2.iNumFiles;
m_SHeader2.lFullSize += (file->GetDataSize() + 4);
}
}
return line;
}
/*
######################################################################################
########## Reading Functions ##########
######################################################################################
*/
void CBaseFile::ReadAllFilesToMemory ()
{
// no file to read from
if ( m_sFilename.Empty() )
return;
// now open the file
FILE *id = fopen ( m_sFilename.c_str(), "rb" );
if ( !id )
return;
// read the header
GetEndOfLine ( id, NULL, false );
// skip past values
fseek ( id, 4, SEEK_CUR );
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 );
if ( m_pIconFile )
{
if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )
m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );
else
{
fseek ( id, 4, SEEK_CUR );
fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );
}
}
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *fit = node->Data();
if ( (!fit->GetData()) && (!fit->Skip()) )
fit->ReadFromFile ( id, fit->GetDataSize() );
else
{
fseek ( id, 4, SEEK_CUR );
fseek ( id, fit->GetDataSize(), SEEK_CUR );
}
}
fclose ( id );
}
bool CBaseFile::ReadFileToMemory(C_File *f)
{
if ( f->GetData() && f->GetDataSize() )
return true;
// no file to read from
if ( m_sFilename.Empty() || !f )
return false;
// check the file is part of the package
if ( !m_lFiles.FindData(f) )
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, 4, SEEK_CUR );
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 );
if ( m_pIconFile )
{
fseek ( id, 4, SEEK_CUR );
fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );
}
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *fit = node->Data();
if (fit == f )
{
fit->ReadFromFile ( id, fit->GetDataSize() );
break;
}
else
{
fseek ( id, 4, SEEK_CUR );
fseek ( id, fit->GetDataSize(), SEEK_CUR );
}
}
fclose(id);
return true;
}
void CBaseFile::ReadIconFileToMemory ()
{
// no file to read from
if ( m_sFilename.Empty() )
return;
if ( !m_pIconFile )
return;
// now open the file
FILE *id = fopen ( m_sFilename.c_str(), "rb" );
if ( !id )
return;
// read the header
GetEndOfLine ( id, NULL, false );
// skip past values
fseek ( id, 4, SEEK_CUR );
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 );
if ( m_pIconFile )
{
if ( (!m_pIconFile->GetData()) && (!m_pIconFile->Skip()) )
m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );
else
{
fseek ( id, 4, SEEK_CUR );
fseek ( id, m_pIconFile->GetDataSize(), SEEK_CUR );
}
}
fclose ( id );
}
bool CBaseFile::InstallFiles ( CyString destdir, CProgressInfo *progress, CLinkList<C_File> *filelist, CyStringList *errorStr, bool enabled, CPackages *packages )
{
// first rename any fake patches
CyStringList lPatches;
if ( enabled )
{
int startfake = 1;
while ( startfake < 99 )
{
CyString filename = destdir;
if ( !filename.Empty() )
filename += "/";
filename += CyString::Number((long)startfake).PadNumber(2);
if ( !CFileIO(filename + ".cat").Exists() )
{
if ( !CFileIO(filename + ".dat").Exists() )
break;
}
startfake++;
}
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *fit = node->Data();
// only do fake patchs
if ( !fit->IsFakePatch() )
continue;
if ( !fit->CheckFileExt ("cat") && !fit->CheckFileExt("dat") )
continue;
// search for the name on the list
SStringList *opposite = lPatches.FindString(fit->GetBaseName());
CyString newname;
if ( opposite )
newname = opposite->data;
else
{
newname = CyString::Number((long)startfake).PadNumber(2);
lPatches.PushBack(fit->GetBaseName(), newname);
}
// rename the file
fit->FixOriginalName();
fit->SetName ( newname + "." + fit->GetFileExt() );
// find the next gap
if ( !opposite )
{
startfake++; // make sure we moved past the one we've just used
while ( startfake < 99 )
{
CyString filename = destdir;
if ( !filename.Empty() )
filename += "/";
filename += CyString::Number((long)startfake).PadNumber(2);
if ( !CFileIO(filename + ".cat").Exists() )
{
if ( !CFileIO(filename + ".dat").Exists() )
break;
}
startfake++;
}
}
}
// find renable text file
if ( packages )
{
int starttext = 3;
while ( starttext < 9999 )
{
CyString filename = destdir;
if ( !filename.Empty() )
filename += "/t/";
filename += SPK::FormatTextName(starttext, packages->GetLanguage(), (packages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));
if ( !CFileIO(filename + ".xml").Exists() )
{
if ( !CFileIO(filename + ".pck").Exists() )
break;
}
starttext++;
}
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *fit = node->Data();
if ( !fit->IsAutoTextFile() )
continue;
CyString newname = SPK::FormatTextName(starttext, packages->GetLanguage(), (packages->GetCurrentGameFlags() & EXEFLAG_TCTEXT));
fit->FixOriginalName();
fit->SetName ( newname + "." + fit->GetFileExt() );
++starttext;
}
}
}
CDirIO Dir(destdir);
int fileCount = 0;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *fit = node->Data();
bool fileEnabled = enabled;
if ( !fileEnabled )
{
if ( (fit->GetFileType() == FILETYPE_UNINSTALL) || (fit->GetFileType() == FILETYPE_README) || (fit->GetFileType() == FILETYPE_ADVERT) )
fileEnabled = true;
else if ( (fit->GetFileType() == FILETYPE_EXTRA) && (fit->GetDir().Left(7).ToLower() == "Extras/") )
fileEnabled = true;
else if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) && (!fit->IsFakePatch()) )
fileEnabled = true;
}
if ( fit->GetGame() && packages->GetGame() ) {
if ( fit->GetGame() != packages->GetGame() )
continue;
}
if ( progress )
{
if ( progress->IsSecond() )
progress->SwitchSecond();
progress->UpdateFile ( fit );
progress->UpdateProgress(fileCount++, m_lFiles.size());
progress->SwitchSecond();
}
// first uncompress the file
bool uncomprToFile = false;
m_sLastError = fit->GetNameDirectory(this);
m_iLastError = SPKERR_UNCOMPRESS;
if ( !fit->UncompressData ( progress ) )
{
if ( fit->GetCompressionType() == SPKCOMPRESS_7ZIP )
{
if ( fit->UncompressToFile ( NullString, this, false, progress ) )
uncomprToFile = true;
}
if ( !uncomprToFile )
{
if ( errorStr )
errorStr->PushBack(m_sLastError, ERRORLOG(SPKINSTALL_UNCOMPRESS_FAIL));
return false;
}
}
ClearError ();
bool dofile = true;
// new check if we should install the file
// first get the version
if ( fit->ReadScriptVersion () && !m_bOverrideFiles )
{
C_File checkfile;
CyString checkfilename = destdir;
if ( !checkfilename.Empty() )
checkfilename += "/";
checkfilename += fit->GetNameDirectory(this);
checkfile.SetFilename ( checkfilename );
checkfile.SetFileType ( fit->GetFileType() );
if ( checkfile.CheckValidFilePointer() )
{
if ( checkfile.ReadScriptVersion() > fit->GetVersion() )
dofile = false;
}
}
// change file pointer
CyString filename = destdir;
if ( !filename.Empty() )
filename += "/";
if ( (IsPatch()) && (fit->GetFileType() == FILETYPE_MOD) )
fit->SetDir ( CyString("Patch") );
if ( fit->IsInMod() )
{
if ( fileEnabled )
fit->SetFilename(filename + fit->GetInMod() + "::" + fit->GetNameDirectory(this));
else
fit->SetFilename(filename + "PluginManager/DisabledFiles.cat::" + fit->GetNameDirectory(this));
}
else
fit->SetFilename ( filename + fit->GetNameDirectory(this) );
if ( !fileEnabled )
{
if ( !fit->IsInMod() )
{
if ( fit->IsFakePatch() )
fit->SetFilename ( filename + "PluginManager/Disabled/FakePatches/FakePatch_" + this->GetNameValidFile() + "_" + m_sAuthor + "_" + fit->GetName() );
else if ( fit->IsAutoTextFile() )
fit->SetFilename ( filename + "PluginManager/Disabled/TextFiles/Text_" + this->GetNameValidFile() + "_" + m_sAuthor + "_" + fit->GetName() );
else
fit->SetFullDir ( filename + "PluginManager/Disabled/" + fit->GetDirectory(this) );
}
fit->SetDisabled(true);
}
C_File *adjustPointer = NULL;
bool checkFile = dofile;
if ( filelist )
{
C_File *cFile = NULL;
if ( checkFile )
{
if ( !fit->IsFakePatch() && fit->GetFileType() != FILETYPE_README )
{
for ( cFile = filelist->First(); cFile; cFile = filelist->Next() )
{
if ( !cFile->MatchFile ( fit ) )
continue;
if ( !m_bOverrideFiles && !cFile->CompareNew ( fit ) )
{
if ( errorStr )
errorStr->PushBack(fit->GetNameDirectory(this), ERRORLOG(SPKINSTALL_SKIPFILE));
dofile = false;
}
break;
}
}
}
// no matching file found, adding to main list
if ( !cFile )
filelist->push_back ( fit );
else
{
// if the file is not enabled, we need to check for any that might be enabled
if ( !fileEnabled )
{
if ( !cFile->GetUsed() )
{
CFileIO rFile(cFile->GetFilePointer());
if ( rFile.Exists() )
{
if ( errorStr )
{
if ( rFile.Remove() )
errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE));
else
errorStr->PushBack(cFile->GetFilePointer().Remove(destdir), ERRORLOG(SPKINSTALL_DELETEFILE_FAIL));
}
}
cFile->SetFilename(fit->GetFilePointer());
cFile->SetDisabled(true);
}
else
{
fit->SetFullDir ( filename + fit->GetDirectory(this) );
fit->SetDisabled(false);
}
}
else
// move it to enabled
{
// found a file, check if its in the disabled directory
CyString dir = cFile->GetFilePointer();
dir = dir.GetToken ( 1, dir.NumToken ('/') - 1, '/' );
CyString lastDir = dir.GetToken ( dir.NumToken('/'), '/' ).ToLower();
// if its disabled, rename it so its enabled
if ( ((cFile->IsDisabled()) || (lastDir == "disabled") || (dir.ToLower().IsIn ("/disabled/"))) && (enabled) )
{
// first check if the directory exists
if ( cFile->IsInMod() )
{
CyString tofile = cFile->GetFilePointer().GetToken("::", 2, 2);
CCatFile tocat;
int err = tocat.Open ( fit->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, true );
if ( (err == CATERR_NONE) || (err == CATERR_CREATED) )
{
tocat.AppendFile ( cFile->GetFilePointer(), tofile );
}
CCatFile fromcat;
err = fromcat.Open ( cFile->GetFilePointer().GetToken("::", 1, 1), "", CATREAD_CATDECRYPT, false );
if ( err == CATERR_NONE )
{
fromcat.RemoveFile(tofile);
}
cFile->SetFilename ( fit->GetFilePointer() );
cFile->SetInMod(fit->GetInMod());
}
else
{
CyString to = cFile->GetDirectory(this);
CDirIO Dir(destdir);
if ( !Dir.Exists(to) )
{
if ( !Dir.Create ( to ) )
{
if ( errorStr )
errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
return false;
}
if ( errorStr )
errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
}
CyString destfile = destdir + "/" + cFile->GetNameDirectory(this);
if ( CFileIO(destfile).Exists() )
CFileIO(destfile).Remove();
rename ( cFile->GetFilePointer().c_str(), destfile.c_str() );
cFile->SetFilename ( destdir + "/" + cFile->GetNameDirectory(this) );
}
cFile->SetDisabled(false);
if ( !dofile && errorStr )
errorStr->PushBack(cFile->GetNameDirectory(this), ERRORLOG(SPKINSTALL_ENABLEFILE));
}
}
adjustPointer = cFile;
if ( dofile )
adjustPointer->SetCreationTime ( fit->GetCreationTime() );
}
}
if ( dofile )
{
// uncompressed to file, rename and move
if ( uncomprToFile )
{
m_iLastError = SPKERR_WRITEFILE;
CyString to = fit->GetDirectory(this);
//to = to.GetToken ( 1, to.NumToken ('/') - 1, '/' );
if ( !fileEnabled )
to = CyString("PluginManager/Disabled/") + to;
CDirIO Dir(destdir);
if ( !Dir.Exists(to) )
{
if ( !Dir.Create ( to ) )
{
if ( errorStr )
errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
return false;
}
if ( errorStr )
errorStr->PushBack(to, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
}
int err = 1;
m_sLastError = to;
if ( !fit->GetTempFile ().Empty() )
err = rename ( fit->GetTempFile().c_str(), to.c_str() );
if ( err )
return false;
}
//otherwise, just extract the file
else
{
// old file is found in list, switch to using new one
if ( (filelist) && (adjustPointer) )
adjustPointer->CopyData(fit, false);
CyString fpointer = fit->GetFilePointer();
m_iLastError = SPKERR_CREATEDIRECTORY;
CyString dir = fit->GetFilePointer().GetToken ( "/", 1, fit->GetFilePointer().NumToken("/") - 1 );
dir = dir.Remove(destdir);
if ( dir[0] == '/' || dir[0] == '\\' )
dir.Erase(0, 1);
m_sLastError = dir;
if ( !dir.IsIn ( "::" ) )
{
if ( !Dir.Exists(dir) )
{
if ( !Dir.Create(dir) )
{
if ( errorStr )
errorStr->PushBack(dir, ERRORLOG(SPKINSTALL_CREATEDIRECTORY_FAIL));
return false;
}
if ( errorStr )
errorStr->PushBack(dir, ERRORLOG(SPKINSTALL_CREATEDIRECTORY));
}
}
else
fit->SetFilename(CCatFile::PckChangeExtension(fit->GetFilePointer()));
m_iLastError = SPKERR_WRITEFILE;
m_sLastError = fit->GetFilePointer();
CyString sInstalledFile = fit->GetNameDirectory(this);
if ( fit->IsDisabled() )
{
sInstalledFile = fit->GetFilePointer().Remove(destdir);
if ( sInstalledFile[0] == '/' || sInstalledFile[0] == '\\' )
sInstalledFile.Erase(0, 1);
}
if ( !fit->WriteFilePointer() )
{
if ( errorStr )
errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE_FAIL));
}
else
{
fit->UpdateSigned();
if ( errorStr )
errorStr->PushBack(sInstalledFile, ERRORLOG(SPKINSTALL_WRITEFILE));
switch(fit->GetFileType())
{
case FILETYPE_SCRIPT:
case FILETYPE_UNINSTALL:
fit->UpdateSignature();
break;
}
}
}
ClearError ();
}
if ( adjustPointer )
{
node->ChangeData(adjustPointer);
delete fit;
}
}
// now clear or data memory
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
// add plugin manager file to identify fake patches
/*
if ( fit->IsFakePatch() && fit->CheckFileExt ("cat") )
{
CFileIO plugin("pluginmanager.txt");
std::vector<CyString> lines;
CyString version;
version.FromFloat(GetLibraryVersion(), 2);
SStringList *strList = lPatches.FindData(fit->GetBaseName());
CyString baseName;
if ( strList )
baseName = strList->str;
else
baseName = fit->GetBaseName();
lines.push_back(CyString("FakePatch:") + baseName);
lines.push_back(CyString("spklibrary:") + version);
lines.push_back(CyString("Package:") + m_sName);
lines.push_back(CyString("Author:") + m_sAuthor);
lines.push_back(CyString("OriginalFile:") + fit->GetOriginalName());
if ( plugin.WriteFile(&lines) )
{
CCatFile cat;
if ( cat.Open(fit->GetFilePointer(), CATREAD_DAT, false) == CATERR_NONE )
{
cat.AppendFile(plugin.GetFilename(), plugin.GetFilename(), true);
cat.WriteCatFile();
}
plugin.Remove();
}
}
*/
node->Data()->DeleteData();
}
return true;
}
/*######################################################################################################*/
/*
Func: ParseHeader
Input: Header String - string formated directly from the file
Return: Boolean - If string is a valid header
Desc: Splits up the main header string to get all required settings
*/
bool CBaseFile::ParseHeader ( CyString header )
{
if ( !this->CheckHeader(header.GetToken ( 1, ';' )) )
return false;
m_SHeader.fVersion = header.GetToken ( 2, ';' ).ToFloat();
if ( m_SHeader.fVersion > FILEVERSION )
return false;
m_SHeader.iValueCompression = header.GetToken ( 3, ';' ).ToInt();
m_SHeader.lValueCompressSize = header.GetToken ( 4, ';' ).ToLong();
return true;
}
bool CSpkFile::CheckHeader ( CyString header )
{
if ( header.Compare("SPKCycrow") )
return true;
return false;
}
bool CBaseFile::CheckHeader ( CyString header )
{
if ( header.Compare("BaseCycrow") )
return true;
return false;
}
/*
Func: ParseFileHeader
Input: Header String - string formated directly from the file
Return: Boolean - If string is a valid header
Desc: Splits up the file header string to get all required settings
*/
bool CBaseFile::ParseFileHeader ( CyString header )
{
if ( header.GetToken ( 1, ';' ) != "FileHeader" )
return false;
m_SHeader2.iNumFiles = header.GetToken ( 2, ';' ).ToInt();
m_SHeader2.lSize = header.GetToken ( 3, ';' ).ToInt();
m_SHeader2.lFullSize = header.GetToken ( 4, ';' ).ToInt();
m_SHeader2.iFileCompression = header.GetToken ( 5, ';' ).ToInt();
m_SHeader2.iDataCompression = header.GetToken ( 6, ';' ).ToInt();
return true;
}
/*
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 CBaseFile::ParseValueLine ( CyString line )
{
CyString first = line.GetToken ( 1, ' ' );
CyString rest = line.GetToken ( 2, -1, ' ' );
if ( first == "Name:" )
m_sName = rest;
else if ( first == "Author:" )
m_sAuthor = rest;
else if ( first == "Version:" )
m_sVersion = rest;
else if ( first == "fGameVersion:" ) {
if ( m_lGames.Back() ) {
m_lGames.Back()->Data()->sVersion = rest;
}
}
else if ( first == "GameVersion:" ) {
if ( m_lGames.Back() ) {
m_lGames.Back()->Data()->iVersion = rest.ToInt();
}
}
else if ( first == "Game:" )
this->AddGameCompatability(rest.ToInt(), NullString);
else if ( first == "GameCompat:" )
this->AddGameCompatability(rest.GetToken(" ", 1, 1).ToInt(), rest.GetToken(" ", 2, 2));
else if ( first == "GameCompatExact:" )
this->AddGameCompatability(rest.GetToken(" ", 1, 1).ToInt(), rest.GetToken(" ", 2));
else if ( first == "Date:" )
m_sCreationDate = rest;
else if ( first == "WebAddress:" )
m_sWebAddress = rest;
else if ( first == "WebSite:" )
m_sWebSite = rest;
else if ( first == "Email:" )
m_sEmail = rest;
else if ( first == "WebMirror1:" || first == "Mirror1:" || first == "WebMirror:" )
this->AddWebMirror(rest);
else if ( first == "WebMirror2:" || first == "Mirror2:" )
this->AddWebMirror(rest);
else if ( first == "PluginType:" )
m_iPluginType = rest.ToInt();
else if ( first == "Desc:" )
{
m_sDescription = rest;
m_sDescription.RemoveFirstChar('\n');
m_sDescription.RemoveFirstChar('\r');
m_sDescription.RemoveFirstSpace();
m_sDescription = m_sDescription.FindReplace(""", "\"");
m_sDescription = m_sDescription.FindReplace(">", ">");
m_sDescription = m_sDescription.FindReplace("<", "<");
m_sDescription = m_sDescription.FindReplace("&", "&");
m_sDescription = m_sDescription.FindReplace("<newline>", "\n");
m_sDescription = m_sDescription.FindReplace("<br>", "\n");
if ( m_sDescription.Left(6).lower() == "<html>" )
{
int foundFirst = -1;
int pos = 0;
while ( foundFirst == -1 )
{
pos = m_sDescription.FindPos(">", pos);
pos++;
if ( pos >= (int)m_sDescription.Length() )
break;
char c = m_sDescription[pos];
if ( c != '<' )
foundFirst = pos;
}
if ( foundFirst == -1 )
m_sDescription = "";
else
{
CyString firstStr = m_sDescription.Left(foundFirst);
firstStr.FindRemove("<br />");
firstStr.FindRemove("<br/>");
CyString lastStr = m_sDescription.Right(m_sDescription.Length() - foundFirst);
m_sDescription = firstStr + lastStr;
}
}
}
else if ( first == "UninstallAfter:" )
AddUninstallAfterText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );
else if ( first == "UninstallBefore:" )
AddUninstallBeforeText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );
else if ( first == "InstallAfter:" )
AddInstallAfterText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );
else if ( first == "InstallBefore:" )
AddInstallBeforeText ( ParseInstallText(rest.GetToken ( 1, '|' )), rest.GetToken ( 2, -1, '|' ) );
else if ( first == "ScriptName:" )
AddLanguageName ( ParseLanguage(rest.GetToken ( 1, ':' )), rest.GetToken ( 2, -1, ':' ) );
else if ( first == "GameChanging:" )
m_iGameChanging = rest.ToInt();
else if ( first == "EaseOfUse:" )
m_iEaseOfUse = rest.ToInt();
else if ( first == "Recommended:" )
m_iRecommended = rest.ToInt();
else if ( first == "NeededLibrary:" )
this->AddNeededLibrary(rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2), rest.GetToken("||", 3, 3));
else if ( first == "FakePatchBefore:" )
this->AddFakePatchOrder(false, rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2));
else if ( first == "FakePatchAfter:" )
this->AddFakePatchOrder(true, rest.GetToken("||", 1, 1), rest.GetToken("||", 2, 2));
else if ( first == "ForumLink:" )
m_sForumLink = rest;
else
return false;
return true;
}
int CBaseFile::ParseLanguage(CyString lang)
{
int langID = lang.ToInt();
if ( !langID )
{
lang = lang.ToLower();
if ( lang == "english" )
return 44;
else if ( lang == "default" )
return 0;
else if ( lang == "german" )
return 49;
else if ( lang == "russian" )
return 7;
else if ( lang == "spanish" )
return 34;
else if ( lang == "french" )
return 33;
}
return langID;
}
int CBaseFile::ParseInstallText(CyString lang)
{
return this->ParseLanguage(lang);
}
/*
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: ReadValues
Input: String - values in one long line
Desc: splits the values data into each line to read the data
*/
void CBaseFile::ReadValues ( CyString values )
{
int num = 0;
CyString *lines = values.SplitToken ( '\n', &num );
for ( int i = 0; i < num; i++ )
ParseValueLine ( lines[i] );
CLEANSPLIT(lines, num)
}
/*
Func: ParseFilesLine
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 CBaseFile::ParseFilesLine ( CyString line )
{
if ( !line.IsIn(":") )
return false;
CyString command = line.GetToken ( 1, ':' );
long size = line.GetToken ( 2, ':').ToInt ();
long usize = line.GetToken ( 3, ':').ToInt ();
long compression = line.GetToken ( 4, ':').ToInt ();
if ( command == "Icon" )
{
m_sIconExt = line.GetToken ( 5, ':' );
m_pIconFile = new C_File ();
m_pIconFile->SetDataSize ( size - 4 );
m_pIconFile->SetDataCompression ( compression );
m_pIconFile->SetUncompressedDataSize ( usize );
return true;
}
time_t time = line.GetToken ( 5,':' ).ToLong();
bool compressToFile = (line.GetToken ( 6, ':').ToInt() == 1) ? true : false;
CyString name = line.GetToken ( 7, ':' );
CyString dir = line.GetToken ( 8, ':' );
if ( name.Empty() )
return true;
bool shared = false;
if ( command.Left(1) == "$" )
{
shared = true;
command.Erase ( 0, 1 );
}
int type = -1;
if ( command == "Script" )
type = FILETYPE_SCRIPT;
else if ( command == "Text" )
type = FILETYPE_TEXT;
else if ( command == "Readme" )
type = FILETYPE_README;
else if ( command == "Map" )
type = FILETYPE_MAP;
else if ( command == "Mod" )
type = FILETYPE_MOD;
else if ( command == "Uninstall" )
type = FILETYPE_UNINSTALL;
else if ( command == "Sound" )
type = FILETYPE_SOUND;
else if ( command == "Mission" )
type = FILETYPE_MISSION;
else if ( command == "Extra" )
type = FILETYPE_EXTRA;
else if ( command == "Screen" )
type = FILETYPE_SCREEN;
else if ( command == "Backup" )
type = FILETYPE_BACKUP;
else if ( command == "Advert" )
type = FILETYPE_ADVERT;
else if ( command == "ShipScene" )
type = FILETYPE_SHIPSCENE;
else if ( command == "CockpitScene" )
type = FILETYPE_COCKPITSCENE;
else if ( command == "ShipOther" )
type = FILETYPE_SHIPOTHER;
else if ( command == "ShipModel" )
type = FILETYPE_SHIPMODEL;
if ( type == -1 )
return false;
C_File *file = new C_File ();
if ( dir.Left(5).Compare("GAME_") ) {
file->SetGame(dir.GetToken("_", 2, 2).ToInt());
dir = NullString;
}
else if ( line.NumToken(":") >= 9 ) {
file->SetGame(line.GetToken(":", 9, 9).GetToken("_", 2, 2).ToInt());
}
file->SetFileType ( type );
file->SetCreationTime ( time );
file->SetName ( name );
file->SetDir ( dir );
file->SetDataSize ( size - 4 );
file->SetDataCompression ( compression );
file->SetUncompressedDataSize ( usize );
file->SetShared ( shared );
file->SetCompressedToFile ( compressToFile );
m_lFiles.push_back ( file );
return true;
}
/*
Func: ParseFiles
Input: String - values in one long line
Desc: splits the files data into each line to read the data
*/
void CBaseFile::ReadFiles ( CyString values )
{
int num = 0;
CyString *lines = values.SplitToken ( '\n', &num );
for ( int i = 0; i < num; i++ )
ParseFilesLine ( lines[i] );
CLEANSPLIT(lines, num)
}
/*
Func: ReadFile
Input: filename - the name of the file to open and read
readdata - If falses, dont read the files to memory, just read the headers and values
Return: boolean - return ture if acceptable format
Desc: Opens and reads the spk file and loads all data into class
*/
bool CBaseFile::ReadFile ( CyString filename, int readtype, CProgressInfo *progress )
{
FILE *id = fopen ( filename.c_str(), "rb" );
if ( !id )
return false;
bool ret = ReadFile ( id, readtype, progress );
if ( ret )
m_sFilename = filename;
fclose ( id );
return ret;
}
bool CBaseFile::ReadFile ( FILE *id, int readtype, CProgressInfo *progress )
{
ClearError ();
// first read the header
if ( !ParseHeader ( GetEndOfLine ( id, NULL, false ) ) )
return false;
if ( readtype == SPKREAD_HEADER )
return true;
// update the progress for each section
int maxProgress = (readtype == SPKREAD_VALUES) ? 3 : 6;
if ( readtype != SPKREAD_ALL && progress )
progress->UpdateProgress(1, maxProgress);
long doneLen = 0;
// next read the data values for the spk files
if ( m_SHeader.lValueCompressSize )
{
// read data to memory
unsigned char *readData = new unsigned char[m_SHeader.lValueCompressSize];
unsigned char size[4];
fread ( size, 4, 1, id );
fread ( readData, sizeof(unsigned char), m_SHeader.lValueCompressSize, id );
unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
// check for zlib compression
if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB )
{
// uncomress the data
unsigned char *uncompr = new unsigned char[uncomprLen];
int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lValueCompressSize );
// update the progress for each section
if ( readtype != SPKREAD_ALL && progress )
progress->UpdateProgress(2, maxProgress);
if ( err == Z_OK )
ReadValues ( CyString ((char *)uncompr) );
doneLen = uncomprLen;
delete uncompr;
}
else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
{
long len = uncomprLen;
unsigned char *compr = LZMADecode_C ( readData, m_SHeader.lValueCompressSize, (size_t*)&len, NULL );
// update the progress for each section
if ( readtype != SPKREAD_ALL && progress )
progress->UpdateProgress(2, maxProgress);
if ( compr )
ReadValues ( CyString ((char *)compr) );
}
// no compression
else
ReadValues ( CyString ((char *)readData) );
delete readData;
}
// update the progress for each section
if ( readtype != SPKREAD_ALL && progress )
progress->UpdateProgress(3, maxProgress);
if ( readtype == SPKREAD_VALUES )
return true;
// next should be the next header
if ( !ParseFileHeader ( GetEndOfLine (id, NULL, false) ) )
return false;
// clear the current file list
m_lFiles.clear(true);
// update the progress for each section
if ( readtype != SPKREAD_ALL && progress )
progress->UpdateProgress(4, maxProgress);
if ( m_SHeader2.lSize )
{
unsigned char *readData = new unsigned char[m_SHeader2.lSize];
unsigned char size[4];
fread ( size, 4, 1, id );
fread ( readData, sizeof(char), m_SHeader2.lSize, id );
unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];
// check for zlib compression
if ( m_SHeader.iValueCompression == SPKCOMPRESS_ZLIB )
{
if ( uncomprLen < (unsigned long)doneLen )
uncomprLen = doneLen;
unsigned char *uncompr = new unsigned char[uncomprLen];
int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader2.lSize );
// update the progress for each section
if ( readtype != SPKREAD_ALL && progress )
progress->UpdateProgress(5, maxProgress);
if ( err == Z_OK )
ReadFiles ( CyString ((char *)uncompr) );
delete uncompr;
}
else if ( m_SHeader.iValueCompression == SPKCOMPRESS_7ZIP )
{
long len = uncomprLen;
unsigned char *compr = LZMADecode_C ( readData, m_SHeader2.lSize, (size_t*)&len, NULL );
// update the progress for each section
if ( readtype != SPKREAD_ALL && progress )
progress->UpdateProgress(5, maxProgress);
if ( compr )
ReadFiles ( CyString ((char *)compr) );
}
else
ReadFiles ( CyString ((char *)readData) );
delete readData;
}
// file mismatch
long numfiles = m_lFiles.size();
if ( m_pIconFile )
++numfiles;
if ( m_SHeader2.iNumFiles != numfiles )
{
m_iLastError = SPKERR_FILEMISMATCH;
return false;
}
// update the progress for each section
if ( readtype != SPKREAD_ALL && progress )
progress->UpdateProgress(6, maxProgress);
if ( readtype == SPKREAD_ALL )
{
int fileCount = 2;
if ( m_pIconFile )
m_pIconFile->ReadFromFile ( id, m_pIconFile->GetDataSize() );
// ok finally we need to read all the files
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
node->Data()->ReadFromFile ( id, node->Data()->GetDataSize() );
if ( progress )
progress->UpdateProgress(fileCount++, m_lFiles.size() + 2);
}
m_bFullyLoaded = true;
}
return true;
}
bool CBaseFile::IsMod()
{
// check for any mod files that are not fake patchs
for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
{
C_File *f = fNode->Data();
if ( f->GetFileType() != FILETYPE_MOD )
continue;
if ( !f->IsFakePatch() )
return true;
}
return false;
}
bool CBaseFile::IsFakePatch()
{
// check for any mod files that are not fake patchs
for ( CListNode<C_File> *fNode = m_lFiles.Front(); fNode; fNode = fNode->next() )
{
C_File *f = fNode->Data();
if ( f->GetFileType() != FILETYPE_MOD )
continue;
if ( f->IsFakePatch() )
return true;
}
return false;
}
CyString CBaseFile::CreateValuesLine ()
{
CyString values ( "Name: " );
values += (m_sName + "\n");
values += (CyString("Author: ") + m_sAuthor + "\n");
values += (CyString("Version: ") + m_sVersion + "\n");
if ( !m_sCreationDate.Empty() )
values += (CyString("Date: ") + m_sCreationDate + "\n");
if ( !m_sWebAddress.Empty() )
values += (CyString("WebAddress: ") + m_sWebAddress + "\n");
if ( !m_sWebSite.Empty() )
values += (CyString("WebSite: ") + m_sWebSite + "\n");
if ( !m_sEmail.Empty() )
values += (CyString("Email: ") + m_sEmail + "\n");
for ( SStringList *str = m_lMirrors.Head(); str; str = str->next )
values += (CyString("WebMirror: ") + str->str + "\n");
if ( !m_sDescription.Empty() )
{
CyString desc = m_sDescription;
desc = desc.FindReplace("<newline>", "<br>");
desc = desc.FindReplace("\n", "<br>");
desc.RemoveChar("\r");
values += (CyString("Desc: ") + desc + "\n");
}
for ( CListNode<SGameCompat> *gc = m_lGames.Front(); gc; gc = gc->next() ) {
if ( !gc->Data()->sVersion.Empty() )
values += CyString("GameCompatExact: ") + (long)gc->Data()->iGame + " " + gc->Data()->sVersion + "\n";
else
values += CyString("GameCompat: ") + (long)gc->Data()->iGame + " " + (long)gc->Data()->iVersion + "\n";
}
if ( !m_sForumLink.Empty() )
values += (CyString("ForumLink: ") + m_sForumLink + "\n");
if ( m_bSigned )
values += "Signed\n";
SInstallText *it;
for ( it = m_lUninstallText.First(); it; it = m_lUninstallText.Next() )
{
if ( !it->sAfter.Empty() )
values += (CyString("UninstallAfter: ") + CyString::Number(it->iLanguage) + "|" + it->sAfter + "\n");
if ( !it->sBefore.Empty() )
values += (CyString("UninstallBefore: ") + CyString::Number(it->iLanguage) + "|" + it->sBefore + "\n");
}
for ( it = m_lInstallText.First(); it; it = m_lInstallText.Next() )
{
if ( !it->sAfter.Empty() )
values += (CyString("InstallAfter: ") + CyString::Number(it->iLanguage) + "|" + it->sAfter + "\n");
if ( !it->sBefore.Empty() )
values += (CyString("InstallBefore: ") + CyString::Number(it->iLanguage) + "|" + it->sBefore + "\n");
}
values += CyString("GameChanging: ") + CyString::Number(m_iGameChanging) + "\n";
values += CyString("EaseOfUse: ") + CyString::Number(m_iEaseOfUse) + "\n";
values += CyString("Recommended: ") + CyString::Number(m_iRecommended) + "\n";
for ( SNames *sn = m_lNames.First(); sn; sn = m_lNames.Next() )
values += CyString("ScriptName: ") + CyString::Number(sn->iLanguage) + ":" + sn->sName + "\n";
for ( CListNode<SNeededLibrary> *libNode = m_lNeededLibrarys.Front(); libNode; libNode = libNode->next() )
{
SNeededLibrary *l = libNode->Data();
values += (CyString("NeededLibrary: ") + l->sName + "||" + l->sAuthor + "||" + l->sMinVersion + "\n");
}
for ( SStringList *fpbNode = m_lFakePatchBefore.Head(); fpbNode; fpbNode = fpbNode->next )
values += (CyString("FakePatchBefore: ") + fpbNode->str + "||" + fpbNode->data + "\n");
for ( SStringList *fpaNode = m_lFakePatchAfter.Head(); fpaNode; fpaNode = fpaNode->next )
values += (CyString("FakePatchAfter: ") + fpaNode->str + "||" + fpaNode->data + "\n");
values += (CyString("PluginType: ") + (long)m_iPluginType + "\n");
return values;
}
/*
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;
}
/*
Func: WriteFile
Input: filename - The filename of the spk file to write to
Desc: Writes the data to an spk file
*/
bool CBaseFile::WriteFile ( CyString filename, CProgressInfo *progress )
{
FILE *id = fopen ( filename.c_str(), "wb" );
if ( !id )
return false;
bool ret = WriteData ( id, progress );
fclose ( id );
return ret;
}
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;
}
bool CBaseFile::WriteHeader(FILE *id, int valueheader, int valueComprLen)
{
fprintf ( id, "BaseCycrow;%.2f;%d;%d\n", FILEVERSION, valueheader, valueComprLen );
if ( ferror(id) )
return false;
return true;
}
bool CBaseFile::WriteData ( FILE *id, CProgressInfo *progress )
{
int valueheader = m_SHeader.iValueCompression, fileheader = m_SHeader.iValueCompression;
if ( valueheader == SPKCOMPRESS_7ZIP )
valueheader = SPKCOMPRESS_ZLIB;
if ( fileheader == SPKCOMPRESS_7ZIP )
fileheader = SPKCOMPRESS_ZLIB;
// get the script values
this->UpdateSigned(true);
CyString values = this->CreateValuesLine();
// compress the values
int valueUncomprLen = (int)values.Length();
unsigned long valueComprLen = 0;
unsigned char *valueCompr = NULL;
bool compressed = false;
if ( valueheader == SPKCOMPRESS_ZLIB )
{
valueComprLen = valueUncomprLen;
if ( valueComprLen < 100 )
valueComprLen = 200;
else if ( valueComprLen < 1000 )
valueComprLen *= 2;
valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
int err = compress ( (unsigned char *)valueCompr, &valueComprLen, (const unsigned char *)values.c_str(), (unsigned long)values.Length(), 0 );
if ( err == Z_OK )
compressed = true;
}
if ( !compressed )
{
valueComprLen = valueUncomprLen;
valueCompr = (unsigned char *)calloc((unsigned int)valueComprLen, 1);
memcpy ( valueCompr, values.c_str(), valueComprLen );
valueheader = SPKCOMPRESS_NONE;
}
// write the main header to the file
if ( !this->WriteHeader(id, valueheader, valueComprLen) )
return false;
// write the compressed data to file
fputc ( (unsigned char)(valueUncomprLen >> 24), id );
fputc ( (unsigned char)(valueUncomprLen >> 16), id );
fputc ( (unsigned char)(valueUncomprLen >> 8), id );
fputc ( (unsigned char)valueUncomprLen, id );
fwrite ( valueCompr, sizeof(char), valueComprLen, id );
free ( valueCompr );
// now compress the files header
// create the files values
CyString files = CreateFilesLine ( true, progress );
// compress the files values
long fileUncomprLen = (long)files.Length(), fileComprLen = fileUncomprLen;
unsigned char *fileCompr = NULL;
compressed = false;
if ( fileUncomprLen )
{
if ( fileheader == SPKCOMPRESS_ZLIB )
{
if ( fileComprLen < 100 )
fileComprLen = 200;
else if ( fileComprLen < 1000 )
fileComprLen *= 2;
fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
int err = compress ( (unsigned char *)fileCompr, (unsigned long *)&fileComprLen, (const unsigned char *)files.c_str(), (unsigned long)files.Length(), 0 );
if ( err == Z_OK )
compressed = true;
}
}
// if unable to compress, store it as plain text
if ( !compressed )
{
fileComprLen = fileUncomprLen;
fileCompr = (unsigned char *)calloc((unsigned int)fileComprLen, 1);
memcpy ( fileCompr, files.c_str(), fileComprLen );
fileheader = SPKCOMPRESS_NONE;
}
// now write the file header
m_SHeader2.lSize = fileComprLen;
fprintf ( id, "FileHeader;%d;%ld;%ld;%d;%d\n", m_SHeader2.iNumFiles, m_SHeader2.lSize, m_SHeader2.lFullSize, fileheader, m_SHeader2.iDataCompression );
fputc ( (unsigned char)(fileUncomprLen >> 24), id );
fputc ( (unsigned char)(fileUncomprLen >> 16), id );
fputc ( (unsigned char)(fileUncomprLen >> 8), id );
fputc ( (unsigned char)fileUncomprLen, id );
fwrite ( fileCompr, sizeof(char), fileComprLen, id );
free ( fileCompr );
if ( progress )
{
progress->UpdateStatus(STATUS_WRITE);
progress->SetDone(0);
long max = 0;
for ( C_File *file = m_lFiles.First(); file; file = m_lFiles.Next() )
max += file->GetDataSize();
if ( m_pIconFile )
max += m_pIconFile->GetDataSize();
progress->SetMax(max);
}
// now finally, write all the file data
if ( m_pIconFile )
{
if ( progress )
progress->UpdateFile(m_pIconFile);
fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 24), id );
fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 16), id );
fputc ( (unsigned char)(m_pIconFile->GetUncompressedDataSize() >> 8), id );
fputc ( (unsigned char)m_pIconFile->GetUncompressedDataSize(), id );
fwrite ( m_pIconFile->GetData(), sizeof(char), m_pIconFile->GetDataSize(), id );
if ( progress )
progress->IncDone(m_pIconFile->GetDataSize());
}
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *file = node->Data();
if ( progress )
progress->UpdateFile(file);
fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 24), id );
fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 16), id );
fputc ( (unsigned char)(file->GetUncompressedDataSize() >> 8), id );
fputc ( (unsigned char)file->GetUncompressedDataSize(), id );
unsigned char *data = file->GetData();
size_t remaining = file->GetDataSize();
while ( remaining )
{
size_t writeSize = WRITECHUNK;
if ( writeSize > remaining )
writeSize = remaining;
size_t written = fwrite ( data, sizeof(char), writeSize, id );
data += written;
remaining -= written;
if ( progress )
progress->IncDone((int)written);
}
}
m_bChanged = 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 CBaseFile::ExtractFile ( C_File *file, CyString dir, bool includedir, CProgressInfo *progress )
{
if ( ReadFileToMemory ( file ) )
{
// now finally, uncompress the file
long len = 0;
unsigned char *data = file->UncompressData ( &len, progress );
if ( !data )
{
// attempt a file decompress
if ( file->GetCompressionType() == SPKCOMPRESS_7ZIP )
{
if ( file->UncompressToFile ( dir, this, includedir, progress ) )
return true;
}
return false;
}
if ( !file->WriteToDir ( dir, this, includedir, NullString, data, len ) )
return false;
return true;
}
else
return false;
}
bool CBaseFile::ExtractFile ( int filenum, CyString dir, bool includedir, CProgressInfo *progress )
{
// invalid valus
if ( filenum < 0 )
return false;
// out of range
if ( filenum > m_lFiles.size() )
return false;
// get the file pointer
C_File *file = m_lFiles.Get ( filenum );
return ExtractFile ( file, dir, includedir, progress );
}
bool CBaseFile::ExtractAll ( CyString dir, int game, bool includedir, CProgressInfo *progress )
{
// 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;
fseek ( id, 0, SEEK_SET );
// 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 );
// now were in the file section
// skip past each one
if ( m_pIconFile )
{
fseek ( id, 4, SEEK_CUR );
fseek ( id, m_pIconFile->GetDataSize (), SEEK_CUR );
}
CDirIO Dir(dir);
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *fit = node->Data();
if ( progress )
progress->UpdateFile ( fit );
if ( (!fit->GetDataSize ()) || (!fit->GetData()) )
{
if ( !fit->ReadFromFile ( id, fit->GetDataSize() ) )
{
fclose ( id );
return false;
}
}
else
fseek ( id, fit->GetDataSize(), SEEK_CUR );
if ( game ) {
if ( fit->GetGame() && fit->GetGame() != game )
continue;
}
// create directory first
Dir.Create(fit->GetDirectory(this));
long size = 0;
unsigned char *data = fit->UncompressData (&size, progress);
if ( (!data) && (fit->GetCompressionType() == SPKCOMPRESS_7ZIP) )
{
if ( !fit->UncompressToFile ( dir, this, includedir, progress ) )
{
fclose ( id );
return false;
}
}
else if ( (!data) || (!fit->WriteToDir ( dir, this, includedir, NullString, data, size )) )
{
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 CBaseFile::UpdateSigned (bool updateFiles)
{
m_bSigned = true;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
C_File *file = node->Data();
if ( updateFiles )
file->UpdateSigned();
// extra, text, soundtrack, readmes and screen files do not require a modified game directly
if ( (file->GetFileType() == FILETYPE_EXTRA) || (file->GetFileType() == FILETYPE_TEXT) || (file->GetFileType() == FILETYPE_SOUND) || (file->GetFileType() == FILETYPE_SCREEN) || (file->GetFileType() == FILETYPE_README) )
continue;
// mods and maps always need modified game
else if ( (file->GetFileType() == FILETYPE_MOD) || (file->GetFileType() == FILETYPE_MAP) )
{
m_bSigned = false;
break;
}
// else should be a script file, script or uninstall type
// all scripts must be signed, if any are not, then no signed status
if ( !file->IsSigned () )
{
m_bSigned = false;
break;
}
}
return m_bSigned;
}
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 CBaseFile::IsPackageNeeded(CyString scriptName, CyString author)
{
for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
{
SNeededLibrary *l = node->Data();
if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
return true;
}
return false;
}
SNeededLibrary *CBaseFile::FindPackageNeeded(CyString scriptName, CyString author)
{
for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
{
SNeededLibrary *l = node->Data();
if ( l->sName.Compare(scriptName) && l->sAuthor.Compare(author) )
return l;
}
return NULL;
}
void CBaseFile::RemoveFakePatchOrder(CyString scriptName, CyString author)
{
RemoveFakePatchOrder(true, scriptName, author);
RemoveFakePatchOrder(false, scriptName, author);
}
void CBaseFile::RemoveFakePatchOrder(bool after, CyString scriptName, CyString author)
{
CyStringList *list;
if ( after )
list = &m_lFakePatchAfter;
else
list = &m_lFakePatchBefore;
for ( SStringList *str = list->Head(); str; str = str->next )
{
// already added
if ( str->str.Compare(scriptName) && str->data.Compare(author) )
str->remove = true;
}
list->RemoveMarked();
}
void CBaseFile::AddFakePatchOrder(bool after, CyString scriptName, CyString author)
{
CyStringList *list;
if ( after )
list = &m_lFakePatchAfter;
else
list = &m_lFakePatchBefore;
// check if the package already exists
for ( SStringList *str = list->Head(); str; str = str->next )
{
// already added
if ( str->str.Compare(scriptName) && str->data.Compare(author) )
return;
}
// cant have it on both list
RemoveFakePatchOrder(!after, scriptName, author);
list->PushBack(scriptName, author);
}
void CBaseFile::AddNeededLibrary(CyString scriptName, CyString author, CyString minVersion)
{
SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
if ( !l )
{
l = new SNeededLibrary;
l->sName = scriptName;
l->sAuthor = author;
m_lNeededLibrarys.push_back(l);
}
l->sMinVersion = minVersion;
}
void CBaseFile::RemovePackageNeeded(CyString scriptName, CyString author)
{
SNeededLibrary *l = this->FindPackageNeeded(scriptName, author);
if ( l )
{
m_lNeededLibrarys.remove(l);
delete l;
}
}
void CBaseFile::ClearNeededPackages()
{
SNeededLibrary *ns = this->FindPackageNeeded("<package>", "<author>");
CyString version;
if ( ns )
version = ns->sMinVersion;
for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
node->DeleteData();
m_lNeededLibrarys.clear();
if ( !version.Empty() )
this->AddNeededLibrary("<package>", "<author>", version);
}
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;
}
bool CBaseFile::GeneratePackagerScript(bool wildcard, CyStringList *list, bool datafile)
{
list->PushBack("#");
list->PushBack(CyString("# Packager Script"));
list->PushBack(CyString("# -- Generated by SPK Libraries V") + CyString::CreateFromFloat(GetLibraryVersion(), 2) + " --");
list->PushBack("#");
list->PushBack("");
if ( !datafile )
{
list->PushBack("# Variable for your game directory, where to get files from");
list->PushBack("# $PATH variable is used to get the current path");
list->PushBack("Variable: $GAMEDIR $PATH");
list->PushBack("");
}
list->PushBack("# The name of the script");
list->PushBack(CyString("Name: ") + m_sName);
list->PushBack("");
list->PushBack("# The author of the script, ie, you");
list->PushBack(CyString("Author: ") + m_sAuthor);
list->PushBack("");
list->PushBack("# The creation data, when it was created");
if ( datafile )
list->PushBack(CyString("Date: ") + m_sCreationDate);
else
{
list->PushBack("# $DATE variable is used to get the current date");
list->PushBack("Date: $DATE");
}
list->PushBack("");
list->PushBack("# The version of script");
if ( datafile )
list->PushBack(CyString("Version: ") + m_sVersion);
else
{
list->PushBack("# $ASK variable is used to get an input when creating");
list->PushBack("Version: $ASK");
}
list->PushBack("");
if ( !m_lGames.empty() ) {
list->PushBack("# The game version the script is for <game> <version> (can have multiple games)");
for ( SGameCompat *g = m_lGames.First(); g; g = m_lGames.Next() ) {
CyString game = CBaseFile::ConvertGameToString(g->iGame);
if ( !g->sVersion.Empty() )
{
game += " ";
game += g->sVersion;
}
else
{
game += " ";
game += (long)g->iVersion;
}
list->PushBack(CyString("Game: ") + game);
}
list->PushBack("");
}
if ( !m_sDescription.Empty() )
{
list->PushBack("# The description of the script, displays when installing");
list->PushBack(CyString("Description: ") + m_sDescription);
list->PushBack("");
}
if ( !m_sWebSite.Empty() )
{
list->PushBack("# A link to the website for the script, ie for an online help page");
list->PushBack(CyString("WebSite: ") + m_sWebSite);
list->PushBack("");
}
if ( !m_sForumLink.Empty() )
{
list->PushBack("# A direct link to the thread in the egosoft forum");
list->PushBack(CyString("ForumLink: ") + m_sForumLink);
list->PushBack("");
}
if ( !m_sWebAddress.Empty() )
{
list->PushBack("# A link to the address for the update file");
list->PushBack(CyString("WebAddress: ") + m_sWebAddress);
list->PushBack("");
}
if ( !m_sEmail.Empty() )
{
list->PushBack("# The email address of the author, to allow users to contract if needed");
list->PushBack(CyString("Email: ") + m_sEmail);
list->PushBack("");
}
if ( m_lMirrors.Count() )
{
list->PushBack("# A link to the mirror address for the update file, can have many of these");
for ( SStringList *node = m_lMirrors.Head(); node; node = node->next )
list->PushBack(CyString("WebMirror: ") + node->str);
list->PushBack("");
}
if ( m_bAutoGenerateUpdateFile )
{
list->PushBack("# Auto generate the package update file when created");
list->PushBack("GenerateUpdateFile");
}
if ( m_lNeededLibrarys.size() )
{
list->PushBack("# Needed Library dependacies, require these to be installed");
for ( CListNode<SNeededLibrary> *node = m_lNeededLibrarys.Front(); node; node = node->next() )
list->PushBack(CyString("Depend: ") + node->Data()->sName + "|" + node->Data()->sMinVersion + "|" + node->Data()->sAuthor);
list->PushBack("");
}
if ( m_iEaseOfUse != -1 && m_iRecommended != -1 && m_iGameChanging != -1 )
{
list->PushBack("# Ratings Values, 0 to 5, <ease> <changing> <recommended>");
list->PushBack(CyString("Ratings: ") + (long)m_iEaseOfUse + " " + (long)m_iGameChanging + " " + (long)m_iRecommended);
list->PushBack("");
}
if ( m_lNames.size() )
{
list->PushBack("# Package names, uses different names for different languages");
for ( CListNode<SNames> *node = m_lNames.Front(); node; node = node->next() )
list->PushBack(CyString("ScriptName: ") + (long)node->Data()->iLanguage + " " + node->Data()->sName);
list->PushBack("");
}
if ( m_lInstallText.size() )
{
list->PushBack("# Install Texts, display text before and/or after installing to inform the use of special conditions");
for ( CListNode<SInstallText> *node = m_lInstallText.Front(); node; node = node->next() )
{
if ( !node->Data()->sBefore.Empty() )
list->PushBack(CyString("InstallBefore: ") + (long)node->Data()->iLanguage + " " + node->Data()->sBefore);
if ( !node->Data()->sAfter.Empty() )
list->PushBack(CyString("InstallAfter: ") + (long)node->Data()->iLanguage + " " + node->Data()->sAfter);
}
list->PushBack("");
}
if ( m_lUninstallText.size() )
{
list->PushBack("# Uninstall Texts, display text before and/or after uninstalling to inform the use of special conditions");
for ( CListNode<SInstallText> *node = m_lUninstallText.Front(); node; node = node->next() )
{
if ( !node->Data()->sBefore.Empty() )
list->PushBack(CyString("UninstallBefore: ") + (long)node->Data()->iLanguage + " " + node->Data()->sBefore);
if ( !node->Data()->sAfter.Empty() )
list->PushBack(CyString("UninstallAfter: ") + (long)node->Data()->iLanguage + " " + node->Data()->sAfter);
}
list->PushBack("");
}
list->PushBack("# Plugin Type, the type the plugin is, mainly used to show users the type, types include: Normal, Stable, Experimental, Cheat, Mod");
switch ( this->GetPluginType() )
{
case PLUGIN_NORMAL:
list->PushBack("PluginType: Normal");
break;
case PLUGIN_STABLE:
list->PushBack("PluginType: Stable");
break;
case PLUGIN_EXPERIMENTAL:
list->PushBack("PluginType: Experimental");
break;
case PLUGIN_CHEAT:
list->PushBack("PluginType: Cheat");
break;
case PLUGIN_MOD:
list->PushBack("PluginType: Mod");
break;
}
list->PushBack("");
return true;
}
bool CBaseFile::GeneratePackagerScriptFile(bool wildcard, CyStringList *list)
{
// now do files and wildcards
CyStringList files;
for ( CListNode<C_File> *f = m_lFiles.Front(); f; f = f->next() )
{
CyString name = "$GAMEDIR/";
bool done = false;
if ( wildcard )
{
CyString base = f->Data()->GetBaseName();
if ( f->Data()->GetFileType() == FILETYPE_SCRIPT )
{
if ( base.GetToken(".", 1, 1).Compare("plugin") || base.GetToken(".", 1, 1).Compare("lib") )
{
name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";
done = true;
}
else if ( base.GetToken(".", 1, 1).Compare("al") && !base.GetToken(".", 2, 2).Compare("plugin") )
{
name += f->Data()->GetDirectory(this) + "/" + base.GetToken(".", 1, 2) + ".*";
done = true;
}
}
else if ( f->Data()->GetFileType() == FILETYPE_TEXT )
{
if ( base.IsIn("-L") )
{
name += f->Data()->GetDirectory(this) + "/" + base.GetToken("-L", 1, 1) + "-L*";
done = true;
}
else
{
name += f->Data()->GetDirectory(this) + "/*" + base.Right(4) + ".*";
done = true;
}
}
}
if ( !done )
name += f->Data()->GetNameDirectory(this);
if ( !f->Data()->GetDir().Empty() )
{
name += "|";
name += f->Data()->GetDir();
}
files.PushBack(CyString("GAME ") + CBaseFile::ConvertGameToString(f->Data()->GetGame()) + " " + name, f->Data()->GetFileTypeString(), true);
}
if ( !files.Empty() )
{
list->PushBack("# Files List, all the files to add, can include wild cards");
for ( SStringList *node = files.Head(); node; node = node->next )
list->PushBack(node->data + ": " + node->str);
list->PushBack("");
}
return true;
}
CyString CBaseFile::GetAutosaveName()
{
CyString cdate = m_sCreationDate;
cdate = cdate.FindReplace("/", ".");
CyString name = m_sName + "-V" + m_sVersion + "-" + cdate;
return name;
}
bool CBaseFile::CheckGameCompatability(int game)
{
if ( m_lGames.empty() )
return true; // no game compatability added, assume its ok for all
for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
if ( node->Data()->iGame == 0 || node->Data()->iGame == game )
return true;
}
return false;
}
bool CBaseFile::CheckGameVersionCompatability(int game, CyString sVersion, int iVersion)
{
if ( m_lGames.empty() )
return true; // no game compatability added, assume its ok for all
bool foundAll = false;
for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
if ( node->Data()->iGame == 0 )
foundAll = true;
else if ( node->Data()->iGame == game ) { // now check the version
if ( node->Data()->sVersion.Empty() ) {
if ( node->Data()->sVersion.CompareVersion(sVersion) == COMPARE_OLDER )
return false;
return true;
}
else {
if ( node->Data()->iVersion > iVersion )
return false;
return true;
}
}
}
return foundAll;
}
bool CBaseFile::RemoveGameCompatability(int game)
{
for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
if ( node->Data()->iGame == game ) {
m_lGames.remove(node);
m_bChanged = true;
return true;
}
}
return false;
}
SGameCompat *CBaseFile::GetGameCompatability(int game)
{
for ( CListNode<SGameCompat> *node = m_lGames.Front(); node; node = node->next() ) {
if ( node->Data()->iGame == game ) {
return node->Data();
}
}
return NULL;
}
void CBaseFile::AddGameCompatability(int game, CyString version)
{
// first check if we already have it on the list
SGameCompat *Found = this->GetGameCompatability(game);
if ( !Found ) {
Found = new SGameCompat;
m_lGames.push_back(Found);
}
Found->iGame = game;
Found->iVersion = -1;
Found->sVersion = NullString;
if ( version.IsIn(".") || !version.IsNumber() )
Found->sVersion = version;
else
Found->iVersion = version.ToInt();
m_bChanged = true;
}
bool CBaseFile::LoadPackageData(CyString first, CyString rest)
{
if ( first.Compare("Name") )
m_sName = rest;
else if ( first.Compare("Author") )
m_sAuthor = rest;
else if ( first.Compare("ScriptName") )
AddLanguageName(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
else if ( first.Compare("UninstallBefore") )
this->AddUninstallBeforeText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
else if ( first.Compare("UninstallAfter") )
this->AddUninstallAfterText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
else if ( first.Compare("InstallBefore") )
this->AddInstallBeforeText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
else if ( first.Compare("InstallAfter") )
this->AddInstallAfterText(ParseLanguage(rest.GetToken(" ", 1, 1)), rest.GetToken(" ", 2));
else if ( first.Compare("Date") )
m_sCreationDate = rest;
else if ( first.Compare("Version") )
m_sVersion = rest;
// old version
else if ( first.Compare("GameVersion") )
this->AddGameCompatability(-1, rest);
else if ( first.Compare("PluginType") )
{
if ( rest.IsNumber() )
this->SetPluginType(rest.ToInt());
else if ( rest.Compare("Normal") )
this->SetPluginType(PLUGIN_NORMAL);
else if ( rest.Compare("Stable") )
this->SetPluginType(PLUGIN_STABLE);
else if ( rest.Compare("Experimental") )
this->SetPluginType(PLUGIN_EXPERIMENTAL);
else if ( rest.Compare("Cheat") )
this->SetPluginType(PLUGIN_CHEAT);
else if ( rest.Compare("Mod") )
this->SetPluginType(PLUGIN_MOD);
}
// new version
else if ( first.Compare("GenerateUpdateFile") )
m_bAutoGenerateUpdateFile = true;
else if ( first.Compare("Game") )
{
CyString sGame = rest.GetToken(" ", 1, 1);
this->AddGameCompatability(CBaseFile::GetGameFromString(sGame), rest.GetToken(" ", 2, 2));
}
else if ( first.Compare("Description") )
m_sDescription = rest;
else if ( first.Compare("AutoSave") || first.Compare("AutoExport") || first.Compare("AutoRarExport") || first.Compare("AutoZipExport") )
{
CyString filename = rest;
CyString name = m_sName;
CyString author = m_sAuthor;
CyString cdate = m_sCreationDate;
cdate = cdate.FindReplace("/", ".").Remove(" ");
if ( filename.IsIn("$AUTOSAVE") )
{
if ( m_iType == TYPE_XSP )
filename.FindReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.xsp");
else
filename.FindReplace("$AUTOSAVE", "$NAME-V$VERSION-$CDATE.spk");
}
if ( filename.IsIn("$NAME") )
filename.FindReplace("$NAME", name.Remove(" "));
if ( filename.IsIn("$AUTHOR") )
filename.FindReplace("$AUTHOR", author.Remove(" "));
if ( filename.IsIn("$DATE") )
filename.FindReplace("$DATE", cdate);
if ( filename.IsIn("$CDATE") )
filename.FindReplace("$CDATE", cdate);
if ( filename.IsIn("$VERSION") )
filename.FindReplace("$VERSION", m_sVersion);
if ( first.Compare("AutoZipExport") || first.Compare("AutoExport") )
m_sExportFilename = CFileIO(filename).ChangeFileExtension("zip");
else if ( first.Compare("AutoRarExport") )
m_sExportFilename = CFileIO(filename).ChangeFileExtension("rar");
else
m_sFilename = filename;
}
else if ( first.Compare("WebSite") )
m_sWebSite = rest;
else if ( first.Compare("ForumLink") || first.Compare("Forum") )
m_sForumLink = rest;
else if ( first.Compare("Email") )
m_sEmail = rest;
else if ( first.Compare("WebAddress") )
m_sWebAddress = rest;
else if ( first.Compare("WebMirror") )
this->AddWebMirror(rest);
else if ( first.Compare("WebMirror1") )
this->AddWebMirror(rest);
else if ( first.Compare("WebMirror2") )
this->AddWebMirror(rest);
else if ( first.Compare("Ftp") )
m_sFtpAddr = rest;
else if ( first.Compare("Ratings") )
{
m_iEaseOfUse = rest.GetToken(" ", 1, 1).ToInt();
m_iGameChanging = rest.GetToken(" ", 2, 2).ToInt();
m_iRecommended = rest.GetToken(" ", 3, 3).ToInt();
}
else if ( first.Compare("EaseOfUse") )
m_iEaseOfUse = rest.ToInt();
else if ( first.Compare("GameChanging") )
m_iGameChanging = rest.ToInt();
else if ( first.Compare("Recommended") )
m_iRecommended = rest.ToInt();
else if ( first.Compare("Depend") )
{
CyString version = rest.GetToken("|", 2, 2);
CyString name = rest.GetToken("|", 1, 1);
CyString author = rest.GetToken("|", 3);
this->AddNeededLibrary(name, author, version);
}
else if ( first.Compare("DependPackage") )
{
CPackages p;
CBaseFile *spk = p.OpenPackage(rest, 0, 0, SPKREAD_VALUES);
if ( spk )
{
this->AddNeededLibrary(spk->GetName(), spk->GetAuthor(), spk->GetVersion());
delete spk;
}
}
else if ( first.Compare("Icon") )
{
C_File *icon = new C_File(rest);
if ( icon->ReadFromFile() )
this->SetIcon(icon, CFileIO(rest).GetFileExtension());
}
else
{
CyString checkType = first;
bool shared = false;
if ( checkType.Left(6).Compare("Shared") )
{
checkType = first.Right(-6);
shared = true;
}
// now check type name
int filetype = GetFileTypeFromString(checkType);
if ( filetype != -1 )
this->AddFileScript(filetype, shared, rest);
else if ( !checkType.Compare("changelog") )
return false;
}
return true;
}
void CBaseFile::AddFileScript(int filetype, bool shared, CyString rest)
{
CyString dir;
if ( rest.IsIn("|") )
{
dir = rest.GetToken("|", 2);
rest = rest.GetToken("|", 1, 1);
}
int game = 0;
if ( rest.GetToken(" ", 1, 1).Left(4).Compare("GAME") ) {
game = CBaseFile::GetGameFromString(rest.GetToken(" ", 2, 2));
rest = rest.GetToken(" ", 3);
}
rest = rest.FindReplace("\\", "/");
// wild cards
if ( rest.IsAnyIn("*?") )
{
CDirIO Dir(CFileIO(rest).GetDir());
CyStringList *dirList = Dir.DirList();
if ( dirList )
{
for ( SStringList *strNode = dirList->Head(); strNode; strNode = strNode->next )
{
CyString file = Dir.File(strNode->str);
if ( file.WildMatch(rest) )
{
C_File *newfile = this->AppendFile(file, filetype, game, dir);
if ( newfile )
newfile->SetShared(shared);
}
}
delete dirList;
}
}
else
{
C_File *file = this->AppendFile(rest, filetype, game, dir);
if ( file )
file->SetShared(shared);
}
}
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);
}
CyString CBaseFile::GetFullFileSizeString() { return SPK::GetSizeString ( this->GetFullFileSize() ); }
unsigned char *CBaseFile::CreateData(size_t *size, CProgressInfo *progress)
{
if ( this->WriteFile("temp.dat", progress) )
{
FILE *id = fopen("temp.dat", "rb");
if ( id )
{
fseek(id, 0, SEEK_END);
*size = ftell(id);
fseek(id, 0, SEEK_SET);
unsigned char *data = new unsigned char[*size];
fread(data, sizeof(unsigned char), *size, id);
fclose(id);
remove("temp.dat");
return data;
}
}
remove("temp.dat");
return NULL;
}
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();
}
void CBaseFile::ConvertNormalMod(C_File *f, CyString to)
{
C_File *match = this->FindMatchingMod(f);
if ( match )
{
// file link
if ( !match->GetData() )
match->ReadFromFile();
match->ChangeBaseName(to);
}
// file link
if ( !f->GetData() )
f->ReadFromFile();
f->ChangeBaseName(to);
}
void CBaseFile::ConvertAutoText(C_File *f)
{
CyString to;
if ( f->GetBaseName().IsIn("-L") )
to = CyString("0000-L") + f->GetBaseName().GetToken("-L", 2, 2);
else if ( f->GetBaseName().IsIn("-l") )
to = CyString("0000-L") + f->GetBaseName().GetToken("-l", 2, 2);
else
to = f->GetBaseName().Left(-4) + "0000";
// file link
if ( !f->GetData() )
f->ReadFromFile();
f->ChangeBaseName(to);
}
void CBaseFile::ConvertFakePatch(C_File *f)
{
// find next available fake patch
int num = 0;
bool found = true;
while ( found )
{
++num;
found = false;
CyString find = CyString::Number(num).PadNumber(2);
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
if ( node->Data()->GetFileType() != FILETYPE_MOD )
continue;
if ( !node->Data()->IsFakePatch() )
continue;
if ( node->Data()->GetBaseName().Compare(find) )
{
found = true;
break;
}
}
}
CyString to = CyString::Number(num).PadNumber(2);
C_File *match = this->FindMatchingMod(f);
// file link
if ( !f->GetData() )
f->ReadFromFile();
f->ChangeBaseName(to);
if ( match )
{
// file link
if ( !match->GetData() )
match->ReadFromFile();
match->ChangeBaseName(to);
}
}
C_File *CBaseFile::FindMatchingMod(C_File *f)
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
if ( node->Data()->GetFileType() != FILETYPE_MOD )
continue;
if ( f->GetFileExt().Compare(node->Data()->GetFileExt()) )
continue;
if ( f->GetBaseName().Compare(node->Data()->GetBaseName()) )
return node->Data();
}
return NULL;
}
void CBaseFile::RenameFile(C_File *f, CyString baseName)
{
if ( f->GetFileType() == FILETYPE_MOD )
{
C_File *match = this->FindMatchingMod(f);
if ( match )
match->ChangeBaseName(baseName);
}
// need to edit the file
if ( f->GetFileType() == FILETYPE_SCRIPT || f->GetFileType() == FILETYPE_UNINSTALL )
f->RenameScript(baseName);
f->ChangeBaseName(baseName);
}
CyString CBaseFile::CreateUpdateFile(CyString dir)
{
CyString file = this->GetNameValidFile() + "_" + m_sAuthor + ".dat";
file.RemoveChar(' ');
CyStringList write;
write.PushBack(CyString("Package: ") + m_sName);
write.PushBack(CyString("Author: ") + m_sAuthor);
write.PushBack(CyString("Version: ") + m_sVersion);
write.PushBack(CyString("File: ") + CFileIO(m_sFilename).GetFilename());
CFileIO File(dir + "/" + file);
if ( File.WriteFile(&write) )
return File.GetFullFilename();
return NullString;
}
CyString CBaseFile::ErrorString(int error, CyString errorStr)
{
if ( error == SPKERR_NONE ) return NullString;
CyString err;
switch(error)
{
case SPKERR_MALLOC:
err = "Memory Failed";
break;
case SPKERR_FILEOPEN:
err = "Failed to open file";
break;
case SPKERR_FILEREAD:
err = "Failed to read file";
break;
case SPKERR_UNCOMPRESS:
err = "Failed to Uncompress";
break;
case SPKERR_WRITEFILE:
err = "Failed to write file";
break;
case SPKERR_CREATEDIRECTORY:
err = "Failed to create directory";
break;
case SPKERR_FILEMISMATCH:
err = "File count mismatch";
break;
}
if ( !err.Empty() )
{
if ( !errorStr.Empty() )
{
err += " (";
err += errorStr + ")";
}
return err;
}
return CyString((long)error);
}
bool CBaseFile::SaveToArchive(CyString filename, int game, CProgressInfo *progress)
{
TCHAR buf[5000];
wsprintf(buf, L"%hs", filename.c_str());
HZIP hz = CreateZip(buf, 0);
if ( !hz ) return false;
// read files and compress
ReadAllFilesToMemory();
if ( !UncompressAllFiles(progress) )
{
CloseZip(hz);
return false;
}
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() )
{
if ( game != -1 ) {
if ( game && node->Data()->GetGame() && node->Data()->GetGame() != game )
continue;
if ( !game && node->Data()->GetGame() )
continue;
}
CyString fname = node->Data()->GetNameDirectory(this);
// create the directory
wsprintf(buf, L"%hs", fname.c_str());
ZipAdd(hz, buf, node->Data()->GetData(), node->Data()->GetDataSize());
}
// add the data file
CyStringList list;
if ( this->GeneratePackagerScript(false, &list, true) )
{
if ( CFileIO("test.tmp").WriteFile(&list) )
{
ZipAdd(hz, L"pluginmanager.txt", L"test.tmp");
CFileIO("test.tmp").Remove();
}
}
CloseZip(hz);
return true;
}
int CBaseFile::GetGameFromString(CyString sGame)
{
int iGame = GAME_ALL;
if ( sGame.Compare("ALL") )
iGame = GAME_ALL;
else if ( sGame.Compare("X3") )
iGame = GAME_X3;
else if ( sGame.Compare("X2") )
iGame = GAME_X2;
else if ( sGame.Compare("X3TC") )
iGame = GAME_X3TC;
else if ( sGame.Compare("X3AP") )
iGame = GAME_X3AP;
else if ( sGame.Compare("XREBIRTH") )
iGame = GAME_XREBIRTH;
else if ( sGame.IsNumber() )
iGame = sGame.ToInt();
return iGame;
}
CyString CBaseFile::ConvertGameToString(int iGame)
{
CyString game = "ALL";
switch(iGame) {
case GAME_ALL:
game = "ALL";
break;
case GAME_X2:
game = "X2";
break;
case GAME_X3:
game = "X3";
break;
case GAME_X3TC:
game = "X3TC";
break;
case GAME_X3AP:
game = "X3AP";
break;
case GAME_XREBIRTH:
game = "XREBIRTH";
break;
default:
game = (long)iGame;
}
return game;
}
bool CBaseFile::IsGameInPackage(int game)
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
if ( node->Data()->GetGame() == game )
return true;
}
return false;
}
bool CBaseFile::IsAnyGameInPackage()
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
if ( node->Data()->GetGame() )
return true;
}
return false;
}
int CBaseFile::FindFirstGameInPackage()
{
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
if ( node->Data()->GetGame() )
return node->Data()->GetGame();
}
return 0;
}
bool CBaseFile::IsMultipleGamesInPackage()
{
int game = 0;
for ( CListNode<C_File> *node = m_lFiles.Front(); node; node = node->next() ) {
if ( node->Data()->GetGame() ) {
if ( game != node->Data()->GetGame() )
return true;
game = node->Data()->GetGame();
}
}
return false;
}