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