Mercurial > fife-parpg
diff engine/core/vfs/vfs.cpp @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children | 90005975cdbb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/engine/core/vfs/vfs.cpp Sun Jun 29 18:44:17 2008 +0000 @@ -0,0 +1,223 @@ +/*************************************************************************** + * Copyright (C) 2005-2008 by the FIFE team * + * http://www.fifengine.de * + * This file is part of FIFE. * + * * + * FIFE is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +// Standard C++ library includes +#include <algorithm> + +// 3rd party library includes +#include <boost/functional.hpp> +#include <boost/regex.hpp> +#include <boost/algorithm/string.hpp> + +// FIFE includes +// These includes are split up in two parts, separated by one empty line +// First block: files included from the FIFE root src directory +// Second block: files included from the same folder +#include "vfs/raw/rawdata.h" +#include "util/base/exception.h" +#include "util/log/logger.h" + +#include "vfs.h" +#include "vfssource.h" +#include "vfssourceprovider.h" + +namespace FIFE { + static Logger _log(LM_VFS); + + + VFS::VFS() : m_sources() {} + + VFS::~VFS() { + cleanup(); + } + + void VFS::cleanup() { + type_sources sources = m_sources; + type_sources::const_iterator end = sources.end(); + for (type_sources::iterator i = sources.begin(); i != end; ++i) + delete *i; + + type_providers::const_iterator end2 = m_providers.end(); + for (type_providers::iterator j = m_providers.begin(); j != end2; ++j) + delete *j; + + m_providers.clear(); + } + + void VFS::addProvider(VFSSourceProvider* provider) { + provider->setVFS(this); + m_providers.push_back(provider); + FL_LOG(_log, LMsg("new provider: ") << provider->getName()); + } + + VFSSource* VFS::createSource(const std::string& path) const { + if ( m_usedfiles.count(path) ) { + FL_WARN(_log, LMsg(path) << " is already used as VFS source"); + return 0; + } + + type_providers::const_iterator end = m_providers.end(); + for (type_providers::const_iterator i = m_providers.begin(); i != end; ++i) { + const VFSSourceProvider* provider = *i; + if (!provider->isReadable(path)) + continue; + + try { + VFSSource* source = provider->createSource(path); + m_usedfiles.insert(path); + return source; + } catch (const Exception& ex) { + FL_WARN(_log, LMsg(provider->getName()) << " thought it could load " << path << " but didn't succeed (" << ex.getMessage() << ")"); + continue; + } catch (...) { + FL_WARN(_log, LMsg(provider->getName()) << " thought it could load " << path << " but didn't succeed (unkown exception)"); + continue; + } + } + + FL_WARN(_log, LMsg("no provider for ") << path << " found"); + return 0; + } + + void VFS::addNewSource(const std::string& path) { + VFSSource* source = createSource(path); + if (source) { + addSource(source); + } else { + FL_WARN(_log, LMsg("Failed to add new VFS source: ") << path); + } + } + + void VFS::addSource(VFSSource* source) { + m_sources.push_back(source); + } + + void VFS::removeSource(VFSSource* source) { + type_sources::iterator i = std::find(m_sources.begin(), m_sources.end(), source); + if (i != m_sources.end()) + m_sources.erase(i); + } + + VFSSource* VFS::getSourceForFile(const std::string& file) const { + std::string lowerpath = lower(file); + type_sources::const_iterator i = std::find_if(m_sources.begin(), m_sources.end(), + boost::bind2nd(boost::mem_fun(&VFSSource::fileExists), lowerpath)); + if (i == m_sources.end()) { + FL_WARN(_log, LMsg("no source for ") << lowerpath << " found"); + return 0; + } + + return *i; + } + + bool VFS::exists(const std::string& file) const { + return getSourceForFile(lower(file)); + } + + bool VFS::isDirectory(const std::string& path) const { + std::vector<std::string> tokens; + // Add a slash in case there isn't one in the string + const std::string newpath = path + "/"; + boost::algorithm::split(tokens, newpath, boost::algorithm::is_any_of("/")); + + std::string currentpath = "/"; + std::vector<std::string>::const_iterator token=tokens.begin(); + while (token != tokens.end()) { + if (*token != "") { + if (*token != "." && *token != ".." && listDirectories(currentpath, *token).size() == 0) { + return false; + } else { + currentpath += *token + "/"; + } + } + token++; + } + + return true; + } + + RawData* VFS::open(const std::string& path) { + std::string lowerpath = lower(path); + FL_DBG(_log, LMsg("Opening: ") << lowerpath); + + VFSSource* source = getSourceForFile(lowerpath); + if (!source) + throw NotFound(path); + + return source->open(lowerpath); + } + + std::string VFS::lower(const std::string& str) const { + std::string result; + result.resize(str.size()); + std::transform(str.begin(), str.end(), result.begin(), tolower); + return result; + } + + std::set<std::string> VFS::listFiles(const std::string& pathstr) const { + std::string lowerpath = lower(pathstr); + std::set<std::string> list; + type_sources::const_iterator end = m_sources.end(); + for (type_sources::const_iterator i = m_sources.begin(); i != end; ++i) { + std::set<std::string> sourcelist = (*i)->listFiles(lowerpath); + list.insert(sourcelist.begin(), sourcelist.end()); + } + + return list; + } + + std::set<std::string> VFS::listFiles(const std::string& path, const std::string& filterregex) const { + std::string lowerpath = lower(path); + std::set<std::string> list = listFiles(lowerpath); + return filterList(list, filterregex); + } + + std::set<std::string> VFS::listDirectories(const std::string& pathstr) const { + std::string lowerpath = lower(pathstr); + std::set<std::string> list; + type_sources::const_iterator end = m_sources.end(); + for (type_sources::const_iterator i = m_sources.begin(); i != end; ++i) { + std::set<std::string> sourcelist = (*i)->listDirectories(lowerpath); + list.insert(sourcelist.begin(), sourcelist.end()); + } + + return list; + } + + std::set<std::string> VFS::listDirectories(const std::string& path, const std::string& filterregex) const { + std::set<std::string> list = listDirectories(lower(path)); + return filterList(list, filterregex); + } + + std::set<std::string> VFS::filterList(const std::set<std::string>& list, const std::string& fregex) const { + std::set<std::string> results; + boost::regex regex(fregex); + std::set<std::string>::const_iterator end = list.end(); + for (std::set<std::string>::const_iterator i = list.begin(); i != end;) { + boost::cmatch match; + if (boost::regex_match((*i).c_str(), match, regex)) { + results.insert(*i); + } + ++i; + } + return results; + } +}