From ea29e41b86dd6efad5b044220505ded798b2503e Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 31 Jul 2010 13:02:58 +0000 Subject: SWORD25: Reimplemented package manager for ScummVM using Common::Archive svn-id: r53194 --- engines/sword25/module.mk | 2 +- engines/sword25/package/packagemanager.cpp | 9 +- engines/sword25/package/packagemanager.h | 6 +- engines/sword25/package/physfspackagemanager.cpp | 497 ---------------------- engines/sword25/package/physfspackagemanager.h | 76 ---- engines/sword25/package/scummvmpackagemanager.cpp | 367 ++++++++++++++++ engines/sword25/package/scummvmpackagemanager.h | 105 +++++ 7 files changed, 482 insertions(+), 580 deletions(-) delete mode 100644 engines/sword25/package/physfspackagemanager.cpp delete mode 100644 engines/sword25/package/physfspackagemanager.h create mode 100644 engines/sword25/package/scummvmpackagemanager.cpp create mode 100644 engines/sword25/package/scummvmpackagemanager.h diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk index 5bd81dd81e..e1320252b1 100644 --- a/engines/sword25/module.mk +++ b/engines/sword25/module.mk @@ -68,7 +68,7 @@ MODULE_OBJS := \ math/walkregion.o \ package/packagemanager.o \ package/packagemanager_script.o \ - package/physfspackagemanager.o \ + package/scummvmpackagemanager.o \ script/luabindhelper.o \ script/luacallback.o \ script/luascript.o \ diff --git a/engines/sword25/package/packagemanager.cpp b/engines/sword25/package/packagemanager.cpp index 3d7e36a71e..2dc07cfae9 100644 --- a/engines/sword25/package/packagemanager.cpp +++ b/engines/sword25/package/packagemanager.cpp @@ -42,10 +42,13 @@ // ----------------------------------------------------------------------------- -BS_PackageManager::BS_PackageManager(BS_Kernel * pKernel) : BS_Service(pKernel) -{ +namespace Sword25 { + +BS_PackageManager::BS_PackageManager(BS_Kernel *pKernel) : BS_Service(pKernel) { if (!_RegisterScriptBindings()) BS_LOG_ERRORLN("Script bindings could not be registered."); else BS_LOGLN("Script bindings registered."); -} \ No newline at end of file +} + +} // End of namespace Sword25 diff --git a/engines/sword25/package/packagemanager.h b/engines/sword25/package/packagemanager.h index cb54f3240b..1d6c71074f 100644 --- a/engines/sword25/package/packagemanager.h +++ b/engines/sword25/package/packagemanager.h @@ -118,14 +118,14 @@ public: * @param FileName The filename of the package to mount * @param MountPosition The directory name under which the package should be mounted * @return Returns true if the mount was successful, otherwise false. - */ + */ virtual bool LoadPackage(const Common::String &FileName, const Common::String &MountPosition) = 0; /** * Mounts the contents of a directory in the specified directory in the virtual directory tree. * @param The name of the directory to mount * @param MountPosition The directory name under which the package should be mounted * @return Returns true if the mount was successful, otherwise false. - */ + */ virtual bool LoadDirectoryAsPackage(const Common::String &DirectoryName, const Common::String &MountPosition) = 0; /** * Downloads a file from the virtual directory tree @@ -190,7 +190,7 @@ public: * Determines whether a file exists * @param FileName The filename * @return Returns true if the file exists, otherwise false. - */ + */ virtual bool FileExists(const Common::String & FileName) = 0; private: diff --git a/engines/sword25/package/physfspackagemanager.cpp b/engines/sword25/package/physfspackagemanager.cpp deleted file mode 100644 index 52aab7d4d6..0000000000 --- a/engines/sword25/package/physfspackagemanager.cpp +++ /dev/null @@ -1,497 +0,0 @@ -/* 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$ - * - */ - -/* - * This code is based on Broken Sword 2.5 engine - * - * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer - * - * Licensed under GNU GPL v2 - * - */ - -// ----------------------------------------------------------------------------- -// Includes -// ----------------------------------------------------------------------------- - -#include "sword25/package/physfspackagemanager.h" - -#include "sword25/kernel/memlog_off.h" -#include -#include -#include "sword25/kernel/memlog_on.h" - -using namespace std; - -// ----------------------------------------------------------------------------- - -#define BS_LOG_PREFIX "PHYSFSPACKAGEMANAGER" - -// ----------------------------------------------------------------------------- -// Hilfsfunktionen -// ----------------------------------------------------------------------------- - -namespace -{ - const char * SafeGetLastError() - { - const char * ErrorMessage = PHYSFS_getLastError(); - return ErrorMessage ? ErrorMessage : "unknown"; - } - - // ------------------------------------------------------------------------- - - void LogPhysfsError(const char * FunctionName) - { - BS_LOG_ERRORLN("%s() failed. Reason: %s.", FunctionName, SafeGetLastError()); - } - - // ------------------------------------------------------------------------- - - void LogPhysfsError(const char * FunctionName, const char * FileName) - { - BS_LOG_ERRORLN("%s() on file \"%s\" failed. Reason: %s.", FunctionName, FileName, SafeGetLastError()); - } - - // ------------------------------------------------------------------------- - - const char PATH_SEPARATOR = '/'; - const char NAVIGATION_CHARACTER = '.'; - - // ------------------------------------------------------------------------- - - std::string RemoveRedundantPathSeparators(const std::string & Path) - { - std::string Result; - - // Über alle Zeichen des Eingabepfades iterieren. - std::string::const_iterator It = Path.begin(); - while (It != Path.end()) - { - if (*It == PATH_SEPARATOR) - { - // Verzeichnistrenner gefunden. - - // Folgen von Verzeichnistrennern überspringen. - while (It != Path.end() && *It == PATH_SEPARATOR) ++It; - - // Einzelnen Verzeichnistrenner ausgeben, nur am Ende des Pfades wird kein Verzeichnistrenner mehr ausgegeben. - if (It != Path.end()) Result.push_back(PATH_SEPARATOR); - } - else - { - // Normales Zeichen gefunden, wird unverändert ausgegeben. - Result.push_back(*It); - ++It; - } - } - - return Result; - } - - // --------------------------------------------------------------------- - - struct PathElement - { - public: - PathElement(std::string::const_iterator Begin, std::string::const_iterator End) : m_Begin(Begin), m_End(End) {} - - std::string::const_iterator GetBegin() const { return m_Begin; } - std::string::const_iterator GetEnd() const { return m_End; } - - private: - std::string::const_iterator m_Begin; - std::string::const_iterator m_End; - }; - - // ------------------------------------------------------------------------- - - std::string NormalizePath(const std::string & Path, const std::string & CurrentDirectory) - { - // Feststellen, ob der Pfad absolut (beginnt mit /) oder relativ ist und im relativen Fall dem Gesamtpfad das aktuelle Verzeichnis - // voranstellen. - std::string WholePath = (Path.size() >= 1 && Path[0] == PATH_SEPARATOR) ? "" : CurrentDirectory + PATH_SEPARATOR; - - // Alle gedoppelten und nachfolgende Verzeichnistrenner aus dem übergebenen Pfad entfernen und den Gesamtpfad zusammensetzen. - // CurrentDirectory wird nicht auf diese Weise gesäubert. Es wird vorrausgesetzt, dass CurrentDirectory keine überflüssigen - // Verzeichnistrenner beinhaltet. - WholePath += RemoveRedundantPathSeparators(Path); - - // Gesamtpfad parsen und in Einzelelemente aufteilen. Dabei werden Vorkommen von ".." und "." korrekt behandelt. - vector PathElements; - size_t SeparatorPos = 0; - while (SeparatorPos < WholePath.size()) - { - // Nächsten Verzeichnistrenner finden. - size_t NextSeparatorPos = WholePath.find(PATH_SEPARATOR, SeparatorPos + 1); - if (NextSeparatorPos == std::string::npos) NextSeparatorPos = WholePath.size(); - - // Anfang und Ende vom Pfadelement berechnen. - std::string::const_iterator ElementBegin = WholePath.begin() + SeparatorPos + 1; - std::string::const_iterator ElementEnd = WholePath.begin() + NextSeparatorPos; - - if (ElementEnd - ElementBegin == 2 && - ElementBegin[0] == NAVIGATION_CHARACTER && - ElementBegin[1] == NAVIGATION_CHARACTER) - { - // Element ist "..", daher wird das vorangegangene Pfadelement aus dem vector entfernt. - if (PathElements.size()) PathElements.pop_back(); - } - else if (ElementEnd - ElementBegin == 1 && - ElementBegin[0] == NAVIGATION_CHARACTER) - { - // Element ist ".", wir tun gar nichts. - } - else - { - // Normales Element in den vector einfügen. - PathElements.push_back(PathElement(WholePath.begin() + SeparatorPos + 1, WholePath.begin() + NextSeparatorPos)); - } - - SeparatorPos = NextSeparatorPos; - } - - if (PathElements.size()) - { - // Die einzelnen Pfadelemente werden durch Verzeichnistrenner getrennt aneinandergesetzt. - // Der so entstandene String wird als Ergebnis zurückgegeben. - ostringstream PathBuilder; - vector::const_iterator It = PathElements.begin(); - while (It != PathElements.end()) - { - PathBuilder << PATH_SEPARATOR << std::string(It->GetBegin(), It->GetEnd()); - ++It; - } - - return PathBuilder.str(); - } - else - { - // Nach dem Parsen sind keine Pfadelemente mehr übrig geblieben, daher wird des Root-Verzeichnis zurückgegeben. - return std::string(1, PATH_SEPARATOR); - } - } - - // ------------------------------------------------------------------------- - // RAII-Klasse für PHYSFS-Filehandles. - // ------------------------------------------------------------------------- - - class PhysfsHandleHolder - { - public: - PhysfsHandleHolder(PHYSFS_File * Handle) : m_Handle(Handle) {} - ~PhysfsHandleHolder() - { - if (m_Handle) - { - if (!PHYSFS_close(m_Handle)) LogPhysfsError("PHYSFS_close"); - } - } - - PHYSFS_File * Get() { return m_Handle; } - PHYSFS_File * Release() - { - PHYSFS_File * Result = m_Handle; - m_Handle = 0; - return Result; - } - - private: - PHYSFS_File * m_Handle; - }; - - // ------------------------------------------------------------------------- - // RAII-Klasse für PHYSFS-Listen. - // ------------------------------------------------------------------------- - - template - class PhysfsListHolder - { - public: - PhysfsListHolder(T List) : m_List(List) {}; - ~PhysfsListHolder() { if (m_List) PHYSFS_freeList(m_List); } - - T Get() { return m_List; } - - private: - T m_List; - }; - - // ------------------------------------------------------------------------- - - PHYSFS_File * OpenFileAndGetSize(const std::string & FileName, const std::string & CurrentDirectory, unsigned int & FileSize) - { - // Datei öffnen. - PhysfsHandleHolder Handle(PHYSFS_openRead(NormalizePath(FileName, CurrentDirectory).c_str())); - if (!Handle.Get()) - { - LogPhysfsError("PHYSFS_openRead", FileName.c_str()); - return 0; - } - - // Dateigröße bestimmen. - PHYSFS_sint64 LongFileSize = PHYSFS_fileLength(Handle.Get()); - if (LongFileSize == -1) - { - BS_LOG_ERRORLN("Unable to determine filelength on PhysicsFS file \"%s\".", FileName.c_str()); - return 0; - } - if (LongFileSize >= UINT_MAX) - { - BS_LOG_ERRORLN("File \"%s\" is too big.", FileName.c_str()); - return 0; - } - - // Rückgabewerte setzen. - FileSize = static_cast(LongFileSize); - return Handle.Release(); - } -} - -// ----------------------------------------------------------------------------- -// Konstruktion / Destruktion -// ----------------------------------------------------------------------------- - -BS_PhysfsPackageManager::BS_PhysfsPackageManager(BS_Kernel * KernelPtr) : - BS_PackageManager(KernelPtr), - m_CurrentDirectory(1, PATH_SEPARATOR) -{ - if (!PHYSFS_init(0)) LogPhysfsError("PHYSFS_init"); -} - -// ----------------------------------------------------------------------------- - -BS_PhysfsPackageManager::~BS_PhysfsPackageManager() -{ - if (!PHYSFS_deinit()) LogPhysfsError("PHYSFS_deinit"); -} - -// ----------------------------------------------------------------------------- - -BS_Service * BS_PhysfsPackageManager_CreateObject(BS_Kernel * KernelPtr) { return new BS_PhysfsPackageManager(KernelPtr); } - -// ----------------------------------------------------------------------------- - -bool BS_PhysfsPackageManager::LoadPackage(const std::string & FileName, const std::string & MountPosition) -{ - if (!PHYSFS_mount(FileName.c_str(), NormalizePath(MountPosition, m_CurrentDirectory).c_str(), 0)) - { - BS_LOG_ERRORLN("Unable to mount file \"%s\" to \"%s\". Reason: %s.", FileName.c_str(), MountPosition.c_str(), SafeGetLastError()); - return false; - } - else - { - BS_LOGLN("Package '%s' mounted as '%s'.", FileName.c_str(), MountPosition.c_str()); - return true; - } -} - -// ----------------------------------------------------------------------------- - -bool BS_PhysfsPackageManager::LoadDirectoryAsPackage(const std::string & DirectoryName, const std::string & MountPosition) -{ - if (!PHYSFS_mount(DirectoryName.c_str(), NormalizePath(MountPosition, m_CurrentDirectory).c_str(), 0)) - { - BS_LOG_ERRORLN("Unable to mount directory \"%s\" to \"%s\". Reason: %s.", DirectoryName.c_str(), MountPosition.c_str(), SafeGetLastError()); - return false; - } - else - { - BS_LOGLN("Directory '%s' mounted as '%s'.", DirectoryName.c_str(), MountPosition.c_str()); - return true; - } -} - -// ----------------------------------------------------------------------------- - -void * BS_PhysfsPackageManager::GetFile(const std::string & FileName, unsigned int * FileSizePtr) -{ - // Datei öffnen und deren Größe bestimmen. - unsigned int FileSize; - PhysfsHandleHolder Handle(OpenFileAndGetSize(FileName, m_CurrentDirectory, FileSize)); - if (!Handle.Get()) return 0; - - // Falls gewünscht, die Größe der Datei zurückgeben. - if (FileSizePtr) *FileSizePtr = FileSize; - - // Datei einlesen. - char * Buffer = new char[FileSize]; - if (PHYSFS_read(Handle.Get(), Buffer, 1, FileSize) <= 0) - { - LogPhysfsError("PHYSFS_read", FileName.c_str()); - delete [] Buffer; - return 0; - } - - return Buffer; -} - -// ----------------------------------------------------------------------------- - -std::string BS_PhysfsPackageManager::GetCurrentDirectory() -{ - return m_CurrentDirectory; -} - -// ----------------------------------------------------------------------------- - -bool BS_PhysfsPackageManager::ChangeDirectory(const std::string & Directory) -{ - // Pfad normalisieren. - std::string CleanedDirectory = NormalizePath(Directory, m_CurrentDirectory); - - // Interne Variable setzen, wenn das Verzeichnis tatsächlich existiert oder das Wurzelverzeichnis ist. - if (CleanedDirectory == std::string(1, PATH_SEPARATOR) || PHYSFS_isDirectory(CleanedDirectory.c_str())) - { - m_CurrentDirectory = CleanedDirectory; - return true; - } - // Fehler ausgeben, wenn das Verzeichnis nicht existiert. - else - { - BS_LOG_ERRORLN("Tried to change to non-existing directory \"%s\". Call is ignored", Directory.c_str()); - return false; - } -} - -// ----------------------------------------------------------------------------- - -std::string BS_PhysfsPackageManager::GetAbsolutePath(const std::string & FileName) -{ - return NormalizePath(FileName, m_CurrentDirectory); -} - -// ----------------------------------------------------------------------------- - -unsigned int BS_PhysfsPackageManager::GetFileSize(const std::string & FileName) -{ - // Datei öffnen und deren Größe bestimmen. - unsigned int FileSize; - PhysfsHandleHolder Handle(OpenFileAndGetSize(FileName, m_CurrentDirectory, FileSize)); - if (!Handle.Get()) return 0xffffffff; - - // Größe der Datei zurückgeben. - return FileSize; -} - -// ----------------------------------------------------------------------------- - -unsigned int BS_PhysfsPackageManager::GetFileType(const std::string & FileName) -{ - std::string NormalizedPath = NormalizePath(FileName, m_CurrentDirectory); - - if (PHYSFS_exists(NormalizedPath.c_str())) - { - return PHYSFS_isDirectory(NormalizedPath.c_str()) ? BS_PackageManager::FT_DIRECTORY : BS_PackageManager::FT_FILE; - } - else - { - BS_LOG_ERRORLN("Cannot determine type of non-existant file \"%s\".", NormalizedPath.c_str()); - return 0; - } -} - -// ----------------------------------------------------------------------------- - -bool BS_PhysfsPackageManager::FileExists(const std::string & FileName) -{ - std::string NormalizedPath = NormalizePath(FileName, m_CurrentDirectory); - return PHYSFS_exists(NormalizedPath.c_str()) != 0; -} - -// ----------------------------------------------------------------------------- -// Dateien suchen -// ----------------------------------------------------------------------------- - -class PhysfsFileSearch : public BS_PackageManager::FileSearch -{ -public: - // Path muss normalisiert sein. - PhysfsFileSearch(BS_PackageManager & PackageManager, const vector & FoundFiles) : - m_PackageManager(PackageManager), - m_FoundFiles(FoundFiles), - m_FoundFilesIt(m_FoundFiles.begin()) - { - } - - virtual std::string GetCurFileName() - { - return *m_FoundFilesIt; - } - - virtual unsigned int GetCurFileType() - { - return m_PackageManager.GetFileType(*m_FoundFilesIt); - } - - virtual unsigned int GetCurFileSize() - { - return m_PackageManager.GetFileSize(*m_FoundFilesIt); - } - - virtual bool NextFile() - { - ++m_FoundFilesIt; - return m_FoundFilesIt != m_FoundFiles.end(); - } - - BS_PackageManager & m_PackageManager; - vector m_FoundFiles; - vector::const_iterator m_FoundFilesIt; -}; - -// ----------------------------------------------------------------------------- - -BS_PackageManager::FileSearch * BS_PhysfsPackageManager::CreateSearch(const std::string& Filter, const std::string& Path, unsigned int TypeFilter) -{ - std::string NormalizedPath = NormalizePath(Path, m_CurrentDirectory); - - // Nach Wildcards gefilterte Ergebnisliste erstellen. - PhysfsListHolder FilesPtr(PHYSFSEXT_enumerateFilesWildcard(NormalizedPath.c_str(), Filter.c_str(), 1)); - - // Diese Liste muss nun wiederum nach den gewünschten Dateitype gefiltert werden. Das Ergebnis wird in einem vector gespeichert, der dann - // einem PhysfsFileSearch-Objekt übergeben wird. - vector FoundFiles; - for (char ** CurFilePtr = FilesPtr.Get(); *CurFilePtr != 0; ++CurFilePtr) - { - // Vollständigen Pfad zur gefunden Datei konstruieren. - std::string FullFilePath = NormalizedPath + std::string(1, PATH_SEPARATOR) + *CurFilePtr; - - // Feststellen, ob der Dateityp erwünscht ist und nur dann den Dateinamen dem Ergebnisvektor hinzufügen. - unsigned int FileType = GetFileType(FullFilePath); - if (FileType & TypeFilter) FoundFiles.push_back(FullFilePath); - } - - // Falls überhaupt eine Datei gefunden wurde, wird ein FileSearch-Objekt zurückgegeben mit dem über die gefundenen Dateien iteriert werden kann. - // Anderenfalls wird 0 zurückgegeben. - if (FoundFiles.size()) - { - return new PhysfsFileSearch(*this, FoundFiles); - } - else - { - return 0; - } -} diff --git a/engines/sword25/package/physfspackagemanager.h b/engines/sword25/package/physfspackagemanager.h deleted file mode 100644 index 121b99f44d..0000000000 --- a/engines/sword25/package/physfspackagemanager.h +++ /dev/null @@ -1,76 +0,0 @@ -/* 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$ - * - */ - -/* - * This code is based on Broken Sword 2.5 engine - * - * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer - * - * Licensed under GNU GPL v2 - * - */ - -#ifndef SWORD25_PHYSFS_PACKAGE_MANAGER_H -#define SWORD25_PHYSFS_PACKAGE_MANAGER_H - -// ----------------------------------------------------------------------------- -// Includes -// ----------------------------------------------------------------------------- - -#include "sword25/kernel/common.h" -#include "sword25/package/packagemanager.h" - -// ----------------------------------------------------------------------------- -// Forward declarations -// ----------------------------------------------------------------------------- - -class BS_Kernel; - -// ----------------------------------------------------------------------------- -// Klassendefinition -// ----------------------------------------------------------------------------- - -class BS_PhysfsPackageManager : public BS_PackageManager -{ -public: - BS_PhysfsPackageManager(BS_Kernel * KernelPtr); - virtual ~BS_PhysfsPackageManager(); - - virtual bool LoadPackage(const std::string & FileName, const std::string& MountPosition); - virtual bool LoadDirectoryAsPackage(const std::string & DirectoryName, const std::string& MountPosition); - virtual void* GetFile(const std::string& FileName, unsigned int * FileSizePtr = 0); - virtual std::string GetCurrentDirectory(); - virtual bool ChangeDirectory(const std::string & Directory); - virtual std::string GetAbsolutePath(const std::string & FileName); - virtual FileSearch* CreateSearch(const std::string & Filter, const std::string& Path, unsigned int TypeFilter = FT_DIRECTORY | FT_FILE); - virtual unsigned int GetFileSize(const std::string & FileName); - virtual unsigned int GetFileType(const std::string & FileName); - virtual bool FileExists(const std::string & FileName); - -private: - std::string m_CurrentDirectory; -}; - -#endif 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::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 + diff --git a/engines/sword25/package/scummvmpackagemanager.h b/engines/sword25/package/scummvmpackagemanager.h new file mode 100644 index 0000000000..d279b7e8ad --- /dev/null +++ b/engines/sword25/package/scummvmpackagemanager.h @@ -0,0 +1,105 @@ +/* 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 SWORD25_SCUMMVM_PACKAGE_MANAGER_H +#define SWORD25_SCUMMVM_PACKAGE_MANAGER_H + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include "common/archive.h" +#include "common/array.h" +#include "common/fs.h" +#include "common/str.h" +#include "sword25/kernel/common.h" +#include "sword25/package/packagemanager.h" + +namespace Sword25 { + +// ----------------------------------------------------------------------------- +// Forward declarations +// ----------------------------------------------------------------------------- + +class BS_Kernel; + +// ----------------------------------------------------------------------------- +// Class definitions +// ----------------------------------------------------------------------------- + +struct PathElement { +public: + PathElement() { } + PathElement(Common::String::const_iterator Begin, Common::String::const_iterator End) : m_Begin(Begin), m_End(End) {} + + Common::String::const_iterator GetBegin() const { return m_Begin; } + Common::String::const_iterator GetEnd() const { return m_End; } + +private: + Common::String::const_iterator m_Begin; + Common::String::const_iterator m_End; +}; + +typedef Common::Array PathElementArray; + +class BS_ScummVMPackageManager : public BS_PackageManager { +private: + class ArchiveEntry { + public: + Common::Archive *Archive; + PathElementArray MountPath; + + ArchiveEntry(Common::Archive *Archive_, const PathElementArray &MountPath_): + Archive(Archive_), MountPath(MountPath_) { + } + ~ArchiveEntry() { + delete Archive; + } + }; + + Common::String _currentDirectory; + Common::FSNode _rootFolder; + Common::List _archiveList; + + Common::FSNode GetFSNode(const Common::String &FileName); +public: + BS_ScummVMPackageManager(BS_Kernel * KernelPtr); + virtual ~BS_ScummVMPackageManager(); + + virtual bool LoadPackage(const Common::String &FileName, const Common::String &MountPosition); + virtual bool LoadDirectoryAsPackage(const Common::String &DirectoryName, const Common::String &MountPosition); + virtual void *GetFile(const Common::String &FileName, unsigned int *FileSizePtr = 0); + virtual Common::String GetCurrentDirectory(); + virtual bool ChangeDirectory(const Common::String &Directory); + virtual Common::String GetAbsolutePath(const Common::String &FileName); + virtual FileSearch *CreateSearch(const Common::String &Filter, const Common::String &Path, unsigned int TypeFilter = FT_DIRECTORY | FT_FILE); + virtual unsigned int GetFileSize(const Common::String &FileName); + virtual unsigned int GetFileType(const Common::String &FileName); + virtual bool FileExists(const Common::String &FileName); +}; + +} // End of namespace Sword25 + +#endif -- cgit v1.2.3