diff options
author | Eugene Sandulenko | 2010-07-29 19:53:02 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2010-10-12 21:38:20 +0000 |
commit | a683a420a9e43705c972b5e74d55e319729e1a81 (patch) | |
tree | bde6e4abd417bdfaec120aa951da9a19be36b654 /engines/sword25/package | |
parent | 7723d91c957d07205c51be32498d45cd0a78568f (diff) | |
download | scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.tar.gz scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.tar.bz2 scummvm-rg350-a683a420a9e43705c972b5e74d55e319729e1a81.zip |
SWORD25: Importing original sources
svn-id: r53171
Diffstat (limited to 'engines/sword25/package')
-rwxr-xr-x | engines/sword25/package/packagemanager.cpp | 36 | ||||
-rwxr-xr-x | engines/sword25/package/packagemanager.h | 188 | ||||
-rwxr-xr-x | engines/sword25/package/packagemanager_script.cpp | 247 | ||||
-rwxr-xr-x | engines/sword25/package/physfspackagemanager.cpp | 487 | ||||
-rwxr-xr-x | engines/sword25/package/physfspackagemanager.h | 61 |
5 files changed, 1019 insertions, 0 deletions
diff --git a/engines/sword25/package/packagemanager.cpp b/engines/sword25/package/packagemanager.cpp new file mode 100755 index 0000000000..ecee060d56 --- /dev/null +++ b/engines/sword25/package/packagemanager.cpp @@ -0,0 +1,36 @@ +// ----------------------------------------------------------------------------- +// This file is part of Broken Sword 2.5 +// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer +// +// Broken Sword 2.5 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. +// +// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// ----------------------------------------------------------------------------- + +#define BS_LOG_PREFIX "PACKAGEMANAGER" + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include "packagemanager.h" + +// ----------------------------------------------------------------------------- + +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 diff --git a/engines/sword25/package/packagemanager.h b/engines/sword25/package/packagemanager.h new file mode 100755 index 0000000000..67c97505c7 --- /dev/null +++ b/engines/sword25/package/packagemanager.h @@ -0,0 +1,188 @@ +// ----------------------------------------------------------------------------- +// This file is part of Broken Sword 2.5 +// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer +// +// Broken Sword 2.5 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. +// +// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// ----------------------------------------------------------------------------- + +/* + BS_PackageManager + ------------- + Dies ist das Package Manager Interface, dass alle Methoden enthält, die ein Package Manager + implementieren muss. + Beim Package Manager ist folgendes zu beachten: + 1. es wird ein komplett neuer (virtueller) Verzeichnisbaum erstellt, + in den Packages und Verzeichnisse gemounted werden können. + 2. zum Trennen von Elementen eines Verzeichnisspfades wird '/' statt '\' verwendet. + 3. LoadDirectoryAsPackage sollte nur zum Testen benutzt werden. Im Final Release sollen sich + alle Dateien in echten Packages befinden. + + Autor: Malte Thiesen, $author$ +*/ + +#ifndef BS_PACKAGE_MANAGER_H +#define BS_PACKAGE_MANAGER_H + +// Includes +#include "kernel/common.h" +#include "kernel/kernel.h" +#include "kernel/service.h" + +// Klassendefinition +/** + @brief Das Package Manager Interface + + Beim Package Manager ist folgendes zu beachten:<br> + 1. es wird ein komplett neuer (virtueller) Verzeichnisbaum erstellt, + in den Packages und Verzeichnisse gemounted werden können.<br> + 2. zum Trennen von Elementen eines Verzeichnisspfades wird '/' statt '\' verwendet.<br> + 3. LoadDirectoryAsPackage sollte nur zum Testen benutzt werden. Im Final Release sollen sich + alle Dateien in echten Packages befinden. +*/ +class BS_PackageManager : public BS_Service +{ +public: + BS_PackageManager(BS_Kernel* pKernel); + virtual ~BS_PackageManager() {}; + + enum FILE_TYPES + { + FT_DIRECTORY = (1<<0), + FT_FILE = (1<<1) + }; + + /** + @brief Mit Instanzen dieses Objektes wird nach Dateien gesucht. + + Objekte diesen Types wird mit BS_PackageManager::CreateSearch erzeugt. + */ + class FileSearch + { + public: + virtual ~FileSearch(){}; + + /** + @brief Gibt den Dateinamen der aktuellen Datei zurück. + @return Gibt den Dateinamen der aktuellen Datei zurück. + */ + virtual std::string GetCurFileName() = 0; + /** + @brief Gibt den Typ der aktuellen Datei zurück. + @return Gibt den Typ der aktuellen Datei zurück.<br> + Dieses ist entweder BS_PackageManager::FT_FILE oder BS_PackageManager::FT_DIRECTORY. + */ + virtual unsigned int GetCurFileType() = 0; + /** + @brief Gibt die Größe der aktuellen Datei zurück. + @return Gibt die Größe der aktuellen Datei zurück.<br> + Bei Verzeichnissen ist dieser Wert immer 0. + */ + virtual unsigned int GetCurFileSize() = 0; + // Sucht die nächste Datei + // Gibt false zurück, falls keine weitere Datei gefunden wurde + /** + @brief Sucht die nächste Datei. + @return Gibt false zurück, falls keine weitere Datei die Suchkriterien erfüllte. + */ + virtual bool NextFile() = 0; + }; + + /** + @brief Mounted den Inhalt eines Packages in das angegebene Verzeichnis im virtuellen Verzeichnisbaum. + @param FileName der Dateiname des zu mountenden Packages + @param MountPosition der Verzeichnisname, unter dem das Package gemounted werden soll + @return Gibt true zurück falls das mounten erfolgreich war, andernfalls false. + */ + virtual bool LoadPackage(const std::string& FileName, const std::string& MountPosition) = 0; + /** + @brief Mounted den Inhalt eines Verzeichnisses in das angegebene Verzeichnis im virtuellen Verzeichnisbaum. + @param DirectoryName der Name des zu mountenden Verzeichnisses + @param MountPosition der Verzeichnisname, unter dem das Verzeichnis gemounted werden soll + @return Gibt true zurück falls das mounten erfolgreich war, andernfalls false. + */ + virtual bool LoadDirectoryAsPackage(const std::string& DirectoryName, const std::string& MountPosition) = 0; + /** + @brief Lädt eine Datei aus dem virtuellen Verzeichnisbaum. + @param FileName der Dateiname der zu ladenden Datei + @param pFileSize Pointer auf die Variable, die die Größe der geladenen Datei enthalten soll<br> + Der Standardwert ist NULL. + @return Gibt einen Pointer auf die Dateidaten zürück, oder NULL, wenn die Datei nicht geladen werden konnte. + @remark Es darf nicht vergessen werden, die Dateidaten nach Benutzung mit BE_DELETE_A freizugeben. + */ + virtual void* GetFile(const std::string& FileName, unsigned int* pFileSize = NULL) = 0; + /** + @brief Gibt den Pfad zum aktuellen Verzeichnis zurück. + @return Gibt einen String zurück, der den Pfad zum aktuellen Verzeichnis enthält.<br> + Falls der Pfad nicht bestimmt werden konnte wird ein leerer String zurückgegeben. + @remark Zum Trennen von Pfadelementen wird "/" und nicht "\" verwendet. + */ + virtual std::string GetCurrentDirectory() = 0; + /** + @brief Wechselt das aktuelle Verzeichnis. + @param Directory ein String der das Verzeichnis bezeichnet, in dass gewechselt werden soll.<br> + Die Pfadangabe darf relativ sein. + @return Gibt true zurück, falls der Vorgang erfolgreich war, ansonsten false. + @remark Zum Trennen von Pfadelementen wird "/" und nicht "\" verwendet. + */ + virtual bool ChangeDirectory(const std::string& Directory) = 0; + /** + @brief Gibt den absoluten Pfad zu einer Datei im virtuellen Verzeichnisbaum zurück. + @param FileName der Dateiname der Datei, deren absoluter Pfad bestimmt werden soll.<br> + Diese Parameter kann sowohl relative als auch absolute Pfadangaben beinhalten. + @return Gibt einen String zurück, der den absoluten Pfad zur übergebenen Datei enthält.<br> + Falls der absolute Pfad nicht bestimmt werden konnte, wird ein leerer String zurückgegeben. + @remark Zum Trennen von Pfadelementen wird "/" und nicht "\" verwendet. + */ + virtual std::string GetAbsolutePath(const std::string& FileName) = 0; + /** + @brief Erstellt ein BS_PackageManager::FileSearch Objekt mit dem Nach Dateien gesucht werden kann. + @param Filter gibt den Suchstring an. Dieser darf die Wildcards '*' und '?' enthalten. + @param Path gibt das Verzeichnis an, welches durchsucht werden soll. + @param TypeFilter ist eine Kombination der Flags BS_PackageManager::FT_DIRECTORY und BS_PackageManager::FT_FILE.<br> + Diese Flags geben an, ob nach Dateien oder Verzeichnissen oder beiden gesucht werden soll.<br> + Der Standardwert ist BS_PackageManager::FT_DIRECTORY | BS_PackageManager::FT_FILE. + @return Gibt einen Pointer auf ein BS_PackageManager::FileSearch Objekt zurück, oder NULL wenn keine Datei gefunden wurde. + @remark Nicht vergessen, das Objekt nach Benutzung mit delete freizugeben. + */ + virtual FileSearch* CreateSearch(const std::string& Filter, const std::string& Path, unsigned int TypeFilter = FT_DIRECTORY | FT_FILE) = 0; + + /** + * @brief Gibt die Dateigröße zurück. + * @param FileName die Datei. + * @return die Dateigröße. Im Falle eines Fehlers wird 0xffffffff zurückgegeben. + * @remarks Bei komprimierten Containern wird die unkomprimierte Größe zurückgegeben. + **/ + virtual unsigned int GetFileSize(const std::string& FileName) = 0; + + /** + @brief Gibt den Typ einer Datei zurück. + @param FileName der Dateiname + @return Gibt den Dateityp zurück (BS_PackageManager::FT_DIRECTORY oder BS_PackageManager::FT_FILE).<br> + Falls die Datei nicht gefunden wurde wird 0 zurückgegeben. + */ + virtual unsigned int GetFileType(const std::string & FileName) = 0; + + /** + @brief Bestimmt, ob eine Datei existiert. + @param FileName der Dateiname + @return Gibt true zurück, wenn die Datei existiert, ansonsten false. + */ + virtual bool FileExists(const std::string & FileName) = 0; + +private: + bool _RegisterScriptBindings(); +}; + +#endif diff --git a/engines/sword25/package/packagemanager_script.cpp b/engines/sword25/package/packagemanager_script.cpp new file mode 100755 index 0000000000..01b6692a4c --- /dev/null +++ b/engines/sword25/package/packagemanager_script.cpp @@ -0,0 +1,247 @@ +// ----------------------------------------------------------------------------- +// This file is part of Broken Sword 2.5 +// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer +// +// Broken Sword 2.5 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. +// +// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include "kernel/common.h" +#include "kernel/kernel.h" +#include "script/script.h" +#include "script/luabindhelper.h" + +#include "packagemanager.h" + +// ----------------------------------------------------------------------------- + +static BS_PackageManager * GetPM() +{ + BS_Kernel * pKernel = BS_Kernel::GetInstance(); + BS_ASSERT(pKernel); + BS_PackageManager * pPM = static_cast<BS_PackageManager *>(pKernel->GetService("package")); + BS_ASSERT(pPM); + return pPM; +} + +// ----------------------------------------------------------------------------- + +static int LoadPackage(lua_State * L) +{ + BS_PackageManager * pPM = GetPM(); + + lua_pushbooleancpp(L, pPM->LoadPackage(luaL_checkstring(L, 1), luaL_checkstring(L, 2))); + + return 1; +} + +// ----------------------------------------------------------------------------- + +static int LoadDirectoryAsPackage(lua_State * L) +{ + BS_PackageManager * pPM = GetPM(); + + lua_pushbooleancpp(L, pPM->LoadDirectoryAsPackage(luaL_checkstring(L, 1), luaL_checkstring(L, 2))); + + return 1; +} + +// ----------------------------------------------------------------------------- + +static int GetCurrentDirectory(lua_State * L) +{ + BS_PackageManager * pPM = GetPM(); + + lua_pushstring(L, pPM->GetCurrentDirectory().c_str()); + + return 1; +} + +// ----------------------------------------------------------------------------- + +static int ChangeDirectory(lua_State * L) +{ + BS_PackageManager * pPM = GetPM(); + + lua_pushbooleancpp(L, pPM->ChangeDirectory(luaL_checkstring(L, 1))); + + return 1; +} + +// ----------------------------------------------------------------------------- + +static int GetAbsolutePath(lua_State * L) +{ + BS_PackageManager * pPM = GetPM(); + + lua_pushstring(L, pPM->GetAbsolutePath(luaL_checkstring(L, 1)).c_str()); + + return 1; +} + +// ----------------------------------------------------------------------------- + +static int GetFileSize(lua_State * L) +{ + BS_PackageManager * pPM = GetPM(); + + lua_pushnumber(L, pPM->GetFileSize(luaL_checkstring(L, 1))); + + return 1; +} + +// ----------------------------------------------------------------------------- + +static int GetFileType(lua_State * L) +{ + BS_PackageManager * pPM = GetPM(); + + lua_pushnumber(L, pPM->GetFileType(luaL_checkstring(L, 1))); + + return 1; +} + +// ----------------------------------------------------------------------------- + +static void SplitSearchPath(const std::string & Path, std::string & Directory, std::string & Filter) +{ + std::string::size_type LastSlash = Path.rfind("/"); + if (LastSlash == std::string::npos) + { + Directory = ""; + Filter = Path; + } + else + { + Directory = Path.substr(0, LastSlash); + Filter = Path.substr(LastSlash + 1); + } +} + +// ----------------------------------------------------------------------------- + +static void DoSearch(lua_State * L, const std::string & Path, unsigned int Type) +{ + BS_PackageManager * pPM = GetPM(); + + // Der Packagemanager-Service muss den Suchstring und den Pfad getrennt übergeben bekommen. + // Um die Benutzbarkeit zu verbessern sollen Skriptprogrammierer dieses als ein Pfad übergeben können. + // Daher muss der übergebene Pfad am letzten Slash aufgesplittet werden. + std::string Directory; + std::string Filter; + SplitSearchPath(Path, Directory, Filter); + + // Ergebnistable auf dem Lua-Stack erstellen + lua_newtable(L); + + // Suche durchführen und die Namen aller gefundenen Dateien in die Ergebnistabelle einfügen. + // Als Indizes werden fortlaufende Nummern verwandt. + unsigned int ResultNr = 1; + BS_PackageManager::FileSearch * pFS = pPM->CreateSearch(Filter, Directory, Type); + if (pFS) + { + do + { + lua_pushnumber(L, ResultNr); + lua_pushstring(L, pFS->GetCurFileName().c_str()); + lua_settable(L, -3); + ResultNr++; + } while(pFS->NextFile()); + } + + delete(pFS); +} + +// ----------------------------------------------------------------------------- + +static int FindFiles(lua_State * L) +{ + DoSearch(L, luaL_checkstring(L, 1), BS_PackageManager::FT_FILE); + return 1; +} + +// ----------------------------------------------------------------------------- + +static int FindDirectories(lua_State * L) +{ + DoSearch(L, luaL_checkstring(L, 1), BS_PackageManager::FT_DIRECTORY); + return 1; +} + +// ----------------------------------------------------------------------------- + +static int GetFileAsString(lua_State * L) +{ + BS_PackageManager * pPM = GetPM(); + + unsigned int FileSize; + void * FileData = pPM->GetFile(luaL_checkstring(L, 1), &FileSize); + if (FileData) + { + lua_pushlstring(L, static_cast<char *>(FileData), FileSize); + delete FileData; + + return 1; + } + else + return 0; +} + +// ----------------------------------------------------------------------------- + +static int FileExists(lua_State * L) +{ + lua_pushbooleancpp(L, GetPM()->FileExists(luaL_checkstring(L, 1))); + return 1; +} + +// ----------------------------------------------------------------------------- + +static const char * PACKAGE_LIBRARY_NAME = "Package"; + +static const luaL_reg PACKAGE_FUNCTIONS[] = +{ + "LoadPackage", LoadPackage, + "LoadDirectoryAsPackage", LoadDirectoryAsPackage, + "GetCurrentDirectory", GetCurrentDirectory, + "ChangeDirectory", ChangeDirectory, + "GetAbsolutePath", GetAbsolutePath, + "GetFileSize", GetFileSize, + "GetFileType", GetFileType, + "FindFiles", FindFiles, + "FindDirectories", FindDirectories, + "GetFileAsString", GetFileAsString, + "FileExists", FileExists, + 0, 0, +}; + +// ----------------------------------------------------------------------------- + +bool BS_PackageManager::_RegisterScriptBindings() +{ + BS_Kernel * pKernel = BS_Kernel::GetInstance(); + BS_ASSERT(pKernel); + BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(pKernel->GetService("script")); + BS_ASSERT(pScript); + lua_State * L = static_cast<lua_State *>(pScript->GetScriptObject()); + BS_ASSERT(L); + + if (!BS_LuaBindhelper::AddFunctionsToLib(L, PACKAGE_LIBRARY_NAME, PACKAGE_FUNCTIONS)) return false; + + return true; +} diff --git a/engines/sword25/package/physfspackagemanager.cpp b/engines/sword25/package/physfspackagemanager.cpp new file mode 100755 index 0000000000..70b9d98578 --- /dev/null +++ b/engines/sword25/package/physfspackagemanager.cpp @@ -0,0 +1,487 @@ +// ----------------------------------------------------------------------------- +// This file is part of Broken Sword 2.5 +// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer +// +// Broken Sword 2.5 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. +// +// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include "physfspackagemanager.h" +#include "util/physfs/physfs.h" +extern "C" +{ + #include "util/physfs/extras/globbing.h" +}; + +#include "kernel/memlog_off.h" +#include <vector> +#include <sstream> +#include "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<PathElement> 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<PathElement>::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<typename T> + 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<unsigned int>(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<std::string> & 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<std::string> m_FoundFiles; + vector<std::string>::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<char **> 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<std::string> 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 new file mode 100755 index 0000000000..236ec4fbbe --- /dev/null +++ b/engines/sword25/package/physfspackagemanager.h @@ -0,0 +1,61 @@ +// ----------------------------------------------------------------------------- +// This file is part of Broken Sword 2.5 +// Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdörfer +// +// Broken Sword 2.5 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. +// +// Broken Sword 2.5 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 Broken Sword 2.5; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +// ----------------------------------------------------------------------------- + +#ifndef BS_PHYSFS_PACKAGE_MANAGER_H +#define BS_PHYSFS_PACKAGE_MANAGER_H + +// ----------------------------------------------------------------------------- +// Includes +// ----------------------------------------------------------------------------- + +#include "kernel/common.h" +#include "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 |