vfs.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <algorithm>
00024
00025
00026 #include <boost/functional.hpp>
00027 #include <boost/regex.hpp>
00028 #include <boost/algorithm/string.hpp>
00029
00030
00031
00032
00033
00034 #include "vfs/raw/rawdata.h"
00035 #include "util/base/exception.h"
00036 #include "util/log/logger.h"
00037
00038 #include "vfs.h"
00039 #include "vfssource.h"
00040 #include "vfssourceprovider.h"
00041
00042 namespace FIFE {
00043 static Logger _log(LM_VFS);
00044
00045
00046 VFS::VFS() : m_sources() {}
00047
00048 VFS::~VFS() {
00049 cleanup();
00050 }
00051
00052 void VFS::cleanup() {
00053 type_sources sources = m_sources;
00054 type_sources::const_iterator end = sources.end();
00055 for (type_sources::iterator i = sources.begin(); i != end; ++i)
00056 delete *i;
00057
00058 type_providers::const_iterator end2 = m_providers.end();
00059 for (type_providers::iterator j = m_providers.begin(); j != end2; ++j)
00060 delete *j;
00061
00062 m_providers.clear();
00063 }
00064
00065 void VFS::addProvider(VFSSourceProvider* provider) {
00066 provider->setVFS(this);
00067 m_providers.push_back(provider);
00068 FL_LOG(_log, LMsg("new provider: ") << provider->getName());
00069 }
00070
00071 VFSSource* VFS::createSource(const std::string& path) const {
00072 if ( m_usedfiles.count(path) ) {
00073 FL_WARN(_log, LMsg(path) << " is already used as VFS source");
00074 return 0;
00075 }
00076
00077 type_providers::const_iterator end = m_providers.end();
00078 for (type_providers::const_iterator i = m_providers.begin(); i != end; ++i) {
00079 const VFSSourceProvider* provider = *i;
00080 if (!provider->isReadable(path))
00081 continue;
00082
00083 try {
00084 VFSSource* source = provider->createSource(path);
00085 m_usedfiles.insert(path);
00086 return source;
00087 } catch (const Exception& ex) {
00088 FL_WARN(_log, LMsg(provider->getName()) << " thought it could load " << path << " but didn't succeed (" << ex.getMessage() << ")");
00089 continue;
00090 } catch (...) {
00091 FL_WARN(_log, LMsg(provider->getName()) << " thought it could load " << path << " but didn't succeed (unkown exception)");
00092 continue;
00093 }
00094 }
00095
00096 FL_WARN(_log, LMsg("no provider for ") << path << " found");
00097 return 0;
00098 }
00099
00100 void VFS::addNewSource(const std::string& path) {
00101 VFSSource* source = createSource(path);
00102 if (source) {
00103 addSource(source);
00104 } else {
00105 FL_WARN(_log, LMsg("Failed to add new VFS source: ") << path);
00106 }
00107 }
00108
00109 void VFS::addSource(VFSSource* source) {
00110 m_sources.push_back(source);
00111 }
00112
00113 void VFS::removeSource(VFSSource* source) {
00114 type_sources::iterator i = std::find(m_sources.begin(), m_sources.end(), source);
00115 if (i != m_sources.end())
00116 m_sources.erase(i);
00117 }
00118
00119 VFSSource* VFS::getSourceForFile(const std::string& file) const {
00120 type_sources::const_iterator i = std::find_if(m_sources.begin(), m_sources.end(),
00121 boost::bind2nd(boost::mem_fun(&VFSSource::fileExists), file));
00122 if (i == m_sources.end()) {
00123 FL_WARN(_log, LMsg("no source for ") << file << " found");
00124 return 0;
00125 }
00126
00127 return *i;
00128 }
00129
00130 bool VFS::exists(const std::string& file) const {
00131 return getSourceForFile(file);
00132 }
00133
00134 bool VFS::isDirectory(const std::string& path) const {
00135 std::vector<std::string> tokens;
00136
00137 const std::string newpath = path + "/";
00138 boost::algorithm::split(tokens, newpath, boost::algorithm::is_any_of("/"));
00139
00140 std::string currentpath = "/";
00141 std::vector<std::string>::const_iterator token=tokens.begin();
00142 while (token != tokens.end()) {
00143 if (*token != "") {
00144 if (*token != "." && *token != ".." && listDirectories(currentpath, *token).size() == 0) {
00145 return false;
00146 } else {
00147 currentpath += *token + "/";
00148 }
00149 }
00150 token++;
00151 }
00152
00153 return true;
00154 }
00155
00156 RawData* VFS::open(const std::string& path) {
00157 FL_DBG(_log, LMsg("Opening: ") << path);
00158
00159 VFSSource* source = getSourceForFile(path);
00160 if (!source)
00161 throw NotFound(path);
00162
00163 return source->open(path);
00164 }
00165
00166 std::set<std::string> VFS::listFiles(const std::string& pathstr) const {
00167 std::set<std::string> list;
00168 type_sources::const_iterator end = m_sources.end();
00169 for (type_sources::const_iterator i = m_sources.begin(); i != end; ++i) {
00170 std::set<std::string> sourcelist = (*i)->listFiles(pathstr);
00171 list.insert(sourcelist.begin(), sourcelist.end());
00172 }
00173
00174 return list;
00175 }
00176
00177 std::set<std::string> VFS::listFiles(const std::string& path, const std::string& filterregex) const {
00178 std::set<std::string> list = listFiles(path);
00179 return filterList(list, filterregex);
00180 }
00181
00182 std::set<std::string> VFS::listDirectories(const std::string& pathstr) const {
00183 std::set<std::string> list;
00184 type_sources::const_iterator end = m_sources.end();
00185 for (type_sources::const_iterator i = m_sources.begin(); i != end; ++i) {
00186 std::set<std::string> sourcelist = (*i)->listDirectories(pathstr);
00187 list.insert(sourcelist.begin(), sourcelist.end());
00188 }
00189
00190 return list;
00191 }
00192
00193 std::set<std::string> VFS::listDirectories(const std::string& path, const std::string& filterregex) const {
00194 std::set<std::string> list = listDirectories(path);
00195 return filterList(list, filterregex);
00196 }
00197
00198 std::set<std::string> VFS::filterList(const std::set<std::string>& list, const std::string& fregex) const {
00199 std::set<std::string> results;
00200 boost::regex regex(fregex);
00201 std::set<std::string>::const_iterator end = list.end();
00202 for (std::set<std::string>::const_iterator i = list.begin(); i != end;) {
00203 boost::cmatch match;
00204 if (boost::regex_match((*i).c_str(), match, regex)) {
00205 results.insert(*i);
00206 }
00207 ++i;
00208 }
00209 return results;
00210 }
00211 }