Subversion Repositories spk

Rev

Rev 202 | 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, const Utils::WString &args, Utils::WStringList* errors)
        {
                if (errors) errors->pushBack(args, ERRORLOG(type));
        }


COriginalFiles::COriginalFiles(const Utils::WString &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->fileList().Front(); checkNode; checkNode = checkNode->next() )
                {
                        C_File *f = checkNode->Data();

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

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

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

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

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

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

        // make sure the directory exissts
        if ( !oDir.exists(newDir) )
        {
                if ( !oDir.create(newDir) )
                {
                        CLog::logf(CLog::Log_Install, 2, L"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, L"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 + L"/" + f->filename())))
        {
                CLog::logf(CLog::Log_Install, 2, L"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, L"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, Utils::WStringList *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 + L"/PluginManager/Original/" + f->getNameDirectory(NULL)) )
                {
                        // 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 + L"/PluginManager/Original/" + f->getNameDirectory(NULL));
                
                if ( of.exists() )
                        of.Rename(_sDir + L"/" + f->getNameDirectory(NULL));

                delete oNode->Data();
        }

        _lFiles.clear();

        return files;
}

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

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

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

                }
        }

        return original;
}


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

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

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

        // set the complete filename, GetNameDirectory returns the directory based on the file type
        uf->setFilename(_sDir + L"/" + uf->getNameDirectory(NULL));

        _lFiles.push_back(uf);
}

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

bool COriginalFiles::writeData(Utils::WStringList &lines)
{
        bool addAny = false;

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

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

                        lines.pushBack(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::WString &searchPath, const CLinkList<C_File> *pFiles)
{
        Utils::WString ext = L"pck";
        switch ( filetype )
        {
                case FILETYPE_SOUND:
                        ext = L"mp3";
                        break;
        }

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

        Utils::WStringList files;
        Dir.dirList(files);
        if (files.empty())
                return;

        for(auto itr = files.begin(); itr != files.end(); itr++)
        {
                CFileIO File(Dir.file((*itr)->str));
                
                if ( File.extension().Compare(ext) )
                        _add(filetype, File.filename(), searchPath, pFiles);
        }
}

/**
 * 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->filename().Compare(file->filename()) )
                        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::WString &filename, const Utils::WString &searchPath, const CLinkList<C_File> *pFiles)
{
        // dont add plugin manager as original files
        if ( filetype == FILETYPE_SCRIPT && filename.contains(L"!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->filename().Compare(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->filename().Compare(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 + L"/" + of->getNameDirectory(NULL));

        _lFiles.push_back(of);
}

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

}