/* 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. * */ #include "common/debug.h" #include "common/fs.h" #include "common/stream.h" #include "zvision/file/search_manager.h" #include "zvision/file/zfs_archive.h" namespace ZVision { SearchManager::SearchManager(const Common::String &rootPath, int depth) { _root = rootPath; if (_root[_root.size() - 1] == '\\' || _root[_root.size() - 1] == '/') _root.deleteLastChar(); Common::FSNode fsNode(_root); listDirRecursive(_dirList, fsNode, depth); for (Common::List::iterator it = _dirList.begin(); it != _dirList.end();) { if ((*it).hasSuffix("\\") || (*it).hasSuffix("/")) (*it).deleteLastChar(); if (it->size() == _root.size()) it = _dirList.erase(it); else if (it->size() > _root.size()) { *it = Common::String(it->c_str() + _root.size() + 1); it++; } else it++; } } SearchManager::~SearchManager() { Common::List::iterator it = _archList.begin(); while (it != _archList.end()) { delete *it; it++; } _archList.clear(); } void SearchManager::addFile(const Common::String &name, Common::Archive *arch) { bool addArch = true; Common::List::iterator it = _archList.begin(); while (it != _archList.end()) { if (*it == arch) { addArch = false; break; } it++; } if (addArch) _archList.push_back(arch); Common::String lowerCaseName = name; lowerCaseName.toLowercase(); SearchManager::Node nod; nod.name = lowerCaseName; nod.arch = arch; SearchManager::MatchList::iterator fit = _files.find(lowerCaseName); if (fit == _files.end()) { _files[lowerCaseName] = nod; } else { Common::SeekableReadStream *stream = fit->_value.arch->createReadStreamForMember(fit->_value.name); if (stream) { if (stream->size() < 10) fit->_value.arch = arch; delete stream; } else { _files[lowerCaseName] = nod; } } } Common::File *SearchManager::openFile(const Common::String &name) { Common::String lowerCaseName = name; lowerCaseName.toLowercase(); SearchManager::MatchList::iterator fit = _files.find(lowerCaseName); if (fit != _files.end()) { Common::File *tmp = new Common::File(); tmp->open(fit->_value.name, *fit->_value.arch); return tmp; } return NULL; } bool SearchManager::openFile(Common::File &file, const Common::String &name) { Common::String lowerCaseName = name; lowerCaseName.toLowercase(); SearchManager::MatchList::iterator fit = _files.find(lowerCaseName); if (fit != _files.end()) return file.open(fit->_value.name, *fit->_value.arch); return false; } bool SearchManager::hasFile(const Common::String &name) { Common::String lowerCaseName = name; lowerCaseName.toLowercase(); SearchManager::MatchList::iterator fit = _files.find(lowerCaseName); if (fit != _files.end()) return true; return false; } bool SearchManager::loadZix(const Common::String &name) { Common::File file; if (!file.open(name)) return false; Common::String line; while (!file.eos()) { line = file.readLine(); if (line.matchString("----------*", true)) break; } if (file.eos()) error("Corrupt ZIX file: %s", name.c_str()); Common::Array archives; while (!file.eos()) { line = file.readLine(); line.trim(); if (line.matchString("----------*", true)) break; else if (line.matchString("DIR:*", true) || line.matchString("CD0:*", true) || line.matchString("CD1:*", true) || line.matchString("CD2:*", true)) { Common::Archive *arc; Common::String path(line.c_str() + 5); for (uint i = 0; i < path.size(); i++) if (path[i] == '\\') path.setChar('/', i); // Check if NEMESIS.ZIX/MEDIUM.ZIX refers to the znemesis folder, and // check the game root folder instead if (path.hasPrefix("znemesis/")) path = Common::String(path.c_str() + 9); // Check if INQUIS.ZIX refers to the ZGI folder, and check the game // root folder instead if (path.hasPrefix("zgi/")) path = Common::String(path.c_str() + 4); if (path.hasPrefix("zgi_e/")) path = Common::String(path.c_str() + 6); if (path.size() && path[0] == '.') path.deleteChar(0); if (path.size() && path[0] == '/') path.deleteChar(0); if (path.size() && path.hasSuffix("/")) path.deleteLastChar(); // Handle paths in case-sensitive file systems (bug #6775) if (path.size()) { for (Common::List::iterator it = _dirList.begin(); it != _dirList.end(); ++it) { if (path.equalsIgnoreCase(*it)) { path = *it; break; } } } if (path.matchString("*.zfs", true)) { arc = new ZfsArchive(path); } else { path = Common::String::format("%s/%s", _root.c_str(), path.c_str()); arc = new Common::FSDirectory(path); } archives.push_back(arc); } } if (file.eos()) error("Corrupt ZIX file: %s", name.c_str()); while (!file.eos()) { line = file.readLine(); line.trim(); uint dr = 0; char buf[32]; if (sscanf(line.c_str(), "%u %s", &dr, buf) == 2) { if (dr <= archives.size() && dr > 0) { addFile(Common::String(buf), archives[dr - 1]); } } } return true; } void SearchManager::addDir(const Common::String &name) { Common::String path; for (Common::List::iterator it = _dirList.begin(); it != _dirList.end(); ++it) if (name.equalsIgnoreCase(*it)) { path = *it; break; } if (path.size() == 0) return; path = Common::String::format("%s/%s", _root.c_str(), path.c_str()); Common::FSDirectory *dir = new Common::FSDirectory(path); Common::ArchiveMemberList list; dir->listMatchingMembers(list, "*.zfs"); for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { Common::String flname = (*iter)->getName(); ZfsArchive *zfs = new ZfsArchive(Common::String::format("%s/%s", name.c_str(), flname.c_str())); Common::ArchiveMemberList zfslist; zfs->listMembers(zfslist); for (Common::ArchiveMemberList::iterator ziter = zfslist.begin(); ziter != zfslist.end(); ++ziter) { Common::String zfsFileName = (*ziter)->getName(); addFile(zfsFileName, zfs); } } list.clear(); dir->listMembers(list); for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { Common::String flname = (*iter)->getName(); addFile(flname, dir); } } void SearchManager::listDirRecursive(Common::List &_list, const Common::FSNode &fsNode, int depth) { Common::FSList fsList; if (fsNode.getChildren(fsList)) { _list.push_back(fsNode.getPath()); if (depth > 1) for (Common::FSList::const_iterator it = fsList.begin(); it != fsList.end(); ++it) listDirRecursive(_list, *it, depth - 1); } } void SearchManager::listMembersWithExtension(MatchList &fileList, Common::String extension) { for (SearchManager::MatchList::iterator it = _files.begin(); it != _files.end(); ++it) { if (it->_key.hasSuffix(extension)) fileList[it->_key] = it->_value; } } } // End of namespace ZVision