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 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(const Utils::WString &file, bool on){// multipackif (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 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 = CFileIO(file).filename();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(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 markedthis->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 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;}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 headerif ( !_parseHeader(File.readEndOfLineStr()) ) 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){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 compressionelse{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 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 = _wfopen(_sFilename.c_str(), L"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 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 fromif (_sFilename.empty())return false;// now open the fileFILE *id = _wfopen(_sFilename.c_str(), L"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(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 fromif (_sFilename.empty())return false;// now open the fileCFileIO File(_sFilename);if ( !File.startRead() ) return false;// read the headerFile.readEndOfLineStr();// 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 (_sFilename.empty())return false;// now open the fileCFileIO File(_sFilename);if ( !File.startRead() ) return false;// read the headerFile.readEndOfLineStr();// 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;}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: ";elseret += L"SpkFile: ";if (ms->bOn)ret += L"1:";elseret += 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);}elsereturn 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]);}