ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

archive.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/archive.h"
00024 #include "common/fs.h"
00025 #include "common/system.h"
00026 #include "common/textconsole.h"
00027 
00028 namespace Common {
00029 
00030 GenericArchiveMember::GenericArchiveMember(const String &name, const Archive *parent)
00031     : _parent(parent), _name(name) {
00032 }
00033 
00034 String GenericArchiveMember::getName() const {
00035     return _name;
00036 }
00037 
00038 SeekableReadStream *GenericArchiveMember::createReadStream() const {
00039     return _parent->createReadStreamForMember(_name);
00040 }
00041 
00042 
00043 int Archive::listMatchingMembers(ArchiveMemberList &list, const String &pattern) const {
00044     // Get all "names" (TODO: "files" ?)
00045     ArchiveMemberList allNames;
00046     listMembers(allNames);
00047 
00048     int matches = 0;
00049 
00050     ArchiveMemberList::const_iterator it = allNames.begin();
00051     for (; it != allNames.end(); ++it) {
00052         // TODO: We match case-insenstivie for now, our API does not define whether that's ok or not though...
00053         // For our use case case-insensitive is probably what we want to have though.
00054         if ((*it)->getName().matchString(pattern, true, true)) {
00055             list.push_back(*it);
00056             matches++;
00057         }
00058     }
00059 
00060     return matches;
00061 }
00062 
00063 
00064 
00065 SearchSet::ArchiveNodeList::iterator SearchSet::find(const String &name) {
00066     ArchiveNodeList::iterator it = _list.begin();
00067     for (; it != _list.end(); ++it) {
00068         if (it->_name == name)
00069             break;
00070     }
00071     return it;
00072 }
00073 
00074 SearchSet::ArchiveNodeList::const_iterator SearchSet::find(const String &name) const {
00075     ArchiveNodeList::const_iterator it = _list.begin();
00076     for (; it != _list.end(); ++it) {
00077         if (it->_name == name)
00078             break;
00079     }
00080     return it;
00081 }
00082 
00083 /*
00084     Keep the nodes sorted according to descending priorities.
00085     In case two or node nodes have the same priority, insertion
00086     order prevails.
00087 */
00088 void SearchSet::insert(const Node &node) {
00089     ArchiveNodeList::iterator it = _list.begin();
00090     for (; it != _list.end(); ++it) {
00091         if (it->_priority < node._priority)
00092             break;
00093     }
00094     _list.insert(it, node);
00095 }
00096 
00097 void SearchSet::add(const String &name, Archive *archive, int priority, bool autoFree) {
00098     if (find(name) == _list.end()) {
00099         Node node(priority, name, archive, autoFree);
00100         insert(node);
00101     } else {
00102         if (autoFree)
00103             delete archive;
00104         warning("SearchSet::add: archive '%s' already present", name.c_str());
00105     }
00106 
00107 }
00108 
00109 void SearchSet::addDirectory(const String &name, const String &directory, int priority, int depth, bool flat) {
00110     FSNode dir(directory);
00111     addDirectory(name, dir, priority, depth, flat);
00112 }
00113 
00114 void SearchSet::addDirectory(const String &name, const FSNode &dir, int priority, int depth, bool flat) {
00115     if (!dir.exists() || !dir.isDirectory())
00116         return;
00117 
00118     add(name, new FSDirectory(dir, depth, flat), priority);
00119 }
00120 
00121 void SearchSet::addSubDirectoriesMatching(const FSNode &directory, String origPattern, bool ignoreCase, int priority, int depth, bool flat) {
00122     FSList subDirs;
00123     if (!directory.getChildren(subDirs))
00124         return;
00125 
00126     String nextPattern, pattern;
00127     String::const_iterator sep = Common::find(origPattern.begin(), origPattern.end(), '/');
00128     if (sep != origPattern.end()) {
00129         pattern = String(origPattern.begin(), sep);
00130 
00131         ++sep;
00132         if (sep != origPattern.end())
00133             nextPattern = String(sep, origPattern.end());
00134     } else {
00135         pattern = origPattern;
00136     }
00137 
00138     // TODO: The code we have for displaying all matches, which vary only in case, might
00139     // be a bit overhead, but as long as we want to display all useful information to the
00140     // user we will need to keep track of all directory names added so far. We might
00141     // want to reconsider this though.
00142     typedef HashMap<String, bool, IgnoreCase_Hash, IgnoreCase_EqualTo> MatchList;
00143     MatchList multipleMatches;
00144     MatchList::iterator matchIter;
00145 
00146     for (FSList::const_iterator i = subDirs.begin(); i != subDirs.end(); ++i) {
00147         String name = i->getName();
00148 
00149         if (matchString(name.c_str(), pattern.c_str(), ignoreCase)) {
00150             matchIter = multipleMatches.find(name);
00151             if (matchIter == multipleMatches.end()) {
00152                 multipleMatches[name] = true;
00153             } else {
00154                 if (matchIter->_value) {
00155                     warning("Clash in case for match of pattern \"%s\" found in directory \"%s\": \"%s\"", pattern.c_str(), directory.getPath().c_str(), matchIter->_key.c_str());
00156                     matchIter->_value = false;
00157                 }
00158 
00159                 warning("Clash in case for match of pattern \"%s\" found in directory \"%s\": \"%s\"", pattern.c_str(), directory.getPath().c_str(), name.c_str());
00160             }
00161 
00162             if (nextPattern.empty())
00163                 addDirectory(name, *i, priority, depth, flat);
00164             else
00165                 addSubDirectoriesMatching(*i, nextPattern, ignoreCase, priority, depth, flat);
00166         }
00167     }
00168 }
00169 
00170 void SearchSet::remove(const String &name) {
00171     ArchiveNodeList::iterator it = find(name);
00172     if (it != _list.end()) {
00173         if (it->_autoFree)
00174             delete it->_arc;
00175         _list.erase(it);
00176     }
00177 }
00178 
00179 bool SearchSet::hasArchive(const String &name) const {
00180     return (find(name) != _list.end());
00181 }
00182 
00183 void SearchSet::clear() {
00184     for (ArchiveNodeList::iterator i = _list.begin(); i != _list.end(); ++i) {
00185         if (i->_autoFree)
00186             delete i->_arc;
00187     }
00188 
00189     _list.clear();
00190 }
00191 
00192 void SearchSet::setPriority(const String &name, int priority) {
00193     ArchiveNodeList::iterator it = find(name);
00194     if (it == _list.end()) {
00195         warning("SearchSet::setPriority: archive '%s' is not present", name.c_str());
00196         return;
00197     }
00198 
00199     if (priority == it->_priority)
00200         return;
00201 
00202     Node node(*it);
00203     _list.erase(it);
00204     node._priority = priority;
00205     insert(node);
00206 }
00207 
00208 bool SearchSet::hasFile(const String &name) const {
00209     if (name.empty())
00210         return false;
00211 
00212     ArchiveNodeList::const_iterator it = _list.begin();
00213     for (; it != _list.end(); ++it) {
00214         if (it->_arc->hasFile(name))
00215             return true;
00216     }
00217 
00218     return false;
00219 }
00220 
00221 int SearchSet::listMatchingMembers(ArchiveMemberList &list, const String &pattern) const {
00222     int matches = 0;
00223 
00224     ArchiveNodeList::const_iterator it = _list.begin();
00225     for (; it != _list.end(); ++it)
00226         matches += it->_arc->listMatchingMembers(list, pattern);
00227 
00228     return matches;
00229 }
00230 
00231 int SearchSet::listMembers(ArchiveMemberList &list) const {
00232     int matches = 0;
00233 
00234     ArchiveNodeList::const_iterator it = _list.begin();
00235     for (; it != _list.end(); ++it)
00236         matches += it->_arc->listMembers(list);
00237 
00238     return matches;
00239 }
00240 
00241 const ArchiveMemberPtr SearchSet::getMember(const String &name) const {
00242     if (name.empty())
00243         return ArchiveMemberPtr();
00244 
00245     ArchiveNodeList::const_iterator it = _list.begin();
00246     for (; it != _list.end(); ++it) {
00247         if (it->_arc->hasFile(name))
00248             return it->_arc->getMember(name);
00249     }
00250 
00251     return ArchiveMemberPtr();
00252 }
00253 
00254 SeekableReadStream *SearchSet::createReadStreamForMember(const String &name) const {
00255     if (name.empty())
00256         return nullptr;
00257 
00258     ArchiveNodeList::const_iterator it = _list.begin();
00259     for (; it != _list.end(); ++it) {
00260         SeekableReadStream *stream = it->_arc->createReadStreamForMember(name);
00261         if (stream)
00262             return stream;
00263     }
00264 
00265     return nullptr;
00266 }
00267 
00268 
00269 SearchManager::SearchManager() {
00270     clear(); // Force a reset
00271 }
00272 
00273 void SearchManager::clear() {
00274     SearchSet::clear();
00275 
00276     // Always keep system specific archives in the SearchManager.
00277     // But we give them a lower priority than the default priority (which is 0),
00278     // so that archives added by client code are searched first.
00279     if (g_system)
00280         g_system->addSysArchivesToSearchSet(*this, -1);
00281 
00282     // Add the current dir as a very last resort.
00283     // See also bug #2137680.
00284     addDirectory(".", ".", -2);
00285 }
00286 
00287 DECLARE_SINGLETON(SearchManager);
00288 
00289 } // namespace Common


Generated on Sat Jul 20 2019 05:00:47 for ResidualVM by doxygen 1.7.1
curved edge   curved edge