Subversion Repositories spk

Rev

Rev 219 | 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(const Utils::WString &file, bool on )
{
        if ( this->addFile(file, on) )
        {
                Utils::WString findFile = CFileIO(file).filename();

                const SMultiSpkFile *p = this->findFile(findFile);
                if ( p )
                {
                        this->CreatePackage(const_cast<SMultiSpkFile*>(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(const Utils::WString &file, bool on)
{
        // multipack
        if (file.contains(L"::" ))
        {
                Utils::WString mfile = file.left(file.findPos(L"::"));
                CMultiSpkFile spkfile;
                if ( spkfile.readFile(mfile, false))
                {
                        SMultiSpkFile *ms = new SMultiSpkFile;
                        ms->bRemove = false;
                        ms->sName = file.right((int)(file.length() - file.findPos(L"::")) - 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;

        CFileIO File(file);
        if ( !File.startRead() ) return false;

        // create entry
        SMultiSpkFile *ms = new SMultiSpkFile;
        ms->bRemove = false;
        ms->pFile = NULL;
        ms->sName = CFileIO(file).filename();
        ms->bOn = on;

        // read data
        ms->sData = (char *)File.readAll((size_t *)&ms->lSize);
        File.close();

        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->author();
                        ms->sScriptName         = baseFile->name();
                        ms->sScriptVersion      = baseFile->version();
                        ms->iType                       = baseFile->GetType();
                }

                delete baseFile;
        }

        addFile(ms);

        return true;
}

SMultiSpkFile *CMultiSpkFile::addFileEntry(const Utils::WString &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;
}


bool CMultiSpkFile::writeFile(const Utils::WString &filename, CProgressInfo *progress)
{
        CFileIO File(filename);
        if ( !File.startWrite() ) return false;

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

        Utils::WString data = _createData();

        int comprLen = (int)((data.length() * sizeof(wchar_t)) / sizeof(char)), 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)uncomprLen, 0 );
                if ( err == Z_OK )
                        compressed = true;
        }

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

        // write the main header to the file
        if ( !File.write("MSPKCycrow;%.2f;%d;%d;%d;%d\n", FILEVERSION, valueheader, data.length(), comprLen, (m_SHeader.bSelection) ? 1 : 0) ) return false;

        // write the compressed data to file
        File.writeSize(uncomprLen);
        File.write(compr, comprLen);
        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(File, NULL);
                else
                        File.write(ms->sData, ms->lSize);
        }

        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();
}


bool CMultiSpkFile::readFile(const Utils::WString &filename, bool bReadData)
{
        CFileIO File(filename);
        if ( !File.startRead() ) return false;

        // first read the header
        if ( !_parseHeader(File.readEndOfLineStr()) ) return false;

        ClearFiles ();

        int doneLen = 0;
        // next read the data values for the spk files
        if ( m_SHeader.lComprLen )
        {
                // read data to memory
                unsigned long uncomprLen = File.readSize();
                unsigned char *readData = File.read(m_SHeader.lComprLen);

                // 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)
                        {
                                if (m_SHeader.fVersion < 4.4f)
                                {
                                        std::string data((char*)uncompr);
                                        _readValues(std::wstring(data.begin(), data.end()));
                                }
                                else
                                {
                                        const wchar_t* data = (const wchar_t*)uncompr;
                                        _readValues(Utils::WString(data));
                                }
                        }
                        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)
                        {
                                if (m_SHeader.fVersion < 4.4f)
                                {
                                        std::string data((char*)compr);
                                        _readValues(std::wstring(data.begin(), data.end()));
                                }
                                else
                                {
                                        const wchar_t* data = (const wchar_t*)compr;
                                        _readValues(Utils::WString(data));
                                }
                        }
                }
                // no compression
                else
                {
                        if (m_SHeader.fVersion < 4.4f)
                        {
                                std::string data((char*)readData);
                                _readValues(std::wstring(data.begin(), data.end()));
                        }
                        else
                        {
                                const wchar_t* data = (const wchar_t*)readData;
                                _readValues(Utils::WString(data));
                        }
                }

                delete readData;
        }

        if ( bReadData ) {
                for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() ) {
                        SMultiSpkFile *ms = node->Data();
                        ms->sData = (char *)File.read(ms->lSize);
                }
        }

        _sFilename = filename;

        File.close();
        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 = _wfopen (_sFilename.c_str(), L"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 = _wfopen(_sFilename.c_str(), L"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 Utils::WString &file, const Utils::WString &dir)
{
        const SMultiSpkFile *ms = findFile(file);
        if ( !ms ) return false;
        return extractFile(ms, dir);
}

bool CMultiSpkFile::extractFile(const SMultiSpkFile *ms, const Utils::WString &dir)
{
        if ( !ms->sData )
        {
                if (!ReadFileToMemory(const_cast<SMultiSpkFile *>(ms)))
                        return false;
        }

        Utils::WString filename = dir;
        if (!dir.empty())
                filename += L"/";
        filename += ms->sName;

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

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

        return true;
}

bool CMultiSpkFile::extractAll(const Utils::WString &dir)
{
        if (_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 = _wfopen((dir + L"/" + ms->sName).c_str(), L"wb" );
                if ( !id )
                        continue;

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

bool CMultiSpkFile::splitMulti(const Utils::WString &filename, const Utils::WString &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;

                Utils::WString destfile = destdir;
                if ( !destfile.empty() )
                        destfile += L"/";
                destfile += ms->sName;
                FILE *id = _wfopen(destfile.c_str(), L"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 (_sFilename.empty())
                return false;

        // now open the file
        FILE *id = _wfopen(_sFilename.c_str(), L"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(const Utils::WString &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(const 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(const Utils::WString &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 (_sFilename.empty())
                return false;

        // now open the file
        CFileIO File(_sFilename);
        if ( !File.startRead() ) return false;

        // read the header
        File.readEndOfLineStr();
        // skip past values
        File.seek(4 + m_SHeader.lComprLen);

        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(File, type, NULL);
                        break;
                }
                else
                        File.seek(it->lSize);
        }

        File.close();
        return ret;
}

bool CMultiSpkFile::readAllPackages( int type, CLinkList<CBaseFile> *addToList )
{
        // no file to read from
        if (_sFilename.empty())
                return false;

        // now open the file
        CFileIO File(_sFilename);
        if ( !File.startRead() ) return false;

        // read the header
        File.readEndOfLineStr();
        // skip past values
        File.seek(4 + m_SHeader.lComprLen);

        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 = File.position();
                        package->readFile(File, 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
                        File.seekStart(tell);
                }
                File.seek(ms->lSize);
        }

        File.close();
        return true;
}


const SMultiSpkFile *CMultiSpkFile::findFile(const Utils::WString &name) const
{
        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(const Utils::WString &name, const Utils::WString &author)
{
        for ( CListNode<SMultiSpkFile> *node = m_lFiles.Front(); node; node = node->next() )
        {
                SMultiSpkFile *ms = node->Data();
                if ( !ms->pFile )
                        continue;

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

        return NULL;
}

Utils::WString CMultiSpkFile::_createData() const
{
        Utils::WString ret;
        if (!_sName.empty())
                ret = L"Name: " + _sName + L"\n";
        for (CListNode<SMultiSpkFile>* node = m_lFiles.Front(); node; node = node->next())
        {
                SMultiSpkFile* ms = node->Data();
                if (ms->iType == TYPE_XSP)
                        ret += L"XspFile: ";
                else
                        ret += L"SpkFile: ";

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

        return ret;
}

bool CMultiSpkFile::_parseHeader(const Utils::WString &header)
{
        if (header.token(L";", 1) != L"MSPKCycrow")
                return false;

        m_SHeader.fVersion = header.token(L";", 2).toFloat();
        if (m_SHeader.fVersion > FILEVERSION)
                return false;

        m_SHeader.iCompression = header.token(L";", 3).toInt();
        m_SHeader.lUncomprLen = header.token(L";", 4).toLong();
        m_SHeader.lComprLen = header.token(L";", 5).toLong();
        m_SHeader.bSelection = (header.token(L";", 4).toInt()) ? true : false;

        return true;
}

bool CMultiSpkFile::_parseValueLine(const Utils::WString &line)
{
        Utils::WString first = line.token(L" ", 1);
        Utils::WString rest = line.tokens(L" ", 2);

        if (first == L"Name:")
                _sName = rest;
        else if (first == L"SpkFile:")
        {
                SMultiSpkFile* ms = new SMultiSpkFile;
                ms->bRemove = false;
                ms->pFile = NULL;
                ms->bOn = (rest.token(L":", 1).toInt()) ? true : false;
                ms->lSize = rest.token(L":", 2).toLong();
                ms->sName = rest.token(L":", 3);
                ms->sData = NULL;
                ms->iType = TYPE_SPK;
                Utils::WString r = rest.tokens(L":", 4);
                if (!r.empty())
                {
                        ms->sScriptName = r.token(L"|", 1);
                        ms->sScriptAuthor = r.token(L"|", 2);
                        ms->sScriptVersion = r.tokens(L"|", 3);
                }
                m_lFiles.push_back(ms);
        }
        else if (first == L"XspFile:")
        {
                SMultiSpkFile* ms = new SMultiSpkFile;
                ms->bRemove = false;
                ms->pFile = NULL;
                ms->bOn = (rest.token(L":", 1).toInt()) ? true : false;
                ms->lSize = rest.token(L":", 2).toLong();
                ms->sName = rest.token(L":", 3);
                ms->sData = NULL;
                ms->iType = TYPE_XSP;
                Utils::WString r = rest.tokens(L":", 4);
                if (!r.empty())
                {
                        ms->sScriptName = r.token(L"|", 1);
                        ms->sScriptAuthor = r.token(L"|", 2);
                        ms->sScriptVersion = r.tokens(L"|", 3);
                }
                m_lFiles.push_back(ms);
        }
        else if (first == L"BaseFile:")
        {
                SMultiSpkFile* ms = new SMultiSpkFile;
                ms->bRemove = false;
                ms->pFile = NULL;
                ms->bOn = (rest.token(L":", 1).toInt()) ? true : false;
                ms->lSize = rest.token(L":", 2).toLong();
                ms->sName = rest.token(L":", 3);
                ms->sData = NULL;
                ms->iType = TYPE_BASE;
                Utils::WString r = rest.tokens(L":", 4);
                if (!r.empty())
                {
                        ms->sScriptName = r.token(L"|", 1);
                        ms->sScriptAuthor = r.token(L"|", 2);
                        ms->sScriptVersion = r.tokens(L"|", 3);
                }
                m_lFiles.push_back(ms);
        }
        else
                return false;

        return true;
}

void CMultiSpkFile::_readValues(const Utils::WString &values)
{
        std::vector<Utils::WString> lines;
        size_t num = values.tokenise(L"\n", lines);

        for (size_t i = 0; i < num; i++)
                _parseValueLine(lines[i]);
}