Rev 56 | Rev 176 | Go to most recent revision | 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 filenameCListNode<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/authorfor ( 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 ){// multipackif ( 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 fileint 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);}elsedelete ms;}return true;}return false;}else if ( check != SPKFILE_SINGLE && check != SPKFILE_SINGLESHIP )return false;CFileIO File(file);if ( !File.startRead() ) return false;// create entrySMultiSpkFile *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;// read datams->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 ( 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: ";elseret += "SpkFile: ";if ( ms->bOn )ret += "1:";elseret += "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 ){CFileIO File(filename);if ( !File.startWrite() ) return false;// make sure we remove all packages that have been markedthis->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 fileif ( !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 fileFile.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);elseFile.write(ms->sData, ms->lSize);}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 );}elsereturn 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 bReadData){CFileIO File(filename);if ( !File.startRead() ) return false;// first read the headerif ( !ParseHeader(File.readEndOfLine()) ) return false;ClearFiles ();int doneLen = 0;// next read the data values for the spk filesif ( m_SHeader.lComprLen ){// read data to memoryunsigned long uncomprLen = File.readSize();unsigned char *readData = File.read(m_SHeader.lComprLen);// check for zlib compressionif ( m_SHeader.iCompression == SPKCOMPRESS_ZLIB ) {// uncomress the dataunsigned 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 compressionelseReadValues ( CyString ((char *)readData) );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);}}m_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 = fopen ( m_sFilename.c_str(), "rb" );if ( !id )return false;// skip past the headerCSpkFile::GetEndOfLine ( id, NULL, false );// seek past the valuesfseek ( 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 );elsefread ( ms->sData, sizeof(char), ms->lSize, id );found = true;break;}elsefseek ( 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 headerCSpkFile::GetEndOfLine ( id, NULL, false );// seek past the valuesfseek ( 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;}elsefseek ( 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 fromif ( m_sFilename.Empty() )return false;// now open the fileFILE *id = fopen ( m_sFilename.c_str(), "rb" );if ( !id )return false;// read the headerCSpkFile::GetEndOfLine ( id, NULL, false );// skip past valuesfseek ( 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 );}elsefseek ( 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 fromif ( m_sFilename.Empty() )return false;// now open the fileCFileIO File(m_sFilename.ToString());if ( !File.startRead() ) return false;// read the headerFile.readEndOfLine();// skip past valuesFile.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;elsems->pFile = new CSpkFile;}ret = it->pFile->readFile(File, type, NULL);break;}elseFile.seek(it->lSize);}File.close();return ret;}bool CMultiSpkFile::ReadAllPackages( int type, CLinkList<CBaseFile> *addToList ){// no file to read fromif ( m_sFilename.Empty() )return false;// now open the fileCFileIO File(m_sFilename.ToString());if ( !File.startRead() ) return false;// read the headerFile.readEndOfLine();// skip past valuesFile.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;elsepackage = 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 failsafeFile.seekStart(tell);}File.seek(ms->lSize);}File.close();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->name().Compare(name.ToString()) && ms->pFile->author().Compare(author.ToString()) )return ms;}return NULL;}