aboutsummaryrefslogtreecommitdiff
path: root/common/fs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'common/fs.cpp')
-rw-r--r--common/fs.cpp179
1 files changed, 179 insertions, 0 deletions
diff --git a/common/fs.cpp b/common/fs.cpp
index fed0669f3f..2f1347226f 100644
--- a/common/fs.cpp
+++ b/common/fs.cpp
@@ -163,4 +163,183 @@ Common::WriteStream *FSNode::createWriteStream() const {
return _realNode->createWriteStream();
}
+FSDirectory::FSDirectory(const FSNode &node, int depth)
+ : _node(node), _cached(false), _depth(depth) {
+}
+
+FSDirectory::FSDirectory(const String &prefix, const FSNode &node, int depth)
+ : _node(node), _cached(false), _depth(depth) {
+
+ setPrefix(prefix);
+}
+
+FSDirectory::FSDirectory(const String &name, int depth)
+ : _node(name), _cached(false), _depth(depth) {
+}
+
+FSDirectory::FSDirectory(const String &prefix, const String &name, int depth)
+ : _node(name), _cached(false), _depth(depth) {
+
+ setPrefix(prefix);
+}
+
+FSDirectory::~FSDirectory() {
+}
+
+void FSDirectory::setPrefix(const String &prefix) {
+ _prefix = prefix;
+
+ if (!_prefix.empty() && !_prefix.hasSuffix("/"))
+ _prefix += "/";
+}
+
+FSNode FSDirectory::getFSNode() const {
+ return _node;
+}
+
+FSNode *FSDirectory::lookupCache(NodeCache &cache, const String &name) const {
+ // make caching as lazy as possible
+ if (!name.empty()) {
+ ensureCached();
+
+ if (cache.contains(name))
+ return &cache[name];
+ }
+
+ return 0;
+}
+
+bool FSDirectory::hasFile(const String &name) {
+ if (name.empty() || !_node.isDirectory())
+ return false;
+
+ FSNode *node = lookupCache(_fileCache, name);
+ return node && node->exists();
+}
+
+ArchiveMemberPtr FSDirectory::getMember(const String &name) {
+ if (name.empty() || !_node.isDirectory())
+ return ArchiveMemberPtr();
+
+ FSNode *node = lookupCache(_fileCache, name);
+
+ if (!node || !node->exists()) {
+ warning("FSDirectory::getMember: FSNode does not exist");
+ return ArchiveMemberPtr();
+ } else if (node->isDirectory()) {
+ warning("FSDirectory::getMember: FSNode is a directory");
+ return ArchiveMemberPtr();
+ }
+
+ return ArchiveMemberPtr(new FSNode(*node));
+}
+
+SeekableReadStream *FSDirectory::createReadStreamForMember(const String &name) const {
+ if (name.empty() || !_node.isDirectory())
+ return 0;
+
+ FSNode *node = lookupCache(_fileCache, name);
+ if (!node)
+ return 0;
+ SeekableReadStream *stream = node->createReadStream();
+ if (!stream)
+ warning("FSDirectory::createReadStreamForMember: Can't create stream for file '%s'", name.c_str());
+
+ return stream;
+}
+
+FSDirectory *FSDirectory::getSubDirectory(const String &name, int depth) {
+ return getSubDirectory(String::emptyString, name, depth);
+}
+
+FSDirectory *FSDirectory::getSubDirectory(const String &prefix, const String &name, int depth) {
+ if (name.empty() || !_node.isDirectory())
+ return 0;
+
+ FSNode *node = lookupCache(_subDirCache, name);
+ if (!node)
+ return 0;
+
+ return new FSDirectory(prefix, *node, depth);
+}
+
+void FSDirectory::cacheDirectoryRecursive(FSNode node, int depth, const String& prefix) const {
+ if (depth <= 0)
+ return;
+
+ FSList list;
+ node.getChildren(list, FSNode::kListAll, false);
+
+ FSList::iterator it = list.begin();
+ for ( ; it != list.end(); ++it) {
+ String name = prefix + it->getName();
+
+ // don't touch name as it might be used for warning messages
+ String lowercaseName = name;
+ lowercaseName.toLowercase();
+
+ // since the hashmap is case insensitive, we need to check for clashes when caching
+ if (it->isDirectory()) {
+ if (_subDirCache.contains(lowercaseName)) {
+ warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring sub-directory '%s'", name.c_str());
+ } else {
+ cacheDirectoryRecursive(*it, depth - 1, lowercaseName + "/");
+ _subDirCache[lowercaseName] = *it;
+ }
+ } else {
+ if (_fileCache.contains(lowercaseName)) {
+ warning("FSDirectory::cacheDirectory: name clash when building cache, ignoring file '%s'", name.c_str());
+ } else {
+ _fileCache[lowercaseName] = *it;
+ }
+ }
+ }
+
+}
+
+void FSDirectory::ensureCached() const {
+ if (_cached)
+ return;
+ cacheDirectoryRecursive(_node, _depth, _prefix);
+ _cached = true;
+}
+
+int FSDirectory::listMatchingMembers(ArchiveMemberList &list, const String &pattern) {
+ if (!_node.isDirectory())
+ return 0;
+
+ // Cache dir data
+ ensureCached();
+
+ String lowercasePattern(pattern);
+ lowercasePattern.toLowercase();
+
+ int matches = 0;
+ NodeCache::iterator it = _fileCache.begin();
+ for ( ; it != _fileCache.end(); ++it) {
+ if (it->_key.matchString(lowercasePattern, true)) {
+ list.push_back(ArchiveMemberPtr(new FSNode(it->_value)));
+ matches++;
+ }
+ }
+ return matches;
+}
+
+int FSDirectory::listMembers(ArchiveMemberList &list) {
+ if (!_node.isDirectory())
+ return 0;
+
+ // Cache dir data
+ ensureCached();
+
+ int files = 0;
+ for (NodeCache::iterator it = _fileCache.begin(); it != _fileCache.end(); ++it) {
+ list.push_back(ArchiveMemberPtr(new FSNode(it->_value)));
+ ++files;
+ }
+
+ return files;
+}
+
+
} // End of namespace Common