mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
** Big Maps Projects code (incl. Multiplayer v1.5 ** ********************************************************** - Merged Big Maps Project code from BMP+MP trunk (Revision: 3340) o Complete SVN Revision history: https://81.169.133.124/source/ja2/branches/Wanne/JA2%201.13%20MP - Before THIS merge, I made a branch of the existing 1.13 source o SVN Branch: https://81.169.133.124/source/ja2/branches/JA2_rev.3336/src - Removed old VS 6.0 and VS 2003 project and solutions files, because compilation is broken long time ago - I will add VS 2010 projects and solution file in the next few days git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@3341 3b4a5df2-a311-0410-b5c6-a8a6f20db521
606 lines
16 KiB
C++
606 lines
16 KiB
C++
#include "vfs_directory_tree.h"
|
|
#include "../File/vfs_dir_file.h"
|
|
#include "../Interface/vfs_location_aware_file_interface.h"
|
|
#include "../os_functions.h"
|
|
|
|
#include <queue>
|
|
#include <list>
|
|
#include <set>
|
|
|
|
#define ERROR_FILE(msg) BuildString().add((msg)).add(L" : ").add(pFile->getPath()).get()
|
|
|
|
namespace vfs
|
|
{
|
|
template<typename WriteType>
|
|
class TSubDir : public vfs::TDirectory<typename vfs::TDirectoryTree<WriteType>::tWriteType>
|
|
{
|
|
typedef vfs::TDirectory<typename vfs::TDirectoryTree<WriteType>::tWriteType> tBaseClass;
|
|
typedef typename tBaseClass::tFileType tFileType;
|
|
|
|
typedef std::map<vfs::Path, tFileType*, vfs::Path::Less> tFileCatalogue;
|
|
public:
|
|
typedef vfs::IBaseLocation::Iterator Iterator;
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
class IterImpl : public vfs::IBaseLocation::Iterator::IImplementation
|
|
{
|
|
friend class TSubDir<WriteType>;
|
|
typedef vfs::IBaseLocation::Iterator::IImplementation tBaseClass;
|
|
|
|
IterImpl(TSubDir<WriteType>* dir): _dir(dir)
|
|
{
|
|
THROWIFFALSE(_dir, L"");
|
|
_iter = _dir->m_mapFiles.begin();
|
|
}
|
|
public:
|
|
IterImpl() : tBaseClass(), _dir(NULL)
|
|
{};
|
|
virtual ~IterImpl()
|
|
{};
|
|
|
|
virtual tFileType* value()
|
|
{
|
|
if(_iter != _dir->m_mapFiles.end())
|
|
{
|
|
return _iter->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
virtual void next()
|
|
{
|
|
if(_iter != _dir->m_mapFiles.end())
|
|
{
|
|
_iter++;
|
|
}
|
|
}
|
|
protected:
|
|
tBaseClass* clone()
|
|
{
|
|
IterImpl* iter = new IterImpl();
|
|
iter->_dir = _dir;
|
|
iter->_iter = _iter;
|
|
return iter;
|
|
}
|
|
private:
|
|
TSubDir<WriteType>* _dir;
|
|
typename tFileCatalogue::iterator _iter;
|
|
};
|
|
/////////////////////////////////////////////////////////////////////
|
|
public:
|
|
TSubDir(vfs::Path const& sMountPoint, vfs::Path const& sRealPath)
|
|
: tBaseClass(sMountPoint,sRealPath)
|
|
{};
|
|
|
|
virtual ~TSubDir();
|
|
|
|
virtual bool fileExists(vfs::Path const& rFileName);
|
|
virtual vfs::IBaseFile* getFile(vfs::Path const& rFileName);
|
|
virtual tFileType* getFileTyped(vfs::Path const& rFileName);
|
|
|
|
virtual tFileType* addFile(vfs::Path const& sFilename, bool bDeleteOldFile=false);
|
|
virtual bool addFile(tFileType* pFile, bool bDeleteOldFile=false);
|
|
|
|
virtual bool createSubDirectory(vfs::Path const& sSubDirPath);
|
|
virtual bool deleteDirectory(vfs::Path const& sDirPath);
|
|
virtual bool deleteFileFromDirectory(vfs::Path const& sFileName);
|
|
|
|
virtual void getSubDirList(std::list<vfs::Path>& rlSubDirs);
|
|
|
|
virtual Iterator begin();
|
|
private:
|
|
tFileCatalogue m_mapFiles;
|
|
};
|
|
|
|
template<>
|
|
vfs::TSubDir<vfs::IWriteType>::tFileType* vfs::TSubDir<vfs::IWriteType>::addFile(vfs::Path const& sFilename, bool bDeleteOldFile);
|
|
template<>
|
|
vfs::TSubDir<vfs::IWritable>::tFileType* vfs::TSubDir<vfs::IWritable>::addFile(vfs::Path const& sFilename, bool bDeleteOldFile);
|
|
|
|
template<>
|
|
bool vfs::TSubDir<vfs::IWriteType>::deleteDirectory(vfs::Path const& sDirPath);
|
|
template<>
|
|
bool vfs::TSubDir<vfs::IWritable>::deleteDirectory(vfs::Path const& sDirPath);
|
|
|
|
template<>
|
|
bool vfs::TSubDir<vfs::IWriteType>::deleteFileFromDirectory(vfs::Path const& rFileName);
|
|
template<>
|
|
bool vfs::TSubDir<vfs::IWritable>::deleteFileFromDirectory(vfs::Path const& rFileName);
|
|
}
|
|
|
|
/********************************************************/
|
|
|
|
template<typename WriteType>
|
|
vfs::TSubDir<WriteType>::~TSubDir()
|
|
{
|
|
typename tFileCatalogue::iterator it = m_mapFiles.begin();
|
|
for(; it != m_mapFiles.end(); ++it)
|
|
{
|
|
if(it->second)
|
|
{
|
|
it->second->close();
|
|
delete it->second;
|
|
}
|
|
}
|
|
m_mapFiles.clear();
|
|
}
|
|
|
|
template<typename WriteType>
|
|
bool vfs::TSubDir<WriteType>::fileExists(vfs::Path const& sFileName)
|
|
{
|
|
typename tFileCatalogue::iterator it = m_mapFiles.find(sFileName);
|
|
bool success = (it != m_mapFiles.end()) && (it->second != NULL);
|
|
return success;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
vfs::IBaseFile* vfs::TSubDir<WriteType>::getFile(vfs::Path const& sFileName)
|
|
{
|
|
return getFileTyped(sFileName);
|
|
}
|
|
|
|
template<typename WriteType>
|
|
typename vfs::TSubDir<WriteType>::tFileType* vfs::TSubDir<WriteType>::getFileTyped(vfs::Path const& sFileName)
|
|
{
|
|
typename tFileCatalogue::iterator it = m_mapFiles.find(sFileName);
|
|
if(it != m_mapFiles.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
template<>
|
|
vfs::TSubDir<vfs::IWriteType>::tFileType* vfs::TSubDir<vfs::IWriteType>::addFile(vfs::Path const& sFilename, bool bDeleteOldFile)
|
|
{
|
|
tFileType* pFile = m_mapFiles[sFilename];
|
|
if(pFile)
|
|
{
|
|
if(!bDeleteOldFile)
|
|
{
|
|
// not allowed to replace old file
|
|
return NULL;
|
|
}
|
|
delete pFile;
|
|
}
|
|
pFile = new vfs::CReadOnlyDirFile(sFilename,this);
|
|
m_mapFiles[sFilename] = pFile;
|
|
|
|
return pFile;
|
|
}
|
|
|
|
template<>
|
|
vfs::TSubDir<vfs::IWritable>::tFileType* vfs::TSubDir<vfs::IWritable>::addFile(vfs::Path const& sFilename, bool bDeleteOldFile)
|
|
{
|
|
tFileType* pFile = m_mapFiles[sFilename];
|
|
if(pFile)
|
|
{
|
|
if(!bDeleteOldFile)
|
|
{
|
|
// not allowed to replace old file
|
|
return NULL;
|
|
}
|
|
delete pFile;
|
|
}
|
|
pFile = new vfs::CDirFile(sFilename,this);
|
|
m_mapFiles[sFilename] = pFile;
|
|
|
|
return pFile;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
bool vfs::TSubDir<WriteType>::addFile(tFileType* pFile, bool bDeleteOldFile)
|
|
{
|
|
if(!pFile)
|
|
{
|
|
return false;
|
|
}
|
|
tFileType* pOldFile = m_mapFiles[pFile->getName()];
|
|
if( pOldFile && (pOldFile != pFile) )
|
|
{
|
|
if(bDeleteOldFile)
|
|
{
|
|
pOldFile->close();
|
|
delete pOldFile;
|
|
}
|
|
}
|
|
m_mapFiles[pFile->getName()] = pFile;
|
|
return true;
|
|
}
|
|
|
|
template<>
|
|
bool vfs::TSubDir<vfs::IWritable>::deleteDirectory(vfs::Path const& sDirPath)
|
|
{
|
|
if( !(this->m_mountPoint == sDirPath) )
|
|
{
|
|
return false;
|
|
}
|
|
tFileCatalogue::iterator it = m_mapFiles.begin();
|
|
for(; it != m_mapFiles.end(); ++it)
|
|
{
|
|
tFileType* pFile = it->second;
|
|
if(pFile)
|
|
{
|
|
pFile->close();
|
|
if(!pFile->deleteFile())
|
|
{
|
|
std::wstringstream wss;
|
|
wss << L"Could not delete file \"" << pFile->getPath()() << L"\"";
|
|
THROWEXCEPTION( ERROR_FILE(L"Could not delete file") );
|
|
}
|
|
delete pFile;
|
|
}
|
|
}
|
|
m_mapFiles.clear();
|
|
return true;
|
|
}
|
|
|
|
template<>
|
|
bool vfs::TSubDir<vfs::IWriteType>::deleteDirectory(vfs::Path const& sDirPath)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
template<>
|
|
bool vfs::TSubDir<vfs::IWritable>::deleteFileFromDirectory(vfs::Path const& rFileName)
|
|
{
|
|
tFileCatalogue::iterator it = m_mapFiles.find(rFileName);
|
|
if( it != m_mapFiles.end() )
|
|
{
|
|
tFileType* pFile = it->second;
|
|
if(pFile)
|
|
{
|
|
pFile->close();
|
|
THROWIFFALSE(pFile->deleteFile(), ERROR_FILE(L"Could not delete file"));
|
|
delete pFile;
|
|
}
|
|
m_mapFiles.erase(it);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<>
|
|
bool vfs::TSubDir<vfs::IWriteType>::deleteFileFromDirectory(vfs::Path const& rFileName)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
bool vfs::TSubDir<WriteType>::createSubDirectory(vfs::Path const& sSubDirPath)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
void vfs::TSubDir<WriteType>::getSubDirList(std::list<vfs::Path>& rlSubDirs)
|
|
{
|
|
}
|
|
|
|
template<typename WriteType>
|
|
typename vfs::TSubDir<WriteType>::Iterator vfs::TSubDir<WriteType>::begin()
|
|
{
|
|
return Iterator(new IterImpl(this));
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
/********************************************************************************************/
|
|
/********************************************************************************************/
|
|
|
|
template<typename WriteType>
|
|
class vfs::TDirectoryTree<WriteType>::IterImpl : public vfs::IBaseLocation::Iterator::IImplementation
|
|
{
|
|
typedef vfs::IBaseLocation::Iterator::IImplementation tBaseClass;
|
|
typedef vfs::TDirectoryTree<WriteType> tDirTree;
|
|
public:
|
|
IterImpl(tDirTree& tree);
|
|
virtual ~IterImpl();
|
|
|
|
virtual typename tDirTree::tFileType* value();
|
|
virtual void next();
|
|
protected:
|
|
virtual tBaseClass* clone()
|
|
{
|
|
IterImpl* iter = new IterImpl(_tree);
|
|
iter->_subdir_iter = _subdir_iter;
|
|
iter->_file_iter = _file_iter;
|
|
return iter;
|
|
}
|
|
private:
|
|
void operator=(typename vfs::TDirectoryTree<WriteType>::IterImpl const& tree);
|
|
tDirTree& _tree;
|
|
typename tDirTree::tDirCatalogue::iterator _subdir_iter;
|
|
typename tDirTree::tLocationType::Iterator _file_iter;
|
|
};
|
|
|
|
template<typename WriteType>
|
|
vfs::TDirectoryTree<WriteType>::IterImpl::IterImpl(vfs::TDirectoryTree<WriteType>& tree)
|
|
: tBaseClass(), _tree(tree)
|
|
{
|
|
_subdir_iter = _tree.m_catDirs.begin();
|
|
if(_subdir_iter != _tree.m_catDirs.end())
|
|
{
|
|
TSubDir<WriteType> *sdir = dynamic_cast<TSubDir<WriteType>*>(_subdir_iter->second);
|
|
typename TSubDir<WriteType>::Iterator it = sdir->begin();
|
|
_file_iter = it;
|
|
if(_file_iter.end())
|
|
{
|
|
next();
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename WriteType>
|
|
vfs::TDirectoryTree<WriteType>::IterImpl::~IterImpl()
|
|
{
|
|
}
|
|
|
|
template<typename WriteType>
|
|
typename vfs::TDirectoryTree<WriteType>::tFileType* vfs::TDirectoryTree<WriteType>::IterImpl::value()
|
|
{
|
|
if(!_file_iter.end())
|
|
{
|
|
return static_cast<vfs::TDirectoryTree<WriteType>::tFileType*>(_file_iter.value());
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
void vfs::TDirectoryTree<WriteType>::IterImpl::next()
|
|
{
|
|
if(!_file_iter.end())
|
|
{
|
|
_file_iter.next();
|
|
}
|
|
// need to loop for the case when one or many sub directories are empty
|
|
while(_file_iter.end())
|
|
{
|
|
if(_subdir_iter == _tree.m_catDirs.end())
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
_subdir_iter++;
|
|
if(_subdir_iter != _tree.m_catDirs.end())
|
|
{
|
|
_file_iter = _subdir_iter->second->begin();
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
template<typename WriteType>
|
|
vfs::TDirectoryTree<WriteType>::TDirectoryTree(vfs::Path const& sMountPoint, vfs::Path const& sRealPath)
|
|
: tBaseClass(sMountPoint,sRealPath)
|
|
{};
|
|
|
|
|
|
template<typename WriteType>
|
|
vfs::TDirectoryTree<WriteType>::~TDirectoryTree()
|
|
{
|
|
typename tDirCatalogue::iterator it = m_catDirs.begin();
|
|
for(;it != m_catDirs.end(); ++it)
|
|
{
|
|
delete it->second;
|
|
it->second = NULL;
|
|
}
|
|
m_catDirs.clear();
|
|
}
|
|
|
|
template<typename WriteType>
|
|
bool vfs::TDirectoryTree<WriteType>::init()
|
|
{
|
|
// contains local path
|
|
typedef vfs::TSubDir<WriteType> tSubDir;
|
|
typedef std::pair<vfs::Path,tSubDir*> tDirs;
|
|
std::queue<tDirs> qSubDirs;
|
|
qSubDirs.push(tDirs(vfs::Path(vfs::Const::EMPTY()),new tSubDir(this->m_mountPoint, this->m_realPath)));
|
|
|
|
m_catDirs[this->m_mountPoint] = qSubDirs.front().second;
|
|
|
|
utf8string sFilename;
|
|
tSubDir *pCurrentDir;
|
|
vfs::Path oCurDir;
|
|
while(!qSubDirs.empty())
|
|
{
|
|
pCurrentDir = qSubDirs.front().second;
|
|
oCurDir = this->m_realPath;
|
|
if( !qSubDirs.front().first.empty())
|
|
{
|
|
oCurDir += qSubDirs.front().first;
|
|
}
|
|
|
|
try
|
|
{
|
|
os::CIterateDirectory::EFileAttribute eFA;
|
|
os::CIterateDirectory iterFS(oCurDir, vfs::Const::STAR());
|
|
while ( iterFS.nextFile(sFilename, eFA) )
|
|
{
|
|
if (StrCmp::Equal(vfs::Const::DOT(),sFilename) || StrCmp::Equal(vfs::Const::DOTDOT(),sFilename) || StrCmp::Equal(vfs::Const::DOTSVN(),sFilename) )
|
|
{
|
|
continue;
|
|
}
|
|
if (eFA == os::CIterateDirectory::FA_DIRECTORY)
|
|
{
|
|
vfs::Path sLocal = qSubDirs.front().first + sFilename;
|
|
|
|
vfs::Path temp = this->m_mountPoint+sLocal;
|
|
tSubDir *pNewDir = new tSubDir(sLocal, this->m_realPath+sLocal);
|
|
qSubDirs.push(tDirs(sLocal,pNewDir));
|
|
m_catDirs[temp] = pNewDir;
|
|
}
|
|
else
|
|
{
|
|
pCurrentDir->addFile(vfs::Path(sFilename));
|
|
}
|
|
}
|
|
}
|
|
catch(CBasicException &ex)
|
|
{
|
|
// probably directory doesn't exist. abort or continue???
|
|
// -> abort AND continue
|
|
logException(ex);
|
|
return false;
|
|
}
|
|
qSubDirs.pop();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
typename vfs::TDirectoryTree<WriteType>::tFileType* vfs::TDirectoryTree<WriteType>::addFile(vfs::Path const& sFilename, bool bDeleteOldFile)
|
|
{
|
|
vfs::Path sDir,sFile;
|
|
sFilename.splitLast(sDir,sFile);
|
|
typename tDirCatalogue::iterator it = m_catDirs.find(sDir);
|
|
if(it == m_catDirs.end())
|
|
{
|
|
vfs::Path sTemp,sCreateDir,sLeft,sRight = sDir;
|
|
while(!sRight.empty())
|
|
{
|
|
sRight.splitFirst(sLeft,sTemp);
|
|
sRight = sTemp;
|
|
sCreateDir += sLeft;
|
|
this->createSubDirectory(sCreateDir);
|
|
}
|
|
it = m_catDirs.find(sDir);
|
|
if(it == m_catDirs.end())
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
if(it->second)
|
|
{
|
|
return it->second->addFile(sFile,bDeleteOldFile);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
bool vfs::TDirectoryTree<WriteType>::addFile(tFileType* pFile, bool bDeleteOldFile)
|
|
{
|
|
// no files from outside
|
|
// these files are not connected with the correct directory object
|
|
return false;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
bool vfs::TDirectoryTree<WriteType>::deleteDirectory(vfs::Path const& sDirPath)
|
|
{
|
|
typename tDirCatalogue::iterator it = m_catDirs.find(sDirPath);
|
|
if(it == m_catDirs.end())
|
|
{
|
|
// no such directory
|
|
return false;
|
|
}
|
|
if(it->second)
|
|
{
|
|
return it->second->deleteDirectory(sDirPath);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
bool vfs::TDirectoryTree<WriteType>::deleteFileFromDirectory(vfs::Path const& sFileName)
|
|
{
|
|
vfs::Path sDir,sFile;
|
|
sFileName.splitLast(sDir,sFile);
|
|
typename tDirCatalogue::iterator it = m_catDirs.find(sDir);
|
|
if(it == m_catDirs.end())
|
|
{
|
|
// no such directory
|
|
return false;
|
|
}
|
|
if(it->second)
|
|
{
|
|
return it->second->deleteFileFromDirectory(sFile);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* IVFSLocation interface
|
|
*/
|
|
template<typename WriteType>
|
|
bool vfs::TDirectoryTree<WriteType>::fileExists(vfs::Path const& sFileName)
|
|
{
|
|
vfs::Path sDir, sFile;
|
|
sFileName.splitLast(sDir, sFile);
|
|
typename tDirCatalogue::iterator it = m_catDirs.find(sDir);
|
|
if(it == m_catDirs.end())
|
|
{
|
|
// no such directory
|
|
return false;
|
|
}
|
|
if(it->second)
|
|
{
|
|
return it->second->fileExists(sFile);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
vfs::IBaseFile* vfs::TDirectoryTree<WriteType>::getFile(vfs::Path const& sFileName)
|
|
{
|
|
return getFileTyped(sFileName);
|
|
}
|
|
|
|
template<typename WriteType>
|
|
typename vfs::TDirectoryTree<WriteType>::tFileType* vfs::TDirectoryTree<WriteType>::getFileTyped(vfs::Path const& sFileName)
|
|
{
|
|
vfs::Path sDir, sFile;
|
|
sFileName.splitLast(sDir, sFile);
|
|
typename tDirCatalogue::iterator it = m_catDirs.find(sDir);
|
|
if(it == m_catDirs.end())
|
|
{
|
|
// no such directory
|
|
return NULL;
|
|
}
|
|
if(it->second)
|
|
{
|
|
return it->second->getFileTyped(sFile);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
bool vfs::TDirectoryTree<WriteType>::createSubDirectory(vfs::Path const& sSubDirPath)
|
|
{
|
|
if(os::createRealDirectory( this->m_realPath + sSubDirPath ))
|
|
{
|
|
if( m_catDirs[sSubDirPath] == NULL)
|
|
{
|
|
m_catDirs[sSubDirPath] = new vfs::TSubDir<WriteType>(sSubDirPath, this->m_realPath + sSubDirPath);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<typename WriteType>
|
|
void vfs::TDirectoryTree<WriteType>::getSubDirList(std::list<vfs::Path>& rlSubDirs)
|
|
{
|
|
typename tDirCatalogue::iterator it = m_catDirs.begin();
|
|
for(;it != m_catDirs.end(); ++it)
|
|
{
|
|
rlSubDirs.push_back(it->first);
|
|
}
|
|
}
|
|
|
|
template<typename WriteType>
|
|
typename vfs::TDirectoryTree<WriteType>::Iterator vfs::TDirectoryTree<WriteType>::begin()
|
|
{
|
|
return Iterator(new IterImpl(*this));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
template class vfs::TDirectoryTree<vfs::IWritable>; // explicit template class instantiation
|
|
template class vfs::TDirectoryTree<vfs::IWriteType>; // explicit template class instantiation
|
|
|