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