aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/package
diff options
context:
space:
mode:
authorEugene Sandulenko2010-07-29 19:53:02 +0000
committerEugene Sandulenko2010-10-12 21:38:20 +0000
commita683a420a9e43705c972b5e74d55e319729e1a81 (patch)
treebde6e4abd417bdfaec120aa951da9a19be36b654 /engines/sword25/package
parent7723d91c957d07205c51be32498d45cd0a78568f (diff)
downloadscummvm-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-xengines/sword25/package/packagemanager.cpp36
-rwxr-xr-xengines/sword25/package/packagemanager.h188
-rwxr-xr-xengines/sword25/package/packagemanager_script.cpp247
-rwxr-xr-xengines/sword25/package/physfspackagemanager.cpp487
-rwxr-xr-xengines/sword25/package/physfspackagemanager.h61
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