FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
vfs.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
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 
25 // 3rd party library includes
26 #include <boost/functional.hpp>
27 #include <boost/regex.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 "vfs/raw/rawdata.h"
35 #include "util/base/exception.h"
36 #include "util/log/logger.h"
37 
38 #include "vfs.h"
39 #include "vfssource.h"
40 #include "vfssourceprovider.h"
41 
42 namespace FIFE {
43  static Logger _log(LM_VFS);
44 
45 
46  VFS::VFS() : m_sources() {}
47 
49  cleanup();
50  }
51 
52  void VFS::cleanup() {
53  type_sources sources = m_sources;
54  type_sources::const_iterator end = sources.end();
55  for (type_sources::iterator i = sources.begin(); i != end; ++i)
56  delete *i;
57 
58  type_providers::const_iterator end2 = m_providers.end();
59  for (type_providers::iterator j = m_providers.begin(); j != end2; ++j)
60  delete *j;
61 
62  m_providers.clear();
63  }
64 
66  provider->setVFS(this);
67  m_providers.push_back(provider);
68  FL_LOG(_log, LMsg("new provider: ") << provider->getName());
69  }
70 
71  VFSSource* VFS::createSource(const std::string& path) const {
72  if ( m_usedfiles.count(path) ) {
73  FL_WARN(_log, LMsg(path) << " is already used as VFS source");
74  return 0;
75  }
76 
77  type_providers::const_iterator end = m_providers.end();
78  for (type_providers::const_iterator i = m_providers.begin(); i != end; ++i) {
79  const VFSSourceProvider* provider = *i;
80  if (!provider->isReadable(path))
81  continue;
82 
83  try {
84  VFSSource* source = provider->createSource(path);
85  m_usedfiles.insert(path);
86  return source;
87  } catch (const Exception& ex) {
88  FL_WARN(_log, LMsg(provider->getName()) << " thought it could load " << path << " but didn't succeed (" << ex.what() << ")");
89  continue;
90  } catch (...) {
91  FL_WARN(_log, LMsg(provider->getName()) << " thought it could load " << path << " but didn't succeed (unkown exception)");
92  continue;
93  }
94  }
95 
96  FL_WARN(_log, LMsg("no provider for ") << path << " found");
97  return 0;
98  }
99 
100  void VFS::addNewSource(const std::string& path) {
101  VFSSource* source = createSource(path);
102  if (source) {
103  addSource(source);
104  } else {
105  FL_WARN(_log, LMsg("Failed to add new VFS source: ") << path);
106  }
107  }
108 
109  void VFS::addSource(VFSSource* source) {
110  m_sources.push_back(source);
111  }
112 
113  void VFS::removeSource(VFSSource* source) {
114  type_sources::iterator i = std::find(m_sources.begin(), m_sources.end(), source);
115  if (i != m_sources.end())
116  m_sources.erase(i);
117  }
118 
119  VFSSource* VFS::getSourceForFile(const std::string& file) const {
120  type_sources::const_iterator i = std::find_if(m_sources.begin(), m_sources.end(),
121  boost::bind2nd(boost::mem_fun(&VFSSource::fileExists), file));
122  if (i == m_sources.end()) {
123  FL_WARN(_log, LMsg("no source for ") << file << " found");
124  return 0;
125  }
126 
127  return *i;
128  }
129 
130  bool VFS::exists(const std::string& file) const {
131  return getSourceForFile(file);
132  }
133 
134  bool VFS::isDirectory(const std::string& path) const {
135  std::vector<std::string> tokens;
136  // Add a slash in case there isn't one in the string
137  const std::string newpath = path + "/";
138  boost::algorithm::split(tokens, newpath, boost::algorithm::is_any_of("/"));
139 
140  std::string currentpath = "/";
141  std::vector<std::string>::const_iterator token=tokens.begin();
142  while (token != tokens.end()) {
143  if (*token != "") {
144  if (*token != "." && *token != ".." && listDirectories(currentpath, *token).size() == 0) {
145  return false;
146  } else {
147  currentpath += *token + "/";
148  }
149  }
150  token++;
151  }
152 
153  return true;
154  }
155 
156  RawData* VFS::open(const std::string& path) {
157  FL_DBG(_log, LMsg("Opening: ") << path);
158 
159  VFSSource* source = getSourceForFile(path);
160  if (!source)
161  throw NotFound(path);
162 
163  return source->open(path);
164  }
165 
166  std::set<std::string> VFS::listFiles(const std::string& pathstr) const {
167  std::set<std::string> list;
168  type_sources::const_iterator end = m_sources.end();
169  for (type_sources::const_iterator i = m_sources.begin(); i != end; ++i) {
170  std::set<std::string> sourcelist = (*i)->listFiles(pathstr);
171  list.insert(sourcelist.begin(), sourcelist.end());
172  }
173 
174  return list;
175  }
176 
177  std::set<std::string> VFS::listFiles(const std::string& path, const std::string& filterregex) const {
178  std::set<std::string> list = listFiles(path);
179  return filterList(list, filterregex);
180  }
181 
182  std::set<std::string> VFS::listDirectories(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)->listDirectories(pathstr);
187  list.insert(sourcelist.begin(), sourcelist.end());
188  }
189 
190  return list;
191  }
192 
193  std::set<std::string> VFS::listDirectories(const std::string& path, const std::string& filterregex) const {
194  std::set<std::string> list = listDirectories(path);
195  return filterList(list, filterregex);
196  }
197 
198  std::set<std::string> VFS::filterList(const std::set<std::string>& list, const std::string& fregex) const {
199  std::set<std::string> results;
200  boost::regex regex(fregex);
201  std::set<std::string>::const_iterator end = list.end();
202  for (std::set<std::string>::const_iterator i = list.begin(); i != end;) {
203  boost::cmatch match;
204  if (boost::regex_match((*i).c_str(), match, regex)) {
205  results.insert(*i);
206  }
207  ++i;
208  }
209  return results;
210  }
211 }