aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorMax Horn2007-09-18 20:02:04 +0000
committerMax Horn2007-09-18 20:02:04 +0000
commitc3d3aebe87d16d4fc3b7ac8581b99fb97241c9ac (patch)
tree17b2ba9f45743d2cf8f8e5faa6c9511e213f15f3 /common
parent5c08cb1bcf84828cc93114fadbc89dd6f9909d06 (diff)
parent1dc13a641dd82825334e81bb3eb3b4ebd69d2552 (diff)
downloadscummvm-rg350-c3d3aebe87d16d4fc3b7ac8581b99fb97241c9ac.tar.gz
scummvm-rg350-c3d3aebe87d16d4fc3b7ac8581b99fb97241c9ac.tar.bz2
scummvm-rg350-c3d3aebe87d16d4fc3b7ac8581b99fb97241c9ac.zip
Patch #1768757: Merge fsnode-gsoc into trunk (MAJOR change, will break compilation on some ports)
svn-id: r28944
Diffstat (limited to 'common')
-rw-r--r--common/advancedDetector.cpp6
-rw-r--r--common/error.h47
-rw-r--r--common/file.cpp63
-rw-r--r--common/file.h5
-rw-r--r--common/fs.cpp210
-rw-r--r--common/fs.h155
-rw-r--r--common/md5.cpp11
-rw-r--r--common/savefile.h52
8 files changed, 432 insertions, 117 deletions
diff --git a/common/advancedDetector.cpp b/common/advancedDetector.cpp
index a342ed910a..f3e8671025 100644
--- a/common/advancedDetector.cpp
+++ b/common/advancedDetector.cpp
@@ -276,7 +276,7 @@ PluginError detectGameForEngineCreation(
FSList fslist;
FilesystemNode dir(ConfMan.get("path"));
- if (!dir.listDir(fslist, FilesystemNode::kListFilesOnly)) {
+ if (!dir.getChildren(fslist, FilesystemNode::kListFilesOnly)) {
return kInvalidPathError;
}
@@ -345,7 +345,7 @@ static ADGameDescList detectGame(const FSList *fslist, const Common::ADParams &p
// Get the information of the existing files
for (FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) {
if (file->isDirectory()) continue;
- tstr = file->name();
+ tstr = file->getName();
tstr.toLowercase();
// Strip any trailing dot
@@ -364,7 +364,7 @@ static ADGameDescList detectGame(const FSList *fslist, const Common::ADParams &p
debug(3, "> %s: %s", tstr.c_str(), md5str);
- if (testFile.open(file->path())) {
+ if (testFile.open(file->getPath())) {
filesSize[tstr] = (int32)testFile.size();
testFile.close();
}
diff --git a/common/error.h b/common/error.h
new file mode 100644
index 0000000000..0ac84df5c3
--- /dev/null
+++ b/common/error.h
@@ -0,0 +1,47 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef COMMON_ERROR_H
+#define COMMON_ERROR_H
+
+/**
+ * This file contains enums with error codes commonly used.
+ */
+
+/**
+ * Errors used in the SaveFileManager class.
+ */
+enum SFMError {
+ SFM_NO_ERROR, //Default state, indicates no error has been recorded
+ SFM_DIR_ACCESS, //stat(), mkdir()::EACCES: Search or write permission denied
+ SFM_DIR_LINKMAX, //mkdir()::EMLINK: The link count of the parent directory would exceed {LINK_MAX}
+ SFM_DIR_LOOP, //stat(), mkdir()::ELOOP: Too many symbolic links encountered while traversing the path
+ SFM_DIR_NAMETOOLONG, //stat(), mkdir()::ENAMETOOLONG: The path name is too long
+ SFM_DIR_NOENT, //stat(), mkdir()::ENOENT: A component of the path path does not exist, or the path is an empty string
+ SFM_DIR_NOTDIR, //stat(), mkdir()::ENOTDIR: A component of the path prefix is not a directory
+ SFM_DIR_ROFS //mkdir()::EROFS: The parent directory resides on a read-only file system
+};
+
+#endif //COMMON_ERROR_H
diff --git a/common/file.cpp b/common/file.cpp
index 2eba1bcb3d..880383d220 100644
--- a/common/file.cpp
+++ b/common/file.cpp
@@ -28,6 +28,7 @@
#include "common/hashmap.h"
#include "common/util.h"
#include "common/hash-str.h"
+#include <errno.h>
#ifdef MACOSX
#include "CoreFoundation/CoreFoundation.h"
@@ -226,7 +227,7 @@ void File::addDefaultDirectoryRecursive(const FilesystemNode &dir, int level, co
return;
FSList fslist;
- if (!dir.listDir(fslist, FilesystemNode::kListAll)) {
+ if (!dir.getChildren(fslist, FilesystemNode::kListAll)) {
// Failed listing the contents of this node, so it is either not a
// directory, or just doesn't exist at all.
return;
@@ -237,7 +238,7 @@ void File::addDefaultDirectoryRecursive(const FilesystemNode &dir, int level, co
// Do not add directories multiple times, unless this time they are added
// with a bigger depth.
- const String &directory(dir.path());
+ const String &directory(dir.getPath());
if (_defaultDirectories->contains(directory) && (*_defaultDirectories)[directory] >= level)
return;
(*_defaultDirectories)[directory] = level;
@@ -247,13 +248,13 @@ void File::addDefaultDirectoryRecursive(const FilesystemNode &dir, int level, co
for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
if (file->isDirectory()) {
- addDefaultDirectoryRecursive(file->path(), level - 1, prefix + file->name() + "/");
+ addDefaultDirectoryRecursive(file->getPath(), level - 1, prefix + file->getName() + "/");
} else {
String lfn(prefix);
- lfn += file->name();
+ lfn += file->getName();
lfn.toLowercase();
if (!_filesMap->contains(lfn)) {
- (*_filesMap)[lfn] = file->path();
+ (*_filesMap)[lfn] = file->getPath();
}
}
}
@@ -364,15 +365,21 @@ bool File::open(const String &filename, AccessMode mode) {
bool File::open(const FilesystemNode &node, AccessMode mode) {
assert(mode == kFileReadMode || mode == kFileWriteMode);
- if (!node.isValid()) {
- warning("File::open: Trying to open an invalid FilesystemNode object");
+ if (!node.exists()) {
+ warning("File::open: Trying to open a FilesystemNode which does not exist");
return false;
} else if (node.isDirectory()) {
warning("File::open: Trying to open a FilesystemNode which is a directory");
return false;
- }
+ } /*else if (!node.isReadable() && mode == kFileReadMode) {
+ warning("File::open: Trying to open an unreadable FilesystemNode object for reading");
+ return false;
+ } else if (!node.isWritable() && mode == kFileWriteMode) {
+ warning("File::open: Trying to open an unwritable FilesystemNode object for writing");
+ return false;
+ }*/
- String filename(node.name());
+ String filename(node.getName());
if (_handle) {
error("File::open: This file object already is opened (%s), won't open '%s'", _name.c_str(), filename.c_str());
@@ -383,7 +390,7 @@ bool File::open(const FilesystemNode &node, AccessMode mode) {
const char *modeStr = (mode == kFileReadMode) ? "rb" : "wb";
- _handle = fopen(node.path().c_str(), modeStr);
+ _handle = fopen(node.getPath().c_str(), modeStr);
if (_handle == NULL) {
if (mode == kFileReadMode)
@@ -402,16 +409,40 @@ bool File::open(const FilesystemNode &node, AccessMode mode) {
return true;
}
+bool File::remove(const String &filename){
+ if (remove(filename.c_str()) != 0) {
+ if(errno == EACCES)
+ ;//TODO: read-only file
+ if(errno == ENOENT)
+ ;//TODO: non-existent file
+
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool File::remove(const FilesystemNode &node){
+ if (remove(node.getPath()) != 0) {
+ if(errno == EACCES)
+ ;//TODO: read-only file
+ if(errno == ENOENT)
+ ;//TODO: non-existent file
+
+ return false;
+ } else {
+ return true;
+ }
+}
+
bool File::exists(const String &filename) {
// First try to find the file it via a FilesystemNode (in case an absolute
// path was passed). But we only use this to filter out directories.
FilesystemNode file(filename);
- // FIXME: can't use isValid() here since at the time of writing
- // FilesystemNode is to be unable to find for example files
- // added in extrapath
- if (file.isDirectory())
- return false;
-
+
+ return (!file.isDirectory() && file.exists());
+
+ //***DEPRECATED COMMENTS BELOW, LEFT FOR DISCUSSION***
// Next, try to locate the file by *opening* it in read mode. This has
// multiple effects:
// 1) It takes _filesMap and _defaultDirectories into consideration -> good
diff --git a/common/file.h b/common/file.h
index 3d816a6104..416ca75ec7 100644
--- a/common/file.h
+++ b/common/file.h
@@ -52,7 +52,7 @@ private:
// code that accidentally copied File objects tended to break in strange
// ways.
File(const File &f);
- File &operator =(const File &f);
+ File &operator =(const File &f);
public:
enum AccessMode {
@@ -86,6 +86,9 @@ public:
virtual void close();
+ virtual bool remove(const String &filename);
+ virtual bool remove(const FilesystemNode &node);
+
/**
* Checks if the object opened a file successfully.
*
diff --git a/common/fs.cpp b/common/fs.cpp
index c33fc42223..3e0959b232 100644
--- a/common/fs.cpp
+++ b/common/fs.cpp
@@ -23,14 +23,45 @@
*/
#include "common/stdafx.h"
-
-#include "backends/fs/abstract-fs.h"
#include "common/util.h"
+#include "backends/fs/abstract-fs.h"
+#include "backends/fs/fs-factory-maker.cpp"
+/*
+ * Simple DOS-style pattern matching function (understands * and ? like used in DOS).
+ * Taken from exult/files/listfiles.cc
+ */
+static bool matchString(const char *str, const char *pat) {
+ const char *p = 0;
+ const char *q = 0;
+
+ for (;;) {
+ switch (*pat) {
+ case '*':
+ p = ++pat;
+ q = str;
+ break;
-FilesystemNode::FilesystemNode(AbstractFilesystemNode *realNode) {
- _realNode = realNode;
- _refCount = new int(1);
+ default:
+ if (*pat != *str) {
+ if (p) {
+ pat = p;
+ str = ++q;
+ if(!*str)
+ return !*pat;
+ break;
+ }
+ else
+ return false;
+ }
+ // fallthrough
+ case '?':
+ if(!*str)
+ return !*pat;
+ pat++;
+ str++;
+ }
+ }
}
FilesystemNode::FilesystemNode() {
@@ -38,6 +69,11 @@ FilesystemNode::FilesystemNode() {
_refCount = 0;
}
+FilesystemNode::FilesystemNode(AbstractFilesystemNode *realNode) {
+ _realNode = realNode;
+ _refCount = new int(1);
+}
+
FilesystemNode::FilesystemNode(const FilesystemNode &node) {
_realNode = node._realNode;
_refCount = node._refCount;
@@ -46,10 +82,12 @@ FilesystemNode::FilesystemNode(const FilesystemNode &node) {
}
FilesystemNode::FilesystemNode(const Common::String &p) {
+ AbstractFilesystemFactory *factory = makeFSFactory();
+
if (p.empty() || p == ".")
- _realNode = AbstractFilesystemNode::getCurrentDirectory();
+ _realNode = factory->makeCurrentDirectoryFileNode();
else
- _realNode = AbstractFilesystemNode::getNodeForPath(p);
+ _realNode = factory->makeFileNodePath(p);
_refCount = new int(1);
}
@@ -57,18 +95,7 @@ FilesystemNode::~FilesystemNode() {
decRefCount();
}
-void FilesystemNode::decRefCount() {
- if (_refCount) {
- assert(*_refCount > 0);
- --(*_refCount);
- if (*_refCount == 0) {
- delete _refCount;
- delete _realNode;
- }
- }
-}
-
-FilesystemNode &FilesystemNode::operator =(const FilesystemNode &node) {
+FilesystemNode &FilesystemNode::operator= (const FilesystemNode &node) {
if (node._refCount)
++(*node._refCount);
@@ -80,40 +107,50 @@ FilesystemNode &FilesystemNode::operator =(const FilesystemNode &node) {
return *this;
}
-bool FilesystemNode::isValid() const {
- if (_realNode == 0)
+bool FilesystemNode::operator<(const FilesystemNode& node) const
+{
+ if (isDirectory() && !node.isDirectory())
+ return true;
+ if (!isDirectory() && node.isDirectory())
return false;
- return _realNode->isValid();
+
+ return scumm_stricmp(getDisplayName().c_str(), node.getDisplayName().c_str()) < 0;
}
-FilesystemNode FilesystemNode::getParent() const {
- if (_realNode == 0)
- return *this;
-
- AbstractFilesystemNode *node = _realNode->parent();
- if (node == 0) {
- return *this;
- } else {
- return FilesystemNode(node);
+void FilesystemNode::decRefCount() {
+ if (_refCount) {
+ assert(*_refCount > 0);
+ --(*_refCount);
+ if (*_refCount == 0) {
+ delete _refCount;
+ delete _realNode;
+ }
}
}
+bool FilesystemNode::exists() const {
+ if (_realNode == 0)
+ return false;
+
+ return _realNode->exists();
+}
+
FilesystemNode FilesystemNode::getChild(const Common::String &n) const {
if (_realNode == 0)
return *this;
assert(_realNode->isDirectory());
- AbstractFilesystemNode *node = _realNode->child(n);
+ AbstractFilesystemNode *node = _realNode->getChild(n);
return FilesystemNode(node);
}
-bool FilesystemNode::listDir(FSList &fslist, ListMode mode) const {
+bool FilesystemNode::getChildren(FSList &fslist, ListMode mode, bool hidden) const {
if (!_realNode || !_realNode->isDirectory())
return false;
AbstractFSList tmp;
- if (!_realNode->listDir(tmp, mode))
+ if (!_realNode->getChildren(tmp, mode, hidden))
return false;
fslist.clear();
@@ -124,33 +161,108 @@ bool FilesystemNode::listDir(FSList &fslist, ListMode mode) const {
return true;
}
+Common::String FilesystemNode::getDisplayName() const {
+ assert(_realNode);
+ return _realNode->getDisplayName();
+}
+
+Common::String FilesystemNode::getName() const {
+ assert(_realNode);
+ return _realNode->getName();
+}
+
+FilesystemNode FilesystemNode::getParent() const {
+ if (_realNode == 0)
+ return *this;
+
+ AbstractFilesystemNode *node = _realNode->getParent();
+ if (node == 0) {
+ return *this;
+ } else {
+ return FilesystemNode(node);
+ }
+}
+
+Common::String FilesystemNode::getPath() const {
+ assert(_realNode);
+ return _realNode->getPath();
+}
+
bool FilesystemNode::isDirectory() const {
if (_realNode == 0)
return false;
+
return _realNode->isDirectory();
}
-Common::String FilesystemNode::displayName() const {
- assert(_realNode);
- return _realNode->displayName();
+bool FilesystemNode::isReadable() const {
+ if (_realNode == 0)
+ return false;
+
+ return _realNode->isReadable();
}
-Common::String FilesystemNode::name() const {
- assert(_realNode);
- return _realNode->name();
+bool FilesystemNode::isWritable() const {
+ if (_realNode == 0)
+ return false;
+
+ return _realNode->isWritable();
}
-Common::String FilesystemNode::path() const {
- assert(_realNode);
- return _realNode->path();
-}
+bool FilesystemNode::lookupFile(FSList &results, FSList &fslist, Common::String &filename, bool hidden, bool exhaustive) const
+{
+ int matches = 0;
+
+ for (FSList::iterator entry = fslist.begin(); entry != fslist.end(); ++entry) {
+ if (entry->isDirectory()) {
+ matches += lookupFileRec(results, *entry, filename, hidden, exhaustive);
+ }
+ }
+ return ((matches > 0) ? true : false);
+}
-bool FilesystemNode::operator< (const FilesystemNode& node) const
+bool FilesystemNode::lookupFile(FSList &results, FilesystemNode &dir, Common::String &filename, bool hidden, bool exhaustive) const
{
- if (isDirectory() && !node.isDirectory())
- return true;
- if (!isDirectory() && node.isDirectory())
+ int matches;
+
+ if (!dir.isDirectory())
return false;
- return scumm_stricmp(displayName().c_str(), node.displayName().c_str()) < 0;
+
+ matches = lookupFileRec(results, dir, filename, hidden, exhaustive);
+
+ return ((matches > 0) ? true : false);
+}
+
+int FilesystemNode::lookupFileRec(FSList &results, FilesystemNode &dir, Common::String &filename, bool hidden, bool exhaustive) const
+{
+ FSList entries;
+ FSList children;
+ int matches = 0;
+ dir.getChildren(entries, FilesystemNode::kListAll, hidden);
+
+ //Breadth search (entries in the same level)
+ for (FSList::iterator entry = entries.begin(); entry != entries.end(); ++entry) {
+ if (entry->isDirectory()) {
+ children.push_back(*entry);
+ } else {
+ //TODO: here we assume all backends implement the lastPathComponent method. It is currently static,
+ // so it might be a good idea to include it inside the backend class. This would enforce its
+ // implementation by all ports.
+ if (matchString(lastPathComponent(entry->getPath()), filename.c_str())) {
+ results.push_back(*entry);
+ matches++;
+
+ if (!exhaustive)
+ break;
+ }
+ }
+ }
+
+ //Depth search (entries in lower levels)
+ for (FSList::iterator child = children.begin(); child != children.end(); ++child) {
+ matches += lookupFileRec(results, *child, filename, hidden, exhaustive);
+ }
+
+ return matches;
}
diff --git a/common/fs.h b/common/fs.h
index 4c275b5b2a..38e5c64a10 100644
--- a/common/fs.h
+++ b/common/fs.h
@@ -33,7 +33,6 @@
class FilesystemNode;
class AbstractFilesystemNode;
-
/**
* List of multiple file system nodes. E.g. the contents of a given directory.
* This is subclass instead of just a typedef so that we can use forward
@@ -41,9 +40,8 @@ class AbstractFilesystemNode;
*/
class FSList : public Common::Array<FilesystemNode> {};
-
/**
- * FilesystemNode provides an abstraction for file pathes, allowing for portable
+ * FilesystemNode provides an abstraction for file paths, allowing for portable
* file system browsing. To this ends, multiple or single roots have to be supported
* (compare Unix with a single root, Windows with multiple roots C:, D:, ...).
*
@@ -64,12 +62,13 @@ class FSList : public Common::Array<FilesystemNode> {};
* paths (MacOS 9 doesn't even have the notion of a "current directory").
* And if we ever want to support devices with no FS in the classical sense (Palm...),
* we can build upon this.
+ *
+ * This class acts as a wrapper around the AbstractFilesystemNode class defined in backends/fs.
*/
class FilesystemNode {
private:
- AbstractFilesystemNode *_realNode;
int *_refCount;
-
+ AbstractFilesystemNode *_realNode;
FilesystemNode(AbstractFilesystemNode *realNode);
public:
@@ -83,9 +82,9 @@ public:
};
/**
- * Create a new invalid FilesystemNode. In other words, isValid() for that
- * node returns false, and if you try to get it's path, an assert is
- * triggered.
+ * Create a new pathless FilesystemNode. Since there's no path associated
+ * with this node, path-related operations (i.e. exists(), isDirectory(),
+ * getPath()) will always return false or raise an assertion.
*/
FilesystemNode();
@@ -113,51 +112,44 @@ public:
/**
* Copy operator.
*/
- FilesystemNode &operator =(const FilesystemNode &node);
-
+ FilesystemNode &operator= (const FilesystemNode &node);
+
/**
- * Checks if the FilesystemNode is valid for any usage
+ * Compare the name of this node to the name of another. Directories
+ * go before normal files.
*/
- bool isValid() const;
+ bool operator<(const FilesystemNode& node) const;
/**
- * Get the parent node of this node. If this node has no parent node,
- * then it returns a duplicate of this node.
+ * Indicates whether the object referred by this path exists in the filesystem or not.
+ *
+ * @return bool true if the path exists, false otherwise.
*/
- FilesystemNode getParent() const;
+ virtual bool exists() const;
/**
* Fetch a child node of this node, with the given name. Only valid for
- * directory nodes (an assertion is triggered otherwise). If no no child
- * node with the given name exists, an invalid node is returned.
+ * directory nodes (an assertion is triggered otherwise).
+ * If no child node with the given name exists, an invalid node is returned.
*/
FilesystemNode getChild(const Common::String &name) const;
-
+
/**
* Return a list of child nodes of this directory node. If called on a node
* that does not represent a directory, false is returned.
+ *
* @return true if succesful, false otherwise (e.g. when the directory does not exist).
- * @todo Rename this to listChildren or getChildren.
*/
- virtual bool listDir(FSList &fslist, ListMode mode = kListDirectoriesOnly) const;
-
- /**
- * Is this node pointing to a directory?
- * @todo Currently we assume that a valid node that is not a directory
- * automatically is a file (ignoring things like symlinks). That might
- * actually be OK... but we could still add an isFile method. Or even replace
- * isValid and isDirectory by a getType() method that can return values like
- * kDirNodeType, kFileNodeType, kInvalidNodeType.
- */
- virtual bool isDirectory() const;
+ virtual bool getChildren(FSList &fslist, ListMode mode = kListDirectoriesOnly, bool hidden = false) const;
/**
* Return a human readable string for this node, usable for display (e.g.
* in the GUI code). Do *not* rely on it being usable for anything else,
* like constructing paths!
+ *
* @return the display name
*/
- virtual Common::String displayName() const;
+ virtual Common::String getDisplayName() const;
/**
* Return a string representation of the name of the file. This is can be
@@ -167,7 +159,7 @@ public:
*
* @return the file name
*/
- virtual Common::String name() const;
+ virtual Common::String getName() const;
/**
* Return a string representation of the file which can be passed to fopen(),
@@ -180,18 +172,107 @@ public:
*
* @return the 'path' represented by this filesystem node
*/
- virtual Common::String path() const;
+ virtual Common::String getPath() const;
+
+ /**
+ * Get the parent node of this node. If this node has no parent node,
+ * then it returns a duplicate of this node.
+ */
+ FilesystemNode getParent() const;
/**
- * Compare the name of this node to the name of another. Directories
- * go before normal files.
+ * Indicates whether the path refers to a directory or not.
+ *
+ * @todo Currently we assume that a node that is not a directory
+ * automatically is a file (ignoring things like symlinks or pipes).
+ * That might actually be OK... but we could still add an isFile method.
+ * Or even replace isDirectory by a getType() method that can return values like
+ * kDirNodeType, kFileNodeType, kInvalidNodeType.
+ */
+ virtual bool isDirectory() const;
+
+ /**
+ * Indicates whether the object referred by this path can be read from or not.
+ *
+ * If the path refers to a directory, readability implies being able to read
+ * and list the directory entries.
+ *
+ * If the path refers to a file, readability implies being able to read the
+ * contents of the file.
+ *
+ * @return bool true if the object can be read, false otherwise.
+ */
+ virtual bool isReadable() const;
+
+ /**
+ * Indicates whether the object referred by this path can be written to or not.
+ *
+ * If the path refers to a directory, writability implies being able to modify
+ * the directory entry (i.e. rename the directory, remove it or write files inside of it).
+ *
+ * If the path refers to a file, writability implies being able to write data
+ * to the file.
+ *
+ * @return bool true if the object can be written to, false otherwise.
*/
- bool operator< (const FilesystemNode& node) const;
+ virtual bool isWritable() const;
+
+ /**
+ * Searches recursively for a filename inside the given directories.
+ *
+ * For each directory in the directory list a breadth-first search is performed,
+ * that is, the current directory entries are scanned before going into subdirectories.
+ *
+ * @param results List to put the matches in.
+ * @param fslist List of directories to search within.
+ * @param filename Name of the file to look for.
+ * @param hidden Whether to search hidden files or not.
+ * @param exhaustive Whether to continue searching after one match has been found.
+ *
+ * @return true if matches could be found, false otherwise.
+ */
+ virtual bool lookupFile(FSList &results, FSList &fslist, Common::String &filename, bool hidden, bool exhaustive) const;
+
+ /**
+ * Searches recursively for a filename inside the given directory.
+ *
+ * The search is performed breadth-first, that is, the current directory entries
+ * are scanned before going into subdirectories.
+ *
+ * @param results List to put the matches in.
+ * @param FilesystemNode Directory to search within.
+ * @param filename Name of the file to look for.
+ * @param hidden Whether to search hidden files or not.
+ * @param exhaustive Whether to continue searching after one match has been found.
+ *
+ * @return true if matches could be found, false otherwise.
+ */
+ virtual bool lookupFile(FSList &results, FilesystemNode &dir, Common::String &filename, bool hidden, bool exhaustive) const;
protected:
+ /**
+ * Decreases the reference count to the FilesystemNode, and if necessary,
+ * deletes the corresponding underlying references.
+ */
void decRefCount();
+
+ /**
+ * Searches recursively for a filename inside the given directory.
+ *
+ * The search is performed breadth-first, that is, the current directory entries
+ * are scanned before going into subdirectories.
+ *
+ * @param results List to put the matches in.
+ * @param FilesystemNode Directory to search within.
+ * @param filename Name of the file to look for.
+ * @param hidden Whether to search hidden files or not.
+ * @param exhaustive Whether to continue searching after one match has been found.
+ *
+ * @return The number of matches found.
+ */
+ int lookupFileRec(FSList &results, FilesystemNode &dir, Common::String &filename, bool hidden, bool exhaustive) const;
};
//} // End of namespace Common
-#endif
+#endif //COMMON_FS_H
diff --git a/common/md5.cpp b/common/md5.cpp
index a48ecb4948..32acdc5b8c 100644
--- a/common/md5.cpp
+++ b/common/md5.cpp
@@ -246,15 +246,18 @@ void md5_finish(md5_context *ctx, uint8 digest[16]) {
}
bool md5_file(const FilesystemNode &file, uint8 digest[16], uint32 length) {
- if (!file.isValid()) {
- warning("md5_file: using an invalid FilesystemNode");
+ if(!file.exists()) {
+ warning("md5_file: using an inexistent FilesystemNode");
+ return false;
+ } else if (!file.isReadable()) {
+ warning("md5_file: using an unreadable FilesystemNode");
return false;
} else if (file.isDirectory()) {
- warning("md5_file: using a diretory FilesystemNode");
+ warning("md5_file: using a directory FilesystemNode");
return false;
}
- return md5_file(file.path().c_str(), digest, length);
+ return md5_file(file.getPath().c_str(), digest, length);
}
bool md5_file(const char *name, uint8 digest[16], uint32 length) {
diff --git a/common/savefile.h b/common/savefile.h
index e1a54638b5..9fdd76ae15 100644
--- a/common/savefile.h
+++ b/common/savefile.h
@@ -30,6 +30,8 @@
#include "common/noncopyable.h"
#include "common/scummsys.h"
#include "common/stream.h"
+#include "common/str.h"
+#include "common/error.h"
namespace Common {
@@ -75,10 +77,40 @@ public:
* returning the single SaveFileManager instances to be used.
*/
class SaveFileManager : NonCopyable {
-
+
+protected:
+ SFMError _error;
+ String _errorDesc;
+
public:
virtual ~SaveFileManager() {}
-
+
+ /**
+ * Clears the last set error code and string.
+ */
+ virtual void clearError() { _error = SFM_NO_ERROR; _errorDesc = ""; }
+
+ /**
+ * Returns the last ocurred error code. If none ocurred, returns SFM_NO_ERROR.
+ *
+ * @return A SFMError indicating the type of the last error.
+ */
+ virtual SFMError getError() { return _error; }
+
+ /**
+ * Returns the last ocurred error description. If none ocurred, returns 0.
+ *
+ * @return A string describing the last error.
+ */
+ virtual String getErrorDesc() { return _errorDesc; }
+
+ /**
+ * Sets the last ocurred error.
+ * @param error Code identifying the last error.
+ * @param errorDesc String describing the last error.
+ */
+ virtual void setError(SFMError error, String errorDesc) { _error = error; _errorDesc = errorDesc; }
+
/**
* Open the file with name filename in the given directory for saving.
* @param filename the filename
@@ -94,12 +126,18 @@ public:
virtual InSaveFile *openForLoading(const char *filename) = 0;
/**
- * Request a list of available savegames with a given prefix.
- * TODO: Document this better!
- * TODO: Or even replace it with a better API. For example, one that
- * returns a list of strings for all present file names.
+ * Removes the given savefile from the filesystem.
+ * @param filename Filename path pointing to the savefile.
+ * @return true if no error ocurred. false otherwise.
+ */
+ virtual bool removeSavefile(const char *filename) = 0;
+
+ /**
+ * Request a list of available savegames with a given regex.
+ * @param regex Regular expression to match. Wildcards like * or ? are available.
+ * returns a list of strings for all present file names.
*/
- virtual void listSavefiles(const char * /* prefix */, bool *marks, int num) = 0;
+ virtual Common::StringList listSavefiles(const char *regex) = 0;
/**
* Get the path to the save game directory.