Subversion Repositories spk

Rev

Rev 1 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "MultiSpkFile.h"
#include "File.h"
#include "XspFile.h"

CMultiSpkFile::~CMultiSpkFile()
{
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( !ms )
                        continue;

                if ( ms->sData )
                {
                        delete ms->sData;
                        ms->sData = NULL;
                }

                if ( ms->pFile )
                {
                        delete ms->pFile;
                        ms->pFile = NULL;
                }

                node->DeleteData();
        }
}

void CMultiSpkFile::CreatePackage(SMultiSpkFile *p)
{
        if ( !p )
                return;

        if ( p->iType == TYPE_XSP )
                p->pFile = new CXspFile();
        else if ( p->iType == TYPE_SPK )
                p->pFile = new CSpkFile();
        else if ( p->iType == TYPE_BASE )
                p->pFile = new CBaseFile();
}

bool CMultiSpkFile::AddFileNow ( CyString file, bool on )
{
        if ( this->AddFile(file, on) )
        {
                CyString findFile = file;
                findFile = findFile.FindReplace ( "\\", "/" );
                findFile = findFile.GetToken ( findFile.NumToken('/'), '/' );

                SMultiSpkFile *p = this->FindFile(findFile);
                if ( p )
                {
                        this->CreatePackage(p);
                        if ( p->pFile->ReadFile ( file, SPKREAD_ALL ) )
                                return true;
                }
        }

        return false;
}

bool CMultiSpkFile::AddFile(SMultiSpkFile *ms)
{
        bool found = false;
        // find if theres any files with the same filename
        CListNode<SMultiSpkFile> *node;
        for ( node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( it->sName.Compare(ms->sName) )
                {
                        m_lFiles.remove ( it );
                        found = true;
                        delete it;
                        break;
                }
        }

        // now find if theres a file with the same script/author
        for ( node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( (it->sScriptAuthor.Compare(ms->sScriptAuthor)) && (it->sScriptName.Compare(ms->sScriptName)) )
                {
                        m_lFiles.remove ( it );
                        found = true;
                        delete it;
                        break;
                }
        }

        m_lFiles.push_back ( ms );

        m_bChanged = true;
        return true;
}
bool CMultiSpkFile::AddFile ( CyString file, bool on )
{
        // multipack
        if ( file.IsIn ( "::" ) )
        {
                CyString mfile = file.Left ( file.FindPos("::") );
                CMultiSpkFile spkfile;
                if ( spkfile.ReadFile ( mfile, false ) )
                {
                        SMultiSpkFile *ms = new SMultiSpkFile;
                        ms->bRemove = false;
                        ms->sName = file.Right ( (int)(file.Length() - file.FindPos("::")) - 2 );
                        ms->pFile = NULL;
                        ms->sData = NULL;
                        if ( spkfile.ExtractData ( ms ) )
                        {
                                ms->bOn = on;
                                AddFile(ms);
                                return true;
                        }
                        delete ms;
                }
                return false;
        }

        // check its a valid file
        int check = CBaseFile::CheckFile ( file );
        if ( check == SPKFILE_MULTI )
        {
                CMultiSpkFile spkfile;
                if ( spkfile.ReadFile ( file, false ) )
                {
                        CLinkList<SMultiSpkFile> *list = spkfile.GetFileList();
                        for ( SMultiSpkFile *it = list->First(); it; it = list->Next() )
                        {
                                SMultiSpkFile *ms = new SMultiSpkFile;
                                ms->bRemove = false;
                                ms->sName = it->sName;
                                ms->pFile = NULL;
                                ms->sData = NULL;
                                if ( spkfile.ExtractData ( ms ) )
                                {
                                        ms->bOn = on;
                                        AddFile(ms);
                                }
                                else
                                        delete ms;
                        }
                        return true;
                }
                return false;
        }
        else if ( check != SPKFILE_SINGLE && check != SPKFILE_SINGLESHIP )
                return false;

        FILE *id = fopen ( file.c_str(), "rb" );
        if ( !id )
                return false;

        // create entry
        SMultiSpkFile *ms = new SMultiSpkFile;
        ms->bRemove = false;
        ms->pFile = NULL;
        ms->sName = file;
        ms->sName = ms->sName.FindReplace ( "\\", "/" );
        ms->sName = ms->sName.GetToken ( ms->sName.NumToken('/'), '/' );
        ms->bOn = on;

        // find file size
        fseek ( id, 0, SEEK_END );
        ms->lSize = ftell ( id );
        fseek ( id, 0, SEEK_SET );

        // read data
        ms->sData = new char[ms->lSize];
        fread ( ms->sData, sizeof(char), ms->lSize, id );

        fclose ( id );

        CBaseFile *baseFile = NULL;
        if ( check == SPKFILE_SINGLE )
                baseFile = new CSpkFile;
        else if ( check == SPKFILE_SINGLESHIP )
                baseFile = new CXspFile;

        if ( baseFile )
        {
                if ( baseFile->ReadFile(file, SPKREAD_VALUES) )
                {
                        ms->sScriptAuthor       = baseFile->GetAuthor();
                        ms->sScriptName         = baseFile->GetName();
                        ms->sScriptVersion      = baseFile->GetVersion();
                        ms->iType                       = baseFile->GetType();
                }

                delete baseFile;
        }

        AddFile(ms);

        return true;
}

SMultiSpkFile *CMultiSpkFile::AddFileEntry ( CyString filename )
{
        SMultiSpkFile *ms = new SMultiSpkFile;
        ms->bRemove = false;
        ms->pFile = NULL;
        ms->sName = filename;
        ms->bOn = true;
        ms->iType = -1;

        m_lFiles.push_back ( ms );
        m_bChanged = true;

        return ms;
}

CyString CMultiSpkFile::CreateData ()
{
        CyString ret;
        if ( !m_sName.Empty() )
                ret = CyString("Name: ") + m_sName + "\n";
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( ms->iType == TYPE_XSP )
                        ret += "XspFile: ";
                else 
                        ret += "SpkFile: ";

                if ( ms->bOn )
                        ret += "1:";
                else
                        ret += "0:";
                ret += ms->lSize;
                ret += ":";
                ret += ms->sName;
                if ( !ms->sScriptName.Empty() )
                        ret += (CyString(":") + ms->sScriptName + "|" + ms->sScriptAuthor + "|" + ms->sScriptVersion);
                ret += "\n";
        }

        return ret;
}

bool CMultiSpkFile::WriteFile ( CyString filename, CProgressInfo *progress )
{
        FILE *id = fopen ( filename.c_str(), "wb" );
        if ( !id )
                return false;

        // make sure we remove all packages that have been marked
        this->RemovePackages();

        CyString data = CreateData ();

        int comprLen = (int)data.Length(), uncomprLen = comprLen;;
        unsigned char *compr = NULL;

        bool compressed = false;
        int valueheader = m_SHeader.iCompression;
        if ( valueheader == SPKCOMPRESS_7ZIP )
                valueheader = SPKCOMPRESS_ZLIB;

        if ( valueheader == SPKCOMPRESS_ZLIB )
        {
                comprLen = uncomprLen;  
                if ( comprLen < 100 )
                        comprLen = 200;
                else if ( comprLen < 1000 )
                        comprLen *= 2;

                compr = (unsigned char *)calloc((unsigned int)comprLen, 1);
                int err = compress ( (unsigned char *)compr, (unsigned long *)&comprLen, (const unsigned char *)data.c_str(), (unsigned long)data.Length(), 0 );
                if ( err == Z_OK )
                        compressed = true;
        }

        if ( !compressed )
        {
                comprLen = uncomprLen;
                compr = (unsigned char *)calloc((unsigned int)comprLen, 1);
                memcpy ( compr, data.c_str(), comprLen );
                valueheader = SPKCOMPRESS_NONE;
        }

        // write the main header to the file
        fprintf ( id, "MSPKCycrow;%.2f;%d;%d;%d;%d\n", FILEVERSION, valueheader, data.Length(), comprLen, (m_SHeader.bSelection) ? 1 : 0 );
        if ( ferror(id) )
        {
                fclose ( id );
                return false;
        }

        // write the compressed data to file
        fputc ( (unsigned char)(uncomprLen >> 24), id ); 
        fputc ( (unsigned char)(uncomprLen >> 16), id ); 
        fputc ( (unsigned char)(uncomprLen >> 8), id ); 
        fputc ( (unsigned char)uncomprLen, id ); 
        fwrite ( compr, sizeof(char), comprLen, id );

        free ( compr );

        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( progress )
                        progress->UpdatePackage(ms);
                if ( (!ms->sData) && (ms->pFile) )
                        ms->pFile->WriteData ( id, NULL );
                else
                        fwrite ( ms->sData, sizeof(char), ms->lSize, id );
        }

        fclose ( id );

        return true;
}

bool CMultiSpkFile::ParseHeader ( CyString header )
{
        if ( header.GetToken ( 1, ';' ) != "MSPKCycrow" )
                return false;

        m_SHeader.fVersion = header.GetToken ( 2, ';' ).ToFloat();
        if ( m_SHeader.fVersion > FILEVERSION )
                return false;

        m_SHeader.iCompression = header.GetToken ( 3, ';' ).ToInt();
        m_SHeader.lUncomprLen = header.GetToken ( 4, ';' ).ToLong();
        m_SHeader.lComprLen = header.GetToken ( 5, ';' ).ToLong();
        m_SHeader.bSelection = (header.GetToken ( 4, ';' ).ToInt()) ? true : false;

        return true;
}

bool CMultiSpkFile::ParseValueLine ( CyString line )
{
        CyString first = line.GetToken ( 1, ' ' );
        CyString rest  = line.GetToken ( 2, -1, ' ' );

        if ( first == "Name:" )
                m_sName = rest;
        else if ( first == "SpkFile:" )
        {
                SMultiSpkFile *ms = new SMultiSpkFile;
                ms->bRemove = false;
                ms->pFile = NULL;
                ms->bOn = (rest.GetToken ( 1, ':' ).ToInt()) ? true : false;
                ms->lSize = rest.GetToken ( 2, ':' ).ToLong();
                ms->sName = rest.GetToken ( 3, ':' );
                ms->sData = NULL;
                ms->iType = TYPE_SPK;
                CyString r = rest.GetToken ( 4, -1, ':' );
                if ( !r.Empty() )
                {
                        ms->sScriptName = r.GetToken ( 1, '|' );
                        ms->sScriptAuthor = r.GetToken ( 2, '|' );
                        ms->sScriptVersion = r.GetToken ( 3, -1, '|' );
                }
                m_lFiles.push_back ( ms );
        }
        else if ( first == "XspFile:" )
        {
                SMultiSpkFile *ms = new SMultiSpkFile;
                ms->bRemove = false;
                ms->pFile = NULL;
                ms->bOn = (rest.GetToken ( 1, ':' ).ToInt()) ? true : false;
                ms->lSize = rest.GetToken ( 2, ':' ).ToLong();
                ms->sName = rest.GetToken ( 3, ':' );
                ms->sData = NULL;
                ms->iType = TYPE_XSP;
                CyString r = rest.GetToken ( 4, -1, ':' );
                if ( !r.Empty() )
                {
                        ms->sScriptName = r.GetToken ( 1, '|' );
                        ms->sScriptAuthor = r.GetToken ( 2, '|' );
                        ms->sScriptVersion = r.GetToken ( 3, -1, '|' );
                }
                m_lFiles.push_back ( ms );
        }
        else if ( first == "BaseFile:" )
        {
                SMultiSpkFile *ms = new SMultiSpkFile;
                ms->bRemove = false;
                ms->pFile = NULL;
                ms->bOn = (rest.GetToken ( 1, ':' ).ToInt()) ? true : false;
                ms->lSize = rest.GetToken ( 2, ':' ).ToLong();
                ms->sName = rest.GetToken ( 3, ':' );
                ms->sData = NULL;
                ms->iType = TYPE_BASE;
                CyString r = rest.GetToken ( 4, -1, ':' );
                if ( !r.Empty() )
                {
                        ms->sScriptName = r.GetToken ( 1, '|' );
                        ms->sScriptAuthor = r.GetToken ( 2, '|' );
                        ms->sScriptVersion = r.GetToken ( 3, -1, '|' );
                }
                m_lFiles.push_back ( ms );
        }
        else
                return false;

        return true;
}

void CMultiSpkFile::RemovePackages()
{
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                if ( !node->Data()->bRemove ) continue;
                node->DeleteData();
        }

        m_lFiles.RemoveEmpty();
}

void CMultiSpkFile::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);
}

bool CMultiSpkFile::ReadFile ( CyString filename, bool readdata )
{
        FILE *id = fopen ( filename.c_str(), "rb" );
        if ( !id )
                return false;

        // first read the header
        if ( !ParseHeader ( CSpkFile::GetEndOfLine ( id, NULL, false ) ) )
                return false;

        ClearFiles ();

        int doneLen = 0;
        // next read the data values for the spk files
        if ( m_SHeader.lComprLen )
        {
                // read data to memory
                unsigned char *readData = new unsigned char[m_SHeader.lComprLen + 1];
                unsigned char size[4];
                fread ( size, 4, 1, id );
                fread ( readData, sizeof(unsigned char), m_SHeader.lComprLen, id );
                unsigned long uncomprLen = (size[0] << 24) + (size[1] << 16) + (size[2] << 8) + size[3];

                // check for zlib compression
                if ( m_SHeader.iCompression == SPKCOMPRESS_ZLIB )
                {
                        // uncomress the data
                        unsigned char *uncompr = new unsigned char[uncomprLen];
                        
                        int err = uncompress ( uncompr, &uncomprLen, readData, m_SHeader.lComprLen );
                        if ( err == Z_OK )
                                ReadValues ( CyString ((char *)uncompr) );
                        doneLen = uncomprLen;
                        delete uncompr;
                }
                else if ( m_SHeader.iCompression == SPKCOMPRESS_7ZIP )
                {
                        long len = uncomprLen;
                        unsigned char *compr = LZMADecode_C ( readData, m_SHeader.lComprLen, (size_t *)&len, NULL );
                        if ( compr )
                                ReadValues ( CyString ((char *)compr) );
                }
                // no compression
                else
                        ReadValues ( CyString ((char *)readData) );

                delete readData;
        }

        if ( readdata )
        {
                for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
                {
                        SMultiSpkFile *ms = node->Data();
                        ms->sData = new char[ms->lSize];
                        fread ( ms->sData, sizeof(char), ms->lSize, id );
                }
        }

        m_sFilename = filename;

        fclose ( id );
        m_bChanged = false;

        return true;
}

unsigned int CMultiSpkFile::GetAvailableFiles()
{
        unsigned int size = 0;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                if ( node->Data()->bRemove ) continue;
                ++size;
        }

        return size;
}

unsigned long CMultiSpkFile::GetFileSize()
{
        unsigned int size = 0;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                if ( node->Data()->bRemove ) continue;
                size += node->Data()->lSize;
        }

        return size;
}

void CMultiSpkFile::ClearFiles ()
{
        m_lFiles.clear(true);
}

bool CMultiSpkFile::ExtractData ( SMultiSpkFile *ms )
{
        FILE *id = fopen ( m_sFilename.c_str(), "rb" );
        if ( !id )
                return false;

        // skip past the header
        CSpkFile::GetEndOfLine ( id, NULL, false );
        // seek past the values
        fseek ( id, 4, SEEK_CUR );
        fseek ( id, m_SHeader.lComprLen, SEEK_CUR );

        bool found = false;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( ms->sName.Compare(it->sName) )
                {
                        ms->lSize = it->lSize;
                        ms->sScriptAuthor = it->sScriptAuthor;
                        ms->sScriptName = it->sScriptName;
                        ms->sScriptVersion = it->sScriptVersion;
                        ms->bOn = it->bOn;
                        ms->iType = it->iType;
                        ms->sData = new char[ms->lSize];
                        if ( it->sData )
                                memcpy ( ms->sData, it->sData, ms->lSize );
                        else
                                fread ( ms->sData, sizeof(char), ms->lSize, id );
                        found = true;
                        break;
                }
                else
                        fseek ( id, it->lSize, SEEK_CUR );
        }

        fclose ( id );
        return found;
}

bool CMultiSpkFile::ReadFileToMemory ( SMultiSpkFile *ms )
{
        if ( ms->sData )
                return true;

        FILE *id = fopen ( m_sFilename.c_str(), "rb" );
        if ( !id )
                return false;

        // skip past the header
        CSpkFile::GetEndOfLine ( id, NULL, false );
        // seek past the values
        fseek ( id, 4, SEEK_CUR );
        fseek ( id, m_SHeader.lComprLen, SEEK_CUR );

        bool found = false;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( it == ms )
                {
                        ms->sData = new char[ms->lSize];
                        fread ( ms->sData, sizeof(char), ms->lSize, id );
                        found = true;
                        break;
                }
                else
                        fseek ( id, it->lSize, SEEK_CUR );
        }

        fclose ( id );
        return found;
}

bool CMultiSpkFile::ExtractFile ( const CyString &file, CyString dir )
{
        SMultiSpkFile *ms = FindFile(file);
        if ( !ms ) return false;
        return ExtractFile(ms, dir);
}

bool CMultiSpkFile::ExtractFile ( SMultiSpkFile *ms, CyString dir )
{
        if ( !ms->sData )
        {
                if ( !ReadFileToMemory ( ms ) )
                        return false;
        }

        CyString filename = dir;
        if ( !dir.Empty() )
                filename += "/";
        filename += ms->sName;

        FILE *id = fopen ( filename.c_str(), "wb" );
        if ( !id )
                return false;

        fwrite ( ms->sData, sizeof(char), ms->lSize, id );
        fclose ( id );

        return true;
}

bool CMultiSpkFile::ExtractAll ( CyString dir )
{
        if ( m_sFilename.Empty() )
                return false;

        if ( !ReadAllFilesToMemory () )
                return false;

        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( ms->bRemove ) continue;
                if ( !ms->sData )
                        continue;

                FILE *id = fopen ( CyString(dir + "/" + ms->sName).c_str(), "wb" );
                if ( !id )
                        continue;

                fwrite ( ms->sData, sizeof(char), ms->lSize, id );
                fclose ( id );
        }
        return true;
}

bool CMultiSpkFile::SplitMulti ( CyString filename, CyString destdir )
{
        if ( !ReadFile ( filename ) )
                return false;

        bool doneone = false;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( ms->bRemove ) continue;
                if ( !ms->sData )
                        continue;

                CyString destfile = destdir;
                if ( !destfile.Empty() )
                        destfile += "/";
                destfile += ms->sName;
                FILE *id = fopen ( destfile.c_str(), "wb" );
                if ( !id )
                        continue;

                fwrite ( ms->sData, sizeof(char), ms->lSize, id );
                fclose ( id );
                doneone = true;
        }

        return doneone;
}

bool CMultiSpkFile::ReadAllFilesToMemory (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;

        // read the header
        CSpkFile::GetEndOfLine ( id, NULL, false );
        // skip past values
        fseek ( id, 4, SEEK_CUR );
        fseek ( id, m_SHeader.lComprLen, SEEK_CUR );

        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( ms->bRemove ) continue;
                if ( progress )
                        progress->UpdatePackage(ms);
                if ( !ms->sData )
                {
                        ms->sData = new char[ms->lSize];
                        fread ( ms->sData, sizeof(char), ms->lSize, id );
                }
                else
                        fseek ( id, ms->lSize, SEEK_CUR );
        }

        return true;
}

bool CMultiSpkFile::RemoveFile ( CyString file )
{
        int num = 0;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( file.Compare(it->sName) )
                        return RemoveFile ( num );
                ++num;
        }
        return false;
}

bool CMultiSpkFile::RemoveFile ( SMultiSpkFile *ms )
{
        int num = 0;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( it == ms )
                        return RemoveFile ( num );
                ++num;
        }
        return false;
}

bool CMultiSpkFile::RemoveFile ( int id )
{
        if ( (id < 0) || (id >= m_lFiles.size()) )
                return false;

        SMultiSpkFile *file = m_lFiles.Get ( id );
        m_lFiles.erase ( id + 1 );

        if ( file )
                delete file;

        m_bChanged = true;
        return true;
}

bool CMultiSpkFile::MarkRemoveFile ( CyString file )
{
        int num = 0;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( file.Compare(it->sName) )
                        return MarkRemoveFile ( num );
                num++;
        }
        return false;
}

bool CMultiSpkFile::MarkRemoveFile ( SMultiSpkFile *ms )
{
        int num = 0;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( it == ms )
                        return MarkRemoveFile ( num );
                ++num;
        }
        return false;
}

bool CMultiSpkFile::MarkRemoveFile ( int id )
{
        if ( (id < 0) || (id >= m_lFiles.size()) )
                return false;

        SMultiSpkFile *file = m_lFiles.Get ( id );
        file->bRemove = true;
        m_bChanged = true;
        return true;
}

void CMultiSpkFile::MarkRemoveAll()
{
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
                node->Data()->bRemove = true;
        m_bChanged = true;
}


bool CMultiSpkFile::ReadSpk( SMultiSpkFile *ms, int type )
{
        if ( ms->pFile->IsFullyLoaded() )
                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
        CSpkFile::GetEndOfLine ( id, NULL, false );
        // skip past values
        fseek ( id, 4, SEEK_CUR );
        fseek ( id, m_SHeader.lComprLen, SEEK_CUR );

        bool ret = false;
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *it = node->Data();
                if ( it == ms )
                {
                        if ( !ms->pFile )
                        {
                                if ( ms->iType == TYPE_XSP )
                                        ms->pFile = new CXspFile;
                                else
                                        ms->pFile = new CSpkFile;
                        }
                        ret = it->pFile->ReadFile ( id, type, NULL );
                        break;
                }
                else
                        fseek ( id, it->lSize, SEEK_CUR );
        }

        fclose ( id );

        return ret;
}

bool CMultiSpkFile::ReadAllPackages( int type, CLinkList<CBaseFile> *addToList )
{
        // 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
        CSpkFile::GetEndOfLine ( id, NULL, false );
        // skip past values
        fseek ( id, 4, SEEK_CUR );
        fseek ( id, m_SHeader.lComprLen, SEEK_CUR );

        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                CBaseFile *package = NULL;
                if ( ms->iType == TYPE_XSP )
                        package = new CXspFile;
                else
                        package = new CSpkFile;

                if ( !addToList )
                {
                        if ( ms->pFile )
                        {
                                delete package;
                                package = ms->pFile;
                        }
                }

                if ( !package->IsFullyLoaded() )
                {
                        long tell = ftell ( id );
                        package->ReadFile ( id, type, NULL );

                        if ( addToList )
                        {
                                addToList->push_back(package);
                                package->SetEnabled(ms->bOn);
                        }
                        else if ( package )
                                ms->pFile = package;

                        // move to correct position in file for next stream of data
                        // should be fine, this is more of a failsafe
                        rewind ( id );
                        fseek ( id, tell, SEEK_CUR );
                }
                fseek ( id, ms->lSize, SEEK_CUR );
        }

        fclose ( id );

        return true;
}


SMultiSpkFile *CMultiSpkFile::FindFile ( CyString name )
{
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( ms->sName.Compare(name) )
                        return ms;
        }
        return NULL;
}

void CMultiSpkFile::UpdatedPackage(CBaseFile *p)
{
        SMultiSpkFile *s = this->FindPackage(p);
        if ( s )
        {
                if ( s->sData )
                        delete s->sData;
                s->sData = (char *)p->CreateData((size_t*)&s->lSize);
        }
}

SMultiSpkFile *CMultiSpkFile::FindPackage(CBaseFile *p)
{
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( ms->pFile == p )
                        return ms;
        }

        return NULL;
}

SMultiSpkFile *CMultiSpkFile::FindPackage(CyString name, CyString author)
{
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( !ms->pFile )
                        continue;

                if ( ms->pFile->GetName().Compare(name) && ms->pFile->GetAuthor().Compare(author) )
                        return ms;
        }

        return NULL;
}