Subversion Repositories spk

Rev

Rev 130 | Rev 160 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed


#include "OriginalFiles.h"
#include "File.h"
#include "Logging/Log.h"
#include "BaseFile.h"
#include "spk.h"
//#include "ProgressInfo.h"

namespace SPK {

void AddLogEntry(int type, CyString args, CyStringList *errors)
{
        if ( errors ) errors->PushBack(args, ERRORLOG_OLD(type));
}


COriginalFiles::COriginalFiles(const Utils::String &dir) : _sDir(dir)
{
}

COriginalFiles::~COriginalFiles(void)
{
        reset();
}

int COriginalFiles::count() const
{
        return _lFiles.size();
}

/**
 * Check for original file
 *
 * Checks if the file is an original file or not
 */
bool COriginalFiles::isOriginal(C_File *f) const
{
        if ( _getFile(f) )
                return true;
        return false;
}

void COriginalFiles::installed(CBaseFile *package)
{
        for ( CListNode<C_File> *oNode = _lFiles.Front(); oNode; oNode = oNode->next() )
        {
                C_File *of = oNode->Data();
                for ( CListNode<C_File> *checkNode = package->GetFileList()->Front(); checkNode; checkNode = checkNode->next() )
                {
                        C_File *f = checkNode->Data();

                        // match the same filetype
                        if ( of->GetFileType() != f->GetFileType() )
                                continue;

                        // same file
                        if ( of->GetFilename().Compare(f->GetFilename()) )
                                _storeOverride(f);
                }
        }
}

void COriginalFiles::backup(CBaseFile *package, CyStringList *errors)
{
        // backup any original files before installing
        CLog::log(CLog::Log_Install, 3, "Checking for any original files to backup");
        CDirIO oDir(_sDir + "/PluginManager/Original");
        for ( CListNode<C_File> *oNode = _lFiles.Front(); oNode; oNode = oNode->next() )
        {
                C_File *of = oNode->Data();
                for ( CListNode<C_File> *checkNode = package->GetFileList()->Front(); checkNode; checkNode = checkNode->next() )
                {
                        C_File *f = checkNode->Data();

                        // match the same filetype
                        if ( of->GetFileType() != f->GetFileType() )
                                continue;

                        // same file
                        if ( of->GetFilename().Compare(f->GetFilename()) )
                        {
                                // check if original file already exists (assume already backed up)
                                if ( !backupFile(of, errors) )
                                        continue;
                                break;
                        }
                }
        }
}

bool COriginalFiles::backupFile(C_File *f, CyStringList *errors)
{
        Utils::String newDir = "PluginManager/Original/" + f->getDirectory(NULL);
        CDirIO oDir(_sDir);
        if ( oDir.exists(newDir + "/" + f->GetFilename().ToString()) )
                return true;

        // make sure the directory exissts
        if ( !oDir.exists(newDir) )
        {
                if ( !oDir.Create(newDir) )
                {
                        CLog::logf(CLog::Log_Install, 2, "Unable to create directory to backup original files, %s", newDir.c_str());
                        AddLogEntry(SPKINSTALL_CREATEDIRECTORY_FAIL, newDir, errors);
                        return false;
                }

                CLog::logf(CLog::Log_Install, 2, "Created new directory, %s", newDir.c_str());
                AddLogEntry(SPKINSTALL_CREATEDIRECTORY, newDir, errors);
        }

        // now lets copy the file
        CFileIO CopyFile(f->filePointer());
        if ( CopyFile.copy(oDir.File(newDir + "/" + f->GetFilename().ToString()).ToString()) )
        {
                CLog::logf(CLog::Log_Install, 2, "Original file: %s has been backed up", f->GetNameDirectory(NULL).c_str());
                AddLogEntry(SPKINSTALL_ORIGINAL_BACKUP, f->GetNameDirectory(NULL), errors);
                return true;
        }
        else
        {
                CLog::logf(CLog::Log_Install, 2, "Failed to backup the original file: %s", f->GetNameDirectory(NULL).c_str());
                AddLogEntry(SPKINSTALL_ORIGINAL_BACKUP_FAIL, f->GetNameDirectory(NULL), errors);
                return false;
        }
}

bool COriginalFiles::doBackup(C_File *f, CyStringList *errors)
{
        bool backed = false;

        C_File *of = this->_getFile(f);
        if ( of ) {
                // check if the orignal file is already backed up
                if ( !CFileIO::Exists(_sDir + "/PluginManager/Original/" + f->GetNameDirectory(NULL).ToString()) )
                {
                        // lets back up the file now
                        backed = this->backupFile(of, errors);
                }
        }

        return backed;
}


int COriginalFiles::restoreAll(CProgressInfo *info, int files, int max)
{
        for ( CListNode<C_File> *oNode = _lFiles.Front(); oNode; oNode = oNode->next() )
        {
                // update the progress
                if ( info ) info->UpdateProgress(files, max);
                ++files;

                C_File *f = oNode->Data();
                CFileIO of(_sDir + "/PluginManager/Original/" + f->GetNameDirectory(NULL).ToString());
                
                if ( of.exists() )
                        of.Rename(_sDir + "/" + f->GetNameDirectory(NULL).ToString());

                delete oNode->Data();
        }

        _lFiles.clear();

        return files;
}

bool COriginalFiles::restoreFile(C_File *f, CyStringList *errors)
{
        bool original = false;

        // check if its an original file and restore
        if ( this->isOriginal(f) )
        {
                CFileIO of(_sDir + "/PluginManager/Original/" + f->GetNameDirectory(NULL).ToString());
                if ( of.exists() )
                {
                        original = true;
                        if ( of.Rename(_sDir + "/" + f->GetNameDirectory(NULL).ToString()) )
                                AddLogEntry(SPKINSTALL_ORIGINAL_RESTORE, f->GetNameDirectory(NULL), errors);
                        else
                                AddLogEntry(SPKINSTALL_ORIGINAL_RESTORE_FAIL, f->GetNameDirectory(NULL), errors);

                        CFileIO backupFile(_sDir + "/PluginManager/Original/Replacements/" + f->GetNameDirectory(NULL).ToString());
                        if ( backupFile.exists() ) backupFile.remove();

                }
        }

        return original;
}


void COriginalFiles::parse(const Utils::String &data)
{
        C_File *uf = new C_File();

        uf->setFileType((FileType)data.token(" ", 1).toLong());

        // Extra files also contain a directory, so make sure we split that up
        if (uf->fileType() == FILETYPE_EXTRA )
        {
                uf->SetDir(data.tokens(" ", 2).tokens(":", 2));
                uf->SetFilename(data.tokens(" ", 2).token(":", 1));
        }
        else
                uf->SetFilename(data.tokens(" ", 2));

        // set the complete filename, GetNameDirectory returns the directory based on the file type
        uf->SetFilename(_sDir + "/" + uf->GetNameDirectory(NULL).ToString());

        _lFiles.push_back(uf);
}

void COriginalFiles::update(bool bForce, const CLinkList<C_File> *pFiles)
{
        if ( _lFiles.empty() || bForce )
        {
                _storeFiles(FILETYPE_SCRIPT, "scripts", pFiles);
                _storeFiles(FILETYPE_TEXT, "t", pFiles);
                _storeFiles(FILETYPE_SOUND, "soundtrack", pFiles);
                _storeFiles(FILETYPE_EXTRA, "mov", pFiles);
        }
}

bool COriginalFiles::writeData(CyStringList *lines)
{
        bool addAny = false;

        if ( !_lFiles.empty() )
        {
                for ( CListNode<C_File> *node = _lFiles.Front(); node; node = node->next() )
                {
                        C_File *uf = node->Data();
                        Utils::String uString = "Original: ";
                        uString += Utils::String::Number((long)uf->GetFileType()) + " ";
                        uString += uf->GetFilename().ToString();

                        // add the directory for Extra files
                        if ( uf->GetFileType() == FILETYPE_EXTRA && !uf->GetDir().Empty())
                        {
                                uString += ":";
                                uString += uf->GetDir().ToString();
                        }

                        lines->PushBack(CyString(uString));
                        addAny = true;
                }
        }

        return addAny;
}


void COriginalFiles::reset()
{
        _lFiles.MemoryClear();
}


/**
 * Update original files list
 *
 * Scan the current directory for any fiels that are already there, ie ones that have not been installed
 * Original files should be all the scripts/sounds, etc that are in an unmodified game directory
 *
 * Save list of files and check if any packages overright these files
 * Any file that gets overrighten from this list will automatically be backed up, and restored once the packages are removed
 */
void COriginalFiles::_storeFiles(FileType filetype, const Utils::String &searchPath, const CLinkList<C_File> *pFiles)
{
        Utils::String ext = "pck";
        switch ( filetype )
        {
                case FILETYPE_SOUND:
                        ext = "mp3";
                        break;
        }

        CDirIO Dir(_sDir + "/" + searchPath);

        CyStringList *files = Dir.DirList();
        if ( !files )
                return;

        for ( SStringList *node = files->Head(); node; node = node->next )
        {
                CFileIO File(Dir.File(node->str));

                
                if ( File.extension().Compare(ext) )
                        _add(filetype, File.filename(), searchPath, pFiles);
        }

        delete files;
}

/**
 * Get original file
 *
 * Finds a matching original file entry and returns it
 */
C_File *COriginalFiles::_getFile(C_File *file) const
{
        if ( !file ) return NULL;

        for ( CListNode<C_File> *node = _lFiles.Front(); node; node = node->next() )
        {
                C_File *of = node->Data();

                // not of the same file type
                if ( of->GetFileType() != file->GetFileType() )
                        continue;

                // same file name, must be the same file
                if ( of->GetFilename().Compare(file->GetFilename()) )
                        return of;
        }

        return NULL;
}


/**
 * Adds a file onto the original files list
 *
 * Checks if it already exists so we dont create multiples
 */
void COriginalFiles::_add(FileType filetype, const Utils::String &filename, const Utils::String &searchPath, const CLinkList<C_File> *pFiles)
{
        // dont add plugin manager as original files
        if ( filetype == FILETYPE_SCRIPT && filename.isin("!init.pmanager") )
                return;

        // first check if a matching one exists
        for ( CListNode<C_File> *node = _lFiles.Front(); node; node = node->next() )
        {
                C_File *file = node->Data();
                if ( file->GetFileType() != filetype )
                        continue;

                if ( file->GetFilename().Compare(CyString(filename)) )
                        return;
        }

        // check that no packages are currently using them either, not original if being used already
        for ( CListNode<C_File> *node = pFiles->Front(); node; node = node->next() )
        {
                C_File *file = node->Data();
                if ( file->GetFileType() != filetype )
                        continue;

                if ( file->GetFilename().Compare(CyString(filename)) )
                        return;
        }

        // add the file entry to the list
        C_File *of = new C_File(filename);
        of->setFileType(filetype);
        if (filetype == FILETYPE_EXTRA)
                of->SetDir(searchPath);
        of->SetFilename(_sDir + "/" + of->GetNameDirectory(NULL).ToString());

        _lFiles.push_back(of);
}

void COriginalFiles::_storeOverride(C_File *f)
{
        CDirIO oDir(_sDir + "/PluginManager/Original/Replacements");
        if ( !oDir.exists() ) oDir.Create();
        CFileIO file(oDir.file(f->GetNameDirectory(NULL).ToString()));
        if ( !file.GetDirIO().exists() ) file.GetDirIO().Create();
        CFileIO fromFile(f->GetFilePointer());
        fromFile.copy(file.fullFilename(), true);
}

}