aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/package/scummvmpackagemanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword25/package/scummvmpackagemanager.cpp')
-rw-r--r--engines/sword25/package/scummvmpackagemanager.cpp367
1 files changed, 367 insertions, 0 deletions
diff --git a/engines/sword25/package/scummvmpackagemanager.cpp b/engines/sword25/package/scummvmpackagemanager.cpp
new file mode 100644
index 0000000000..fa2001dbed
--- /dev/null
+++ b/engines/sword25/package/scummvmpackagemanager.cpp
@@ -0,0 +1,367 @@
+/* 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$
+ *
+ */
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "common/archive.h"
+#include "common/config-manager.h"
+#include "common/str-array.h"
+#include "common/unzip.h"
+#include "sword25/package/scummvmpackagemanager.h"
+
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "SCUMMVMPACKAGEMANAGER"
+
+namespace Sword25 {
+
+const char PATH_SEPARATOR = '/';
+const char NAVIGATION_CHARACTER = '.';
+
+// -----------------------------------------------------------------------------
+// Support functions and classes
+// -----------------------------------------------------------------------------
+
+static Common::String RemoveRedundantPathSeparators(const Common::String &Path) {
+ Common::String Result;
+
+ // Iterate over all the chracters of the input path
+ Common::String::const_iterator It = Path.begin();
+ while (It != Path.end()) {
+ if (*It == PATH_SEPARATOR) {
+ // Directory separater found
+
+ // Skip over directory separator(s)
+ while (It != Path.end() && *It == PATH_SEPARATOR) ++It;
+
+ // Unless it's the end of the path, add the separator
+ if (It != Path.end()) Result += PATH_SEPARATOR;
+ } else {
+ // Normal characters are copied over unchanged
+ Result += *It;
+ ++It;
+ }
+ }
+
+ return Result;
+}
+
+// ---------------------------------------------------------------------
+
+static PathElementArray SeparatePath(const Common::String &Path, const Common::String &CurrentDirectory) {
+ // Determine whether the path is absolute (begins with /) or relative, in which case it's added
+ // to the current directory
+ Common::String wholePath = (Path.size() >= 1 && Path[0] == PATH_SEPARATOR) ? "" : CurrentDirectory + PATH_SEPARATOR;
+
+ // Add in the provided path
+ wholePath += RemoveRedundantPathSeparators(Path);
+
+ // Parse the path and divide into it's components. This ensures that occurences of ".." and "."
+ // are handled correctly.
+ PathElementArray pathElements;
+ size_t separatorPos = 0;
+ while (separatorPos < wholePath.size()) {
+ // Find next directory separator
+ const char *p = strchr(wholePath.c_str() + separatorPos + 1, PATH_SEPARATOR);
+ size_t nextseparatorPos = (p == NULL) ? wholePath.size() : p - wholePath.c_str();
+
+ // Calculate the beginning and end of the path element
+ Common::String::const_iterator elementBegin = wholePath.begin() + separatorPos + 1;
+ Common::String::const_iterator elementEnd = wholePath.begin() + nextseparatorPos;
+
+ if (elementEnd - elementBegin == 2 &&
+ elementBegin[0] == NAVIGATION_CHARACTER &&
+ elementBegin[1] == NAVIGATION_CHARACTER) {
+ // element is "..", therefore the previous path element should be removed
+ if (pathElements.size()) pathElements.pop_back();
+ } else if (elementEnd - elementBegin == 1 &&
+ elementBegin[0] == NAVIGATION_CHARACTER) {
+ // element is ".", so we do nothing
+ } else {
+ // Normal elements get added to the list
+ pathElements.push_back(PathElement(wholePath.begin() + separatorPos + 1, wholePath.begin() + nextseparatorPos));
+ }
+
+ separatorPos = nextseparatorPos;
+ }
+
+ return pathElements;
+}
+
+static Common::String NormalizePath(const Common::String &Path, const Common::String &CurrentDirectory) {
+ // Get the path elements for the file
+ PathElementArray pathElements = SeparatePath(Path, CurrentDirectory);
+
+ if (pathElements.size()) {
+ // The individual path elements are fitted together, separated by a directory
+ // separator. The resulting string is returned as a result
+ Common::String Result;
+
+ PathElementArray::const_iterator It = pathElements.begin();
+ while (It != pathElements.end()) {
+ Result += PATH_SEPARATOR;
+ Result += Common::String(It->GetBegin(), It->GetEnd());
+ ++It;
+ }
+
+ return Result;
+ } else {
+ // The path list has no elements, therefore the root directory is returned
+ return Common::String(PATH_SEPARATOR);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Constructor / Destructor
+// -----------------------------------------------------------------------------
+
+BS_ScummVMPackageManager::BS_ScummVMPackageManager(BS_Kernel *KernelPtr) :
+ BS_PackageManager(KernelPtr),
+ _currentDirectory(PATH_SEPARATOR),
+ _rootFolder(ConfMan.get("path")) {
+}
+
+// -----------------------------------------------------------------------------
+
+BS_ScummVMPackageManager::~BS_ScummVMPackageManager() {
+}
+
+// -----------------------------------------------------------------------------
+
+BS_Service *BS_ScummVMPackageManager_CreateObject(BS_Kernel *KernelPtr) {
+ return new BS_ScummVMPackageManager(KernelPtr);
+}
+
+// -----------------------------------------------------------------------------
+
+/**
+ * Scans through the archive list for a specified file
+ */
+Common::FSNode BS_ScummVMPackageManager::GetFSNode(const Common::String &FileName) {
+ // Get the path elements for the file
+ PathElementArray pathElements = SeparatePath(FileName, _currentDirectory);
+
+ // Loop through checking each archive
+ Common::List<ArchiveEntry>::iterator i;
+ for (i = _archiveList.begin(); i != _archiveList.end(); ++i) {
+ if (i->MountPath.size() > pathElements.size())
+ // The mount path has more subfolder depth than the search entry, so skip it
+ continue;
+
+ // Check the path against that of the archive
+ PathElementArray::iterator iPath = pathElements.begin();
+ PathElementArray::iterator iEntry = i->MountPath.begin();
+
+ for (; iEntry != i->MountPath.end(); ++iEntry, ++iPath) {
+ if (Common::String(iPath->GetBegin(), iPath->GetEnd()) ==
+ Common::String(iEntry->GetBegin(), iEntry->GetEnd()))
+ break;
+ }
+
+ if (iEntry == i->MountPath.end()) {
+ // Look into the archive for the desired file
+// Common::Archive *archiveFolder = i->Archive;
+
+ // TODO: Loop through any folders in the archive
+ for (; iPath != pathElements.end(); ++iPath) {
+
+ }
+
+ // Return the found node
+ return Common::FSNode();
+ }
+ }
+
+ return Common::FSNode();
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_ScummVMPackageManager::LoadPackage(const Common::String &FileName, const Common::String &MountPosition) {
+ // Get the path elements for the file
+ PathElementArray pathElements = SeparatePath(MountPosition, _currentDirectory);
+
+ Common::Archive *zipFile = Common::makeZipArchive(FileName);
+ if (zipFile == NULL) {
+ BS_LOG_ERRORLN("Unable to mount file \"%s\" to \"%s\"", FileName.c_str(), MountPosition.c_str());
+ return false;
+ } else {
+ BS_LOGLN("Package '%s' mounted as '%s'.", FileName.c_str(), MountPosition.c_str());
+ _archiveList.push_back(ArchiveEntry(zipFile, pathElements));
+ return true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_ScummVMPackageManager::LoadDirectoryAsPackage(const Common::String &DirectoryName, const Common::String &MountPosition) {
+ // Get the path elements for the file
+ PathElementArray pathElements = SeparatePath(MountPosition, _currentDirectory);
+
+ Common::FSNode directory(DirectoryName);
+ Common::Archive *folderArchive = new Common::FSDirectory(directory);
+ if (!directory.exists() || (folderArchive == NULL)) {
+ BS_LOG_ERRORLN("Unable to mount directory \"%s\" to \"%s\".", DirectoryName.c_str(), MountPosition.c_str());
+ return false;
+ } else {
+ BS_LOGLN("Directory '%s' mounted as '%s'.", DirectoryName.c_str(), MountPosition.c_str());
+ _archiveList.push_front(ArchiveEntry(folderArchive, pathElements));
+ return true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void *BS_ScummVMPackageManager::GetFile(const Common::String &FileName, unsigned int *FileSizePtr) {
+ Common::File f;
+ Common::FSNode fileNode = GetFSNode(FileName);
+ if (!fileNode.exists()) return 0;
+ if (!f.open(fileNode)) return 0;
+
+ // If the filesize is desired, then output the size
+ if (FileSizePtr) *FileSizePtr = f.size();
+
+ // Read the file
+ byte *buffer = new byte[f.size()];
+ if (!f.read(buffer, f.size())) return 0;
+
+ f.close();
+ return buffer;
+}
+
+// -----------------------------------------------------------------------------
+
+Common::String BS_ScummVMPackageManager::GetCurrentDirectory() {
+ return _currentDirectory;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_ScummVMPackageManager::ChangeDirectory(const Common::String &Directory) {
+ // Get the path elements for the file
+ _currentDirectory = NormalizePath(Directory, _currentDirectory);
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+Common::String BS_ScummVMPackageManager::GetAbsolutePath(const Common::String &FileName) {
+ return NormalizePath(FileName, _currentDirectory);
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_ScummVMPackageManager::GetFileSize(const Common::String &FileName) {
+ Common::File f;
+ Common::FSNode fileNode = GetFSNode(FileName);
+ if (!fileNode.exists()) return 0;
+ if (!f.open(fileNode)) return 0;
+
+ uint32 fileSize = f.size();
+ f.close();
+ return fileSize;
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_ScummVMPackageManager::GetFileType(const Common::String &FileName) {
+ Common::File f;
+ Common::FSNode fileNode = GetFSNode(FileName);
+ if (!fileNode.exists()) return 0;
+
+ return fileNode.isDirectory() ? BS_PackageManager::FT_DIRECTORY : BS_PackageManager::FT_FILE;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_ScummVMPackageManager::FileExists(const Common::String &FileName) {
+ Common::FSNode fileNode = GetFSNode(FileName);
+ return fileNode.exists();
+}
+
+// -----------------------------------------------------------------------------
+// File find
+// -----------------------------------------------------------------------------
+
+class ArchiveFileSearch : public BS_PackageManager::FileSearch {
+public:
+ // Path must be normalised
+ ArchiveFileSearch(BS_PackageManager &PackageManager, const Common::StringArray &FoundFiles) :
+ _packageManager(PackageManager),
+ _foundFiles(FoundFiles),
+ _foundFilesIt(_foundFiles.begin()) {
+ }
+
+ virtual Common::String GetCurFileName() {
+ return *_foundFilesIt;
+ }
+
+ virtual unsigned int GetCurFileType() {
+ return _packageManager.GetFileType(*_foundFilesIt);
+ }
+
+ virtual unsigned int GetCurFileSize() {
+ return _packageManager.GetFileSize(*_foundFilesIt);
+ }
+
+ virtual bool NextFile() {
+ ++_foundFilesIt;
+ return _foundFilesIt != _foundFiles.end();
+ }
+
+ BS_PackageManager & _packageManager;
+ Common::StringArray _foundFiles;
+ Common::StringArray::const_iterator _foundFilesIt;
+};
+
+// -----------------------------------------------------------------------------
+
+BS_PackageManager::FileSearch *BS_ScummVMPackageManager::CreateSearch(
+ const Common::String &Filter, const Common::String &Path, unsigned int TypeFilter) {
+ Common::String NormalizedPath = NormalizePath(Path, _currentDirectory);
+
+ Common::FSNode folderNode = GetFSNode(Path);
+ if (!folderNode.exists() || !folderNode.isDirectory()) return NULL;
+
+ Common::Archive *folder = new Common::FSDirectory(folderNode);
+ Common::ArchiveMemberList memberList;
+
+ if (folder->listMatchingMembers(memberList, Filter) == 0)
+ return NULL;
+
+ // Create a list of the matching names
+ Common::StringArray nameList;
+ for (Common::ArchiveMemberList::iterator i = memberList.begin(); i != memberList.end(); ++i) {
+ nameList.push_back((*i)->getName());
+ }
+
+ // Return a ArchiveFileSearch object that encapsulates the name list
+ return new ArchiveFileSearch(*this, nameList);
+}
+
+} // End of namespace Sword25
+