vfs.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 #include <algorithm>
00024 
00025 // 3rd party library includes
00026 #include <boost/functional.hpp>
00027 #include <boost/regex.hpp>
00028 #include <boost/algorithm/string.hpp>
00029 
00030 // FIFE includes
00031 // These includes are split up in two parts, separated by one empty line
00032 // First block: files included from the FIFE root src directory
00033 // Second block: files included from the same folder
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         // Add a slash in case there isn't one in the string
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 }