diff options
author | Vicent Marti | 2008-10-05 11:21:07 +0000 |
---|---|---|
committer | Vicent Marti | 2008-10-05 11:21:07 +0000 |
commit | 5f30b1f320ca34fa05246736d9fe074c204cdf38 (patch) | |
tree | 9ef23f441455f0f807bb3a59c5d93854a5851456 /common | |
parent | e32fc0ccca2570fc560969507351cf99a304ebf4 (diff) | |
parent | 99f8add65cb61d1e8da23f734da249687d24919e (diff) | |
download | scummvm-rg350-5f30b1f320ca34fa05246736d9fe074c204cdf38.tar.gz scummvm-rg350-5f30b1f320ca34fa05246736d9fe074c204cdf38.tar.bz2 scummvm-rg350-5f30b1f320ca34fa05246736d9fe074c204cdf38.zip |
Merged several revisions from SVNMerge.
Fixed theme loading to use the new ArchiveMember class.
Original SVNMerge.py log:
=====================
Merged revisions 34686,34688-34689,34691-34698,34700-34705,34707-34713,34715-34722,34725-34727,34731-34732,34734-34738,34746 via svnmerge from
https://tanoku@scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
........
r34686 | cyx | 2008-09-29 21:09:56 +0200 (Mon, 29 Sep 2008) | 1 line
add constructor to SearchSet::Node for proper init of structure members with gcc 3.4.x (see tracker items #2120595, #2106292)
........
r34688 | cyx | 2008-09-29 22:08:26 +0200 (Mon, 29 Sep 2008) | 1 line
restrict _heXmapNum to HE versions, should fix #2135822
........
r34689 | eriktorbjorn | 2008-09-29 22:40:58 +0200 (Mon, 29 Sep 2008) | 4 lines
Since no one has come up with any better suggestion... this should fix #2123258
("COMI: Crash after video (SAN) play"). The eos() function won't return true
until we've tried to read *past* the end of the stream.
........
r34691 | tanoku | 2008-09-30 00:29:07 +0200 (Tue, 30 Sep 2008) | 1 line
Ported ZipArchive::getAllNames() implementation from GUI branch.
........
r34692 | fingolfin | 2008-09-30 11:07:03 +0200 (Tue, 30 Sep 2008) | 1 line
Order alphabetically
........
r34693 | fingolfin | 2008-09-30 11:08:17 +0200 (Tue, 30 Sep 2008) | 1 line
SAGA: Removed patchesCount from SAGAGameDescription
........
r34694 | fingolfin | 2008-09-30 11:09:39 +0200 (Tue, 30 Sep 2008) | 1 line
SCUMM HE: Use FilesystemNode::openForReading() instead of 'new Common::File' (didn't cover all instances, though)
........
r34695 | fingolfin | 2008-09-30 11:11:25 +0200 (Tue, 30 Sep 2008) | 1 line
SAGA: Forgot to commit saga.h
........
r34696 | fingolfin | 2008-09-30 11:12:02 +0200 (Tue, 30 Sep 2008) | 1 line
Added multiple new open() methods to Common::File, which make it possible to use this class as a generic convenience wrapper around all kinds of SeekableReadStream; also renamed the name() method to the less confusing getName()
........
r34697 | fingolfin | 2008-09-30 13:33:43 +0200 (Tue, 30 Sep 2008) | 1 line
cleanup
........
r34698 | tanoku | 2008-09-30 13:53:37 +0200 (Tue, 30 Sep 2008) | 1 line
Fixed functionality of ZipArchive::getAllNames(). Now it expects a possibly non-empty string list and returns the amount of new filenames added to it.
........
r34700 | fingolfin | 2008-09-30 14:27:38 +0200 (Tue, 30 Sep 2008) | 1 line
Renamed Engine::quit to Engine::shouldQuit (previously, it was easily confused with Engine::quitGame); also cleaned up engine.h a bit
........
r34701 | fingolfin | 2008-09-30 14:37:28 +0200 (Tue, 30 Sep 2008) | 1 line
cleanup
........
r34702 | fingolfin | 2008-09-30 14:38:44 +0200 (Tue, 30 Sep 2008) | 1 line
AdvancedDetector: Do not (ab)use paths to keep track of files, rather, use FSNodes -- partial (?) fix for bug #2137680
........
r34703 | fingolfin | 2008-09-30 14:58:27 +0200 (Tue, 30 Sep 2008) | 1 line
SAGA: Some code cleanup
........
r34704 | fingolfin | 2008-09-30 14:59:29 +0200 (Tue, 30 Sep 2008) | 1 line
SKY: Fix detector to not (ab)use FSNode::getPath; if you want to open a FSNode, just pass it to File::open
........
r34705 | thebluegr | 2008-09-30 15:19:14 +0200 (Tue, 30 Sep 2008) | 1 line
Fixed crash when starting IHNM, a regression from commit #34693
........
r34707 | fingolfin | 2008-09-30 17:42:19 +0200 (Tue, 30 Sep 2008) | 1 line
Fixing ConfigManager::loadConfigFile
........
r34708 | fingolfin | 2008-09-30 18:23:35 +0200 (Tue, 30 Sep 2008) | 1 line
AGI: Another case where it is better to use FSNodes directly, instead of converting them to path strings
........
r34709 | fingolfin | 2008-09-30 18:34:38 +0200 (Tue, 30 Sep 2008) | 1 line
Modified FilePluginProvider to use FSNodes (instead of raw filenames / paths) in its API
........
r34710 | fingolfin | 2008-09-30 18:38:46 +0200 (Tue, 30 Sep 2008) | 1 line
AGI: Got rid of yet another unwarranted use of FSNode::getPath
........
r34711 | fingolfin | 2008-09-30 18:53:04 +0200 (Tue, 30 Sep 2008) | 1 line
AGI: Simplify WagFileParser by not reading data into a memory stream first (this was there to improve performance on systems with slow seeking; those systems should use another approach, see scummvm-devel)
........
r34712 | thebluegr | 2008-09-30 18:55:10 +0200 (Tue, 30 Sep 2008) | 1 line
Fix crash when starting ITE, a regression from commit #34705
........
r34713 | fingolfin | 2008-09-30 19:09:41 +0200 (Tue, 30 Sep 2008) | 1 line
Fix ThemeBrowser to use FSNodes, not getPath()
........
r34715 | Kirben | 2008-10-02 16:41:50 +0200 (Thu, 02 Oct 2008) | 1 line
Correct HE version for Putt-Putt Enters the Race (French/Windows).
........
r34716 | fingolfin | 2008-10-02 18:58:59 +0200 (Thu, 02 Oct 2008) | 1 line
Renamed FilesystemNode -> FSNode
........
r34717 | fingolfin | 2008-10-02 19:08:15 +0200 (Thu, 02 Oct 2008) | 1 line
cleanup
........
r34718 | fingolfin | 2008-10-02 19:17:18 +0200 (Thu, 02 Oct 2008) | 1 line
Ignore String::deleteLastChar when called on an empty string
........
r34719 | fingolfin | 2008-10-02 19:20:21 +0200 (Thu, 02 Oct 2008) | 1 line
Fix for bug #2142743: Assertion on clicking "Theme" in Options
........
r34720 | fingolfin | 2008-10-02 19:48:01 +0200 (Thu, 02 Oct 2008) | 7 lines
Engine class changed:
- Moved initCommonGFX() && GUIErrorMessage() out of class Engine
- got rid of the _autosavePeriod member (this prevented users from
changing the autosave period during runtime)
- Got rid of an evil 'using GUI::Dialog' statement
- Clarified some Doxygen comments
........
r34721 | fingolfin | 2008-10-02 19:52:29 +0200 (Thu, 02 Oct 2008) | 1 line
Add the current dir to the global SearchSet, i.e. to SearchMan (this should fix the problems on Windows, and maybe other systems, see 'bug' #2137680)
........
r34722 | fingolfin | 2008-10-02 19:55:08 +0200 (Thu, 02 Oct 2008) | 1 line
Forgot to mention yet another Engine class change: mainMenuDialog -> openMainMenuDialog; and also forgot to commit this related file :/
........
r34725 | fingolfin | 2008-10-02 20:11:40 +0200 (Thu, 02 Oct 2008) | 1 line
typo
........
r34726 | thebluegr | 2008-10-03 00:04:34 +0200 (Fri, 03 Oct 2008) | 1 line
Merged loadHotSpotsMads() and loadHotSpotsM4()
........
r34727 | lordhoto | 2008-10-03 02:16:21 +0200 (Fri, 03 Oct 2008) | 2 lines
Fixed typos (thanks to Raziel^ for spotting them).
........
r34731 | fingolfin | 2008-10-03 18:07:57 +0200 (Fri, 03 Oct 2008) | 1 line
Fixed Engine::hasFeature to use proper types (i.e., MetaEngine::MetaEngineFeature instead of int)
........
r34732 | fingolfin | 2008-10-03 18:14:12 +0200 (Fri, 03 Oct 2008) | 1 line
SCUMM: Added french Monkey VGA variant, see bug #2129199
........
r34734 | lordhoto | 2008-10-03 18:57:40 +0200 (Fri, 03 Oct 2008) | 2 lines
Committed slightly modified patch #2034983 "Case-insensitivy and directory handling for engines".
........
r34735 | lordhoto | 2008-10-03 20:18:42 +0200 (Fri, 03 Oct 2008) | 2 lines
Check all 'kyra.dat' files in setup paths instead of only the first one found.
........
r34736 | lordhoto | 2008-10-03 20:23:57 +0200 (Fri, 03 Oct 2008) | 2 lines
Cleanup.
........
r34737 | dreammaster | 2008-10-04 13:10:25 +0200 (Sat, 04 Oct 2008) | 1 line
Bugfix to prevent NPC characters managing to walk beyond room exits without leaving the room, and thus getting stuck
........
r34738 | fingolfin | 2008-10-04 15:09:01 +0200 (Sat, 04 Oct 2008) | 1 line
Renamed some MetaEngine feature flags; removed explicit numbers from this feature flag list (nothing should rely on their specific values, anyway); added a note that Engine::hasFeature should become independant of MetaEngine::hasFeature
........
r34746 | john_doe | 2008-10-04 23:40:14 +0200 (Sat, 04 Oct 2008) | 3 lines
- Declared all stack functions as inline
- Sleep some ms after 500 opcodes to reduce CPU load
- Fixed odd bug in LGoP2 where text disappeared quickly without waiting for user input by returning 0x38 in sfShowPage
........
svn-id: r34749
Diffstat (limited to 'common')
-rw-r--r-- | common/advancedDetector.cpp | 15 | ||||
-rw-r--r-- | common/archive.cpp | 127 | ||||
-rw-r--r-- | common/archive.h | 58 | ||||
-rw-r--r-- | common/config-manager.cpp | 3 | ||||
-rw-r--r-- | common/file.cpp | 68 | ||||
-rw-r--r-- | common/file.h | 64 | ||||
-rw-r--r-- | common/fs.cpp | 58 | ||||
-rw-r--r-- | common/fs.h | 35 | ||||
-rw-r--r-- | common/md5.cpp | 10 | ||||
-rw-r--r-- | common/md5.h | 6 | ||||
-rw-r--r-- | common/str.cpp | 3 | ||||
-rw-r--r-- | common/system.cpp | 4 | ||||
-rw-r--r-- | common/unzip.cpp | 31 | ||||
-rw-r--r-- | common/unzip.h | 2 | ||||
-rw-r--r-- | common/xmlparser.h | 2 |
15 files changed, 286 insertions, 200 deletions
diff --git a/common/advancedDetector.cpp b/common/advancedDetector.cpp index 1b0db4755a..1ec8c47715 100644 --- a/common/advancedDetector.cpp +++ b/common/advancedDetector.cpp @@ -246,9 +246,9 @@ PluginError AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) c path = "."; warning("No path was provided. Assuming the data files are in the current directory"); } - FilesystemNode dir(path); + FSNode dir(path); FSList files; - if (!dir.isDirectory() || !dir.getChildren(files, FilesystemNode::kListAll)) { + if (!dir.isDirectory() || !dir.getChildren(files, FSNode::kListAll)) { warning("Game data path does not exist or is not a directory (%s)", path.c_str()); return kNoGameDataFoundError; } @@ -290,6 +290,7 @@ PluginError AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) c typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> StringSet; typedef HashMap<String, int32, IgnoreCase_Hash, IgnoreCase_EqualTo> IntMap; +typedef HashMap<String, FSNode, IgnoreCase_Hash, IgnoreCase_EqualTo> FileMap; static void reportUnknown(const StringMap &filesMD5, const IntMap &filesSize) { // TODO: This message should be cleaned up / made more specific. @@ -307,10 +308,10 @@ static void reportUnknown(const StringMap &filesMD5, const IntMap &filesSize) { printf("\n"); } -static ADGameDescList detectGameFilebased(const StringMap &allFiles, const Common::ADParams ¶ms); +static ADGameDescList detectGameFilebased(const FileMap &allFiles, const Common::ADParams ¶ms); static ADGameDescList detectGame(const FSList &fslist, const Common::ADParams ¶ms, Language language, Platform platform, const Common::String extra) { - StringMap allFiles; + FileMap allFiles; StringSet detectFiles; StringMap filesMD5; @@ -334,7 +335,7 @@ static ADGameDescList detectGame(const FSList &fslist, const Common::ADParams &p if (tstr.lastChar() == '.') tstr.deleteLastChar(); - allFiles[tstr] = file->getPath(); // Record the presence of this file + allFiles[tstr] = *file; // Record the presence of this file } // Compute the set of files for which we need MD5s for. I.e. files which are @@ -356,7 +357,7 @@ static ADGameDescList detectGame(const FSList &fslist, const Common::ADParams &p debug(3, "+ %s", fname.c_str()); char md5str[32+1]; - if (!md5_file_string(allFiles[fname].c_str(), md5str, params.md5Bytes)) + if (!md5_file_string(allFiles[fname], md5str, params.md5Bytes)) continue; filesMD5[fname] = md5str; @@ -464,7 +465,7 @@ static ADGameDescList detectGame(const FSList &fslist, const Common::ADParams &p * the maximal number of matching files. In case of a tie, the entry * coming first in the list is chosen. */ -static ADGameDescList detectGameFilebased(const StringMap &allFiles, const Common::ADParams ¶ms) { +static ADGameDescList detectGameFilebased(const FileMap &allFiles, const Common::ADParams ¶ms) { const ADFileBasedFallback *ptr; const char* const* filenames; diff --git a/common/archive.cpp b/common/archive.cpp index 49e43a5973..40c2f01ee6 100644 --- a/common/archive.cpp +++ b/common/archive.cpp @@ -30,11 +30,23 @@ namespace Common { +GenericArchiveMember::GenericArchiveMember(String name, Archive *parent) + : _parent(parent), _name(name) { +} + +String GenericArchiveMember::getName() const { + return _name; +} + +SeekableReadStream *GenericArchiveMember::open() { + return _parent->openFile(_name); +} + -int Archive::matchPattern(StringList &list, const String &pattern) { +int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern) { // Get all "names" (TODO: "files" ?) - StringList allNames; - getAllNames(allNames); + ArchiveMemberList allNames; + listMembers(allNames); int matches = 0; @@ -42,9 +54,9 @@ int Archive::matchPattern(StringList &list, const String &pattern) { String lowercasePattern = pattern; lowercasePattern.toLowercase(); - StringList::iterator it = allNames.begin(); + ArchiveMemberList::iterator it = allNames.begin(); for ( ; it != allNames.end(); it++) { - if (it->matchString(lowercasePattern)) { + if ((*it)->getName().matchString(lowercasePattern)) { list.push_back(*it); matches++; } @@ -53,8 +65,36 @@ int Archive::matchPattern(StringList &list, const String &pattern) { return matches; } +/** + * FSDirectoryMemeber is the implementation of ArchiveMember used by + * by FSDirectory. It is right now a light wrapper or FSNode. + */ +class FSDirectoryMember : public ArchiveMember { + FSNode _node; + +public: + FSDirectoryMember(FSNode &node) : _node(node) { + } + + /* + NOTE/FIXME: since I assume that the only use case for getName() + is for error messages, I am returning the full path of the node + here. This seems better than we did before, when matchPattern + and getAllNames used to work with StringList, and we used to + put the relative path of the file to the list instead. + */ + String getName() const { + return _node.getPath(); + } + + SeekableReadStream *open() { + return _node.openForReading(); + } +}; + +typedef SharedPtr<FSDirectoryMember> FSDirectoryMemberPtr; -FSDirectory::FSDirectory(const FilesystemNode &node, int depth) +FSDirectory::FSDirectory(const FSNode &node, int depth) : _node(node), _cached(false), _depth(depth) { } @@ -65,11 +105,11 @@ FSDirectory::FSDirectory(const String &name, int depth) FSDirectory::~FSDirectory() { } -FilesystemNode FSDirectory::getFSNode() const { +FSNode FSDirectory::getFSNode() const { return _node; } -FilesystemNode FSDirectory::lookupCache(NodeCache &cache, const String &name) { +FSNode FSDirectory::lookupCache(NodeCache &cache, const String &name) { // make caching as lazy as possible if (!name.empty()) { if (!_cached) { @@ -81,7 +121,7 @@ FilesystemNode FSDirectory::lookupCache(NodeCache &cache, const String &name) { return cache[name]; } - return FilesystemNode(); + return FSNode(); } bool FSDirectory::hasFile(const String &name) { @@ -89,7 +129,7 @@ bool FSDirectory::hasFile(const String &name) { return false; } - FilesystemNode node = lookupCache(_fileCache, name); + FSNode node = lookupCache(_fileCache, name); return node.exists(); } @@ -98,13 +138,13 @@ SeekableReadStream *FSDirectory::openFile(const String &name) { return 0; } - FilesystemNode node = lookupCache(_fileCache, name); + FSNode node = lookupCache(_fileCache, name); if (!node.exists()) { - warning("FSDirectory::openFile: FilesystemNode does not exist"); + warning("FSDirectory::openFile: FSNode does not exist"); return 0; } else if (node.isDirectory()) { - warning("FSDirectory::openFile: FilesystemNode is a directory"); + warning("FSDirectory::openFile: FSNode is a directory"); return 0; } @@ -121,17 +161,17 @@ FSDirectory *FSDirectory::getSubDirectory(const String &name) { return 0; } - FilesystemNode node = lookupCache(_subDirCache, name); + FSNode node = lookupCache(_subDirCache, name); return new FSDirectory(node); } -void FSDirectory::cacheDirectoryRecursive(FilesystemNode node, int depth, const String& prefix) { +void FSDirectory::cacheDirectoryRecursive(FSNode node, int depth, const String& prefix) { if (depth <= 0) { return; } FSList list; - node.getChildren(list, FilesystemNode::kListAll, false); + node.getChildren(list, FSNode::kListAll, false); FSList::iterator it = list.begin(); for ( ; it != list.end(); it++) { @@ -160,7 +200,7 @@ void FSDirectory::cacheDirectoryRecursive(FilesystemNode node, int depth, const } -int FSDirectory::matchPattern(StringList &list, const String &pattern) { +int FSDirectory::listMatchingMembers(ArchiveMemberList &list, const String &pattern) { if (!_node.isDirectory()) return 0; @@ -170,40 +210,25 @@ int FSDirectory::matchPattern(StringList &list, const String &pattern) { _cached = true; } - // Small optimization: Ensure the StringList has to grow at most once - list.reserve(list.size() + _fileCache.size()); - - // Add all filenames from our cache + String lowercasePattern(pattern); + lowercasePattern.toLowercase(); + + int matches = 0; NodeCache::iterator it = _fileCache.begin(); for ( ; it != _fileCache.end(); it++) { - if (it->_key.matchString(pattern)) - list.push_back(it->_key); + if ((*it)._key.matchString(lowercasePattern)) { + list.push_back(FSDirectoryMemberPtr(new FSDirectoryMember((*it)._value))); + matches++; + } } - - return _fileCache.size(); + return matches; } -int FSDirectory::getAllNames(StringList &list) { - if (!_node.isDirectory()) - return 0; +int FSDirectory::listMembers(ArchiveMemberList &list) { + return listMatchingMembers(list, "*"); +} - // Cache dir data - if (!_cached) { - cacheDirectoryRecursive(_node, _depth, ""); - _cached = true; - } - // Small optimization: Ensure the StringList has to grow at most once - list.reserve(list.size() + _fileCache.size()); - - // Add all filenames from our cache - NodeCache::iterator it = _fileCache.begin(); - for ( ; it != _fileCache.end(); it++) { - list.push_back((*it)._key); - } - - return _fileCache.size(); -} @@ -234,7 +259,7 @@ void SearchSet::insert(const Node &node) { void SearchSet::add(const String& name, ArchivePtr archive, int priority) { if (find(name) == _list.end()) { - Node node = { priority, name, archive }; + Node node(priority, name, archive); insert(node); } else { warning("SearchSet::add: archive '%s' already present", name.c_str()); @@ -289,23 +314,23 @@ bool SearchSet::hasFile(const String &name) { return false; } -int SearchSet::matchPattern(StringList &list, const String &pattern) { +int SearchSet::listMatchingMembers(ArchiveMemberList &list, const String &pattern) { int matches = 0; ArchiveList::iterator it = _list.begin(); for ( ; it != _list.end(); it++) { - matches += (*it)._arc->matchPattern(list, pattern); + matches += (*it)._arc->listMatchingMembers(list, pattern); } return matches; } -int SearchSet::getAllNames(StringList &list) { +int SearchSet::listMembers(ArchiveMemberList &list) { int matches = 0; ArchiveList::iterator it = _list.begin(); for ( ; it != _list.end(); it++) { - matches += (*it)._arc->getAllNames(list); + matches += (*it)._arc->listMembers(list); } return matches; @@ -352,6 +377,10 @@ void SearchManager::clear() { // But we give them a lower priority than the default priority (which is 0), // so that archives added by client code are searched first. g_system->addSysArchivesToSearchSet(*this, -1); + + // Add the current dir as a very last resort. + // See also bug #2137680. + add(".", ArchivePtr(new FSDirectory(".")), -2); } } // namespace Common diff --git a/common/archive.h b/common/archive.h index 246d9da8cf..2fc86b1b57 100644 --- a/common/archive.h +++ b/common/archive.h @@ -36,6 +36,35 @@ namespace Common { +class ArchiveMember { +public: + virtual ~ArchiveMember() { } + virtual String getName() const = 0; + virtual SeekableReadStream *open() = 0; +}; + +typedef List<SharedPtr<ArchiveMember> > ArchiveMemberList; + +class Archive; + +/** + * Simple ArchiveMemeber implementation which allows + * creation of ArchiveMember compatible objects via + * a simple Archive and name pair. + * + * Note that GenericArchiveMember objects will not + * be working anymore after the 'parent' object + * is destroyed. + */ +class GenericArchiveMember : public ArchiveMember { + Archive *_parent; + String _name; +public: + GenericArchiveMember(String name, Archive *parent); + String getName() const; + SeekableReadStream *open(); +}; + /** * FilePtr is a convenient way to keep track of a SeekableReadStream without * having to worry about releasing its memory. @@ -63,7 +92,7 @@ public: * * @return the number of names added to list */ - virtual int matchPattern(StringList &list, const String &pattern); + virtual int listMatchingMembers(ArchiveMemberList &list, const String &pattern); /** * Add all the names present in the Archive to list. Returned @@ -72,7 +101,7 @@ public: * * @return the number of names added to list */ - virtual int getAllNames(StringList &list) = 0; + virtual int listMembers(ArchiveMemberList &list) = 0; /** * Create a stream bound to a file in the archive. @@ -93,21 +122,21 @@ typedef SharedPtr<Archive> ArchivePtr; * 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 - * FilesystemNode implementation. + * FSNode implementation. */ class FSDirectory : public Archive { - FilesystemNode _node; + FSNode _node; // Caches are case insensitive, clashes are dealt with when creating // Key is stored in lowercase. - typedef HashMap<String, FilesystemNode, IgnoreCase_Hash, IgnoreCase_EqualTo> NodeCache; + typedef HashMap<String, FSNode, IgnoreCase_Hash, IgnoreCase_EqualTo> NodeCache; NodeCache _fileCache, _subDirCache; // look for a match - FilesystemNode lookupCache(NodeCache &cache, const String &name); + FSNode lookupCache(NodeCache &cache, const String &name); // cache management - void cacheDirectoryRecursive(FilesystemNode node, int depth, const String& prefix); + void cacheDirectoryRecursive(FSNode node, int depth, const String& prefix); bool _cached; int _depth; @@ -122,14 +151,14 @@ public: * 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. */ - FSDirectory(const FilesystemNode &node, int depth = 1); + FSDirectory(const FSNode &node, int depth = 1); virtual ~FSDirectory(); /** * This return the underlying FSNode of the FSDirectory. */ - FilesystemNode getFSNode() const; + FSNode getFSNode() const; /** * Create a new FSDirectory pointing to a sub directory of the instance. @@ -138,8 +167,8 @@ public: FSDirectory *getSubDirectory(const String &name); virtual bool hasFile(const String &name); - virtual int matchPattern(StringList &list, const String &pattern); - virtual int getAllNames(StringList &list); + virtual int listMatchingMembers(ArchiveMemberList &list, const String &pattern); + virtual int listMembers(ArchiveMemberList &list); virtual SeekableReadStream *openFile(const String &name); }; @@ -156,6 +185,9 @@ class SearchSet : public Archive { int _priority; String _name; ArchivePtr _arc; + Node(int priority, const String &name, ArchivePtr arc) + : _priority(priority), _name(name), _arc(arc) { + } }; typedef List<Node> ArchiveList; ArchiveList _list; @@ -192,8 +224,8 @@ public: void setPriority(const String& name, int priority); virtual bool hasFile(const String &name); - virtual int matchPattern(StringList &list, const String &pattern); - virtual int getAllNames(StringList &list); + virtual int listMatchingMembers(ArchiveMemberList &list, const String &pattern); + virtual int listMembers(ArchiveMemberList &list); /** * Implements openFile from Archive base class. The current policy is diff --git a/common/config-manager.cpp b/common/config-manager.cpp index b741757cc5..0d01c39c4f 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -77,8 +77,9 @@ void ConfigManager::loadDefaultConfigFile() { void ConfigManager::loadConfigFile(const String &filename) { _filename = filename; + FSNode node(filename); File cfg_file; - if (!cfg_file.open(filename)) { + if (!cfg_file.open(node)) { printf("Creating configuration file: %s\n", filename.c_str()); } else { printf("Using configuration file: %s\n", _filename.c_str()); diff --git a/common/file.cpp b/common/file.cpp index 6558dfea33..ed432ce565 100644 --- a/common/file.cpp +++ b/common/file.cpp @@ -32,20 +32,20 @@ namespace Common { void File::addDefaultDirectory(const String &directory) { - FilesystemNode dir(directory); + FSNode dir(directory); addDefaultDirectoryRecursive(dir, 1); } void File::addDefaultDirectoryRecursive(const String &directory, int level) { - FilesystemNode dir(directory); + FSNode dir(directory); addDefaultDirectoryRecursive(dir, level); } -void File::addDefaultDirectory(const FilesystemNode &directory) { +void File::addDefaultDirectory(const FSNode &directory) { addDefaultDirectoryRecursive(directory, 1); } -void File::addDefaultDirectoryRecursive(const FilesystemNode &dir, int level) { +void File::addDefaultDirectoryRecursive(const FSNode &dir, int level) { if (level <= 0 || !dir.exists() || !dir.isDirectory()) return; @@ -65,61 +65,59 @@ File::~File() { close(); } - bool File::open(const String &filename) { + return open(filename, SearchMan); +} + +bool File::open(const String &filename, Archive &archive) { assert(!filename.empty()); assert(!_handle); - _name.clear(); clearIOFailed(); - if (SearchMan.hasFile(filename)) { + SeekableReadStream *stream = 0; + if (archive.hasFile(filename)) { debug(3, "Opening hashed: %s", filename.c_str()); - _handle = SearchMan.openFile(filename); - } else if (SearchMan.hasFile(filename + ".")) { + stream = archive.openFile(filename); + } else if (archive.hasFile(filename + ".")) { // WORKAROUND: Bug #1458388: "SIMON1: Game Detection fails" // sometimes instead of "GAMEPC" we get "GAMEPC." (note trailing dot) debug(3, "Opening hashed: %s.", filename.c_str()); - _handle = SearchMan.openFile(filename + "."); + stream = archive.openFile(filename + "."); } - if (_handle == NULL) - debug(2, "File::open: '%s' not found", filename.c_str()); - else - _name = filename; - - return _handle != NULL; + return open(stream, filename); } -bool File::open(const FilesystemNode &node) { +bool File::open(const FSNode &node) { + assert(!_handle); if (!node.exists()) { - warning("File::open: FilesystemNode does not exist"); + warning("File::open: '%s' does not exist", node.getPath().c_str()); return false; } else if (node.isDirectory()) { - warning("File::open: FilesystemNode is a directory"); + warning("File::open: '%s' is a directory", node.getPath().c_str()); return false; } - 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()); - } + SeekableReadStream *stream = node.openForReading(); + return open(stream, node.getPath()); +} +bool File::open(SeekableReadStream *stream, const Common::String &name) { + assert(!_handle); clearIOFailed(); - _name.clear(); - - _handle = node.openForReading(); - - if (_handle == NULL) - debug(2, "File::open: '%s' not found", node.getPath().c_str()); - else - _name = filename; + if (stream) { + _handle = stream; + _name = name; + } else { + debug(2, "File::open: opening '%s' failed", name.c_str()); + } return _handle != NULL; } + bool File::exists(const String &filename) { if (SearchMan.hasFile(filename)) { return true; @@ -198,15 +196,15 @@ bool DumpFile::open(const String &filename) { assert(!filename.empty()); assert(!_handle); - FilesystemNode node(filename); + FSNode node(filename); return open(node); } -bool DumpFile::open(const FilesystemNode &node) { +bool DumpFile::open(const FSNode &node) { assert(!_handle); if (node.isDirectory()) { - warning("DumpFile::open: FilesystemNode is a directory"); + warning("DumpFile::open: FSNode is a directory"); return false; } diff --git a/common/file.h b/common/file.h index a2739f795f..0634aecdd3 100644 --- a/common/file.h +++ b/common/file.h @@ -27,13 +27,14 @@ #define COMMON_FILE_H #include "common/scummsys.h" +#include "common/archive.h" #include "common/noncopyable.h" #include "common/str.h" #include "common/stream.h" namespace Common { -class FilesystemNode; +class FSNode; /** * TODO: vital to document this core class properly!!! For both users and implementors @@ -43,7 +44,7 @@ protected: /** File handle to the actual file; 0 if no file is open. */ SeekableReadStream *_handle; - /** The name of this file, for debugging. */ + /** The name of this file, kept for debugging purposes. */ String _name; public: @@ -51,11 +52,12 @@ public: static void addDefaultDirectory(const String &directory); static void addDefaultDirectoryRecursive(const String &directory, int level = 4); - static void addDefaultDirectory(const FilesystemNode &directory); - static void addDefaultDirectoryRecursive(const FilesystemNode &directory, int level = 4); + static void addDefaultDirectory(const FSNode &directory); + static void addDefaultDirectoryRecursive(const FSNode &directory, int level = 4); static void resetDefaultDirectories(); + File(); virtual ~File(); @@ -64,14 +66,56 @@ public: * (those were/are added by addDefaultDirectory and/or * addDefaultDirectoryRecursive). * - * @param filename: the file to check for - * @return: true if the file exists, else false + * @param filename the file to check for + * @return true if the file exists, false otherwise */ static bool exists(const String &filename); + /** + * Try to open the file with the given filename, by searching SearchMan. + * @note Must not be called if this file already is open (i.e. if isOpen returns true). + * + * @param filename the name of the file to open + * @return true if file was opened successfully, false otherwise + */ virtual bool open(const String &filename); - virtual bool open(const FilesystemNode &node); + /** + * Try to open the file with the given filename from within the given archive. + * @note Must not be called if this file already is open (i.e. if isOpen returns true). + * + * @param filename the name of the file to open + * @param archive the archive in which to search for the file + * @return true if file was opened successfully, false otherwise + */ + virtual bool open(const String &filename, Archive &archive); + + /** + * Try to open the file corresponding to the give node. Will check whether the + * node actually refers to an existing file (and not a directory), and handle + * those cases gracefully. + * @note Must not be called if this file already is open (i.e. if isOpen returns true). + * + * @param filename the name of the file to open + * @param archive the archive in which to search for the file + * @return true if file was opened successfully, false otherwise + */ + virtual bool open(const FSNode &node); + + /** + * Try to 'open' the given stream. That is, we just wrap around it, and if stream + * is a NULL pointer, we gracefully treat this as if opening failed. + * @note Must not be called if this file already is open (i.e. if isOpen returns true). + * + * @param stream a pointer to a SeekableReadStream, or 0 + * @param name a string describing the 'file' corresponding to stream + * @return true if stream was 0, false otherwise + */ + virtual bool open(SeekableReadStream *stream, const Common::String &name); + + /** + * Close the file, if open. + */ virtual void close(); /** @@ -82,11 +126,11 @@ public: bool isOpen() const; /** - * Returns the filename of the opened file. + * Returns the filename of the opened file for debugging purposes. * * @return: the filename */ - const char *name() const { return _name.c_str(); } + const char *getName() const { return _name.c_str(); } bool ioFailed() const; void clearIOFailed(); @@ -117,7 +161,7 @@ public: virtual ~DumpFile(); virtual bool open(const String &filename); - virtual bool open(const FilesystemNode &node); + virtual bool open(const FSNode &node); virtual void close(); diff --git a/common/fs.cpp b/common/fs.cpp index 4d31ac09fa..c1ef26e42d 100644 --- a/common/fs.cpp +++ b/common/fs.cpp @@ -29,48 +29,48 @@ namespace Common { -FilesystemNode::FilesystemNode() { +FSNode::FSNode() { } -FilesystemNode::FilesystemNode(AbstractFilesystemNode *realNode) +FSNode::FSNode(AbstractFSNode *realNode) : _realNode(realNode) { } -FilesystemNode::FilesystemNode(const Common::String &p) { +FSNode::FSNode(const Common::String &p) { FilesystemFactory *factory = g_system->getFilesystemFactory(); - AbstractFilesystemNode *tmp = 0; + AbstractFSNode *tmp = 0; if (p.empty() || p == ".") tmp = factory->makeCurrentDirectoryFileNode(); else tmp = factory->makeFileNodePath(p); - _realNode = Common::SharedPtr<AbstractFilesystemNode>(tmp); + _realNode = Common::SharedPtr<AbstractFSNode>(tmp); } -bool FilesystemNode::operator<(const FilesystemNode& node) const { +bool FSNode::operator<(const FSNode& node) const { if (isDirectory() != node.isDirectory()) return isDirectory(); return getDisplayName().compareToIgnoreCase(node.getDisplayName()) < 0; } -bool FilesystemNode::exists() const { +bool FSNode::exists() const { if (_realNode == 0) return false; return _realNode->exists(); } -FilesystemNode FilesystemNode::getChild(const Common::String &n) const { +FSNode FSNode::getChild(const Common::String &n) const { // If this node is invalid or not a directory, return an invalid node if (_realNode == 0 || !_realNode->isDirectory()) - return FilesystemNode(); + return FSNode(); - AbstractFilesystemNode *node = _realNode->getChild(n); - return FilesystemNode(node); + AbstractFSNode *node = _realNode->getChild(n); + return FSNode(node); } -bool FilesystemNode::getChildren(FSList &fslist, ListMode mode, bool hidden) const { +bool FSNode::getChildren(FSList &fslist, ListMode mode, bool hidden) const { if (!_realNode || !_realNode->isDirectory()) return false; @@ -81,61 +81,61 @@ bool FilesystemNode::getChildren(FSList &fslist, ListMode mode, bool hidden) con fslist.clear(); for (AbstractFSList::iterator i = tmp.begin(); i != tmp.end(); ++i) { - fslist.push_back(FilesystemNode(*i)); + fslist.push_back(FSNode(*i)); } return true; } -Common::String FilesystemNode::getDisplayName() const { +Common::String FSNode::getDisplayName() const { assert(_realNode); return _realNode->getDisplayName(); } -Common::String FilesystemNode::getName() const { +Common::String FSNode::getName() const { assert(_realNode); return _realNode->getName(); } -FilesystemNode FilesystemNode::getParent() const { +FSNode FSNode::getParent() const { if (_realNode == 0) return *this; - AbstractFilesystemNode *node = _realNode->getParent(); + AbstractFSNode *node = _realNode->getParent(); if (node == 0) { return *this; } else { - return FilesystemNode(node); + return FSNode(node); } } -Common::String FilesystemNode::getPath() const { +Common::String FSNode::getPath() const { assert(_realNode); return _realNode->getPath(); } -bool FilesystemNode::isDirectory() const { +bool FSNode::isDirectory() const { if (_realNode == 0) return false; return _realNode->isDirectory(); } -bool FilesystemNode::isReadable() const { +bool FSNode::isReadable() const { if (_realNode == 0) return false; return _realNode->isReadable(); } -bool FilesystemNode::isWritable() const { +bool FSNode::isWritable() const { if (_realNode == 0) return false; return _realNode->isWritable(); } -bool FilesystemNode::lookupFile(FSList &results, const Common::String &p, bool hidden, bool exhaustive, int depth) const { +bool FSNode::lookupFile(FSList &results, const Common::String &p, bool hidden, bool exhaustive, int depth) const { if (!isDirectory()) return false; @@ -146,7 +146,7 @@ bool FilesystemNode::lookupFile(FSList &results, const Common::String &p, bool h pattern.toUppercase(); // First match all files on this level - getChildren(children, FilesystemNode::kListAll, hidden); + getChildren(children, FSNode::kListAll, hidden); for (FSList::iterator entry = children.begin(); entry != children.end(); ++entry) { if (entry->isDirectory()) { if (depth != 0) @@ -173,27 +173,27 @@ bool FilesystemNode::lookupFile(FSList &results, const Common::String &p, bool h return !results.empty(); } -Common::SeekableReadStream *FilesystemNode::openForReading() const { +Common::SeekableReadStream *FSNode::openForReading() const { if (_realNode == 0) return 0; if (!_realNode->exists()) { - warning("FilesystemNode::openForReading: FilesystemNode does not exist"); + warning("FSNode::openForReading: FSNode does not exist"); return false; } else if (_realNode->isDirectory()) { - warning("FilesystemNode::openForReading: FilesystemNode is a directory"); + warning("FSNode::openForReading: FSNode is a directory"); return false; } return _realNode->openForReading(); } -Common::WriteStream *FilesystemNode::openForWriting() const { +Common::WriteStream *FSNode::openForWriting() const { if (_realNode == 0) return 0; if (_realNode->isDirectory()) { - warning("FilesystemNode::openForWriting: FilesystemNode is a directory"); + warning("FSNode::openForWriting: FSNode is a directory"); return 0; } diff --git a/common/fs.h b/common/fs.h index c5f7ca6b4c..e2db955c87 100644 --- a/common/fs.h +++ b/common/fs.h @@ -29,11 +29,11 @@ #include "common/ptr.h" #include "common/str.h" -class AbstractFilesystemNode; +class AbstractFSNode; namespace Common { -class FilesystemNode; +class FSNode; class SeekableReadStream; class WriteStream; @@ -42,21 +42,22 @@ class WriteStream; * This is subclass instead of just a typedef so that we can use forward * declarations of it in other places. */ -class FSList : public Common::Array<FilesystemNode> {}; +class FSList : public Common::Array<FSNode> {}; /** - * 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:, ...). + * FSNode, short for "File System Node", provides an abstraction for file + * paths, allowing for portable file system browsing. This means for example, + * that multiple or single roots have to be supported (compare Unix with a + * single root, Windows with multiple roots C:, D:, ...). * * To this end, we abstract away from paths; implementations can be based on * paths (and it's left to them whether / or \ or : is the path separator :-); * but it is also possible to use inodes or vrefs (MacOS 9) or anything else. */ -class FilesystemNode { +class FSNode { private: - Common::SharedPtr<AbstractFilesystemNode> _realNode; - FilesystemNode(AbstractFilesystemNode *realNode); + Common::SharedPtr<AbstractFSNode> _realNode; + FSNode(AbstractFSNode *realNode); public: /** @@ -69,14 +70,14 @@ public: }; /** - * Create a new pathless FilesystemNode. Since there's no path associated + * Create a new pathless FSNode. 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(); + FSNode(); /** - * Create a new FilesystemNode referring to the specified path. This is + * Create a new FSNode referring to the specified path. This is * the counterpart to the path() method. * * If path is empty or equals ".", then a node representing the "current @@ -84,15 +85,15 @@ public: * operating system doesn't support the concept), some other directory is * used (usually the root directory). */ - explicit FilesystemNode(const Common::String &path); + explicit FSNode(const Common::String &path); - virtual ~FilesystemNode() {} + virtual ~FSNode() {} /** * Compare the name of this node to the name of another. Directories * go before normal files. */ - bool operator<(const FilesystemNode& node) const; + bool operator<(const FSNode& node) const; /** * Indicates whether the object referred by this node exists in the filesystem or not. @@ -118,7 +119,7 @@ public: * @param name the name of a child of this directory * @return the node referring to the child with the given name */ - FilesystemNode getChild(const Common::String &name) const; + FSNode getChild(const Common::String &name) const; /** * Return a list of all child nodes of this directory node. If called on a node @@ -165,7 +166,7 @@ public: * 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; + FSNode getParent() const; /** * Indicates whether the node refers to a directory or not. diff --git a/common/md5.cpp b/common/md5.cpp index 4eeb3d9a39..107990481f 100644 --- a/common/md5.cpp +++ b/common/md5.cpp @@ -246,15 +246,15 @@ void md5_finish(md5_context *ctx, uint8 digest[16]) { PUT_UINT32(ctx->state[3], digest, 12); } -bool md5_file(const FilesystemNode &file, uint8 digest[16], uint32 length) { +bool md5_file(const FSNode &file, uint8 digest[16], uint32 length) { if (!file.exists()) { - warning("md5_file: using an inexistent FilesystemNode"); + warning("md5_file: using an inexistent FSNode"); return false; } else if (!file.isReadable()) { - warning("md5_file: using an unreadable FilesystemNode"); + warning("md5_file: using an unreadable FSNode"); return false; } else if (file.isDirectory()) { - warning("md5_file: using a directory FilesystemNode"); + warning("md5_file: using a directory FSNode"); return false; } @@ -316,7 +316,7 @@ bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length) { return true; } -bool md5_file_string(const FilesystemNode &file, char *md5str, uint32 length) { +bool md5_file_string(const FSNode &file, char *md5str, uint32 length) { uint8 digest[16]; if (!md5_file(file, digest, length)) return false; diff --git a/common/md5.h b/common/md5.h index a8642b1322..ffed7d7524 100644 --- a/common/md5.h +++ b/common/md5.h @@ -29,11 +29,11 @@ namespace Common { -class FilesystemNode; +class FSNode; class ReadStream; bool md5_file(const char *name, uint8 digest[16], uint32 length = 0); -bool md5_file(const FilesystemNode &file, uint8 digest[16], uint32 length = 0); +bool md5_file(const FSNode &file, uint8 digest[16], uint32 length = 0); bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length = 0); // The following two methods work similar to the above two, but @@ -41,7 +41,7 @@ bool md5_file(ReadStream &stream, uint8 digest[16], uint32 length = 0); // a human readable lowercase hexstring representing the digest. // The md5str parameter must point to a buffer of 32+1 chars. bool md5_file_string(const char *name, char *md5str, uint32 length = 0); -bool md5_file_string(const FilesystemNode &file, char *md5str, uint32 length = 0); +bool md5_file_string(const FSNode &file, char *md5str, uint32 length = 0); bool md5_file_string(ReadStream &stream, char *md5str, uint32 length = 0); diff --git a/common/str.cpp b/common/str.cpp index 6c48738533..303ed7bfac 100644 --- a/common/str.cpp +++ b/common/str.cpp @@ -339,7 +339,8 @@ bool String::matchString(const String &pat) const { } void String::deleteLastChar() { - deleteChar(_size - 1); + if (_size > 0) + deleteChar(_size - 1); } void String::deleteChar(uint32 p) { diff --git a/common/system.cpp b/common/system.cpp index d9bc027e91..0e29dded38 100644 --- a/common/system.cpp +++ b/common/system.cpp @@ -163,7 +163,7 @@ static Common::String getDefaultConfigFileName() { } Common::SeekableReadStream *OSystem::openConfigFileForReading() { - Common::FilesystemNode file(getDefaultConfigFileName()); + Common::FSNode file(getDefaultConfigFileName()); return file.openForReading(); } @@ -171,7 +171,7 @@ Common::WriteStream *OSystem::openConfigFileForWriting() { #ifdef __DC__ return 0; #else - Common::FilesystemNode file(getDefaultConfigFileName()); + Common::FSNode file(getDefaultConfigFileName()); return file.openForWriting(); #endif } diff --git a/common/unzip.cpp b/common/unzip.cpp index 24744203da..9049b000d7 100644 --- a/common/unzip.cpp +++ b/common/unzip.cpp @@ -1363,7 +1363,7 @@ class ZipArchiveMember : public ArchiveMember { unzFile _zipFile; public: - ZipArchiveMember(FilesystemNode &node) : _node(node) { + ZipArchiveMember(FSNode &node) : _node(node) { } String getName() const { @@ -1392,26 +1392,6 @@ bool ZipArchive::hasFile(const Common::String &name) { return (_zipFile && unzLocateFile(_zipFile, name.c_str(), 2) == UNZ_OK); } -int ZipArchive::getAllNames(Common::StringList &list) { - if (!_zipFile) - return 0; - - if (unzGoToFirstFile(_zipFile) != UNZ_OK) - return 0; - - char fileNameBuffer[UNZ_MAXFILENAMEINZIP + 1]; - int fileCount = 0; - - do { - unzGetCurrentFileInfo(_zipFile, 0, fileNameBuffer, UNZ_MAXFILENAMEINZIP + 1, 0, 0, 0, 0); - list.push_back(Common::String(fileNameBuffer)); - fileCount++; - } while (unzGoToNextFile(_zipFile) == UNZ_OK); - - return fileCount; -} - -/* int ZipArchive::listMembers(Common::ArchiveMemberList &list) { if (!_zipFile) return 0; @@ -1424,14 +1404,13 @@ int ZipArchive::listMembers(Common::ArchiveMemberList &list) { unzGetCurrentFileInfo(_zipFile, NULL, szCurrentFileName, sizeof(szCurrentFileName)-1, NULL, 0, NULL, 0); - - szCurrentFileName + list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(szCurrentFileName, this))); matches++; - err = unzGoToNextFile(file); + err = unzGoToNextFile(_zipFile); } - return 0; + + return matches; } -*/ Common::SeekableReadStream *ZipArchive::openFile(const Common::String &name) { if (!_zipFile) diff --git a/common/unzip.h b/common/unzip.h index e4eb754eee..e6c1863e51 100644 --- a/common/unzip.h +++ b/common/unzip.h @@ -44,7 +44,7 @@ public: bool isOpen() const; virtual bool hasFile(const String &name); - virtual int getAllNames(StringList &list); + virtual int listMembers(Common::ArchiveMemberList &list); virtual Common::SeekableReadStream *openFile(const Common::String &name); }; diff --git a/common/xmlparser.h b/common/xmlparser.h index ad9ad799f0..5f649f517f 100644 --- a/common/xmlparser.h +++ b/common/xmlparser.h @@ -201,7 +201,7 @@ public: return true; } - bool loadFile(const FilesystemNode &node) { + bool loadFile(const FSNode &node) { Common::File *f = new Common::File; if (!f->open(node)) { |