Rev 82 | Rev 101 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "VirtualFileSystem.h"#include "File_IO.h"#include "CatFile.h"#include "XspFile.h"#include "Packages.h"namespace SPK {CVirtualFileSystem::CVirtualFileSystem(){m_bLoaded = false;m_pMap = new FileList;m_pModMap = new FileList;m_pTexts = new CTextDB();m_pModTexts = new CTextDB();m_sAddon = "";m_iLang = 0;}CVirtualFileSystem::~CVirtualFileSystem(void){if ( m_pMap ) delete m_pMap;if ( m_pModMap ) delete m_pModMap;if ( m_pTexts ) delete m_pTexts;if ( m_pModTexts ) delete m_pModTexts;}void CVirtualFileSystem::setLanguage(int iLang){m_iLang = iLang;}bool CVirtualFileSystem::LoadFilesystem(const Utils::String &dir, int maxPatch){return this->LoadFilesystem(dir, "", maxPatch);}bool CVirtualFileSystem::LoadFilesystem(const Utils::String &dir, const Utils::String &mod, int maxPatch){m_sDir = dir;this->_clear();int number = 1;while ( CFileIO(CyString(dir) + "/" + CyString::Number(number).PadNumber(2) + ".cat").ExistsOld() ){if ( maxPatch && maxPatch < number ) break;CyString file = CyString(dir) + "/" + CyString::Number(number).PadNumber(2);if ( !CFileIO(file + ".dat").ExistsOld() )break;CCatFile cat;if ( cat.Open(file + ".cat", m_sAddon, CATREAD_JUSTCONTENTS, false) == CATERR_NONE ){for ( CListNode<SInCatFile> *c = cat.GetFiles()->Front(); c; c = c->next() ) {this->_addModFile(CFileIO(c->Data()->sFile).GetFullFilename().ToString(), CyString(file + ".cat").ToString(), m_pMap);m_bLoaded = true;}}++number;}// add all the files from the modif ( !mod.empty() )this->addMod(mod);// now add all the extracted datathis->_addDir(m_sDir, "");return m_bLoaded;}void CVirtualFileSystem::_addDir(const Utils::String &sStart, const Utils::String &sDir){CDirIO Dir(sStart + "/" + sDir);CyStringList *list = Dir.DirList();if ( list ) {for ( SStringList *strNode = list->Head(); strNode; strNode = strNode->next ) {if ( CDirIO(Dir.Dir(strNode->str)).IsDir() ) _addDir(sStart, sDir + "/" + strNode->str.ToString());else if ( CFileIO(strNode->str).CheckFileExtension("cat") ) continue;else if ( CFileIO(strNode->str).CheckFileExtension("dat") ) continue;else this->_addFile(sDir + "/" + strNode->str.ToString(), Dir.File(strNode->str).ToString(), m_pMap);}}}void CVirtualFileSystem::_addFile(const Utils::String &sFile, const Utils::String &sDest, FileList *pList){(*pList)[sFile.asFilename().removeIf(0, '/').lower()] = sDest.findReplace("//", "/");}void CVirtualFileSystem::_addModFile(const Utils::String &sFile, const Utils::String &sMod, FileList *pList){this->_addFile(sFile, sMod + "::" + sFile, pList);}bool CVirtualFileSystem::loadMod(const Utils::String &mod){bool loaded = false;if ( !m_pModMap ) m_pModMap = new FileList;CCatFile cat;if ( CCatFile::Opened(cat.Open(mod, m_sAddon, CATREAD_JUSTCONTENTS, false), false) ){for ( CListNode<SInCatFile> *c = cat.GetFiles()->Front(); c; c = c->next() ) {this->_addModFile(CFileIO(c->Data()->sFile).GetFullFilename().ToString(), mod, m_pModMap);loaded = true;}}return loaded;}bool CVirtualFileSystem::addMod(const Utils::String &mod){bool loaded = false;if ( !m_pMap ) m_pMap = new FileList;CCatFile cat;if ( CCatFile::Opened(cat.Open(mod, m_sAddon, CATREAD_JUSTCONTENTS, false), false) ){for ( CListNode<SInCatFile> *c = cat.GetFiles()->Front(); c; c = c->next() ){this->_addModFile(CFileIO(c->Data()->sFile).GetFullFilename().ToString(), mod, m_pMap);loaded = true;}}return loaded;}bool CVirtualFileSystem::textExists(int iLang, int iPage, int iID) const{if ( m_pTexts ) {if ( m_pTexts->exists(iLang, iPage, iID) ) return m_pTexts->exists(iLang, iPage, iID);}if ( m_pModTexts ) {if ( m_pModTexts->exists(iLang, iPage, iID) ) return m_pModTexts->exists(iLang, iPage, iID);}return false;}Utils::String CVirtualFileSystem::findText(int iLang, int iPage, int iID) const{if ( m_pTexts ) {if ( m_pTexts->exists(iLang, iPage, iID) ) return m_pTexts->get(iLang, iPage, iID);}if ( m_pModTexts ) {if ( m_pModTexts->exists(iLang, iPage, iID) ) return m_pModTexts->get(iLang, iPage, iID);}return Utils::String("ReadText") + (long)iPage + "-" + (long)iID;}bool CVirtualFileSystem::isFileAvailable(const Utils::String &file){return !this->_findFile(file).empty();}Utils::String CVirtualFileSystem::_findFile(const Utils::String &file){Utils::String toFile = file.findReplace("\\", "/").lower();if ( m_pModMap && !m_pModMap->empty() ) {if ( !m_sAddon.empty() ) {FileListItr aitr = m_pModMap->find(CFileIO(m_sAddon + "/" + toFile).GetFullFilename().ToLower().c_str());if ( aitr == m_pModMap->end() ) aitr = m_pModMap->find(CFileIO(_convertExtension(m_sAddon + "/" + toFile)).GetFullFilename().ToLower().c_str());if ( aitr != m_pModMap->end() ) return aitr->second;}FileListItr itr = m_pModMap->find(CFileIO(toFile).GetFullFilename().ToLower().c_str());if ( itr == m_pModMap->end() ) itr = m_pModMap->find(CFileIO(_convertExtension(toFile)).GetFullFilename().ToLower().c_str());if ( itr != m_pModMap->end() ) return itr->second;}else if ( m_pMap && !m_pMap->empty() ) {if ( !m_sAddon.empty() ) {FileListItr aitr = m_pMap->find(CFileIO(m_sAddon + "/" + toFile).fullFilename().lower().c_str());if ( aitr == m_pMap->end() ) aitr = m_pMap->find(CFileIO(_convertExtension(m_sAddon + "/" + file)).fullFilename().lower().c_str());if ( aitr != m_pMap->end() ) return aitr->second;}FileListItr itr = m_pMap->find(CFileIO(file).GetFullFilename().ToLower().c_str());if ( itr == m_pMap->end() ) itr = m_pMap->find(CFileIO(_convertExtension(file)).GetFullFilename().ToLower().c_str());if ( itr != m_pMap->end() ) return itr->second;}return "";}Utils::String CVirtualFileSystem::_extractFromCat(const Utils::String &sCat, const Utils::String &sFile, const Utils::String &sTo){CCatFile catFile;if ( catFile.Open(sCat, m_sAddon, CATREAD_CATDECRYPT, false) == CATERR_NONE ){// check for the fileif ( catFile.ExtractFile(sFile, sTo) ) return sTo;if ( catFile.Error() == CATERR_INVALIDDEST || catFile.Error() == CATERR_CANTCREATEDIR ) {if ( catFile.ExtractFile(sFile) ) return sFile;}}return "";}Utils::String CVirtualFileSystem::_extract(const Utils::String &sFile, const Utils::String &sTo){// check if we need to unpack the fileif ( CCatFile::CheckPackedExtension(sFile) ) {CFileIO File(sFile);C_File f(CyString(File.fullFilename()));if ( !f.readFromFile(File) ) return "";if ( !f.UnPCKFile() ) return "";if ( !f.WriteToFile(sTo) ) return "";return sTo;}return sFile;}Utils::String CVirtualFileSystem::ExtractGameFile(const Utils::String &file, const Utils::String &to){Utils::String sIn = _findFile(file);Utils::String sFile = file;if ( sIn.empty() ) return "";if ( sIn.isin("::") ) {sFile = sIn.token("::", 2);sIn = sIn.token("::", 1);return _extractFromCat(sIn, sFile, to);}return _extract(sIn, to);}Utils::String CVirtualFileSystem::_convertExtension(const Utils::String &sFile){CFileIO File(sFile);if ( File.CheckFileExtension("pck") ) {return File.ChangeFileExtension("xml").ToString();}else if ( File.CheckFileExtension("xml") ) {return File.ChangeFileExtension("pck").ToString();}else if ( File.CheckFileExtension("pbb") ) {return File.ChangeFileExtension("bob").ToString();}else if ( File.CheckFileExtension("bob") ) {return File.ChangeFileExtension("pbb").ToString();}else if ( File.CheckFileExtension("pbd") ) {return File.ChangeFileExtension("bod").ToString();}else if ( File.CheckFileExtension("bod") ) {return File.ChangeFileExtension("pbd").ToString();}return sFile;}CyStringList *CVirtualFileSystem::GetTShipsEntries(){Utils::String sTo = this->ExtractGameFile("types/tships.pck", CPackages::tempDirectory() + "/tships.txt");if ( !sTo.empty() ) {CFileIO TShips(sTo);if ( TShips.exists() ){CyStringList *lines = TShips.ReadLinesStr();if ( lines ){// remove any commands, blank lines, and start// and put the id as the dataint entries = -1;for ( SStringList *str = lines->Head(); str; str = str->next ){str->str.RemoveFirstSpace();str->str.RemoveChar(9);str->str.RemoveChar('\r');str->str.RemoveChar('\n');if ( str->str.Empty() ){str->remove = true;continue;}if ( str->str[0] == '/' ){str->remove = true;continue;}if ( entries == -1 ){entries = str->str.GetToken(";", 2, 2).ToInt();str->remove = true;continue;}// hopefully we now have a valid tships lineint num = -1;while ( str->data.Empty() )str->data = str->str.GetToken(";", num--, (num + 2));}}// remove the tmp fileTShips.remove();if ( lines )lines->RemoveMarked();return lines;}}return NULL;}C_File *CVirtualFileSystem::extractGameFileToPackage(CBaseFile *pPackage, const Utils::String &sFile, FileType iFileType){return this->extractGameFileToPackage(pPackage, sFile, iFileType, sFile);}C_File *CVirtualFileSystem::extractGameFileToPackage(CBaseFile *pPackage, const Utils::String &sFile, FileType iFileType, const Utils::String &sTo){Utils::String to = this->ExtractGameFile(sFile, CPackages::tempDirectory() + "tmp.dat");if ( !to.empty() ) {CFileIO File(to);C_File *f = pPackage->AddFile(CFileIO(sTo).GetFilename(), CFileIO(sTo).GetDir(), iFileType);if ( f ) {if ( f->ReadFromFile(CPackages::GetTempDirectory() + "tmp.dat") ) {File.remove();return f;}}File.remove();}return NULL;}Utils::String CVirtualFileSystem::getTShipsEntry(const Utils::String &sId){CyStringList *ships = this->GetTShipsEntries();if ( ships ){SStringList *node = ships->FindData(CyString(sId).upper());if ( node )return node->str.ToString();}return "";}void CVirtualFileSystem::extractTexts(CXspFile *pPackage, int textId){//TODO: check for better finding of files in mapfor ( FileListItr itr = m_pMap->begin(); itr != m_pMap->end(); ++itr ) {Utils::String str = itr->first;if ( !m_sAddon.empty() ) {if ( !str.left(m_sAddon.length() + 3).Compare(m_sAddon + "/t/") && !str.left(m_sAddon.length() + 3).Compare(m_sAddon + "\\t\\") )continue;}else {if ( !str.left(2).Compare("t\\") && !str.left(2).Compare("t/") && !str.left(8).Compare("addon\t\\") && !str.left(8).Compare("addon/t/") )continue;}Utils::String sTo = this->ExtractGameFile(str, CPackages::tempDirectory() + "tmp.dat");if ( !sTo.empty() ) {pPackage->AddTextFromFile(sTo, textId);CFileIO::Remove(sTo);}}}void CVirtualFileSystem::updateTexts(int iFromPage, int iToPage){this->_updateTexts(iFromPage, iToPage, m_pMap, m_pTexts);}void CVirtualFileSystem::updateTexts(int iPage){this->_updateTexts(iPage, iPage, m_pMap, m_pTexts);}void CVirtualFileSystem::updateModTexts(int iFromPage, int iToPage){this->_updateTexts(iFromPage, iToPage, m_pModMap, m_pModTexts);}void CVirtualFileSystem::updateModTexts(int iPage){this->_updateTexts(iPage, iPage, m_pModMap, m_pModTexts);}void CVirtualFileSystem::_clear(){m_bLoaded = false;if ( m_pMap ) delete m_pMap;m_pMap = new FileList;if ( m_pModMap ) delete m_pModMap;m_pModMap = new FileList;}void CVirtualFileSystem::_updateTexts(int iFromPage, int iToPage, FileList *pFileList, CTextDB *pTextList){// read all text filesfor ( FileListItr itr = pFileList->begin(); itr != pFileList->end(); ++itr ) {Utils::String str = itr->first;if ( !m_sAddon.empty() ) {if ( !str.left(m_sAddon.length() + 3).Compare(m_sAddon + "/t/") && !str.left(m_sAddon.length() + 3).Compare(m_sAddon + "\\t\\") )continue;}else {if ( !str.left(2).Compare("t\\") && !str.left(2).Compare("t/") )continue;}Utils::String sTo = this->ExtractGameFile(str, CPackages::tempDirectory() + "tmp.dat");if ( !sTo.empty() ) {// add all texts into the map, id=(pageid, tid) data=textUtils::String baseFile = CFileIO(str).baseName();int lang = (baseFile.isin("-L")) ? baseFile.right(3) : baseFile.truncate(-4);if ( m_iLang && lang != m_iLang ) continue;// open the text file to addpTextList->parseTextFile(iFromPage, iToPage, sTo, lang);}}}void CVirtualFileSystem::clearMods(bool bIncludeStandard){if ( bIncludeStandard ) {if ( m_pTexts ) delete m_pTexts;m_pTexts = new CTextDB();}if ( m_pModTexts ) delete m_pModTexts;m_pModTexts = new CTextDB();}bool CVirtualFileSystem::loadShipData(CyStringList *list){bool ret = false;Utils::String sTo = this->ExtractGameFile("types/TShips.pck", CPackages::tempDirectory() + "tmp.dat");if ( !sTo.empty() ) {CFileIO File(sTo);CyStringList *lines = File.ReadLinesStr();if ( lines ){bool readFirst = false;for ( SStringList *str = lines->Head(); str; str = str->next ){if ( str->str.Empty() )continue;str->str.RemoveChar('\r');str->str.RemoveChar(9);str->str.RemoveFirstSpace();if ( str->str.Empty() )continue;if ( str->str[0] == '/' || str->str[0] == '#' )continue;if ( !readFirst )readFirst = true;else{CyString t = str->str.GetToken(";", -2);while ( t.Right(1) == ";" )t.Truncate((int)t.Length() - 1);list->PushBack(t, str->str);}}delete lines;ret = true;}File.remove();}return ret;}} //NAMESPACE