aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/archive.cpp30
-rw-r--r--common/archive.h82
2 files changed, 91 insertions, 21 deletions
diff --git a/common/archive.cpp b/common/archive.cpp
index 96ead55abd..c39912bfe4 100644
--- a/common/archive.cpp
+++ b/common/archive.cpp
@@ -71,7 +71,7 @@ int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern)
*/
class FSDirectoryMember : public ArchiveMember {
FSNode _node;
-
+
public:
FSDirectoryMember(FSNode &node) : _node(node) {
}
@@ -98,13 +98,33 @@ 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;
}
@@ -113,7 +133,7 @@ FSNode FSDirectory::lookupCache(NodeCache &cache, const String &name) {
// make caching as lazy as possible
if (!name.empty()) {
if (!_cached) {
- cacheDirectoryRecursive(_node, _depth, "");
+ cacheDirectoryRecursive(_node, _depth, _prefix);
_cached = true;
}
@@ -157,12 +177,16 @@ SeekableReadStream *FSDirectory::openFile(const String &name) {
}
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);
- return new FSDirectory(node, depth);
+ return new FSDirectory(prefix, node, depth);
}
void FSDirectory::cacheDirectoryRecursive(FSNode node, int depth, const String& prefix) {
diff --git a/common/archive.h b/common/archive.h
index c8d22124fd..ee12196e6f 100644
--- a/common/archive.h
+++ b/common/archive.h
@@ -36,6 +36,14 @@
namespace Common {
+/**
+ * ArchiveMember is an abstract interface to represent elements inside
+ * implementations of Archive.
+ *
+ * Archive subclasses must provide their own implementation of ArchiveMember,
+ * and use it when serving calls to listMembers() and listMatchingMembers().
+ * Alternatively, the GenericArchiveMember below can be used.
+ */
class ArchiveMember {
public:
virtual ~ArchiveMember() { }
@@ -48,7 +56,7 @@ typedef List<SharedPtr<ArchiveMember> > ArchiveMemberList;
class Archive;
/**
- * Simple ArchiveMemeber implementation which allows
+ * Simple ArchiveMember implementation which allows
* creation of ArchiveMember compatible objects via
* a simple Archive and name pair.
*
@@ -65,11 +73,6 @@ public:
SeekableReadStream *open();
};
-/**
- * FilePtr is a convenient way to keep track of a SeekableReadStream without
- * having to worry about releasing its memory.
- */
-typedef SharedPtr<SeekableReadStream> FilePtr;
/**
* Archive allows searches of (file)names into an arbitrary container.
@@ -116,13 +119,32 @@ typedef SharedPtr<Archive> ArchivePtr;
/**
* FSDirectory models a directory tree from the filesystem and allows users
- * to access it through the Archive interface. FSDirectory can represent a
- * single directory, or a tree with specified depth, rooted in a 'base'
- * directory.
- * Searching is case-insensitive, as the main intended goal is supporting
- * retrieval of game data. First case-insensitive match is returned when
- * searching, thus making FSDirectory heavily dependant on the underlying
- * FSNode implementation.
+ * to access it through the Archive interface. Searching is case-insensitive,
+ * since the intended goal is supporting retrieval of game data.
+ *
+ * FSDirectory can represent a single directory, or a tree with specified depth,
+ * depending on the value passed to the 'depth' parameter in the constructors.
+ * Filenames are cached with their relative path, with elements separated by
+ * backslashes, e.g.:
+ *
+ * c:\my\data\file.ext
+ *
+ * would be cached as 'data/file.ext' if FSDirectory was created on 'c:/my' with
+ * depth > 1. If depth was 1, then the 'data' subdirectory would have been
+ * ignored, instead.
+ * Again, only BACKSLASHES are used as separators independently from the
+ * underlying file system.
+ *
+ * Relative paths can be specified when calling matching functions like openFile(),
+ * hasFile(), listMatchingMembers() and listMembers(). Please see the function
+ * specific comments for more information.
+ *
+ * Client code can customize cache by using the constructors with the 'prefix'
+ * parameter. In this case, the prefix is prepended to each entry in the cache,
+ * and effectively treated as a 'virtual' parent subdirectory. FSDirectory adds
+ * a trailing backslash to prefix if needed. Following on with the previous example
+ * and using 'your' as prefix, the cache entry would have been 'your/data/file.ext'.
+ *
*/
class FSDirectory : public Archive {
FSNode _node;
@@ -131,6 +153,8 @@ class FSDirectory : public Archive {
// Key is stored in lowercase.
typedef HashMap<String, FSNode, IgnoreCase_Hash, IgnoreCase_EqualTo> NodeCache;
NodeCache _fileCache, _subDirCache;
+ Common::String _prefix; // string that is prepended to each cache item key
+ void setPrefix(const String &prefix);
// look for a match
FSNode lookupCache(NodeCache &cache, const String &name);
@@ -143,15 +167,18 @@ class FSDirectory : public Archive {
public:
/**
* Create a FSDirectory representing a tree with the specified depth. Will result in an
- * unbound FSDirectory if name is not found on the filesystem or is not a directory.
+ * unbound FSDirectory if name is not found on the filesystem or if the node is not a
+ * valid directory.
*/
FSDirectory(const String &name, int depth = 1);
+ FSDirectory(const FSNode &node, int depth = 1);
/**
- * Create a FSDirectory representing a tree with the specified depth. Will result in an
- * unbound FSDirectory if node does not exist or is not a directory.
+ * Create a FSDirectory representing a tree with the specified depth. The parameter
+ * prefix is prepended to the keys in the cache. See class comment.
*/
- FSDirectory(const FSNode &node, int depth = 1);
+ FSDirectory(const String &prefix, const String &name, int depth = 1);
+ FSDirectory(const String &prefix, const FSNode &node, int depth = 1);
virtual ~FSDirectory();
@@ -161,14 +188,33 @@ public:
FSNode getFSNode() const;
/**
- * Create a new FSDirectory pointing to a sub directory of the instance.
+ * Create a new FSDirectory pointing to a sub directory of the instance. See class comment
+ * for an explanation of the prefix parameter.
* @return a new FSDirectory instance
*/
FSDirectory *getSubDirectory(const String &name, int depth = 1);
+ FSDirectory *getSubDirectory(const String &prefix, const String &name, int depth = 1);
+ /**
+ * Checks for existence in the cache. A full match of relative path and filename is needed
+ * for success.
+ */
virtual bool hasFile(const String &name);
+
+ /**
+ * Returns a list of matching file names. Pattern can use GLOB wildcards.
+ */
virtual int listMatchingMembers(ArchiveMemberList &list, const String &pattern);
+
+ /**
+ * Returns a list of all the files in the cache.
+ */
virtual int listMembers(ArchiveMemberList &list);
+
+ /**
+ * Open the specified file. A full match of relative path and filename is needed
+ * for success.
+ */
virtual SeekableReadStream *openFile(const String &name);
};