FIFE  be64c707dea6b3250bd4355bf5c825d25920087d
vfs.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2019 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <algorithm>
24 #include <regex>
25 
26 // 3rd party library includes
27 #include <boost/functional.hpp>
28 #include <boost/algorithm/string.hpp>
29 
30 // FIFE includes
31 // These includes are split up in two parts, separated by one empty line
32 // First block: files included from the FIFE root src directory
33 // Second block: files included from the same folder
34 #include "util/base/exception.h"
35 #include "util/log/logger.h"
36 
37 #include "vfs.h"
38 #include "vfssource.h"
39 #include "vfssourceprovider.h"
40 
41 namespace FIFE {
45  static Logger _log(LM_VFS);
46 
47  VFS::VFS() : m_sources() {}
48 
50  cleanup();
51  }
52 
53  void VFS::cleanup() {
54  type_sources sources = m_sources;
55  type_sources::const_iterator end = sources.end();
56  for (type_sources::iterator i = sources.begin(); i != end; ++i)
57  delete *i;
58 
59  type_providers::const_iterator end2 = m_providers.end();
60  for (type_providers::iterator j = m_providers.begin(); j != end2; ++j)
61  delete *j;
62 
63  m_providers.clear();
64  }
65 
67  provider->setVFS(this);
68  m_providers.push_back(provider);
69  FL_LOG(_log, LMsg("new provider: ") << provider->getName());
70  }
71 
72  VFSSource* VFS::createSource(const std::string& path) {
73 
74  if (hasSource(path)) {
75  FL_WARN(_log, LMsg(path) << " is already used as VFS source");
76  return 0;
77  }
78 
79  type_providers::const_iterator end = m_providers.end();
80  for (type_providers::const_iterator i = m_providers.begin(); i != end; ++i) {
81  VFSSourceProvider* provider = *i;
82  if (!provider->isReadable(path))
83  continue;
84 
85  try {
86  VFSSource* source = provider->createSource(path);
87  return source;
88  } catch (const Exception& ex) {
89  FL_WARN(_log, LMsg(provider->getName()) << " thought it could load " << path << " but didn't succeed (" << ex.what() << ")");
90  continue;
91  } catch (...) {
92  FL_WARN(_log, LMsg(provider->getName()) << " thought it could load " << path << " but didn't succeed (unknown exception)");
93  continue;
94  }
95  }
96 
97  FL_WARN(_log, LMsg("no provider for ") << path << " found");
98  return 0;
99  }
100 
101  void VFS::addNewSource(const std::string& path) {
102  VFSSource* source = createSource(path);
103  if (source) {
104  addSource(source);
105  } else {
106  FL_WARN(_log, LMsg("Failed to add new VFS source: ") << path);
107  }
108  }
109 
110  void VFS::addSource(VFSSource* source) {
111  m_sources.push_back(source);
112  }
113 
114  void VFS::removeSource(VFSSource* source) {
115  type_sources::iterator i = std::find(m_sources.begin(), m_sources.end(), source);
116  if (i != m_sources.end())
117  m_sources.erase(i);
118  }
119 
120  void VFS::removeSource(const std::string& path) {
121  type_providers::iterator end = m_providers.end();
122  for (type_providers::iterator i = m_providers.begin(); i != end; ++i) {
123  VFSSourceProvider* provider = *i;
124  if (provider->hasSource(path)) {
125  VFSSource* source = provider->getSource(path);
126  type_sources::iterator i = std::find(m_sources.begin(), m_sources.end(), source);
127  if (i == m_sources.end()) {
128  removeSource(*i);
129  return;
130  }
131  }
132  }
133  }
134 
135  VFSSource* VFS::getSourceForFile(const std::string& file) const {
136  type_sources::const_iterator i = std::find_if(m_sources.begin(), m_sources.end(),
137  boost::bind2nd(boost::mem_fun(&VFSSource::fileExists), file));
138  if (i == m_sources.end()) {
139  FL_WARN(_log, LMsg("no source for ") << file << " found");
140  return 0;
141  }
142 
143  return *i;
144  }
145 
146  bool VFS::exists(const std::string& file) const {
147  return getSourceForFile(file) != 0;
148  }
149 
150  bool VFS::isDirectory(const std::string& path) const {
151  std::vector<std::string> tokens;
152  // Add a slash in case there isn't one in the string
153  const std::string newpath = path + "/";
154  boost::algorithm::split(tokens, newpath, boost::algorithm::is_any_of("/"));
155 
156  std::string currentpath = "/";
157  std::vector<std::string>::const_iterator token=tokens.begin();
158  while (token != tokens.end()) {
159  if (*token != "") {
160  if (*token != "." && *token != ".." && listDirectories(currentpath, *token).size() == 0) {
161  return false;
162  } else {
163  currentpath += *token + "/";
164  }
165  }
166  ++token;
167  }
168 
169  return true;
170  }
171 
172  RawData* VFS::open(const std::string& path) {
173  FL_DBG(_log, LMsg("Opening: ") << path);
174 
175  VFSSource* source = getSourceForFile(path);
176  if (!source)
177  throw NotFound(path);
178 
179  return source->open(path);
180  }
181 
182  std::set<std::string> VFS::listFiles(const std::string& pathstr) const {
183  std::set<std::string> list;
184  type_sources::const_iterator end = m_sources.end();
185  for (type_sources::const_iterator i = m_sources.begin(); i != end; ++i) {
186  std::set<std::string> sourcelist = (*i)->listFiles(pathstr);
187  list.insert(sourcelist.begin(), sourcelist.end());
188  }
189 
190  return list;
191  }
192 
193  std::set<std::string> VFS::listFiles(const std::string& path, const std::string& filterregex) const {
194  std::set<std::string> list = listFiles(path);
195  return filterList(list, filterregex);
196  }
197 
198  std::set<std::string> VFS::listDirectories(const std::string& pathstr) const {
199  std::set<std::string> list;
200  type_sources::const_iterator end = m_sources.end();
201  for (type_sources::const_iterator i = m_sources.begin(); i != end; ++i) {
202  std::set<std::string> sourcelist = (*i)->listDirectories(pathstr);
203  list.insert(sourcelist.begin(), sourcelist.end());
204  }
205 
206  return list;
207  }
208 
209  std::set<std::string> VFS::listDirectories(const std::string& path, const std::string& filterregex) const {
210  std::set<std::string> list = listDirectories(path);
211  return filterList(list, filterregex);
212  }
213 
214  std::set<std::string> VFS::filterList(const std::set<std::string>& list, const std::string& fregex) const {
215  std::set<std::string> results;
216  std::regex regex(fregex);
217  std::set<std::string>::const_iterator end = list.end();
218  for (std::set<std::string>::const_iterator i = list.begin(); i != end;) {
219  std::cmatch match;
220  if (std::regex_match((*i).c_str(), match, regex)) {
221  results.insert(*i);
222  }
223  ++i;
224  }
225  return results;
226  }
227 
228  bool VFS::hasSource(const std::string& path) const {
229  type_providers::const_iterator end = m_providers.end();
230  for (type_providers::const_iterator i = m_providers.begin(); i != end; ++i) {
231  const VFSSourceProvider* provider = *i;
232  if (provider->hasSource(path)) {
233  const VFSSource* source = provider->getSource(path);
234  type_sources::const_iterator i = std::find(m_sources.begin(), m_sources.end(), source);
235  if (i == m_sources.end())
236  return false;
237  return true;
238  }
239  }
240  return false;
241  }
242 }
#define FL_WARN(logger, msg)
Definition: logger.h:72
void addProvider(VFSSourceProvider *provider)
add new VFSSourceProvider
Definition: vfs.cpp:66
virtual bool fileExists(const std::string &file) const =0
check if the given file exists
bool exists(const std::string &file) const
Check if the given file exists.
Definition: vfs.cpp:146
Helper class to create log strings out from separate parts Usage: LMsg("some text") << variable << "...
Definition: logger.h:82
const std::string & getName() const
Returns the name of this VFSSourceProvider.
VFSSource abstract baseclass.
Definition: vfssource.h:46
RawData * open(const std::string &path)
Open a file.
Definition: vfs.cpp:172
static Logger _log(LM_AUDIO)
VFSSource * getSourceForFile(const std::string &file) const
Definition: vfs.cpp:135
void cleanup()
Definition: vfs.cpp:53
Exception base class.
Definition: exception.h:43
virtual bool isReadable(const std::string &file) const =0
Check if a given file is readable for this VFSSource.
virtual VFSSource * getSource(const std::string &path) const =0
Get the source instance of the path.
std::set< std::string > listFiles(const std::string &path) const
Get a filelist of the given directory.
Definition: vfs.cpp:182
void removeSource(VFSSource *source)
remove a VFSSource
Definition: vfs.cpp:114
VFSSourceProvider abstract baseclass.
void addSource(VFSSource *source)
Add a new VFSSource.
Definition: vfs.cpp:110
virtual ~VFS()
Destructor.
Definition: vfs.cpp:49
virtual const char * what() const
Returns the error message.
Definition: exception.cpp:41
VFS()
Constructor Called by the Engine on startup.
Definition: vfs.cpp:47
#define FL_LOG(logger, msg)
Definition: logger.h:71
std::set< std::string > listDirectories(const std::string &path) const
Get a directorylist of the given directory.
Definition: vfs.cpp:198
Definition: modules.h:59
void addNewSource(const std::string &path)
create a new Source and add it to VFS
Definition: vfs.cpp:101
VFSSource * createSource(const std::string &path)
tries to create a new VFSSource for the given file
Definition: vfs.cpp:72
virtual bool hasSource(const std::string &path) const =0
Check whether the provider already has created a source with that path.
void setVFS(VFS *vfs)
Get the VFS this provider is using.
bool hasSource(const std::string &path) const
Checks if a source is already present in a provider.
Definition: vfs.cpp:228
#define FL_DBG(logger, msg)
Definition: logger.h:70
bool isDirectory(const std::string &path) const
Check if the given path is a directory.
Definition: vfs.cpp:150
type_providers m_providers
Definition: vfs.h:164
virtual VFSSource * createSource(const std::string &file)=0
Create a new instance of a VFSSource initialized with the given file.
virtual RawData * open(const std::string &file) const =0
open a file inside this source
type_sources m_sources
Definition: vfs.h:167
std::set< std::string > filterList(const std::set< std::string > &list, const std::string &fregex) const
Definition: vfs.cpp:214
Used to access diffrent kinds of data.
Definition: rawdata.h:48
std::vector< VFSSource * > type_sources
Definition: vfs.h:166