aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword25/kernel')
-rwxr-xr-xengines/sword25/kernel/bs_stdint.h17
-rwxr-xr-xengines/sword25/kernel/callbackregistry.cpp123
-rwxr-xr-xengines/sword25/kernel/callbackregistry.h62
-rwxr-xr-xengines/sword25/kernel/common.h55
-rwxr-xr-xengines/sword25/kernel/cpuinfo.cpp260
-rwxr-xr-xengines/sword25/kernel/cpuinfo.h128
-rwxr-xr-xengines/sword25/kernel/debug/debugtools.cpp156
-rwxr-xr-xengines/sword25/kernel/debug/debugtools.h52
-rwxr-xr-xengines/sword25/kernel/debug/memorydumper.cpp184
-rwxr-xr-xengines/sword25/kernel/debug/memorydumper.h57
-rwxr-xr-xengines/sword25/kernel/filesystemutil.h102
-rwxr-xr-xengines/sword25/kernel/filesystemutil_win32.cpp256
-rwxr-xr-xengines/sword25/kernel/hashmap.h34
-rwxr-xr-xengines/sword25/kernel/inputpersistenceblock.cpp191
-rwxr-xr-xengines/sword25/kernel/inputpersistenceblock.h71
-rwxr-xr-xengines/sword25/kernel/kernel.cpp412
-rwxr-xr-xengines/sword25/kernel/kernel.h344
-rwxr-xr-xengines/sword25/kernel/kernel_script.cpp775
-rwxr-xr-xengines/sword25/kernel/log.cpp224
-rwxr-xr-xengines/sword25/kernel/log.h123
-rwxr-xr-xengines/sword25/kernel/md5.cpp385
-rwxr-xr-xengines/sword25/kernel/md5.h56
-rwxr-xr-xengines/sword25/kernel/memleaks.cpp130
-rwxr-xr-xengines/sword25/kernel/memleaks.h60
-rwxr-xr-xengines/sword25/kernel/memlog_off.h27
-rwxr-xr-xengines/sword25/kernel/memlog_on.h27
-rwxr-xr-xengines/sword25/kernel/objectregistry.h182
-rwxr-xr-xengines/sword25/kernel/outputpersistenceblock.cpp123
-rwxr-xr-xengines/sword25/kernel/outputpersistenceblock.h60
-rwxr-xr-xengines/sword25/kernel/persistable.h36
-rwxr-xr-xengines/sword25/kernel/persistenceblock.h112
-rwxr-xr-xengines/sword25/kernel/persistenceservice.cpp459
-rwxr-xr-xengines/sword25/kernel/persistenceservice.h71
-rwxr-xr-xengines/sword25/kernel/resmanager.cpp293
-rwxr-xr-xengines/sword25/kernel/resmanager.h185
-rwxr-xr-xengines/sword25/kernel/resource.cpp45
-rwxr-xr-xengines/sword25/kernel/resource.h97
-rwxr-xr-xengines/sword25/kernel/resservice.h110
-rwxr-xr-xengines/sword25/kernel/service.h57
-rwxr-xr-xengines/sword25/kernel/service_ids.h56
-rwxr-xr-xengines/sword25/kernel/string.h117
-rwxr-xr-xengines/sword25/kernel/timer.cpp53
-rwxr-xr-xengines/sword25/kernel/timer.h69
-rwxr-xr-xengines/sword25/kernel/win32window.cpp425
-rwxr-xr-xengines/sword25/kernel/win32window.h77
-rwxr-xr-xengines/sword25/kernel/wincodegenerator.cpp72
-rwxr-xr-xengines/sword25/kernel/wincodegenerator.h43
-rwxr-xr-xengines/sword25/kernel/wincodegenerator_win32.cpp128
-rwxr-xr-xengines/sword25/kernel/window.cpp53
-rwxr-xr-xengines/sword25/kernel/window.h176
50 files changed, 7410 insertions, 0 deletions
diff --git a/engines/sword25/kernel/bs_stdint.h b/engines/sword25/kernel/bs_stdint.h
new file mode 100755
index 0000000000..5334c3051c
--- /dev/null
+++ b/engines/sword25/kernel/bs_stdint.h
@@ -0,0 +1,17 @@
+#ifndef BS_STDINT_H
+#define BS_STDINT_H
+
+#ifdef _MSC_VER
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+ typedef unsigned __int64 uint64_t;
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef signed __int64 int64_t;
+#else
+ #include <stdint.h>
+#endif
+
+#endif
diff --git a/engines/sword25/kernel/callbackregistry.cpp b/engines/sword25/kernel/callbackregistry.cpp
new file mode 100755
index 0000000000..abdf2bd704
--- /dev/null
+++ b/engines/sword25/kernel/callbackregistry.cpp
@@ -0,0 +1,123 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// Alle Callbackfunktionen die von Objekten gerufen werden, die persistiert werden können, müssen hier registriert werden.
+// Beim Speichern wird statt des Pointers der Bezeichner gespeichert. Beim Laden wird der Bezeichner wieder in einen Pointer umgewandelt.
+// Diese Klasse führt also so etwas ähnliches wie eine Importtabelle für Callback-Funktionen.
+//
+// Dieses Vorgehen hat mehrere Vorteile:
+// 1. Die Speicherstände sind plattformunabhängig. Es werden keine Pointer auf Funktionen gespeichert, sondern nur Namen von Callbackfunktionen.
+// Diese können beim Laden über diese Klasse in systemabhängige Pointer umgewandelt werden.
+// 2. Speicherstände können auch nach einem Engineupdate weiterhin benutzt werden. Beim Erstellen einer neun Binary verschieben sich häufig die
+// Funktionen. Eine Callbackfunktion könnte sich also nach einem Update an einer anderen Stelle befinden als davor. Wenn im Spielstand der
+// Pointer gespeichert war, stürtzt das Programm beim Äufrufen dieser Callbackfunktion ab. Durch das Auflösungverfahren wird beim Laden der
+// Callbackbezeichner in den neuen Funktionspointer umgewandelt und der Aufruf kann erfolgen.
+
+// -----------------------------------------------------------------------------
+// Logging
+// -----------------------------------------------------------------------------
+
+#define BS_LOG_PREFIX "CALLBACKREGISTRY"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "callbackregistry.h"
+
+// -----------------------------------------------------------------------------
+
+bool BS_CallbackRegistry::RegisterCallbackFunction(const std::string & Name, void * Ptr)
+{
+ if (Name == "")
+ {
+ BS_LOG_ERRORLN("The empty string is not allowed as a callback function name.");
+ return false;
+ }
+
+ if (FindPtrByName(Name) != 0)
+ {
+ BS_LOG_ERRORLN("There is already a callback function with the name \"%s\".", Name.c_str());
+ return false;
+ }
+ if (FindNameByPtr(Ptr) != "")
+ {
+ BS_LOG_ERRORLN("There is already a callback function with the pointer 0x%x.", Ptr);
+ return false;
+ }
+
+ StoreCallbackFunction(Name, Ptr);
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+void * BS_CallbackRegistry::ResolveCallbackFunction(const std::string & Name) const
+{
+ void * Result = FindPtrByName(Name);
+
+ if (!Result)
+ {
+ BS_LOG_ERRORLN("There is no callback function with the name \"%s\".", Name.c_str());
+ }
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+std::string BS_CallbackRegistry::ResolveCallbackPointer(void * Ptr) const
+{
+ const std::string & Result = FindNameByPtr(Ptr);
+
+ if (Result == "")
+ {
+ BS_LOG_ERRORLN("There is no callback function with the pointer 0x%x.", Ptr);
+ }
+
+ return Result;
+}
+
+// -----------------------------------------------------------------------------
+
+void * BS_CallbackRegistry::FindPtrByName(const std::string & Name) const
+{
+ // Eintrag in der Map finden und den Pointer zurückgeben.
+ NameToPtrMap::const_iterator It = m_NameToPtrMap.find(Name);
+ return It == m_NameToPtrMap.end() ? 0 : It->second;
+}
+
+// -----------------------------------------------------------------------------
+
+std::string BS_CallbackRegistry::FindNameByPtr(void * Ptr) const
+{
+ // Eintrag in der Map finden und den Namen zurückgeben.
+ PtrToNameMap::const_iterator It = m_PtrToNameMap.find(Ptr);
+ return It == m_PtrToNameMap.end() ? "" : It->second;
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_CallbackRegistry::StoreCallbackFunction(const std::string & Name, void * Ptr)
+{
+ // Callback-Funktion in beide Maps eintragen.
+ m_NameToPtrMap[Name] = Ptr;
+ m_PtrToNameMap[Ptr] = Name;
+}
diff --git a/engines/sword25/kernel/callbackregistry.h b/engines/sword25/kernel/callbackregistry.h
new file mode 100755
index 0000000000..68d2e85b80
--- /dev/null
+++ b/engines/sword25/kernel/callbackregistry.h
@@ -0,0 +1,62 @@
+// -----------------------------------------------------------------------------
+// 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_CALLBACK_REGISTRY_H
+#define BS_CALLBACK_REGISTRY_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+
+#include "kernel/memlog_off.h"
+#include <map>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+class BS_CallbackRegistry
+{
+public:
+ static BS_CallbackRegistry & GetInstance()
+ {
+ static BS_CallbackRegistry Instance;
+ return Instance;
+ }
+
+ bool RegisterCallbackFunction(const std::string & Name, void * Ptr);
+ void * ResolveCallbackFunction(const std::string & Name) const;
+ std::string ResolveCallbackPointer(void * Ptr) const;
+
+private:
+ typedef std::map<std::string, void *> NameToPtrMap;
+ NameToPtrMap m_NameToPtrMap;
+ typedef std::map<void *, std::string> PtrToNameMap;
+ PtrToNameMap m_PtrToNameMap;
+
+ void * FindPtrByName(const std::string & Name) const;
+ std::string FindNameByPtr(void * Ptr) const;
+ void StoreCallbackFunction(const std::string & Name, void * Ptr);
+};
+
+
+#endif
diff --git a/engines/sword25/kernel/common.h b/engines/sword25/kernel/common.h
new file mode 100755
index 0000000000..29e4a20e73
--- /dev/null
+++ b/engines/sword25/kernel/common.h
@@ -0,0 +1,55 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ common.h
+ -----------
+ Diese Datei enthält Funktionen und Makros, die im gesamten Projekt bekannt sein müssen.
+ Daher ist es äußerst wichtig, dass diese Headerdatei in jede andere Headerdatei des Projektes
+ eingefügt wird.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef BS_COMMON_H
+#define BS_COMMON_H
+
+// Globale Konstanten
+#if _DEBUG && !DEBUG
+ #define DEBUG
+#endif
+
+#define BS_ACTIVATE_LOGGING // Wenn definiert, wird Logging aktiviert
+
+// Engine Includes
+#include "memleaks.h"
+#include "log.h"
+
+#ifdef DEBUG
+#define BS_ASSERT(EXP) \
+ if (!(EXP)) \
+ { \
+ BS_Log::Log("!!ASSERTION FAILED!! - FILE: %s - LINE: %d.\n", __FILE__, __LINE__); \
+ __asm { int 3 }; \
+ }
+#else
+#define BS_ASSERT(EXP) do { (void)(EXP); } while(0)
+#endif
+
+#endif
diff --git a/engines/sword25/kernel/cpuinfo.cpp b/engines/sword25/kernel/cpuinfo.cpp
new file mode 100755
index 0000000000..f65f7e6125
--- /dev/null
+++ b/engines/sword25/kernel/cpuinfo.cpp
@@ -0,0 +1,260 @@
+// -----------------------------------------------------------------------------
+// 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 "CPUINFO"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "cpuinfo.h"
+
+// -----------------------------------------------------------------------------
+// Konstanten
+// -----------------------------------------------------------------------------
+
+// Standard CPU-Features
+static const unsigned int MMX_BITMASK = 1 << 23;
+static const unsigned int SSE_BITMASK = 1 << 25;
+static const unsigned int SSE2_BITMASK = 1 << 26;
+
+// Erweiterte CPU-Features
+static const unsigned int _3DNOW_BITMASK = 1 << 30;
+static const unsigned int _3DNOWEXT_BITMASK = 1 << 31;
+
+// -----------------------------------------------------------------------------
+// Konstruktion
+// -----------------------------------------------------------------------------
+
+BS_CPUInfo::BS_CPUInfo() :
+ _VendorID(V_UNKNOWN),
+ _VendorString("unknown"),
+ _CPUName("unknown"),
+ _MMXSupported(false),
+ _SSESupported(false),
+ _SSE2Supported(false),
+ _3DNowSupported(false),
+ _3DNowExtSupported(false)
+{
+ if (!_IsCPUIDSupported())
+ {
+ BS_LOG_ERRORLN("CPUID instruction ist not supported. Could not gather processor information.");
+ return;
+ }
+
+ if (!_ReadVendor())
+ {
+ BS_LOG_WARNINGLN("Unrecognized CPU vendor.");
+ }
+
+ if (!_ReadCPUName())
+ {
+ BS_LOG_WARNINGLN("Could not determine CPU name.");
+ }
+
+ if (!_ReadCPUFeatures())
+ {
+ BS_LOG_WARNINGLN("Could not determine CPU-features.");
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_CPUInfo::_IsCPUIDSupported() const
+{
+ __try
+ {
+ __asm
+ {
+ mov eax, 0
+ cpuid
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_CPUInfo::_ReadVendor()
+{
+ static struct
+ {
+ char* VendorString;
+ BS_CPUInfo::VENDORID ID;
+ } VENDOR_TABLE[] =
+ {
+ "GenuineIntel", V_INTEL,
+ "AuthenticAMD", V_AMD,
+ "CyrixInstead", V_CYRIX,
+ "CentaurHauls", V_CENTAUR,
+ "NexGenDriven", V_NEXGEN,
+ "GenuineTMx86", V_TRANSMETA,
+ "RiseRiseRise", V_RISE,
+ "UMC UMC UMC", V_UMC,
+ "SiS SiS SiS", V_SIS,
+ "Geode by NSC", V_NSC,
+ 0, V_UNKNOWN,
+ };
+
+ // Vendor-String bestimmen
+ char Buffer[13];
+ __asm
+ {
+ xor eax, eax
+ cpuid
+ mov dword ptr [Buffer], ebx
+ mov dword ptr [Buffer + 4], edx
+ mov dword ptr [Buffer + 8], ecx
+ mov byte ptr [Buffer + 12], 0
+ }
+ _VendorString = Buffer;
+
+ // Vendor-ID bestimmen
+ int i;
+ for (i = 0; VENDOR_TABLE[i].VendorString; i++) if (_VendorString == VENDOR_TABLE[i].VendorString) break;
+ _VendorID = VENDOR_TABLE[i].ID;
+
+ return _VendorID != V_UNKNOWN;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_CPUInfo::_ReadCPUName()
+{
+ // Feststellen, ob das CPU-Name Feature vorhanden ist.
+ unsigned int Result;
+ __asm
+ {
+ mov eax, 0x80000000
+ cpuid
+ mov Result, eax
+ }
+ if (Result < 0x80000004) return false;
+
+ // CPU-Namen einlesen
+ char Buffer[49];
+ __asm
+ {
+ mov eax,0x80000002
+ cpuid
+ mov dword ptr [Buffer + 0], eax
+ mov dword ptr [Buffer + 4], ebx
+ mov dword ptr [Buffer + 8], ecx
+ mov dword ptr [Buffer + 12], edx
+ mov eax,0x80000003
+ cpuid
+ mov dword ptr [Buffer + 16], eax
+ mov dword ptr [Buffer + 20], ebx
+ mov dword ptr [Buffer + 24], ecx
+ mov dword ptr [Buffer + 28], edx
+ mov eax,0x80000004
+ cpuid
+ mov dword ptr [Buffer + 32], eax
+ mov dword ptr [Buffer + 36], ebx
+ mov dword ptr [Buffer + 40], ecx
+ mov dword ptr [Buffer + 44], edx
+ mov byte ptr [Buffer + 48], 0
+ }
+ std::string TempCPUName = Buffer;
+ if (TempCPUName.size() != 0)
+ {
+ // Führende und nachfolgende Leerzeichen entfernen
+ std::string::const_iterator StringBegin = TempCPUName.begin();
+ for (; StringBegin != TempCPUName.end() && *StringBegin == ' '; StringBegin++);
+ std::string::const_iterator StringEnd = TempCPUName.end() - 1;
+ for(; StringEnd >= TempCPUName.begin() && *StringEnd == ' '; StringEnd--);
+
+ if (StringBegin != TempCPUName.end() && StringEnd >= TempCPUName.begin())
+ {
+ _CPUName = std::string(StringBegin, StringEnd + 1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_CPUInfo::_ReadCPUFeatures()
+{
+ {
+ // Feststellen ob die Standard-Features abgefragt werden können
+ unsigned int Result;
+ __asm
+ {
+ xor eax, eax
+ cpuid
+ mov Result, eax
+ }
+
+ // Nicht einmal die Standard-Features können abgefragt werden, also muss abgebrochen werden
+ if (Result < 1) return false;
+
+ // Standard-Features abfragen
+ unsigned int Features;
+ __asm
+ {
+ mov eax, 1
+ cpuid
+ mov Features, edx
+ }
+
+ _MMXSupported = (Features & MMX_BITMASK) != 0;
+ _SSESupported = (Features & SSE_BITMASK) != 0;
+ _SSE2Supported = (Features & SSE2_BITMASK) != 0;
+ }
+
+
+ // Feststellen ob erweiterte CPU-Features abgefragt werden können
+ {
+ unsigned int Result;
+ __asm
+ {
+ mov eax, 0x80000000
+ cpuid
+ mov Result, eax
+ }
+
+ // Die erweiterten Features können nicht abgefragt werden, aber die Standard-Features wurden schon
+ // abgefragt, daher wird true zurückgegeben.
+ if (Result < 0x80000001) return true;
+
+ // Erweiterte Features abfragen
+ unsigned int Features;
+ __asm
+ {
+ mov eax, 0x80000001
+ cpuid
+ mov Features, edx
+ }
+
+ _3DNowSupported = (Features & _3DNOW_BITMASK) != 0;
+ _3DNowExtSupported = (Features & _3DNOWEXT_BITMASK) != 0;
+ }
+
+ return true;
+}
diff --git a/engines/sword25/kernel/cpuinfo.h b/engines/sword25/kernel/cpuinfo.h
new file mode 100755
index 0000000000..fab763861a
--- /dev/null
+++ b/engines/sword25/kernel/cpuinfo.h
@@ -0,0 +1,128 @@
+// -----------------------------------------------------------------------------
+// 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_CPUINFO_H
+#define BS_CPUINFO_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "common.h"
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+/**
+ @brief Diese Singleton-Klasse stellt Informationen über die CPU zur verfügung.
+*/
+
+class BS_CPUInfo
+{
+public:
+ /**
+ @brief Definiert die Vendor-IDs
+ */
+ enum VENDORID
+ {
+ V_UNKNOWN,
+ V_INTEL,
+ V_AMD,
+ V_CYRIX,
+ V_CENTAUR,
+ V_NEXGEN,
+ V_TRANSMETA,
+ V_RISE,
+ V_UMC,
+ V_SIS,
+ V_NSC,
+ };
+
+ /**
+ @brief Gibt eine Referenz auf die einzige Instanz dieser Klasse zurück.
+ */
+ static const BS_CPUInfo & GetInstance()
+ {
+ static BS_CPUInfo Instance;
+ return Instance;
+ }
+
+ /**
+ @brief Gibt die Vendor-ID des CPU-Herstellers zurück.
+ @remark Gibt BS_CPUInfo::V_UNKNOWN zurück, wenn die Vendor-ID nicht bestimmt werden konnte.
+ */
+ VENDORID GetVendorID() const { return _VendorID; }
+
+ /**
+ @brief Gibt den Vendor-String zurück.
+ @remark Gibt "unknown" zurück, wenn der Vendor-String nicht bestimmt werden konnte.
+ */
+ const std::string & GetVendorString() const { return _VendorString; }
+
+ /**
+ @brief Gibt den CPU-Namen zurück.
+ @remark Gibt "unknown" zurück, wenn der CPU-Name nicht bestimmt werden konnte.
+ */
+ const std::string & GetCPUName() const { return _CPUName; }
+
+ /**
+ @brief Gibt zurück, ob der Prozessor MMX untersützt.
+ */
+ bool IsMMXSupported() const { return _MMXSupported; }
+
+ /**
+ @brief Gibt zurück, ob der Prozessor SSE unterstützt.
+ */
+ bool IsSSESupported() const { return _SSESupported; }
+
+ /**
+ @brief Gibt zurück, ob der Prozessor SSE2 unterstützt.
+ */
+ bool IsSSE2Supported() const { return _SSE2Supported; }
+
+ /**
+ @brief Gibt zurück, ob der Prozessor 3DNow! unterstützt.
+ */
+ bool Is3DNowSupported() const { return _3DNowSupported; }
+
+ /**
+ @brief Gibt zurück, ob der Prozessor 3DNow!-Ext. unterstützt.
+ */
+ bool Is3DNowExtSupported() const { return _3DNowExtSupported; }
+
+private:
+ BS_CPUInfo();
+
+ VENDORID _VendorID;
+ std::string _VendorString;
+ std::string _CPUName;
+ bool _MMXSupported;
+ bool _SSESupported;
+ bool _SSE2Supported;
+ bool _3DNowSupported;
+ bool _3DNowExtSupported;
+
+ bool _ReadVendor();
+ bool _ReadCPUFeatures();
+ bool _ReadCPUName();
+ bool _IsCPUIDSupported() const;
+};
+
+#endif
diff --git a/engines/sword25/kernel/debug/debugtools.cpp b/engines/sword25/kernel/debug/debugtools.cpp
new file mode 100755
index 0000000000..91abe66ba7
--- /dev/null
+++ b/engines/sword25/kernel/debug/debugtools.cpp
@@ -0,0 +1,156 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <vector>
+#include <string>
+#include <sstream>
+#include <fstream>
+using namespace std;
+
+#include "kernel/md5.h"
+#include "kernel/filesystemutil.h"
+#include "debugtools.h"
+
+// -----------------------------------------------------------------------------
+// Konstanten und Hilfsfunktionen
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const char * VERSION_ID_ERROR = "???";
+ const unsigned int READBUFFER_SIZE = 1024 * 100;
+
+ const char * SUBVERSION_ENTRIES_FILENAME = ".svn\\entries";
+
+ // -------------------------------------------------------------------------
+
+ unsigned int ParseUnsignedInt(const string & Str, bool & Success)
+ {
+ istringstream iss(Str);
+
+ unsigned int Result = 0;
+ iss >> Result;
+
+ Success = !iss.fail();
+
+ return Result;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+const char * BS_Debugtools::GetVersionID()
+{
+ // Falls die Versions-ID noch nicht bekannt ist, muss sie bestimmt werden
+ static string VersionIDString;
+ if (VersionIDString.size() == 0)
+ {
+ // Dateinamen der EXE-Datei bestimmen
+ char FileName[MAX_PATH + 1];
+ if (GetModuleFileName(0, FileName, sizeof(FileName)) == 0) return VERSION_ID_ERROR;
+
+ // Datei öffnen
+ HANDLE FileHandle = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if (INVALID_HANDLE_VALUE == FileHandle) return VERSION_ID_ERROR;
+
+ // Datei stückchenweise Einlesen und MD5-Hash bilden
+ BS_MD5 md5;
+ std::vector<unsigned char> ReadBuffer(READBUFFER_SIZE);
+ DWORD BytesRead = 0;
+ do
+ {
+ // MD5-Hash für das eingelesene Dateistück berechnen.
+ md5.Update(&ReadBuffer[0], BytesRead);
+
+ if (ReadFile(FileHandle, &ReadBuffer[0], READBUFFER_SIZE, &BytesRead, 0) == FALSE)
+ {
+ CloseHandle(FileHandle);
+ return VERSION_ID_ERROR;
+ }
+ } while (BytesRead > 0);
+
+ // Datei schließen
+ CloseHandle(FileHandle);
+
+ // Falls sich das aktuelle Verzeichnis in einem Subversion-Repository befindet, wird auch die Subversion-Revision mit in die ID gehasht.
+ // Dieses stellt im Beta-Test sicher, dass jede Änderung einer Datei, und nicht nur der EXE, zu einer neuen Versions-ID führt.
+ unsigned int SubversionRevision = GetSubversionRevision();
+ if (SubversionRevision != 0) md5.Update(reinterpret_cast<unsigned char *>(&SubversionRevision), sizeof(unsigned int));
+
+ // MD5 abschließen
+ unsigned char Digest[16];
+ md5.GetDigest(Digest);
+
+ // VersionsID-String erstellen
+ std::ostringstream VersionIDBuf;
+ VersionIDBuf << std::hex;
+ for (unsigned int i = 0; i < sizeof(Digest); i++)
+ {
+ VersionIDBuf << (unsigned int) Digest[i];
+ }
+ VersionIDString = VersionIDBuf.str();
+ }
+
+ return VersionIDString.c_str();
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_Debugtools::GetSubversionRevision()
+{
+ // Existiert eine entries Datei?
+ if (BS_FileSystemUtil::GetInstance().FileExists(SUBVERSION_ENTRIES_FILENAME))
+ {
+ bool Success;
+ char Buffer[512];
+
+ // entries Datei öffnen.
+ ifstream File(SUBVERSION_ENTRIES_FILENAME);
+ if (File.fail()) return 0;
+
+ // Das Format auslesen und feststellen, ob wir es unterstützen.
+ File.getline(Buffer, sizeof(Buffer), 0x0A);
+ unsigned int FormatVersion = ParseUnsignedInt(Buffer, Success);
+ if (File.fail() || !Success || FormatVersion < 7) return 0;
+
+ // Den Namen des ersten Eintrages auslesen. Dieses muss ein leerer String sein und somit das aktuelle Verzeichnis benennen.
+ File.getline(Buffer, sizeof(Buffer), 0x0A);
+ if (File.fail() || strlen(Buffer) != 0) return 0;
+
+ // Den Typ des Eintrages auslesen. Dieser muss "dir" sein.
+ File.getline(Buffer, sizeof(Buffer), 0x0A);
+ if (File.fail() || strcmp(Buffer, "dir") != 0) return 0;
+
+ // Die Revision des Eintrages auslesen.
+ File.getline(Buffer, sizeof(Buffer), 0x0A);
+ unsigned int Revision = ParseUnsignedInt(Buffer, Success);
+ if (File.fail() || !Success) return 0;
+
+ return Revision;
+ }
+
+ return 0;
+}
diff --git a/engines/sword25/kernel/debug/debugtools.h b/engines/sword25/kernel/debug/debugtools.h
new file mode 100755
index 0000000000..30dd04a83d
--- /dev/null
+++ b/engines/sword25/kernel/debug/debugtools.h
@@ -0,0 +1,52 @@
+// -----------------------------------------------------------------------------
+// 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 DEBUGTOOLS_H
+#define DEBUGTOOLS_H
+
+class BS_Debugtools
+{
+public:
+ /**
+ @brief Gibt eine ID zurück, die die benutzte Programmversion eindeutig identifiziert.
+
+ Um die Version zu ermitteln wird der MD5-Hash über die EXE-Datei gebildet.
+ Falls die ausführende Datei in einem SVN-Repository liegt wird zusätzlich die Revision des Verzeichnisses gehasht.
+
+ @return Gibt einen String zurück, der die Versions-ID des Programmes angibt.<br>
+ Falls die Versions-ID nicht bestimmt werden konnte wird "???" zurückgegeben.
+ @remark Diese Methode ist momentan nur für WIN32 implementiert.
+ */
+ static const char * GetVersionID();
+
+ /**
+
+ @brief Gibt die Subversion-Revisionsnummer der Engine zurück.
+
+ Diese Funktion versucht die aktuelle Revision aus der SVN entries Datei für das aktuelle Verzeichnis zu extrahieren.
+ Dabei werden die SVN entries Formatversionen 7 und größer unterstützt.
+ Die neueste Version ist aktuell 9. Für folgende Versionen wird angenommen, dass sich das Format des Headers nicht mehr ändert.
+
+ @return Gibt die Revisionsnummer zurück. Falls die ausführende Datei nicht in einem SVN-Repository liegt oder die Revision nicht
+ festgestellt werden konnte wird 0 zurückgegeben.
+ */
+ static unsigned int GetSubversionRevision();
+};
+
+#endif
diff --git a/engines/sword25/kernel/debug/memorydumper.cpp b/engines/sword25/kernel/debug/memorydumper.cpp
new file mode 100755
index 0000000000..3c79f67bf8
--- /dev/null
+++ b/engines/sword25/kernel/debug/memorydumper.cpp
@@ -0,0 +1,184 @@
+// -----------------------------------------------------------------------------
+// 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 <string>
+#include <ctime>
+#include <sstream>
+#include <iomanip>
+#include "..\filesystemutil.h"
+#include "memorydumper.h"
+#include "debugtools.h"
+
+using namespace std;
+
+#define BS_LOG_PREFIX "MEMORYDUMPER"
+
+// -----------------------------------------------------------------------------
+// Konstanten
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const char * DBG_HELP_DLL_FILENAME = "dbghelp.dll";
+ const char * MINIDUMPWRITEDUMP_FUNCTIONNAME = "MiniDumpWriteDump";
+ const char * DUMPS_DIRECTORYNAME = "dumps";
+ const char * DUMPFILE_EXTENSION = ".dmp";
+}
+
+// -----------------------------------------------------------------------------
+// Construction / Destruction
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ HMODULE LoadDbghelpDLL()
+ {
+ // Zunächst wird versucht die DLL in dem Verzeichnis der EXE-Datei zu finden, da diese die gewünschte Funktionalität unterstützt
+
+ // Pfad der EXE-Datei bestimmen
+ char ExePath[MAX_PATH];
+ if (GetModuleFileNameA(0, ExePath, sizeof(ExePath)))
+ {
+ // EXE-Dateinamen abschneiden und den DLL-Dateinamen anhängen
+ string DllPath = ExePath;
+ string::size_type SlashPos;
+ if ((SlashPos = DllPath.rfind("\\")) != string::npos)
+ {
+ DllPath.resize(SlashPos + 1);
+ DllPath += DBG_HELP_DLL_FILENAME;
+
+ HMODULE DllModule = LoadLibraryA(DllPath.c_str());
+ if (DllModule) return DllModule;
+ }
+ }
+
+ // Falls dies fehlgeschlagen ist, wird versucht die Version zu laden, die Windows uns anbietet, wenn wir keinen kompletten Pfad angeben.
+ return LoadLibraryA(DBG_HELP_DLL_FILENAME);
+ }
+}
+
+BS_MemoryDumper::BS_MemoryDumper() :
+ m_DbghelpDLL(0)
+{
+ m_DbghelpDLL = LoadDbghelpDLL();
+ if (m_DbghelpDLL)
+ {
+ m_MiniDumpWriteDump = reinterpret_cast<MINIDUMPWRITEDUMP>(GetProcAddress(m_DbghelpDLL, MINIDUMPWRITEDUMP_FUNCTIONNAME));
+ if (!m_MiniDumpWriteDump)
+ {
+ BS_LOG_ERRORLN("Your version of \"%s\" is too old. Dumping is not possible.", DBG_HELP_DLL_FILENAME);
+ }
+ }
+ else
+ {
+ BS_LOG_ERRORLN("Could not load \"%s\". Dumping is not possible.", DBG_HELP_DLL_FILENAME);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+BS_MemoryDumper::~BS_MemoryDumper()
+{
+ // DLL-Entladen
+ if (m_DbghelpDLL) FreeLibrary(m_DbghelpDLL);
+}
+
+
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ bool EnsureOutputDirectoryExists()
+ {
+ // Windows.h definiert ein Makro CreateDirectory. Damit wir die Methode CreateDirectory aufrufen können müssen wir das Makro entfernen.
+ #ifdef CreateDirectory
+ #undef CreateDirectory
+ #endif
+
+ return BS_FileSystemUtil::GetInstance().CreateDirectory(
+ BS_FileSystemUtil::GetInstance().GetUserdataDirectory() +
+ BS_FileSystemUtil::GetInstance().GetPathSeparator() +
+ DUMPS_DIRECTORYNAME);
+ }
+
+ string CreateOutputFilename()
+ {
+ // Aktuelle Zeit bestimmen.
+ time_t Time = time(0);
+ tm * Timeinfo = localtime(&Time);
+
+ // Den Ausgabedateinamen in folgender Form erstellen:
+ // <BenutzerdatenVerzeichnis>\dumps\YYYY-MM-DD HH-MM.dmp
+ ostringstream oss;
+ oss << BS_FileSystemUtil::GetInstance().GetUserdataDirectory() << BS_FileSystemUtil::GetInstance().GetPathSeparator()
+ << DUMPS_DIRECTORYNAME << BS_FileSystemUtil::GetInstance().GetPathSeparator()
+ << setfill('0')
+ << setw(4) << (Timeinfo->tm_year + 1900) << "-"
+ << setw(2) << (Timeinfo->tm_mon + 1) << "-"
+ << setw(2) << Timeinfo->tm_mday << " "
+ << setw(2) << Timeinfo->tm_hour << "-"
+ << setw(2) << Timeinfo->tm_min << "-"
+ << BS_Debugtools::GetVersionID()
+ << DUMPFILE_EXTENSION;
+ return oss.str();
+ }
+}
+
+bool BS_MemoryDumper::WriteDump(_EXCEPTION_POINTERS * ExceptionInfoPtr, string & Filename)
+{
+ // Dumpen ist nur möglich, wenn zuvor die dbghelp.dll geladen werden konnte.
+ if (!m_DbghelpDLL)
+ {
+ BS_LOG_ERRORLN("Cannot write dump because \"%s\" could not be loaded previously.", DBG_HELP_DLL_FILENAME);
+ return false;
+ }
+
+ // Temporäre Datei erstellen, die den Dump aufnehmen soll
+ HANDLE File;
+ Filename = CreateOutputFilename();
+ if (!EnsureOutputDirectoryExists() ||
+ (File = CreateFile(Filename.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0)) != INVALID_HANDLE_VALUE)
+ {
+ _MINIDUMP_EXCEPTION_INFORMATION ExInfo;
+
+ ExInfo.ThreadId = GetCurrentThreadId();
+ ExInfo.ExceptionPointers = ExceptionInfoPtr;
+ ExInfo.ClientPointers = 0;
+
+ // Dump schreiben
+ bool Result = m_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), File, MiniDumpNormal, &ExInfo, 0, 0) != 0;
+ if (!Result)
+ {
+ BS_LOG_ERRORLN("MiniDumpWriteDump() failed. Memory dump could not be created.");
+ DeleteFileA(Filename.c_str());
+ }
+
+ CloseHandle(File);
+ return Result;
+ }
+ else
+ {
+ BS_LOG_ERRORLN("Could not create a file to accomodate the memory dump.");
+ return false;
+ }
+}
diff --git a/engines/sword25/kernel/debug/memorydumper.h b/engines/sword25/kernel/debug/memorydumper.h
new file mode 100755
index 0000000000..5fac12e830
--- /dev/null
+++ b/engines/sword25/kernel/debug/memorydumper.h
@@ -0,0 +1,57 @@
+// -----------------------------------------------------------------------------
+// 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_MEMORYDUMPER_H
+#define BS_MEMORYDUMPER_H
+
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <dbghelp.h>
+#include <string>
+
+#include "kernel/common.h"
+
+
+// -----------------------------------------------------------------------------
+// Class declaration
+// -----------------------------------------------------------------------------
+
+class BS_MemoryDumper
+{
+public:
+ BS_MemoryDumper();
+ ~BS_MemoryDumper();
+
+ bool WriteDump(_EXCEPTION_POINTERS * ExceptionInfoPtr, std::string & Filename);
+
+private:
+ typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
+ CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+ MINIDUMPWRITEDUMP m_MiniDumpWriteDump;
+ HMODULE m_DbghelpDLL;
+};
+
+#endif
diff --git a/engines/sword25/kernel/filesystemutil.h b/engines/sword25/kernel/filesystemutil.h
new file mode 100755
index 0000000000..63f76617c0
--- /dev/null
+++ b/engines/sword25/kernel/filesystemutil.h
@@ -0,0 +1,102 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ Die Klasse BS_FileSystemUtil stellt einen Wrapper für dateisystemspezifische Operationen dar, die nicht über die C/C++ Bibliotheken
+ abgedeckt werden.
+
+ Jede unterstützte Plattform muss dieses Interface implementieren und die Singleton-Methode BS_FileSystemUtil::GetInstance()
+ implementieren.
+*/
+
+#ifndef BS_FILESYSTEMUTIL_H
+#define BS_FILESYSTEMUTIL_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/bs_stdint.h"
+
+#include "kernel/memlog_off.h"
+#include <string>
+#include <vector>
+#include <ctime>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_FileSystemUtil
+{
+public:
+ static BS_FileSystemUtil & GetInstance();
+ virtual ~BS_FileSystemUtil() {};
+
+ /*
+ Diese Funktion gibt den Namen des Verzeichnisses zurück, in dem sämtliche Benutzerdaten gespeichert werden sollen.
+
+ Dieses sind z.B. Screenshots, Spielstände, Konfigurationsdateien, Logdateien, ...
+ Unter Windows Vista ist dieses beispielsweise: C:\Users\Malte\Documents\Broken Sword 2.5
+ Falls dieses Verzeichnis noch nicht existiert, wird es automatisch erstellt.
+
+ @return Gibt den Namen des Verzeichnisses für Benutzerdaten zurück.
+ */
+ virtual std::string GetUserdataDirectory() = 0;
+ /*
+ @return Gibt den Pfadtrenner zurück (z.B. \ unter Windows und / unter Linux).
+ */
+ virtual std::string GetPathSeparator() = 0;
+ /*
+ @param Filename der Pfad zu einer Datei.
+ @return Gibt die Größe der angegebenen Datei zurück. Falls die Größe nicht bestimmt werden konnte, oder die Datei nicht existiert wird -1 zurückgegeben.
+ */
+ virtual uint64_t GetFileSize(const std::string & Filename) = 0;
+ /*
+ @param Filename der Pfad zu einer Datei.
+ @return Gibt den Zeitstempel des Zeitpunktes zurück an dem die Datei zuletzt verändert wurde. Bei einem Fehler wird 0 zurückgegeben.
+ */
+ virtual time_t GetFileTime(const std::string & Filename) = 0;
+ /*
+ @param Filename der Pfad zu einer Datei.
+ @return Gibt true zurück, wenn die Datei existiert.
+ */
+ virtual bool FileExists(const std::string & Filename) = 0;
+ /*
+ Diese Funktion erstellt einen Verzeichnis mit sämtlichen Unterverzeichnissen.
+
+ Wenn des Parameter "\b\c\d\e" ist und der Pfad "\b\c" bereits existiert, werden die Verzeichnisse
+ "d" und "e" erstellt.
+
+ @param DirectoryName der Name des zu erstellenden Verzeichnisses.
+ @return Gibt true zurück, wenn die Verzeichnisse erstellt werden konnten, ansonsten false.
+ */
+ virtual bool CreateDirectory(const std::string & DirectoryName) = 0;
+ /*
+ Erstellt eine Liste aller Dateinamen in einem Verzeichnis.
+
+ @param Directory das zu durchsuchende Verzeichnis.
+ @return Gibt einen vector mit allen gefundenen Dateinamen zurück.
+ */
+ virtual std::vector<std::string> GetFilesInDirectory(const std::string & Path) = 0;
+};
+
+#endif
diff --git a/engines/sword25/kernel/filesystemutil_win32.cpp b/engines/sword25/kernel/filesystemutil_win32.cpp
new file mode 100755
index 0000000000..2b4ce49f3d
--- /dev/null
+++ b/engines/sword25/kernel/filesystemutil_win32.cpp
@@ -0,0 +1,256 @@
+// -----------------------------------------------------------------------------
+// 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 "filesystemutil.h"
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <ShlObj.h>
+#include <memory.h>
+
+using namespace std;
+
+#define BS_LOG_PREFIX "FILESYSTEMUTILWIN32"
+
+// -----------------------------------------------------------------------------
+// Konstanten und Hilfsfunktionen
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const char * DIRECTORY_NAME = "Broken Sword 2.5";
+
+ // -------------------------------------------------------------------------
+
+ string GetAbsolutePath(const string & Path)
+ {
+ char Buffer[MAX_PATH];
+ if (!::GetFullPathNameA(Path.c_str(), MAX_PATH, Buffer, 0))
+ {
+ // Bei der Ausführung von GetFullPathNameA() ist ein Fehler aufgetreten.
+ // Wir können an dieser Stelle nichts andere machen, als einen leeren String zurückzugeben.
+ BS_LOG_ERRORLN("A call to GetFullPathNameA() failed.");
+ return "";
+ }
+
+ // Ergebnis zurückgeben.
+ return string(Buffer);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_FileSystemUtilWin32 : public BS_FileSystemUtil
+{
+public:
+ virtual string GetUserdataDirectory()
+ {
+ // Die C++ Dateisystemfunktionen können leider nicht mit Unicode-Dateinamen umgehen.
+ // Für uns ist das problematisch, wenn wir in das %APPDATA%-Verzeichnis eines Benutzers zugreifen wollen,
+ // dessen Name Unicode-Zeichen enthält, die sich mit der aktuellen Codepage nicht als ANSI-String darstellen
+ // lassen.
+ // Wir behelfen uns damit, dass wir das Verzeichnis als Unicode-String abfragen, in die kurze
+ // Verzeichnisdarstellung konvertieren und das Ergebnis in einen ANSI-String konvertieren.
+ // Kurze Dateinamen sollten keine Unicode-Zeichen enthalten, ich habe allerdings keine offizielle Aussage dazu
+ // gefunden.
+
+ WCHAR PathBuffer[MAX_PATH];
+
+ // Das %APPDATA%-Verzeichnis erfragen.
+ if (::SHGetSpecialFolderPathW(0, PathBuffer, CSIDL_APPDATA, FALSE) == FALSE)
+ {
+ BS_LOG_ERRORLN("SHGetSpecialFolderPathW() failed");
+ return "";
+ }
+
+ // Die kurze Variante des Verzeichnisses erfragen.
+ if (::GetShortPathNameW(PathBuffer, PathBuffer, MAX_PATH) == 0)
+ {
+ BS_LOG_ERRORLN("GetShortPathNameW() failed");
+ return "";
+ }
+
+ // Die Verzeichnisangabe in einen ANSI-String konvertieren.
+ char AnsiPathBuffer[MAX_PATH];
+ BOOL UsedDefaultChar = FALSE;
+ if (::WideCharToMultiByte(CP_ACP, 0, PathBuffer, -1, AnsiPathBuffer, MAX_PATH, 0, &UsedDefaultChar) == 0)
+ {
+ BS_LOG_ERRORLN("WideCharToMultiByte() failed");
+ return "";
+ }
+
+ // Falls bei der Konvertierung ein zum Einsatz kam, ist das Ergebnis nicht eindeutig und damit nicht
+ // verwendbar.
+ if (UsedDefaultChar)
+ {
+ BS_LOG_ERRORLN("Conversion from unicode to ANSI is ambiguous.");
+ return "";
+ }
+
+ // Verzeichnis zurückgeben.
+ return string(AnsiPathBuffer) + "\\" + DIRECTORY_NAME;
+ }
+
+ virtual string GetPathSeparator()
+ {
+ return string("\\");
+ }
+
+ virtual uint64_t GetFileSize(const std::string & Filename)
+ {
+ WIN32_FILE_ATTRIBUTE_DATA fileAttributeData;
+ // Dateiattribute einlesen.
+ if (::GetFileAttributesExA(Filename.c_str(), GetFileExInfoStandard, &fileAttributeData) != 0)
+ {
+ // Die Dateigröße wird von Windows in zwei 32-Bit Zahlen angegeben. Diese werden an dieser Stelle in eine 64-Bit Zahl umgewandelt.
+ uint64_t fileSize = fileAttributeData.nFileSizeHigh;
+ fileSize <<= 32;
+ fileSize |= fileAttributeData.nFileSizeLow;
+ return fileSize;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ virtual time_t GetFileTime(const std::string & Filename)
+ {
+ WIN32_FILE_ATTRIBUTE_DATA fileAttributeData;
+ if (::GetFileAttributesExA(Filename.c_str(), GetFileExInfoStandard, &fileAttributeData) != 0)
+ {
+ __int64 timestamp;
+ memcpy(&timestamp, &fileAttributeData.ftLastWriteTime, sizeof(FILETIME));
+ return (timestamp - 0x19DB1DED53E8000) / 10000000;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ virtual bool FileExists(const std::string & Filename)
+ {
+ return ::GetFileAttributesA(Filename.c_str()) != INVALID_FILE_ATTRIBUTES;
+ }
+
+ // Windows.h enthält ein Makro mit dem Namen CreateDirectory. Dieses muss entfernt werden bevor die Definition von
+ // unserem CreateDirectory() folgt.
+ #ifdef CreateDirectory
+ #undef CreateDirectory
+ #endif
+
+ virtual bool CreateDirectory(const string & DirectoryName)
+ {
+ return CreateDirectoryRecursive(GetAbsolutePath(DirectoryName));
+ }
+
+ virtual vector<string> GetFilesInDirectory(const std::string & Directory)
+ {
+ vector<string> Result;
+
+ // Suchstring erstellen, dabei muss der leere String (aktuelles Verzeichnis) gesondert behandelt werden.
+ string SearchPattern;
+ if (Directory.empty())
+ SearchPattern = "*";
+ else
+ SearchPattern = Directory + "\\*";
+
+ // Die erste Datei suchen.
+ WIN32_FIND_DATAA FindData;
+ HANDLE FindHandle = ::FindFirstFileA(SearchPattern.c_str(), &FindData);
+
+ while (FindHandle != INVALID_HANDLE_VALUE)
+ {
+ // Verzeichnisse ignorieren.
+ // Beim erstellen des Ergebnispfades muss wieder der Sonderfall der leeren Verzeichnisangabe berücksichtigt werden.
+ if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ Result.push_back(FindData.cFileName);
+
+ // Solange weitermachen, bis keine Dateien mehr gefunden werden.
+ if (FindNextFileA(FindHandle, &FindData) == 0)
+ {
+ FindClose(&FindHandle);
+ break;
+ }
+ }
+
+ return Result;
+ }
+
+private:
+ bool CreateDirectoryRecursive(string & DirectoryName)
+ {
+ //
+ // http://www.codeguru.com/Cpp/W-P/files/article.php/c4439/
+ // (c) Assaf Tzur-El
+ //
+
+ DWORD attr;
+ int pos;
+ bool result = true;
+
+ // Check for trailing slash:
+ pos = DirectoryName.find_last_of("\\");
+ if (DirectoryName.length() == pos + 1) // last character is "\"
+ {
+ DirectoryName.resize(pos);
+ }
+
+ // Look for existing object:
+ attr = ::GetFileAttributesA(DirectoryName.c_str());
+ if (0xFFFFFFFF == attr) // doesn't exist yet - create it!
+ {
+ pos = DirectoryName.find_last_of("\\");
+ if (0 < pos)
+ {
+ // Create parent dirs:
+ result = CreateDirectoryRecursive(DirectoryName.substr(0, pos));
+ }
+ // Create node:
+ result = result && ::CreateDirectoryA(DirectoryName.c_str(), NULL);
+ }
+ else if (!(FILE_ATTRIBUTE_DIRECTORY & attr))
+ { // object already exists, but is not a dir
+ ::SetLastError(ERROR_FILE_EXISTS);
+ result = false;
+ }
+
+ return result;
+ }
+};
+
+// -----------------------------------------------------------------------------
+// Singleton-Methode der Elternklasse
+// Hiermit wird sichergestellt, dass wenn immer diese Datei kompiliert wird,
+// die Singleton-Methode der Oberklasse diese Klasse instanziiert.
+// Unterscheidung zwischen den Plattformen wird so nur durch Linken gegen andere
+// Dateien realisiert.
+// -----------------------------------------------------------------------------
+
+BS_FileSystemUtil & BS_FileSystemUtil::GetInstance()
+{
+ static BS_FileSystemUtilWin32 Instance;
+ return Instance;
+}
diff --git a/engines/sword25/kernel/hashmap.h b/engines/sword25/kernel/hashmap.h
new file mode 100755
index 0000000000..0aa663332c
--- /dev/null
+++ b/engines/sword25/kernel/hashmap.h
@@ -0,0 +1,34 @@
+// -----------------------------------------------------------------------------
+// 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_HASHMAP_H
+#define BS_HASHMAP_H
+
+// stdext::hash_map wird erst seit VC7 untersützt, bei älteren Microsoft-Compilern wird auf std::map zurückgegriffen
+#include "kernel/memlog_off.h"
+#if _MSC_VER >= 1300
+#include <hash_map>
+#define BS_Hashmap stdext::hash_map
+#else
+#include <map>
+#define BS_Hashmap std::map
+#endif
+#include "kernel/memlog_on.h"
+
+#endif
diff --git a/engines/sword25/kernel/inputpersistenceblock.cpp b/engines/sword25/kernel/inputpersistenceblock.cpp
new file mode 100755
index 0000000000..dd0e6437c3
--- /dev/null
+++ b/engines/sword25/kernel/inputpersistenceblock.cpp
@@ -0,0 +1,191 @@
+// -----------------------------------------------------------------------------
+// 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 "INPUTPERSISTENCEBLOCK"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "inputpersistenceblock.h"
+
+using namespace std;
+
+// -----------------------------------------------------------------------------
+// Construction / Destruction
+// -----------------------------------------------------------------------------
+
+BS_InputPersistenceBlock::BS_InputPersistenceBlock(const void * Data, unsigned int DataLength) :
+ m_Data(static_cast<const unsigned char *>(Data), static_cast<const unsigned char *>(Data) + DataLength),
+ m_ErrorState(NONE)
+{
+ m_Iter = m_Data.begin();
+}
+
+// -----------------------------------------------------------------------------
+
+BS_InputPersistenceBlock::~BS_InputPersistenceBlock()
+{
+ if (m_Iter != m_Data.end()) BS_LOG_WARNINGLN("Persistence block was not read to the end.");
+}
+
+// -----------------------------------------------------------------------------
+// Reading
+// -----------------------------------------------------------------------------
+
+void BS_InputPersistenceBlock::Read(signed int & Value)
+{
+ if (CheckMarker(SINT_MARKER))
+ {
+ RawRead(&Value, sizeof(signed int));
+ Value = ConvertEndianessFromStorageToSystem(Value);
+ }
+ else
+ {
+ Value = 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_InputPersistenceBlock::Read(unsigned int & Value)
+{
+ if (CheckMarker(UINT_MARKER))
+ {
+ RawRead(&Value, sizeof(unsigned int));
+ Value = ConvertEndianessFromStorageToSystem(Value);
+ }
+ else
+ {
+ Value = 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_InputPersistenceBlock::Read(float & Value)
+{
+ if (CheckMarker(FLOAT_MARKER))
+ {
+ RawRead(&Value, sizeof(float));
+ Value = ConvertEndianessFromStorageToSystem(Value);
+ }
+ else
+ {
+ Value = 0.0f;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_InputPersistenceBlock::Read(bool & Value)
+{
+ if (CheckMarker(BOOL_MARKER))
+ {
+ unsigned int UIntBool;
+ RawRead(&UIntBool, sizeof(float));
+ UIntBool = ConvertEndianessFromStorageToSystem(UIntBool);
+ Value = UIntBool == 0 ? false : true;
+ }
+ else
+ {
+ Value = 0.0f;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_InputPersistenceBlock::Read(std::string & Value)
+{
+ Value = "";
+
+ if (CheckMarker(STRING_MARKER))
+ {
+ unsigned int Size;
+ Read(Size);
+
+ if (CheckBlockSize(Size))
+ {
+ Value = std::string(reinterpret_cast<const char *>(&*m_Iter), Size);
+ m_Iter += Size;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_InputPersistenceBlock::Read(vector<unsigned char> & Value)
+{
+ if (CheckMarker(BLOCK_MARKER))
+ {
+ unsigned int Size;
+ Read(Size);
+
+ if (CheckBlockSize(Size))
+ {
+ Value = vector<unsigned char>(m_Iter, m_Iter + Size);
+ m_Iter += Size;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_InputPersistenceBlock::RawRead(void * DestPtr, size_t Size)
+{
+ if (CheckBlockSize(Size))
+ {
+ memcpy(DestPtr, &*m_Iter, Size);
+ m_Iter += Size;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_InputPersistenceBlock::CheckBlockSize(int Size)
+{
+ if (m_Data.end() - m_Iter >= Size)
+ {
+ return true;
+ }
+ else
+ {
+ m_ErrorState = END_OF_DATA;
+ BS_LOG_ERRORLN("Unexpected end of persistence block.");
+ return false;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_InputPersistenceBlock::CheckMarker(unsigned char Marker)
+{
+ if (!IsGood() || !CheckBlockSize(1)) return false;
+
+ if (*m_Iter++ == Marker)
+ {
+ return true;
+ }
+ else
+ {
+ m_ErrorState = OUT_OF_SYNC;
+ BS_LOG_ERRORLN("Wrong type marker found in persistence block.");
+ return false;
+ }
+}
diff --git a/engines/sword25/kernel/inputpersistenceblock.h b/engines/sword25/kernel/inputpersistenceblock.h
new file mode 100755
index 0000000000..3a1335943b
--- /dev/null
+++ b/engines/sword25/kernel/inputpersistenceblock.h
@@ -0,0 +1,71 @@
+// -----------------------------------------------------------------------------
+// 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_INPUTPERSISTENCEBLOCK_H
+#define BS_INPUTPERSISTENCEBLOCK_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/persistenceblock.h"
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+
+// -----------------------------------------------------------------------------
+// Class declaration
+// -----------------------------------------------------------------------------
+
+class BS_InputPersistenceBlock : public BS_PersistenceBlock
+{
+public:
+ enum ErrorState
+ {
+ NONE,
+ END_OF_DATA,
+ OUT_OF_SYNC,
+ };
+
+ BS_InputPersistenceBlock(const void * Data, unsigned int DataLength);
+ virtual ~BS_InputPersistenceBlock();
+
+ void Read(signed int & Value);
+ void Read(unsigned int & Value);
+ void Read(float & Value);
+ void Read(bool & Value);
+ void Read(std::string & Value);
+ void Read(std::vector<unsigned char> & Value);
+
+ bool IsGood() const { return m_ErrorState == NONE; }
+ ErrorState GetErrorState() const { return m_ErrorState; }
+
+private:
+ bool CheckMarker(unsigned char Marker);
+ bool CheckBlockSize(int Size);
+ void RawRead(void * DestPtr, size_t Size);
+
+ std::vector<unsigned char> m_Data;
+ std::vector<unsigned char>::const_iterator m_Iter;
+ ErrorState m_ErrorState;
+};
+
+#endif
diff --git a/engines/sword25/kernel/kernel.cpp b/engines/sword25/kernel/kernel.cpp
new file mode 100755
index 0000000000..e6d8ec2872
--- /dev/null
+++ b/engines/sword25/kernel/kernel.cpp
@@ -0,0 +1,412 @@
+// -----------------------------------------------------------------------------
+// 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 WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <windows.h>
+#include <psapi.h>
+#pragma comment(lib, "psapi.lib")
+
+#include <math.h>
+#include <algorithm>
+
+#include "kernel.h"
+#include "timer.h"
+#include "service_ids.h"
+
+#include "gfx/graphicengine.h"
+#include "sfx/soundengine.h"
+#include "input/inputengine.h"
+#include "package/packagemanager.h"
+#include "script/script.h"
+#include "fmv/movieplayer.h"
+#include "persistenceservice.h"
+#include "cpuinfo.h"
+
+#define BS_LOG_PREFIX "KERNEL"
+
+BS_Kernel * BS_Kernel::_Instance = 0;
+
+// Konstruktion / Destruktion
+// --------------------------
+BS_Kernel::BS_Kernel() :
+ _pWindow(NULL),
+ _Running(false),
+ _pResourceManager(NULL),
+ _InitSuccess(false)
+{
+ // TODO:
+ // Messagebox ausgeben wenn nicht gelogged werden kann -> log.txt schreibgeschützt
+ BS_LOGLN("created.");
+
+ // CPU-Daten in die Log-Datei schreiben
+ const BS_CPUInfo & CI = BS_CPUInfo::GetInstance();
+ BS_LOGLN("CPU detected (vendor name: \"%s\", CPU name: \"%s\").", CI.GetVendorString().c_str(), CI.GetCPUName().c_str());
+ BS_LOGLN("CPU features: %s%s%s%s%s.",
+ CI.IsMMXSupported() ? "MMX" : "",
+ CI.IsSSESupported() ? " SSE" : "",
+ CI.IsSSE2Supported() ? " SSE2" : "",
+ CI.Is3DNowSupported() ? " 3DNow!" : "",
+ CI.Is3DNowExtSupported() ? " 3DNow!Ext" : "");
+
+ // Sicherstellen, dass der Prozessor über MMX verfügt
+ if (!CI.IsMMXSupported())
+ {
+ BS_LOG_ERRORLN("MMX support needed.");
+ return;
+ }
+
+ // Feststellen, ob der Timer unterstützt wird.
+ if (!BS_Timer::IsTimerAvaliable())
+ {
+ BS_LOG_ERRORLN("This machine doesn't support a performance counter.");
+ return;
+ }
+
+ // Die BS_SERVICE_TABLE auslesen und kernelinterne Strukturen vorbereiten
+ for (unsigned int i = 0; i < BS_SERVICE_COUNT; i++)
+ {
+ // Ist die Superclass schon registriert?
+ Superclass* pCurSuperclass = NULL;
+ std::vector<Superclass*>::iterator Iter;
+ for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter)
+ if ((*Iter)->GetIdentifier() == BS_SERVICE_TABLE[i].SuperclassIdentifier)
+ {
+ pCurSuperclass = *Iter;
+ break;
+ }
+
+ // Falls die Superclass noch nicht registriert war, wird dies jetzt gemacht
+ if (!pCurSuperclass)
+ _SuperclassList.push_back(new Superclass(this, BS_SERVICE_TABLE[i].SuperclassIdentifier));
+ }
+
+ // Fensterobjekt erstellen
+ _pWindow = BS_Window::CreateBSWindow(0,0,0,0,false);
+ if (!_pWindow)
+ {
+ BS_LOG_ERRORLN("Failed to create the window.");
+ }
+ else
+ BS_LOGLN("Window created.");
+
+ // Resource-Manager erstellen
+ _pResourceManager = new BS_ResourceManager(this);
+
+ // Random-Number-Generator initialisieren
+ srand(GetMilliTicks());
+
+ // Die Skriptengine initialisieren
+ // Die Skriptengine muss bereits von Kernel und nicht vom Benutzer gestartet werden, damit der Kernel seine Funktionen bei seiner Erzeugung
+ // registrieren kann.
+ BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(NewService("script", "lua"));
+ if (!pScript || !pScript->Init())
+ {
+ _InitSuccess = false;
+ return;
+ }
+
+ // Scriptbindings des Kernels registrieren
+ if (!_RegisterScriptBindings())
+ {
+ BS_LOG_ERRORLN("Script bindings could not be registered.");
+ _InitSuccess = false;
+ return;
+ }
+ BS_LOGLN("Script bindings registered.");
+
+ _InitSuccess = true;
+}
+
+BS_Kernel::~BS_Kernel()
+{
+ // Services in umgekehrter Reihenfolge der Erstellung endladen.
+ while (!_ServiceCreationOrder.empty())
+ {
+ Superclass * superclass = GetSuperclassByIdentifier(_ServiceCreationOrder.top());
+ if (superclass) superclass->DisconnectService();
+ _ServiceCreationOrder.pop();
+ }
+
+ // Superclasslist leeren
+ while (_SuperclassList.size())
+ {
+ delete _SuperclassList.back();
+ _SuperclassList.pop_back();
+ }
+
+ // Fensterobjekt freigeben
+ delete _pWindow;
+ BS_LOGLN("Window destroyed.");
+
+ // Resource-Manager freigeben
+ delete _pResourceManager;
+
+ BS_LOGLN("destroyed.");
+}
+
+// Service Methoden
+// ----------------
+BS_Kernel::Superclass::Superclass (BS_Kernel* pKernel, const std::string& Identifier) :
+ _pKernel(pKernel),
+ _Identifier(Identifier),
+ _ServiceCount(0),
+ _ActiveService(NULL)
+{
+ for (unsigned int i = 0; i < BS_SERVICE_COUNT; i++)
+ if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier)
+ _ServiceCount++;
+}
+
+BS_Kernel::Superclass::~Superclass()
+{
+ DisconnectService();
+}
+
+std::string BS_Kernel::Superclass::GetServiceIdentifier(unsigned int Number)
+{
+ if (Number > _ServiceCount) return NULL;
+
+ unsigned int CurServiceOrd = 0;
+ for (unsigned int i = 0; i < BS_SERVICE_COUNT; i++)
+ {
+ if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier)
+ if (Number == CurServiceOrd)
+ return BS_SERVICE_TABLE[i].ServiceIdentifier;
+ else
+ CurServiceOrd++;
+ }
+
+ return std::string("");
+}
+
+BS_Service* BS_Kernel::Superclass::NewService(const std::string& ServiceIdentifier)
+{
+ for (unsigned int i = 0; i < BS_SERVICE_COUNT; i++)
+ if (BS_SERVICE_TABLE[i].SuperclassIdentifier == _Identifier &&
+ BS_SERVICE_TABLE[i].ServiceIdentifier == ServiceIdentifier)
+ {
+ BS_Service* NewService = BS_SERVICE_TABLE[i].CreateMethod(_pKernel);
+
+ if (NewService)
+ {
+ DisconnectService();
+ BS_LOGLN("Service '%s' created from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
+ _ActiveService = NewService;
+ _ActiveServiceName = BS_SERVICE_TABLE[i].ServiceIdentifier;
+ return _ActiveService;
+ }
+ else
+ {
+ BS_LOG_ERRORLN("Failed to create service '%s' from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
+ return NULL;
+ }
+ }
+
+ BS_LOG_ERRORLN("Service '%s' is not avaliable from superclass '%s'.", ServiceIdentifier.c_str(), _Identifier.c_str());
+ return NULL;
+}
+
+bool BS_Kernel::Superclass::DisconnectService()
+{
+ if (_ActiveService)
+ {
+ delete _ActiveService;
+ _ActiveService = 0;
+ BS_LOGLN("Active service '%s' disconnected from superclass '%s'.", _ActiveServiceName.c_str(), _Identifier.c_str());
+ return true;
+ }
+
+ return false;
+}
+
+BS_Kernel::Superclass* BS_Kernel::GetSuperclassByIdentifier(const std::string & Identifier)
+{
+ std::vector<Superclass*>::iterator Iter;
+ for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter)
+ {
+ if ((*Iter)->GetIdentifier() == Identifier)
+ return *Iter;
+ }
+
+ // BS_LOG_ERRORLN("Superclass '%s' does not exist.", Identifier.c_str());
+ return NULL;
+}
+
+unsigned int BS_Kernel::GetSuperclassCount()
+{
+ return _SuperclassList.size();
+}
+
+std::string BS_Kernel::GetSuperclassIdentifier(unsigned int Number)
+{
+ if (Number > _SuperclassList.size()) return NULL;
+
+ unsigned int CurSuperclassOrd = 0;
+ std::vector<Superclass*>::iterator Iter;
+ for (Iter = _SuperclassList.begin(); Iter != _SuperclassList.end(); ++Iter)
+ {
+ if (CurSuperclassOrd == Number)
+ return ((*Iter)->GetIdentifier());
+
+ CurSuperclassOrd++;
+ }
+
+ return std::string("");
+}
+
+unsigned int BS_Kernel::GetServiceCount(const std::string & SuperclassIdentifier)
+{
+ Superclass* pSuperclass;
+ if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return 0;
+
+ return pSuperclass->GetServiceCount();
+
+}
+
+std::string BS_Kernel::GetServiceIdentifier(const std::string & SuperclassIdentifier, unsigned int Number)
+{
+ Superclass* pSuperclass;
+ if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
+
+ return (pSuperclass->GetServiceIdentifier(Number));
+}
+
+BS_Service* BS_Kernel::NewService(const std::string& SuperclassIdentifier, const std::string& ServiceIdentifier)
+{
+ Superclass* pSuperclass;
+ if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
+
+ // Die Reihenfolge merken, in der Services erstellt werden, damit sie später in umgekehrter Reihenfolge entladen werden können.
+ _ServiceCreationOrder.push(SuperclassIdentifier);
+
+ return pSuperclass->NewService(ServiceIdentifier);
+}
+
+bool BS_Kernel::DisconnectService(const std::string& SuperclassIdentifier)
+{
+ Superclass* pSuperclass;
+ if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return false;
+
+ return pSuperclass->DisconnectService();
+}
+
+BS_Service* BS_Kernel::GetService(const std::string& SuperclassIdentifier)
+{
+ Superclass* pSuperclass;
+ if (!(pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier))) return NULL;
+
+ return (pSuperclass->GetActiveService());
+}
+
+std::string BS_Kernel::GetActiveServiceIdentifier(const std::string& SuperclassIdentifier)
+{
+ Superclass * pSuperclass = GetSuperclassByIdentifier(SuperclassIdentifier);
+ if (!pSuperclass) return std::string("");
+
+ return (pSuperclass->GetActiveServiceName());
+}
+
+// -----------------------------------------------------------------------------
+
+int BS_Kernel::GetRandomNumber(int Min, int Max)
+{
+ BS_ASSERT(Min <= Max);
+ unsigned int MaxInternal = (Min - Max + 1) < 0 ? - (Min - Max + 1) : (Min - Max + 1);
+ return (rand() % MaxInternal) + Min;
+}
+
+// Timer Methoden
+// --------------
+unsigned int BS_Kernel::GetMilliTicks()
+{
+ return BS_Timer::GetMilliTicks();
+}
+
+uint64_t BS_Kernel::GetMicroTicks()
+{
+ return BS_Timer::GetMicroTicks();
+}
+
+// Sonstige Methoden
+// -----------------
+
+size_t BS_Kernel::GetUsedMemory()
+{
+ PROCESS_MEMORY_COUNTERS pmc;
+ pmc.cb = sizeof(pmc);
+ if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
+ {
+ return pmc.WorkingSetSize;
+ }
+ else
+ {
+ BS_LOG_ERRORLN("Call to GetProcessMemoryInfo() failed. Error code: %d", GetLastError());
+ return 0;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+BS_GraphicEngine * BS_Kernel::GetGfx()
+{
+ return static_cast<BS_GraphicEngine *>(GetService("gfx"));
+}
+
+// -----------------------------------------------------------------------------
+
+BS_SoundEngine * BS_Kernel::GetSfx()
+{
+ return static_cast<BS_SoundEngine *>(GetService("sfx"));
+}
+
+// -----------------------------------------------------------------------------
+
+BS_InputEngine * BS_Kernel::GetInput()
+{
+ return static_cast<BS_InputEngine *>(GetService("input"));
+}
+
+// -----------------------------------------------------------------------------
+
+BS_PackageManager * BS_Kernel::GetPackage()
+{
+ return static_cast<BS_PackageManager *>(GetService("package"));
+}
+
+// -----------------------------------------------------------------------------
+
+BS_ScriptEngine * BS_Kernel::GetScript()
+{
+ return static_cast<BS_ScriptEngine *>(GetService("script"));
+}
+
+// -----------------------------------------------------------------------------
+
+BS_MoviePlayer * BS_Kernel::GetFMV()
+{
+ return static_cast<BS_MoviePlayer *>(GetService("fmv"));
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_Kernel::Sleep(unsigned int Msecs) const
+{
+ ::Sleep(Msecs);
+}
diff --git a/engines/sword25/kernel/kernel.h b/engines/sword25/kernel/kernel.h
new file mode 100755
index 0000000000..539ce7a9fb
--- /dev/null
+++ b/engines/sword25/kernel/kernel.h
@@ -0,0 +1,344 @@
+// -----------------------------------------------------------------------------
+// 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_Kernel
+ ---------
+ Dies ist die Hauptklasse der Engine.
+ Diese Klasse erzeugt und verwaltet alle anderen Enginelemente, wie Soundengine, Graphikengine...
+ Es ist nicht notwendig alle Enginenelemente einzeln freizugeben, dieses wird von der Kernelklasse übernommen.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef _BS_KERNEL_H
+#define _BS_KERNEL_H
+
+// Includes
+#include "memlog_off.h"
+#include <vector>
+#include <stack>
+#include <string>
+#include "memlog_on.h"
+
+#include "common.h"
+#include "bs_stdint.h"
+#include "window.h"
+#include "resmanager.h"
+
+
+// Klassendefinition
+class BS_Service;
+class BS_GraphicEngine;
+class BS_ScriptEngine;
+class BS_SoundEngine;
+class BS_InputEngine;
+class BS_PackageManager;
+class BS_MoviePlayer;
+
+/**
+ @brief Dies ist die Hauptklasse der Engine.
+
+ Diese Klasse erzeugt und verwaltet alle anderen Engineelemente, wie Soundengine, Graphikengine...<br>
+ Es ist nicht notwendig alle Enginenelemente einzeln freizugeben, dieses wird von der Kernelklasse übernommen.
+*/
+class BS_Kernel
+{
+public:
+ // Fenster Methoden
+ // ----------------
+ /**
+ @brief Gibt einen Pointer auf das Fensterobjekt zurück.
+ @return Gibt einen Pointer auf das Fensterobjekt zurück.
+ */
+ BS_Window* GetWindow() {return _pWindow; }
+
+ // Service Methoden
+ // ----------------
+
+ /**
+ @brief Erzeugt einen neuen Service der angegebenen Superclass mit dem übergebenen Identifier.
+ @param SuperclassIdentifier der Name der Superclass des Services<br>
+ z.B: "sfx", "gfx", "package" ...
+ @param ServiceIdentifier der Name des Services<br>
+ Für die Superclass "sfx" könnten das z.B. "fmod" oder "directsound" sein.
+ @return Gibt einen Pointer auf den Service zurück, oder NULL wenn der Service nicht erstellt werden konnte.
+ @remark Alle Services müssen in service_ids.h eingetragen sein, sonst können sie hier nicht erstellt werden.
+ */
+ BS_Service* NewService(const std::string & SuperclassIdentifier, const std::string & ServiceIdentifier);
+ /**
+ @brief Beendet den aktuellen Service einer Superclass.
+ @param SuperclassIdentfier der Name der Superclass dessen aktiver Service beendet werden soll<br>
+ z.B: "sfx", "gfx", "package" ...
+ @return Gibt bei Erfolg true zurück und false wenn die Superclass nicht existiert oder wenn kein Service aktiv war.
+ */
+ bool DisconnectService(const std::string & SuperclassIdentifier);
+
+ /**
+ @brief Gibt einen Pointer auf das momentan aktive Serviceobjekt einer Superclass zurück.
+ @param SuperclassIdentfier der Name der Superclass<br>
+ z.B: "sfx", "gfx", "package" ...
+ @return Gibt einen Pointer auf den Service zurück, oder NULL wenn kein Service aktiv war.
+ */
+ BS_Service* GetService(const std::string& SuperclassIdentifier);
+
+ /**
+ @brief Gibt den Namen des aktuell aktiven Serviceobjektes einer Superclass zurück.
+ @param SuperclassIdentfier der Name der Superclass<br>
+ z.B: "sfx", "gfx", "package" ...
+ @return Gibt den Namen des Serviceobjektes zurück, oder einen leeren String, wenn ein Fehler aufgetreten ist.
+ */
+ std::string GetActiveServiceIdentifier(const std::string& SuperclassIdentifier);
+
+ /**
+ @brief Gibt die Anzahl der Registrierten Superclasses zurück.
+ @return Gibt die Anzahl der Registrierten Superclasses zurück.
+ */
+ unsigned int GetSuperclassCount();
+
+ // Gibt den Identifier der mit Number bezeichneten Superclass zurück
+ /**
+ @brief Gibt den Identifier einer Superclass zurück.
+ @param Number die Nummer der Superclass, dessen Bezeichner man erfahren möchte<br>
+ Hierbei ist zu beachten, dass die erste Superclass die Nummer 0 erhält. Number muss also eine Zahl zwischen
+ 0 und GetSuperclassCount() - 1 sein.
+ @return Gibt den Identifier der Superclass zurück.
+ @remark Die Anzahl der Superclasses kann man mit GetSuperclassCount() erfahren.
+ */
+ std::string GetSuperclassIdentifier(unsigned int Number);
+
+ // Gibt die Anzahl der für die mit SuperclassIdentifier bezeichneten Superclass vorhandenen
+ // Services zurück
+ /**
+ @brief Gibt die Anzahl an Services zurück, die in einer Superclass registriert sind.
+ @param SuperclassIdentifier der Name der Superclass<br>
+ z.B: "sfx", "gfx", "package" ...
+ @return Gibt die Anzahl an Services zurück, die in der Superclass registriert sind.
+ */
+ unsigned int GetServiceCount(const std::string & SuperclassIdentifier);
+
+ /**
+ @brief Gibt den Identifier eines Services in einer Superclass zurück.
+ @param SuperclassIdentifier der Name der Superclass<br>
+ z.B: "sfx", "gfx", "package" ...
+ @param Number die Nummer des Services, dessen Bezeichner man erfahren will.<br>
+ Hierbei ist zu beachten, dass der erste Service die Nummer 0 erhält. Number muss also eine Zahl zwischen
+ 0 und GetServiceCount() - 1 sein.
+ @return Gibt den Identifier des Services zurück
+ @remark Die Anzahl der Services in einer Superclass kann man mit GetServiceCount() erfahren.
+ */
+ std::string GetServiceIdentifier(const std::string & SuperclassIdentifier, unsigned int Number);
+ /**
+ @brief Gibt die vergangene Zeit seit dem Systemstart in Millisekunden zurück.
+ */
+ unsigned int GetMilliTicks();
+ /**
+ @brief Gibt die vergangene Zeit seit dem Systemstart in Microsekunden zurück.
+ @remark Diese Methode sollte nur verwendet werden, falls GetMilliTick() für den gewünschten Einsatz zu ungenau ist.
+ */
+ uint64_t GetMicroTicks();
+ /**
+ @brief Gibt an, ob die Konstruktion erfolgreich war.
+ @return Gibt true zurück, wenn die Konstruktion erfolgreich war.
+ */
+ bool GetInitSuccess() { return _InitSuccess; }
+ /**
+ @brief Gibt einen Pointer auf den BS_ResourceManager zurück.
+ */
+ BS_ResourceManager* GetResourceManager() { return _pResourceManager; }
+ /**
+ @brief Gibt zurück wie viel Speicher von diesem Prozess belegt ist.
+ */
+ size_t GetUsedMemory();
+ /**
+ @brief Gibt eine Zufallszahl zurück.
+ @param Min der minimale Wert, den die Zufallszahl haben darf
+ @param Max der maximale Wert, den die Zufallszahl haben darf
+ @return Gibt eine Zufallszahl zurück, die zwischen Min und Max liegt.
+ */
+ int GetRandomNumber(int Min, int Max);
+ /**
+ @brief Gibt einen Pointer auf den aktiven Gfx-Service zurück oder NULL wenn kein Gfx-Service aktiv.
+ */
+ BS_GraphicEngine * GetGfx();
+ /**
+ @brief Gibt einen Pointer auf den aktiven Sfx-Service zurück oder NULL wenn kein Sfx-Service aktiv.
+ */
+ BS_SoundEngine * GetSfx();
+ /**
+ @brief Gibt einen Pointer auf den aktiven Input-Service zurück oder NULL wenn kein Input-Service aktiv.
+ */
+ BS_InputEngine * GetInput();
+ /**
+ @brief Gibt einen Pointer auf den aktiven Package-Service zurück oder NULL wenn kein Package-Service aktiv.
+ */
+ BS_PackageManager * GetPackage();
+ /**
+ @brief Gibt einen Pointer auf den aktiven Script-Service zurück oder NULL wenn kein Script-Service aktiv.
+ */
+ BS_ScriptEngine * GetScript();
+ /**
+ @brief Gibt einen Pointer auf den aktiven FMV-Service zurück oder NULL wenn kein FMV-Service aktiv.
+ */
+ BS_MoviePlayer * GetFMV();
+
+ /**
+ @brief Stoppt den Prozess für eine gewisse Zeit.
+ @param Msecs Zeit in Millisekunden, die der Prozess gestoppt werden soll.
+ @remark Es wird nicht garantiert, dass der Prozess genau nach der angegebenen Zeit wieder aktiv wird.
+ */
+ void Sleep(unsigned int Msecs) const;
+
+ /**
+ @brief Gibt das einzige Exemplar des Kernels zurück (Singleton).
+ */
+
+ static BS_Kernel * GetInstance()
+ {
+ if (!_Instance) _Instance = new BS_Kernel();
+ return _Instance;
+ }
+
+ /**
+ @brief Zerstört das einzige Exemplar des Kernels.
+ @remark Diese Methode darf nur zum Beenden des System aufgerufen werden. Nachfolgende Aufrufe sämtlicher Kernelmethoden liefern
+ undefinierte Ergebnisse.
+ */
+
+ static void DeleteInstance()
+ {
+ if (_Instance)
+ {
+ delete(_Instance);
+ _Instance = 0;
+ }
+ }
+
+ /**
+ @brief Löst eine Schutzverletzung aus.
+ @remark Diese Methode dient zum Testen des Crash-Handlings.
+ */
+ void Crash() const
+ {
+ __asm
+ {
+ xor eax, eax
+ mov [eax], 0
+ }
+ }
+
+private:
+
+ // -----------------------------------------------------------------------------
+ // Konstruktion / Destruktion
+ // Private da Singleton
+ // -----------------------------------------------------------------------------
+
+ BS_Kernel();
+ virtual ~BS_Kernel();
+
+ // -----------------------------------------------------------------------------
+ // Singleton-Exemplar
+ // -----------------------------------------------------------------------------
+ static BS_Kernel * _Instance;
+
+ // Service Daten
+ // -------------
+ class Superclass
+ {
+ private:
+ BS_Kernel* _pKernel;
+ unsigned int _ServiceCount;
+ std::string _Identifier;
+ BS_Service* _ActiveService;
+ std::string _ActiveServiceName;
+
+ public:
+ Superclass (BS_Kernel* pKernel, const std::string& Identifier);
+ ~Superclass();
+
+ unsigned int GetServiceCount() const { return _ServiceCount; }
+ std::string GetIdentifier() const { return _Identifier; }
+ BS_Service* GetActiveService() const { return _ActiveService; }
+ std::string GetActiveServiceName() const { return _ActiveServiceName; }
+ std::string GetServiceIdentifier(unsigned int Number);
+ BS_Service* NewService(const std::string& ServiceIdentifier);
+ bool DisconnectService();
+ };
+
+ std::vector<Superclass*> _SuperclassList;
+ std::stack<std::string> _ServiceCreationOrder;
+ Superclass* GetSuperclassByIdentifier(const std::string& Identifier);
+
+ bool _InitSuccess; // Gibt an, ob die Konstruktion erfolgreich war
+ bool _Running; // Gibt an, ob die Applikation im nächsten Durchlauf des Main-Loops noch weiterlaufen soll
+
+ // Fenster Variablen
+ // -----------------
+ BS_Window* _pWindow;
+
+ /*
+ // CPU-Feature Variablen und Methoden
+ // ----------------------------------
+ enum _CPU_FEATURES_BITMASKS
+ {
+ _MMX_BITMASK = (1 << 23),
+ _SSE_BITMASK = (1 << 25),
+ _SSE2_BITMASK = (1 << 26),
+ _3DNOW_BITMASK = (1 << 30),
+ _3DNOWEXT_BITMASK = (1 << 31)
+ };
+
+ bool _DetectCPU();
+
+ bool _MMXPresent;
+ bool _SSEPresent;
+ bool _SSE2Present;
+ bool _3DNowPresent;
+ bool _3DNowExtPresent;
+ CPU_TYPES _CPUType;
+ std::string _CPUVendorID;
+ */
+
+ // Resourcemanager
+ // ---------------
+ BS_ResourceManager* _pResourceManager;
+
+ bool _RegisterScriptBindings();
+};
+
+// Dies ist nur eine kleine Klasse, die die Daten eines Services verwaltet.
+// Ist ein wenig unschön, ich weiss, aber mit std::string ließ sich dass nicht mit einer
+// einfachen struct bewerkstelligen.
+class BS_ServiceInfo
+{
+public:
+ BS_ServiceInfo(const std::string& SuperclassIdentifier, const std::string& ServiceIdentifier, BS_Service* (*CreateMethod)(BS_Kernel*))
+ {
+ this->SuperclassIdentifier = SuperclassIdentifier;
+ this->ServiceIdentifier = ServiceIdentifier;
+ this->CreateMethod = CreateMethod;
+ };
+
+ std::string SuperclassIdentifier;
+ std::string ServiceIdentifier;
+ BS_Service* (*CreateMethod)(BS_Kernel*);
+};
+
+#endif
diff --git a/engines/sword25/kernel/kernel_script.cpp b/engines/sword25/kernel/kernel_script.cpp
new file mode 100755
index 0000000000..4436e05e55
--- /dev/null
+++ b/engines/sword25/kernel/kernel_script.cpp
@@ -0,0 +1,775 @@
+// -----------------------------------------------------------------------------
+// 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 "common.h"
+#include "kernel.h"
+#include "filesystemutil.h"
+#include "window.h"
+#include "resmanager.h"
+#include "persistenceservice.h"
+#include "wincodegenerator.h"
+#include "debug/debugtools.h"
+#include "script/script.h"
+#include "script/luabindhelper.h"
+
+// -----------------------------------------------------------------------------
+
+static int DisconnectService(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushboolean(L, pKernel->DisconnectService(luaL_checkstring(L, 1)));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetActiveServiceIdentifier(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushstring(L, pKernel->GetActiveServiceIdentifier(luaL_checkstring(L,1)).c_str());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSuperclassCount(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushnumber(L, pKernel->GetSuperclassCount());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSuperclassIdentifier(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushstring(L, pKernel->GetSuperclassIdentifier(static_cast<unsigned int>(luaL_checknumber(L,1))).c_str());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetServiceCount(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushnumber(L, pKernel->GetServiceCount(luaL_checkstring(L, 1)));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetServiceIdentifier(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushstring(L, pKernel->GetServiceIdentifier(luaL_checkstring(L, 1), static_cast<unsigned int>(luaL_checknumber(L, 2))).c_str());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetMilliTicks(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushnumber(L, pKernel->GetMilliTicks());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetTimer(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushnumber(L, static_cast<lua_Number>(pKernel->GetMicroTicks()) / 1000000.0);
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int StartService(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+
+ lua_pushbooleancpp(L, pKernel->NewService(luaL_checkstring(L, 1), luaL_checkstring(L, 2)) != NULL);
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int Sleep(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ pKernel->Sleep(static_cast<unsigned int>(luaL_checknumber(L, 1) * 1000));
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int Crash(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ pKernel->Crash();
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int ExecuteFile(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ScriptEngine * pSE = static_cast<BS_ScriptEngine *>(pKernel->GetService("script"));
+ BS_ASSERT(pSE);
+
+ lua_pushbooleancpp(L, pSE->ExecuteFile(luaL_checkstring(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetUserdataDirectory(lua_State * L)
+{
+ lua_pushstring(L, BS_FileSystemUtil::GetInstance().GetUserdataDirectory().c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetPathSeparator(lua_State * L)
+{
+ lua_pushstring(L, BS_FileSystemUtil::GetInstance().GetPathSeparator().c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int FileExists(lua_State * L)
+{
+ lua_pushbooleancpp(L, BS_FileSystemUtil::GetInstance().FileExists(luaL_checkstring(L, 1)));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int CreateDirectory(lua_State * L)
+{
+ lua_pushbooleancpp(L, BS_FileSystemUtil::GetInstance().CreateDirectory(luaL_checkstring(L, 1)));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetWinCode(lua_State * L)
+{
+ lua_pushstring(L, BS_WinCodeGenerator::GetWinCode().c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSubversionRevision(lua_State * L)
+{
+ lua_pushnumber(L, BS_Debugtools::GetSubversionRevision());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetUsedMemory(lua_State * L)
+{
+ lua_pushnumber(L, BS_Kernel::GetInstance()->GetUsedMemory());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static const char * KERNEL_LIBRARY_NAME = "Kernel";
+
+static const luaL_reg KERNEL_FUNCTIONS[] =
+{
+ "DisconnectService", DisconnectService,
+ "GetActiveServiceIdentifier", GetActiveServiceIdentifier,
+ "GetSuperclassCount", GetSuperclassCount,
+ "GetSuperclassIdentifier", GetSuperclassIdentifier,
+ "GetServiceCount", GetServiceCount,
+ "GetServiceIdentifier", GetServiceIdentifier,
+ "GetMilliTicks", GetMilliTicks,
+ "GetTimer", GetTimer,
+ "StartService", StartService,
+ "Sleep", Sleep,
+ "Crash", Crash,
+ "ExecuteFile", ExecuteFile,
+ "GetUserdataDirectory", GetUserdataDirectory,
+ "GetPathSeparator", GetPathSeparator,
+ "FileExists", FileExists,
+ "CreateDirectory", CreateDirectory,
+ "GetWinCode", GetWinCode,
+ "GetSubversionRevision", GetSubversionRevision,
+ "GetUsedMemory", GetUsedMemory,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static int IsVisible(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushbooleancpp(L, pWindow->IsVisible());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetVisible(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ pWindow->SetVisible(lua_tobooleancpp(L, 1));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetX(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushnumber(L, pWindow->GetX());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetY(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushnumber(L, pWindow->GetY());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetX(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ pWindow->SetX(static_cast<int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetY(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ pWindow->SetY(static_cast<int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetClientX(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushnumber(L, pWindow->GetClientX());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetClientY(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushnumber(L, pWindow->GetClientY());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetWidth(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushnumber(L, pWindow->GetWidth());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetHeight(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushnumber(L, pWindow->GetHeight());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetWidth(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ pWindow->SetWidth(static_cast<int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetHeight(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ pWindow->SetHeight(static_cast<int>(luaL_checknumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetTitle(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushstring(L, pWindow->GetTitle().c_str());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetTitle(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ pWindow->SetTitle(luaL_checkstring(L, 1));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int ProcessMessages(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushbooleancpp(L, pWindow->ProcessMessages());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int CloseWanted(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushbooleancpp(L, pWindow->CloseWanted());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int WaitForFocus(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushbooleancpp(L, pWindow->WaitForFocus());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int HasFocus(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_Window * pWindow = pKernel->GetWindow();
+ BS_ASSERT(pWindow);
+
+ lua_pushbooleancpp(L, pWindow->HasFocus());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static const char * WINDOW_LIBRARY_NAME = "Window";
+
+static const luaL_reg WINDOW_FUNCTIONS[] =
+{
+ "IsVisible", IsVisible,
+ "SetVisible", SetVisible,
+ "GetX", GetX,
+ "SetX", SetX,
+ "GetY", GetY,
+ "SetY", SetY,
+ "GetClientX", GetClientX,
+ "GetClientY", GetClientY,
+ "GetWidth", GetWidth,
+ "GetHeight", GetHeight,
+ "SetWidth", SetWidth,
+ "SetHeight", SetHeight,
+ "GetTitle", GetTitle,
+ "SetTitle", SetTitle,
+ "ProcessMessages", ProcessMessages,
+ "CloseWanted", CloseWanted,
+ "WaitForFocus", WaitForFocus,
+ "HasFocus", HasFocus,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static int PrecacheResource(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ResourceManager * pResource = pKernel->GetResourceManager();
+ BS_ASSERT(pResource);
+
+ lua_pushbooleancpp(L, pResource->PrecacheResource(luaL_checkstring(L, 1)));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int ForcePrecacheResource(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ResourceManager * pResource = pKernel->GetResourceManager();
+ BS_ASSERT(pResource);
+
+ lua_pushbooleancpp(L, pResource->PrecacheResource(luaL_checkstring(L, 1), true));
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetMaxMemoryUsage(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ResourceManager * pResource = pKernel->GetResourceManager();
+ BS_ASSERT(pResource);
+
+ lua_pushnumber(L, pResource->GetMaxMemoryUsage());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetMaxMemoryUsage(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ResourceManager * pResource = pKernel->GetResourceManager();
+ BS_ASSERT(pResource);
+
+ pResource->SetMaxMemoryUsage(static_cast<unsigned int>(lua_tonumber(L, 1)));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int EmptyCache(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ResourceManager * pResource = pKernel->GetResourceManager();
+ BS_ASSERT(pResource);
+
+ pResource->EmptyCache();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int IsLogCacheMiss(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ResourceManager * pResource = pKernel->GetResourceManager();
+ BS_ASSERT(pResource);
+
+ lua_pushbooleancpp(L, pResource->IsLogCacheMiss());
+
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SetLogCacheMiss(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ResourceManager * pResource = pKernel->GetResourceManager();
+ BS_ASSERT(pResource);
+
+ pResource->SetLogCacheMiss(lua_tobooleancpp(L, 1));
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static int DumpLockedResources(lua_State * L)
+{
+ BS_Kernel * pKernel = BS_Kernel::GetInstance();
+ BS_ASSERT(pKernel);
+ BS_ResourceManager * pResource = pKernel->GetResourceManager();
+ BS_ASSERT(pResource);
+
+ pResource->DumpLockedResources();
+
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+static const char * RESOURCE_LIBRARY_NAME = "Resource";
+
+static const luaL_reg RESOURCE_FUNCTIONS[] =
+{
+ "PrecacheResource", PrecacheResource,
+ "ForcePrecacheResource", ForcePrecacheResource,
+ "GetMaxMemoryUsage", GetMaxMemoryUsage,
+ "SetMaxMemoryUsage", SetMaxMemoryUsage,
+ "EmptyCache", EmptyCache,
+ "IsLogCacheMiss", IsLogCacheMiss,
+ "SetLogCacheMiss", SetLogCacheMiss,
+ "DumpLockedResources", DumpLockedResources,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+static int ReloadSlots(lua_State * L)
+{
+ BS_PersistenceService::GetInstance().ReloadSlots();
+ lua_pushnil(L);
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSlotCount(lua_State * L)
+{
+ lua_pushnumber(L, BS_PersistenceService::GetInstance().GetSlotCount());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int IsSlotOccupied(lua_State * L)
+{
+ lua_pushbooleancpp(L, BS_PersistenceService::GetInstance().IsSlotOccupied(static_cast<unsigned int>(luaL_checknumber(L, 1)) - 1));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSavegameDirectory(lua_State * L)
+{
+ lua_pushstring(L, BS_PersistenceService::GetInstance().GetSavegameDirectory().c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int IsSavegameCompatible(lua_State * L)
+{
+ lua_pushbooleancpp(L, BS_PersistenceService::GetInstance().IsSavegameCompatible(static_cast<unsigned int>(luaL_checknumber(L, 1)) - 1));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSavegameDescription(lua_State * L)
+{
+ lua_pushstring(L, BS_PersistenceService::GetInstance().GetSavegameDescription(static_cast<unsigned int>(luaL_checknumber(L, 1)) - 1).c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetSavegameFilename(lua_State * L)
+{
+ lua_pushstring(L, BS_PersistenceService::GetInstance().GetSavegameFilename(static_cast<unsigned int>(luaL_checknumber(L, 1)) - 1).c_str());
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int LoadGame(lua_State * L)
+{
+ lua_pushbooleancpp(L, BS_PersistenceService::GetInstance().LoadGame(static_cast<unsigned int>(luaL_checknumber(L, 1)) - 1));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static int SaveGame(lua_State * L)
+{
+ lua_pushbooleancpp(L, BS_PersistenceService::GetInstance().SaveGame(static_cast<unsigned int>(luaL_checknumber(L, 1)) - 1, luaL_checkstring(L, 2)));
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static const char * PERSISTENCE_LIBRARY_NAME = "Persistence";
+
+static const luaL_reg PERSISTENCE_FUNCTIONS[] =
+{
+ "ReloadSlots", ReloadSlots,
+ "GetSlotCount", GetSlotCount,
+ "IsSlotOccupied", IsSlotOccupied,
+ "GetSavegameDirectory", GetSavegameDirectory,
+ "IsSavegameCompatible", IsSavegameCompatible,
+ "GetSavegameDescription", GetSavegameDescription,
+ "GetSavegameFilename", GetSavegameFilename,
+ "LoadGame", LoadGame,
+ "SaveGame", SaveGame,
+ 0, 0,
+};
+
+// -----------------------------------------------------------------------------
+
+bool BS_Kernel::_RegisterScriptBindings()
+{
+ BS_ScriptEngine * pScript = static_cast<BS_ScriptEngine *>(GetService("script"));
+ BS_ASSERT(pScript);
+ lua_State * L = static_cast<lua_State *>(pScript->GetScriptObject());
+ BS_ASSERT(L);
+
+ if (!BS_LuaBindhelper::AddFunctionsToLib(L, KERNEL_LIBRARY_NAME, KERNEL_FUNCTIONS)) return false;
+ if (!BS_LuaBindhelper::AddFunctionsToLib(L, WINDOW_LIBRARY_NAME, WINDOW_FUNCTIONS)) return false;
+ if (!BS_LuaBindhelper::AddFunctionsToLib(L, RESOURCE_LIBRARY_NAME, RESOURCE_FUNCTIONS)) return false;
+ if (!BS_LuaBindhelper::AddFunctionsToLib(L, PERSISTENCE_LIBRARY_NAME, PERSISTENCE_FUNCTIONS)) return false;
+
+ return true;
+}
diff --git a/engines/sword25/kernel/log.cpp b/engines/sword25/kernel/log.cpp
new file mode 100755
index 0000000000..bf1d5147b1
--- /dev/null
+++ b/engines/sword25/kernel/log.cpp
@@ -0,0 +1,224 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string>
+
+#include "filesystemutil.h"
+#include "log.h"
+#include "debug/debugtools.h"
+
+// Konstanten
+static const char* BF_LOG_FILENAME = "log.txt";
+static const size_t LOG_BUFFERSIZE = 1024 * 16;
+
+// Logging soll nur stattfinden wenn es aktiviert ist
+#ifdef BS_ACTIVATE_LOGGING
+
+FILE* BS_Log::_LogFile = NULL;
+bool BS_Log::_LineBegin = true;
+const char* BS_Log::_Prefix = NULL;
+const char* BS_Log::_File = NULL;
+int BS_Log::_Line = 0;
+bool BS_Log::_AutoNewline = false;
+std::vector<BS_Log::LOG_LISTENER_CALLBACK> BS_Log::_LogListener;
+
+bool BS_Log::_CreateLog()
+{
+ // Logfile öffnen
+ BS_FileSystemUtil::GetInstance().CreateDirectory(BS_FileSystemUtil::GetInstance().GetUserdataDirectory());
+ _LogFile = fopen((BS_FileSystemUtil::GetInstance().GetUserdataDirectory() + "\\" + BF_LOG_FILENAME).c_str(), "w");
+
+ if (_LogFile)
+ {
+ // Sicherstellen, dass es beim Beenden geschlossen wird
+ atexit(_CloseLog);
+
+ // Titelzeile in das Logfile schreiben
+ Log("Broken Sword 2.5 Engine - Build: %s - %s - VersionID: %s\n", __DATE__, __TIME__, BS_Debugtools::GetVersionID());
+ Log("-----------------------------------------------------------------------------------------------------\n");
+
+ return true;
+ }
+
+ // Log-File konnte nicht erstellt werden
+ return false;
+}
+
+void BS_Log::_CloseLog()
+{
+ if (_LogFile) fclose(_LogFile);
+}
+
+void BS_Log::Log(const char* Format, ...)
+{
+ char Message[LOG_BUFFERSIZE];
+
+ // Nachricht erzeugen
+ va_list ArgList;
+ va_start(ArgList, Format);
+ _vsnprintf(Message, sizeof(Message), Format, ArgList);
+
+ // Nachricht loggen
+ _WriteLog(Message);
+
+ _FlushLog();
+}
+
+void BS_Log::LogPrefix(const char* Prefix, const char* Format, ...)
+{
+ char Message[LOG_BUFFERSIZE];
+ char ExtFormat[LOG_BUFFERSIZE];
+
+ // Falls die Ausgabe am Anfang einer neuen Zeile aufgehört hat, muss die neue Ausgabe mit dem Präfix
+ // beginnen
+ ExtFormat[0] = 0;
+ if (_LineBegin)
+ {
+ _snprintf(ExtFormat, sizeof(ExtFormat), "%s%s: ", ExtFormat, Prefix);
+ _LineBegin = false;
+ }
+ // Formatstring zeilenweise durchgehen und an jeden Zeilenanfang das Präfix setzen
+ for (;;)
+ {
+ const char* NextLine = strstr(Format, "\n");
+ if (!NextLine || *(NextLine + strlen("\n")) == 0)
+ {
+ _snprintf(ExtFormat, sizeof(ExtFormat), "%s%s", ExtFormat, Format);
+ if (NextLine) _LineBegin = true;
+ break;
+ }
+ else
+ {
+ strncat(ExtFormat, Format, (NextLine - Format) + strlen("\n"));
+ _snprintf(ExtFormat, sizeof(ExtFormat), "%s%s: ", ExtFormat, Prefix);
+ }
+
+ Format = NextLine + strlen("\n");
+ }
+
+ // Nachricht erzeugen
+ va_list ArgList;
+ va_start(ArgList, Format);
+ _vsnprintf(Message, sizeof(Message), ExtFormat, ArgList);
+
+ // Nachricht schreiben
+ _WriteLog(Message);
+
+ _FlushLog();
+}
+
+void BS_Log::LogDecorated(const char* Format, ...)
+{
+ // Nachricht erzeugen
+ char Message[LOG_BUFFERSIZE];
+ va_list ArgList;
+ va_start(ArgList, Format);
+ _vsnprintf(Message, sizeof(Message), Format, ArgList);
+
+ // Zweiten Prefix erzeugen, falls gewünscht
+ char SecondaryPrefix[1024];
+ if (_File && _Line)
+ _snprintf(SecondaryPrefix, sizeof(SecondaryPrefix), "(file: %s, line: %d) - ", _File, _Line);
+
+ // Nachricht zeilenweise ausgeben und an jeden Zeilenanfang das Präfix setzen
+ char* MessageWalker = Message;
+ for (;;)
+ {
+ char* NextLine = strstr(MessageWalker, "\n");
+ if (NextLine)
+ {
+ *NextLine = 0;
+ if (_LineBegin)
+ {
+ _WriteLog(_Prefix);
+ if (_File && _Line)
+ _WriteLog(SecondaryPrefix);
+ }
+ _WriteLog(MessageWalker);
+ _WriteLog("\n");
+ MessageWalker = NextLine + sizeof("\n") - 1;
+ _LineBegin = true;
+ }
+ else
+ {
+ if (_LineBegin)
+ {
+ _WriteLog(_Prefix);
+ if (_File && _Line)
+ _WriteLog(SecondaryPrefix);
+ }
+ _WriteLog(MessageWalker);
+ _LineBegin = false;
+ break;
+ }
+ }
+
+ // Falls gewünscht, wird ans Ende der Nachricht automatisch ein Newline angehängt.
+ if (_AutoNewline)
+ {
+ _WriteLog("\n");
+ _LineBegin = true;
+ }
+
+ // Pseudoparameter zurücksetzen
+ _Prefix = NULL;
+ _File = 0;
+ _Line = 0;
+ _AutoNewline = false;
+
+ _FlushLog();
+}
+
+int BS_Log::_WriteLog(const char* Message)
+{
+ if (!_LogFile) if (!_CreateLog()) return false;
+
+ std::vector<LOG_LISTENER_CALLBACK>::iterator Iter = _LogListener.begin();
+ for (; Iter != _LogListener.end(); ++Iter)
+ (*Iter)(Message);
+
+ fprintf(_LogFile, Message);
+
+ return true;
+}
+
+void BS_Log::_FlushLog()
+{
+ fflush(_LogFile);
+}
+
+void (*BS_LogPtr)(const char *, ...) = BS_Log::Log;
+extern "C"
+{
+ void BS_Log_C(const char* Message)
+ {
+ BS_LogPtr(Message);
+ }
+}
+
+#else
+
+extern "C"
+{
+ void BS_Log_C(const char* Message) {};
+}
+
+#endif
diff --git a/engines/sword25/kernel/log.h b/engines/sword25/kernel/log.h
new file mode 100755
index 0000000000..867b19d70e
--- /dev/null
+++ b/engines/sword25/kernel/log.h
@@ -0,0 +1,123 @@
+// -----------------------------------------------------------------------------
+// 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_LOG_H
+#define BS_LOG_H
+
+// Includes
+#include "memlog_off.h"
+#include <stdio.h>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include "memlog_on.h"
+
+#include "common.h"
+
+// Logging soll nur stattfinden wenn es aktiviert ist
+#ifdef BS_ACTIVATE_LOGGING
+
+// Logging-Makros
+#define BS_LOG BS_Log::SetPrefix(BS_LOG_PREFIX ": "), BS_Log::LogDecorated
+#define BS_LOGLN BS_Log::SetPrefix(BS_LOG_PREFIX ": "), BS_Log::SetAutoNewline(true), BS_Log::LogDecorated
+#define BS_LOG_WARNING BS_Log::SetPrefix(BS_LOG_PREFIX ": WARNING - "), BS_Log::LogDecorated
+#define BS_LOG_WARNINGLN BS_Log::SetPrefix(BS_LOG_PREFIX ": WARNING - "), BS_Log::SetAutoNewline(true), BS_Log::LogDecorated
+#define BS_LOG_ERROR BS_Log::SetPrefix(BS_LOG_PREFIX ": ERROR - "), BS_Log::LogDecorated
+#define BS_LOG_ERRORLN BS_Log::SetPrefix(BS_LOG_PREFIX ": ERROR - "), BS_Log::SetAutoNewline(true), BS_Log::LogDecorated
+#define BS_LOG_EXTERROR BS_Log::SetPrefix(BS_LOG_PREFIX ": ERROR "), BS_Log::SetFile(__FILE__), BS_Log::SetLine(__LINE__), BS_Log::LogDecorated
+#define BS_LOG_EXTERRORLN BS_Log::SetPrefix(BS_LOG_PREFIX ": ERROR "), BS_Log::SetFile(__FILE__), BS_Log::SetLine(__LINE__), BS_Log::SetAutoNewline(true), BS_Log::LogDecorated
+
+// Die Version der Logging-Klasse mit aktiviertem Logging
+class BS_Log
+{
+public:
+ static void Clear();
+ static void Log(const char* Format, ...);
+ static void LogPrefix(const char* Prefix, const char* Format, ...);
+ static void LogDecorated(const char* Format, ...);
+
+ static void SetPrefix(const char* Prefix) { _Prefix = Prefix; }
+ static void SetFile(const char* File) { _File = File; }
+ static void SetLine(int Line) { _Line = Line; }
+ static void SetAutoNewline(bool AutoNewline) { _AutoNewline = AutoNewline; }
+
+ typedef void (*LOG_LISTENER_CALLBACK)(const char *);
+ static void RegisterLogListener(LOG_LISTENER_CALLBACK Callback) { _LogListener.push_back(Callback); }
+ static bool IsListenerRegistered(LOG_LISTENER_CALLBACK Callback) { return std::find(_LogListener.begin(), _LogListener.end(), Callback) != _LogListener.end(); }
+
+private:
+ static FILE* _LogFile;
+ static bool _LineBegin;
+ static const char* _Prefix;
+ static const char* _File;
+ static int _Line;
+ static bool _AutoNewline;
+ static std::vector<LOG_LISTENER_CALLBACK> _LogListener;
+
+ static bool _CreateLog();
+ static void _CloseLog();
+
+ static int _WriteLog(const char* Message);
+ static void _FlushLog();
+};
+
+// Hilfsfunktion, die es C-Funktionen ermöglicht zu loggen (wird für Lua gebraucht).
+extern "C"
+{
+ void BS_Log_C(const char* Message);
+}
+
+#else
+
+// Logging-Makros
+#define BS_LOG
+#define BS_LOGLN
+#define BS_LOG_WARNING
+#define BS_LOG_WARNINGLN
+#define BS_LOG_ERROR
+#define BS_LOG_ERRORLN
+#define BS_LOG_EXTERROR
+#define BS_LOG_EXTERRORLN
+
+// Die Version der Logging-Klasse mit deaktiviertem Logging
+class BS_Log
+{
+public:
+ // Die Log Funktionen werden zu do-nothing Funktionen und wird daher vom Compiler (hoffentlich) rausoptimiert
+ static void Log(const char* Text, ...) {};
+ static void LogPrefix(const char* Prefix, const char* Format, ...) {};
+ static void LogDecorated(const char* Format, ...) {};
+
+ static void SetPrefix(const char* Prefix) {};
+ static void SetFile(const char* File) {};
+ static void SetLine(int Line) {};
+ static void SetAutoNewline(bool AutoNewline) {};
+
+ typedef void (*LOG_LISTENER_CALLBACK)(const char *);
+ static void RegisterLogListener(LOG_LISTENER_CALLBACK Callback) {};
+};
+
+extern "C"
+{
+ void BS_Log_C(const char* Message);
+}
+
+#endif
+
+#endif
diff --git a/engines/sword25/kernel/md5.cpp b/engines/sword25/kernel/md5.cpp
new file mode 100755
index 0000000000..a336f3ab61
--- /dev/null
+++ b/engines/sword25/kernel/md5.cpp
@@ -0,0 +1,385 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// The code in this file is based in part on code from Aladdin
+// Enterprises released under the following terms:
+//
+// Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+//
+// L. Peter Deutsch
+// ghost@aladdin.com
+
+#include "md5.h"
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+BS_MD5::BS_MD5()
+{
+ md5_init(&m_state);
+}
+
+void BS_MD5::Update(const unsigned char * Buffer, unsigned int Length)
+{
+ md5_append(&m_state, Buffer, Length);
+}
+
+void BS_MD5::GetDigest(unsigned char Digest[16])
+{
+ md5_finish(&m_state, Digest);
+}
diff --git a/engines/sword25/kernel/md5.h b/engines/sword25/kernel/md5.h
new file mode 100755
index 0000000000..d2ac60afc8
--- /dev/null
+++ b/engines/sword25/kernel/md5.h
@@ -0,0 +1,56 @@
+// -----------------------------------------------------------------------------
+// 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_MD5_H
+#define BS_MD5_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/bs_stdint.h"
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+typedef uint8_t md5_byte_t; /* 8-bit byte */
+typedef uint32_t md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+class BS_MD5
+{
+public:
+ BS_MD5();
+
+ void Update(const unsigned char * Buffer, unsigned int Length);
+ void GetDigest(unsigned char Digest[16]);
+
+private:
+ md5_state_t m_state;
+};
+
+#endif
diff --git a/engines/sword25/kernel/memleaks.cpp b/engines/sword25/kernel/memleaks.cpp
new file mode 100755
index 0000000000..646465f5b2
--- /dev/null
+++ b/engines/sword25/kernel/memleaks.cpp
@@ -0,0 +1,130 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#ifdef BS_MEMLOG
+
+// Die folgende Zeile stellt sicher, dass alle Objekte in dieser Datei vor allen anderen erstellt und nach allen anderen
+// zerstört werden.
+// Damit wird sichergestellt, dass z.B. Singletons nicht fälschlicherweise als Memory-Leaks erkannt werden.
+// TODO Visual C++ 8 kommt mit der aktuellen Implementation nicht klar und stürzt sowohl beim Start aus auch beim
+// Beenden ab. Es muss eine Alternativimplementation her. An sichersten ist es wohl, wenn gar keine STL-Objekte benutzt
+// werden.
+// #pragma warning (disable : 4074)
+// #pragma init_seg(compiler)
+
+#include "filesystemutil.h"
+
+#include "memlog_off.h"
+#include <vector>
+#include <algorithm>
+#include <string>
+
+#include <stdio.h>
+#include <string.h>
+
+typedef struct
+{
+ unsigned int address;
+ unsigned int size;
+ std::string file;
+ unsigned int line;
+} ALLOC_INFO;
+
+static const char * MEMLEAK_LOG_FILE = "memory_leaks.txt";
+static const unsigned int BUCKET_COUNT = 1021;
+std::vector< std::vector<ALLOC_INFO> > TrackData(BUCKET_COUNT);
+
+static unsigned int TotalSize = 0;
+
+// Diese Klasse stellt sicher, dass beim Programmende, das Memory-Leak Log geschrieben wird.
+static class LeakDumper
+{
+public:
+ LeakDumper() : OutputFilename(BS_FileSystemUtil::GetInstance().GetUserdataDirectory() + "\\" + MEMLEAK_LOG_FILE)
+ {
+ // Sicherstellen, dass das Ausgabeverzeichnis für die Datei existiert.
+ BS_FileSystemUtil::GetInstance().CreateDirectory(BS_FileSystemUtil::GetInstance().GetUserdataDirectory());
+ }
+
+ ~LeakDumper()
+ {
+ DumpUnfreed(OutputFilename.c_str());
+ }
+
+ std::string OutputFilename;
+} LeakDumperInstance;
+
+void DumpUnfreed(const char * OutputFilename)
+{
+ FILE * Log = fopen(OutputFilename, "w");
+ fputs("MEMORY LEAK REPORT:\n----------------------\n", Log);
+ std::vector< std::vector<ALLOC_INFO> >::iterator BucketIter = TrackData.begin();
+ for (; BucketIter != TrackData.end(); ++BucketIter)
+ {
+ std::vector<ALLOC_INFO>::iterator Iter = (*BucketIter).begin();
+ for (; Iter != (*BucketIter).end(); ++Iter)
+ {
+ ALLOC_INFO & CurItem = (*Iter);
+ fprintf(Log, "%-50s LINE:%d ADDRESS:0x%x SIZE:%d\n",
+ CurItem.file.c_str(),
+ CurItem.line,
+ CurItem.address,
+ CurItem.size);
+ }
+ }
+
+ fprintf(Log, "----------------------\nTotal unfreed bytes: %d\n", TotalSize);
+
+ fclose(Log);
+}
+
+void AddTrack(unsigned int addr, unsigned int asize, const char *fname, unsigned int lnum)
+{
+ std::vector<ALLOC_INFO> & CurBucket = TrackData[(addr >> 3) % BUCKET_COUNT];
+ ALLOC_INFO Info;
+ Info.address = addr;
+ Info.size = asize;
+ Info.file = fname;
+ Info.line = lnum;
+ CurBucket.push_back(Info);
+
+ TotalSize += asize;
+}
+
+void RemoveTrack(unsigned int addr)
+{
+ if (addr != 0 && TrackData.size() == BUCKET_COUNT)
+ {
+ std::vector<ALLOC_INFO> & CurBucket = TrackData[(addr >> 3) % BUCKET_COUNT];
+ std::vector<ALLOC_INFO>::iterator Iter = CurBucket.begin();
+ for (; Iter != CurBucket.end(); ++Iter)
+ {
+ if ((*Iter).address == addr)
+ {
+ TotalSize -= (*Iter).size;
+
+ std::swap(*Iter, CurBucket.back());
+ CurBucket.pop_back();
+ return;
+ }
+ }
+ }
+}
+
+#endif
diff --git a/engines/sword25/kernel/memleaks.h b/engines/sword25/kernel/memleaks.h
new file mode 100755
index 0000000000..c4193e3b74
--- /dev/null
+++ b/engines/sword25/kernel/memleaks.h
@@ -0,0 +1,60 @@
+// -----------------------------------------------------------------------------
+// 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 BF_MEMLEAKS_H
+#define BF_MEMLEAKS_H
+
+#ifdef BS_MEMLOG
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4291)
+#endif
+
+#include "memlog_off.h"
+
+#include <malloc.h>
+
+void DumpUnfreed(const char * OutputFilename);
+void AddTrack(unsigned int addr, unsigned int asize, const char *fname, unsigned int lnum);
+void RemoveTrack(unsigned int addr);
+
+inline void * __cdecl operator new(unsigned int size, const char *file, int line)
+{
+ void *ptr = malloc(size);
+ if (ptr) AddTrack((unsigned int)ptr, size, file, line);
+ return(ptr);
+};
+
+inline void __cdecl operator delete(void *p)
+{
+ RemoveTrack((unsigned int)p);
+ free(p);
+};
+
+inline void __cdecl operator delete[](void *p)
+{
+ RemoveTrack((unsigned int)p);
+ free(p);
+};
+
+#endif
+
+#include "memlog_on.h"
+
+#endif
diff --git a/engines/sword25/kernel/memlog_off.h b/engines/sword25/kernel/memlog_off.h
new file mode 100755
index 0000000000..81acac991f
--- /dev/null
+++ b/engines/sword25/kernel/memlog_off.h
@@ -0,0 +1,27 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// Deaktivieren der Memory-Leak Detektion
+
+#ifdef BS_MEMLOG
+ #ifdef new
+ #undef new
+ #undef DEBUG_NEW
+ #endif
+#endif
diff --git a/engines/sword25/kernel/memlog_on.h b/engines/sword25/kernel/memlog_on.h
new file mode 100755
index 0000000000..7dbdd81330
--- /dev/null
+++ b/engines/sword25/kernel/memlog_on.h
@@ -0,0 +1,27 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+// Aktivieren der Memory-Leak Detektion
+
+#ifdef BS_MEMLOG
+ #ifndef DEBUG_NEW
+ #define DEBUG_NEW new(__FILE__, __LINE__)
+ #endif
+ #define new DEBUG_NEW
+#endif
diff --git a/engines/sword25/kernel/objectregistry.h b/engines/sword25/kernel/objectregistry.h
new file mode 100755
index 0000000000..e1c80c8b36
--- /dev/null
+++ b/engines/sword25/kernel/objectregistry.h
@@ -0,0 +1,182 @@
+// -----------------------------------------------------------------------------
+// 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_OBJECTREGISTRY_H
+#define BS_OBJECTREGISTRY_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/hashmap.h"
+
+// -----------------------------------------------------------------------------
+// Klassendeklaration
+// -----------------------------------------------------------------------------
+
+template<typename T>
+class BS_ObjectRegistry
+{
+public:
+ BS_ObjectRegistry() : m_NextHandle(1) {};
+
+ // -------------------------------------------------------------------------
+
+ unsigned int RegisterObject(T * ObjectPtr)
+ {
+ // Null-Pointer können nicht registriert werden.
+ if (ObjectPtr == 0)
+ {
+ LogErrorLn("Cannot register a null pointer.");
+ return 0;
+ }
+
+ // Falls das Objekt bereits registriert wurde, wird eine Warnung ausgeben und das Handle zurückgeben.
+ unsigned int Handle = FindHandleByPtr(ObjectPtr);
+ if (Handle != 0)
+ {
+ LogWarningLn("Tried to register a object that was already registered.");
+ return Handle;
+ }
+ // Ansonsten wird das Objekt in beide Maps eingetragen und das neue Handle zurückgeben.
+ else
+ {
+ m_Handle2PtrMap[m_NextHandle] = ObjectPtr;
+ m_Ptr2HandleMap[ObjectPtr] = m_NextHandle;
+
+ return m_NextHandle++;
+ }
+ }
+
+ // -----------------------------------------------------------------------------
+
+ unsigned int RegisterObject(T * ObjectPtr, unsigned int Handle)
+ {
+ // Null-Pointer und Null-Handle können nicht registriert werden.
+ if (ObjectPtr == 0 || Handle == 0)
+ {
+ LogErrorLn("Cannot register a null pointer or a null handle.");
+ return 0;
+ }
+
+ // Falls das Objekt bereits registriert wurde, wird ein Fehler ausgegeben und 0 zurückgeben.
+ unsigned int HandleTest = FindHandleByPtr(ObjectPtr);
+ if (HandleTest != 0)
+ {
+ LogErrorLn("Tried to register a object that was already registered.");
+ return 0;
+ }
+ // Falls das Handle bereits vergeben ist, wird ein Fehler ausgegeben und 0 zurückgegeben.
+ else if (FindPtrByHandle(Handle) != 0)
+ {
+ LogErrorLn("Tried to register a handle that is already taken.");
+ return 0;
+ }
+ // Ansonsten wird das Objekt in beide Maps eingetragen und das gewünschte Handle zurückgeben.
+ else
+ {
+ m_Handle2PtrMap[Handle] = ObjectPtr;
+ m_Ptr2HandleMap[ObjectPtr] = Handle;
+
+ // Falls das vergebene Handle größer oder gleich dem nächsten automatische vergebenen Handle ist, wird das nächste automatisch
+ // vergebene Handle erhöht.
+ if (Handle >= m_NextHandle) m_NextHandle = Handle + 1;
+
+ return Handle;
+ }
+ }
+
+ // -----------------------------------------------------------------------------
+
+ void DeregisterObject(T * ObjectPtr)
+ {
+ unsigned int Handle = FindHandleByPtr(ObjectPtr);
+
+ if (Handle != 0)
+ {
+ // Registriertes Objekt aus beiden Maps entfernen.
+ m_Handle2PtrMap.erase(FindHandleByPtr(ObjectPtr));
+ m_Ptr2HandleMap.erase(ObjectPtr);
+ }
+ else
+ {
+ LogWarningLn("Tried to remove a object that was not registered.");
+ }
+ }
+
+ // -----------------------------------------------------------------------------
+
+ T * ResolveHandle(unsigned int Handle)
+ {
+ // Zum Handle gehöriges Objekt in der Hash-Map finden.
+ T * ObjectPtr = FindPtrByHandle(Handle);
+
+ // Pointer zurückgeben. Im Fehlerfall ist dieser 0.
+ return ObjectPtr;
+ }
+
+ // -----------------------------------------------------------------------------
+
+ unsigned int ResolvePtr(T * ObjectPtr)
+ {
+ // Zum Pointer gehöriges Handle in der Hash-Map finden.
+ unsigned int Handle = FindHandleByPtr(ObjectPtr);
+
+ // Handle zurückgeben. Im Fehlerfall ist dieses 0.
+ return Handle;
+ }
+
+protected:
+ typedef BS_Hashmap<unsigned int, T *> HANDLE2PTR_MAP;
+ typedef BS_Hashmap<T *, unsigned int> PTR2HANDLE_MAP;
+
+ HANDLE2PTR_MAP m_Handle2PtrMap;
+ PTR2HANDLE_MAP m_Ptr2HandleMap;
+ unsigned int m_NextHandle;
+
+ // -----------------------------------------------------------------------------
+
+ T * FindPtrByHandle(unsigned int Handle)
+ {
+ // Zum Handle gehörigen Pointer finden.
+ HANDLE2PTR_MAP::const_iterator it = m_Handle2PtrMap.find(Handle);
+
+ // Pointer zurückgeben, oder, falls keiner gefunden wurde, 0 zurückgeben.
+ return (it != m_Handle2PtrMap.end()) ? it->second : 0;
+ }
+
+ // -----------------------------------------------------------------------------
+
+ unsigned int FindHandleByPtr(T * ObjectPtr)
+ {
+ // Zum Pointer gehöriges Handle finden.
+ PTR2HANDLE_MAP::const_iterator it = m_Ptr2HandleMap.find(ObjectPtr);
+
+ // Handle zurückgeben, oder, falls keines gefunden wurde, 0 zurückgeben.
+ return (it != m_Ptr2HandleMap.end()) ? it->second : 0;
+ }
+
+ // -----------------------------------------------------------------------------
+
+ virtual void LogErrorLn(const char * Message) const = 0;
+ virtual void LogWarningLn(const char * Message) const = 0;
+};
+
+#endif
diff --git a/engines/sword25/kernel/outputpersistenceblock.cpp b/engines/sword25/kernel/outputpersistenceblock.cpp
new file mode 100755
index 0000000000..37410caaec
--- /dev/null
+++ b/engines/sword25/kernel/outputpersistenceblock.cpp
@@ -0,0 +1,123 @@
+// -----------------------------------------------------------------------------
+// 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 "OUTPUTPERSISTENCEBLOCK"
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "outputpersistenceblock.h"
+
+// -----------------------------------------------------------------------------
+// Constants
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const unsigned int INITIAL_BUFFER_SIZE = 1024 * 64;
+}
+
+// -----------------------------------------------------------------------------
+// Construction / Destruction
+// -----------------------------------------------------------------------------
+
+BS_OutputPersistenceBlock::BS_OutputPersistenceBlock()
+{
+ m_Data.reserve(INITIAL_BUFFER_SIZE);
+}
+
+// -----------------------------------------------------------------------------
+// Writing
+// -----------------------------------------------------------------------------
+
+void BS_OutputPersistenceBlock::Write(signed int Value)
+{
+ WriteMarker(SINT_MARKER);
+ Value = ConvertEndianessFromSystemToStorage(Value);
+ RawWrite(&Value, sizeof(Value));
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OutputPersistenceBlock::Write(unsigned int Value)
+{
+ WriteMarker(UINT_MARKER);
+ Value = ConvertEndianessFromSystemToStorage(Value);
+ RawWrite(&Value, sizeof(Value));
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OutputPersistenceBlock::Write(float Value)
+{
+ WriteMarker(FLOAT_MARKER);
+ Value = ConvertEndianessFromSystemToStorage(Value);
+ RawWrite(&Value, sizeof(Value));
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OutputPersistenceBlock::Write(bool Value)
+{
+ WriteMarker(BOOL_MARKER);
+
+ unsigned int UIntBool = Value ? 1 : 0;
+ UIntBool = ConvertEndianessFromSystemToStorage(UIntBool);
+ RawWrite(&UIntBool, sizeof(UIntBool));
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OutputPersistenceBlock::Write(const std::string & String)
+{
+ WriteMarker(STRING_MARKER);
+
+ Write(String.size());
+ RawWrite(String.c_str(), String.size());
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OutputPersistenceBlock::Write(const void * BufferPtr, size_t Size)
+{
+ WriteMarker(BLOCK_MARKER);
+
+ Write(Size);
+ RawWrite(BufferPtr, Size);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OutputPersistenceBlock::WriteMarker(unsigned char Marker)
+{
+ m_Data.push_back(Marker);
+}
+
+// -----------------------------------------------------------------------------
+
+void BS_OutputPersistenceBlock::RawWrite(const void * DataPtr, size_t Size)
+{
+ if (Size > 0)
+ {
+ unsigned int OldSize = m_Data.size();
+ m_Data.resize(OldSize + Size);
+ memcpy(&m_Data[OldSize], DataPtr, Size);
+ }
+}
diff --git a/engines/sword25/kernel/outputpersistenceblock.h b/engines/sword25/kernel/outputpersistenceblock.h
new file mode 100755
index 0000000000..1f730769b8
--- /dev/null
+++ b/engines/sword25/kernel/outputpersistenceblock.h
@@ -0,0 +1,60 @@
+// -----------------------------------------------------------------------------
+// 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_OUTPUTPERSISTENCEBLOCK_H
+#define BS_OUTPUTPERSISTENCEBLOCK_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/persistenceblock.h"
+#include "kernel/memlog_off.h"
+#include <vector>
+#include "kernel/memlog_on.h"
+
+
+// -----------------------------------------------------------------------------
+// Class declaration
+// -----------------------------------------------------------------------------
+
+class BS_OutputPersistenceBlock : public BS_PersistenceBlock
+{
+public:
+ BS_OutputPersistenceBlock();
+
+ void Write(signed int Value);
+ void Write(unsigned int Value);
+ void Write(float Value);
+ void Write(bool Value);
+ void Write(const std::string & String);
+ void Write(const void * BufferPtr, size_t Size);
+
+ const void * GetData() const { return &m_Data[0]; }
+ unsigned int GetDataSize() const { return m_Data.size(); }
+
+private:
+ void WriteMarker(unsigned char Marker);
+ void RawWrite(const void * DataPtr, size_t Size);
+
+ std::vector<unsigned char> m_Data;
+};
+
+#endif
diff --git a/engines/sword25/kernel/persistable.h b/engines/sword25/kernel/persistable.h
new file mode 100755
index 0000000000..b1b8bd2c12
--- /dev/null
+++ b/engines/sword25/kernel/persistable.h
@@ -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
+// -----------------------------------------------------------------------------
+
+#ifndef BS_PERSISTABLE_H
+#define BS_PERSISTABLE_H
+
+class BS_OutputPersistenceBlock;
+class BS_InputPersistenceBlock;
+
+class BS_Persistable
+{
+public:
+ virtual ~BS_Persistable() {};
+
+ virtual bool Persist(BS_OutputPersistenceBlock & Writer) = 0;
+ virtual bool Unpersist(BS_InputPersistenceBlock & Reader) = 0;
+
+};
+
+#endif
diff --git a/engines/sword25/kernel/persistenceblock.h b/engines/sword25/kernel/persistenceblock.h
new file mode 100755
index 0000000000..4dda4388b7
--- /dev/null
+++ b/engines/sword25/kernel/persistenceblock.h
@@ -0,0 +1,112 @@
+// -----------------------------------------------------------------------------
+// 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_PERSISTENCEBLOCK_H
+#define BS_PERSISTENCEBLOCK_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+
+
+// -----------------------------------------------------------------------------
+// Class definition
+// -----------------------------------------------------------------------------
+
+class BS_PersistenceBlock
+{
+public:
+ static unsigned int GetSInt32Size() { return sizeof(signed int) + sizeof(unsigned char); }
+ static unsigned int GetUInt32Size() { return sizeof(unsigned int) + sizeof(unsigned char); }
+ static unsigned int GetFloat32Size() { return sizeof(float) + sizeof(unsigned char); }
+ static unsigned int GetBoolSize() { return sizeof(unsigned char) + sizeof(unsigned char); }
+ static unsigned int GetStringSize(const std::string & String) { return static_cast<unsigned int>(sizeof(unsigned int) + String.size() + sizeof(unsigned char)); }
+
+protected:
+ enum
+ {
+ SINT_MARKER,
+ UINT_MARKER,
+ FLOAT_MARKER,
+ STRING_MARKER,
+ BOOL_MARKER,
+ BLOCK_MARKER,
+ };
+
+ // -----------------------------------------------------------------------------
+ // Endianess Conversions
+ // -----------------------------------------------------------------------------
+ //
+ // Alles wird in Little Endian gespeichert.
+ // Auf Big Endian-Systemen muss die Bytereihenfolge daher vor dem Speichern und nach dem Einlesen gespeicherter Werte vertauscht werden.
+ //
+
+ template<typename T>
+ static T ConvertEndianessFromSystemToStorage(T Value)
+ {
+ if (IsBigEndian()) ReverseByteOrder(&Value);
+ return Value;
+ }
+
+ template<typename T>
+ static T ConvertEndianessFromStorageToSystem(T Value)
+ {
+ if (IsBigEndian()) ReverseByteOrder(&Value);
+ return Value;
+ }
+
+private:
+ static bool IsBigEndian()
+ {
+ unsigned int Dummy = 1;
+ unsigned char * DummyPtr = reinterpret_cast<unsigned char *>(&Dummy);
+ return DummyPtr[0] == 0;
+ }
+
+ template<typename T>
+ static void Swap(T & One, T & Two)
+ {
+ T Temp = One;
+ One = Two;
+ Two = Temp;
+ }
+
+ static void ReverseByteOrder(void * Ptr)
+ {
+ // Kehrt die Bytereihenfolge des 32-Bit Wortes um auf das Ptr zeigt.
+ unsigned char * CharPtr = static_cast<unsigned char *>(Ptr);
+ Swap(CharPtr[0], CharPtr[3]);
+ Swap(CharPtr[1], CharPtr[2]);
+ }
+};
+
+// -----------------------------------------------------------------------------
+// Compile time asserts
+// -----------------------------------------------------------------------------
+
+#define CTASSERT(ex) typedef char ctassert_type[(ex) ? 1 : -1];
+CTASSERT(sizeof(unsigned char) == 1);
+CTASSERT(sizeof(signed int) == 4);
+CTASSERT(sizeof(unsigned int) == 4);
+CTASSERT(sizeof(float) == 4);
+#undef CTASSERT
+
+#endif
diff --git a/engines/sword25/kernel/persistenceservice.cpp b/engines/sword25/kernel/persistenceservice.cpp
new file mode 100755
index 0000000000..51491a6c2b
--- /dev/null
+++ b/engines/sword25/kernel/persistenceservice.cpp
@@ -0,0 +1,459 @@
+// -----------------------------------------------------------------------------
+// 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.h"
+#include "persistenceservice.h"
+#include "inputpersistenceblock.h"
+#include "outputpersistenceblock.h"
+#include "filesystemutil.h"
+#include "gfx/graphicengine.h"
+#include "sfx/soundengine.h"
+#include "input/inputengine.h"
+#include "math/regionregistry.h"
+#include "script/script.h"
+#include "debug/debugtools.h"
+#include "util/zlib/zlib.h"
+
+#include "kernel/memlog_off.h"
+#include <sstream>
+#include <fstream>
+#include <algorithm>
+#include <locale>
+#include "kernel/memlog_on.h"
+
+using namespace std;
+
+#define BS_LOG_PREFIX "PERSISTENCESERVICE"
+
+// -----------------------------------------------------------------------------
+// Konstanten und Hilfsfunktionen
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const char * SAVEGAME_EXTENSION = ".b25s";
+ const char * SAVEGAME_DIRECTORY = "saves";
+ const char * FILE_MARKER = "BS25SAVEGAME";
+ const unsigned int SLOT_COUNT = 18;
+ const unsigned int FILE_COPY_BUFFER_SIZE = 1024 * 10;
+
+ // -------------------------------------------------------------------------
+
+ string GenerateSavegameFilename(unsigned int SlotID)
+ {
+ ostringstream oss;
+ oss << SlotID << SAVEGAME_EXTENSION;
+ return oss.str();
+ }
+
+ // -------------------------------------------------------------------------
+
+ string GenerateSavegamePath(unsigned int SlotID)
+ {
+ ostringstream oss;
+ oss << BS_PersistenceService::GetSavegameDirectory() << BS_FileSystemUtil::GetInstance().GetPathSeparator() << GenerateSavegameFilename(SlotID);
+ return oss.str();
+ }
+
+ // -------------------------------------------------------------------------
+
+ string FormatTimestamp(time_t Time)
+ {
+ // Zeitstempel in Einzelkomponenten auflösen.
+ tm * Timeinfo = localtime(&Time);
+
+ // Zeitangabe im lokalen Format in einen String-Stream schreiben.
+ locale Locale("");
+ ostringstream StringBuilder;
+ StringBuilder.imbue(Locale);
+ char * Pattern = "%x %X";
+ use_facet<time_put<char> >(Locale).put(StringBuilder,
+ StringBuilder, StringBuilder.fill(), Timeinfo, Pattern, Pattern + strlen(Pattern));
+
+ // Formatierten String zurückgeben.
+ return StringBuilder.str();
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Private Implementation (Pimpl-Pattern)
+// -----------------------------------------------------------------------------
+
+struct SavegameInformation
+{
+ bool IsOccupied;
+ bool IsCompatible;
+ string Description;
+ string Filename;
+ unsigned int GamedataLength;
+ unsigned int GamedataOffset;
+ unsigned int GamedataUncompressedLength;
+
+ SavegameInformation() { Clear(); }
+
+ void Clear()
+ {
+ IsOccupied = false;
+ IsCompatible = false;
+ Description = "";
+ Filename = "";
+ GamedataLength = 0;
+ GamedataOffset = 0;
+ GamedataUncompressedLength = 0;
+ }
+};
+
+struct BS_PersistenceService::Impl
+{
+ SavegameInformation m_SavegameInformations[SLOT_COUNT];
+
+ // -----------------------------------------------------------------------------
+
+ Impl()
+ {
+ ReloadSlots();
+ }
+
+ // -----------------------------------------------------------------------------
+
+ void ReloadSlots()
+ {
+ // Über alle Spielstanddateien iterieren und deren Infos einlesen.
+ for (unsigned int i = 0; i < SLOT_COUNT; ++i)
+ {
+ ReadSlotSavegameInformation(i);
+ }
+ }
+
+ void ReadSlotSavegameInformation(unsigned int SlotID)
+ {
+ // Aktuelle Slotinformationen in den Ausgangszustand versetzen, er wird im Folgenden neu gefüllt.
+ SavegameInformation & CurSavegameInfo = m_SavegameInformations[SlotID];
+ CurSavegameInfo.Clear();
+
+ // Den Dateinamen für den Spielstand des Slots generieren.
+ string Filename = GenerateSavegamePath(SlotID);
+
+ // Feststellen, ob eine Spielstanddatei dieses Namens existiert.
+ if (BS_FileSystemUtil::GetInstance().FileExists(Filename))
+ {
+ // Die Spielstanddatei öffnen.
+ ifstream File(Filename.c_str(), ifstream::binary);
+ if (File.good() && File.is_open())
+ {
+ // Die Headerdaten einlesen.
+ string StoredMarker, StoredVersionID;
+ File >> StoredMarker >> StoredVersionID >> CurSavegameInfo.GamedataLength >> CurSavegameInfo.GamedataUncompressedLength;
+
+ // Falls die Headerdaten gelesen werden konnten und der Marker stimmt, nehmen wir an eine gültige Spielstanddatei zu haben.
+ if (File.good() && StoredMarker == FILE_MARKER)
+ {
+ // Der Slot wird als belegt markiert.
+ CurSavegameInfo.IsOccupied = true;
+ // Speichern, ob der Spielstand kompatibel mit der aktuellen Engine-Version ist.
+ CurSavegameInfo.IsCompatible = (StoredVersionID == BS_Debugtools::GetVersionID());
+ // Dateinamen des Spielstandes speichern.
+ CurSavegameInfo.Filename = GenerateSavegameFilename(SlotID);
+ // Die Beschreibung des Spielstandes besteht aus einer textuellen Darstellung des Änderungsdatums der Spielstanddatei.
+ CurSavegameInfo.Description = FormatTimestamp(BS_FileSystemUtil::GetInstance().GetFileTime(Filename));
+ // Den Offset zu den gespeicherten Spieldaten innerhalb der Datei speichern.
+ // Dieses entspricht der aktuellen Position + 1, da nach der letzten Headerinformation noch ein Leerzeichen als trenner folgt.
+ CurSavegameInfo.GamedataOffset = static_cast<unsigned int>(File.tellg()) + 1;
+ }
+
+ }
+ }
+ }
+};
+
+// -----------------------------------------------------------------------------
+// Construction / Destruction
+// -----------------------------------------------------------------------------
+
+BS_PersistenceService & BS_PersistenceService::GetInstance()
+{
+ static BS_PersistenceService Instance;
+ return Instance;
+}
+
+// -----------------------------------------------------------------------------
+
+BS_PersistenceService::BS_PersistenceService() : m_impl(new Impl)
+{
+}
+
+// -----------------------------------------------------------------------------
+
+BS_PersistenceService::~BS_PersistenceService()
+{
+ delete m_impl;
+}
+
+// -----------------------------------------------------------------------------
+// Implementation
+// -----------------------------------------------------------------------------
+
+void BS_PersistenceService::ReloadSlots()
+{
+ m_impl->ReloadSlots();
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_PersistenceService::GetSlotCount()
+{
+ return SLOT_COUNT;
+}
+
+// -----------------------------------------------------------------------------
+
+std::string BS_PersistenceService::GetSavegameDirectory()
+{
+ return BS_FileSystemUtil::GetInstance().GetUserdataDirectory() + BS_FileSystemUtil::GetInstance().GetPathSeparator() + SAVEGAME_DIRECTORY;
+}
+
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ bool CheckSlotID(unsigned int SlotID)
+ {
+ // Überprüfen, ob die Slot-ID zulässig ist.
+ if (SlotID >= SLOT_COUNT)
+ {
+ BS_LOG_ERRORLN("Tried to access an invalid slot (%d). Only slot ids from 0 to %d are allowed.", SlotID, SLOT_COUNT - 1);
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PersistenceService::IsSlotOccupied(unsigned int SlotID)
+{
+ if (!CheckSlotID(SlotID)) return false;
+ return m_impl->m_SavegameInformations[SlotID].IsOccupied;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PersistenceService::IsSavegameCompatible(unsigned int SlotID)
+{
+ if (!CheckSlotID(SlotID)) return false;
+ return m_impl->m_SavegameInformations[SlotID].IsCompatible;
+}
+
+// -----------------------------------------------------------------------------
+
+string & BS_PersistenceService::GetSavegameDescription(unsigned int SlotID)
+{
+ static string EmptyString;
+ if (!CheckSlotID(SlotID)) return EmptyString;
+ return m_impl->m_SavegameInformations[SlotID].Description;
+}
+
+// -----------------------------------------------------------------------------
+
+string & BS_PersistenceService::GetSavegameFilename(unsigned int SlotID)
+{
+ static string EmptyString;
+ if (!CheckSlotID(SlotID)) return EmptyString;
+ return m_impl->m_SavegameInformations[SlotID].Filename;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PersistenceService::SaveGame(unsigned int SlotID, const std::string & ScreenshotFilename)
+{
+ // Überprüfen, ob die Slot-ID zulässig ist.
+ if (SlotID >= SLOT_COUNT)
+ {
+ BS_LOG_ERRORLN("Tried to save to an invalid slot (%d). Only slot ids form 0 to %d are allowed.", SlotID, SLOT_COUNT - 1);
+ return false;
+ }
+
+ // Dateinamen erzeugen.
+ string Filename = GenerateSavegamePath(SlotID).c_str();
+
+ try
+ {
+ // Sicherstellen, dass das Verzeichnis für die Spielstanddateien existiert.
+ BS_FileSystemUtil::GetInstance().CreateDirectory(GetSavegameDirectory());
+
+ // Spielstanddatei öffnen und die Headerdaten schreiben.
+ ofstream File(Filename.c_str(), ofstream::binary);
+ File << string(FILE_MARKER) << " " << string(BS_Debugtools::GetVersionID()) << " ";
+ if (!File.good())
+ {
+ BS_LOG_ERRORLN("Unable to write header data to savegame file \"%s\".", Filename.c_str());
+ throw 0;
+ }
+
+ // Alle notwendigen Module persistieren.
+ BS_OutputPersistenceBlock Writer;
+ bool Success = true;
+ Success &= BS_Kernel::GetInstance()->GetScript()->Persist(Writer);
+ Success &= BS_RegionRegistry::GetInstance().Persist(Writer);
+ Success &= BS_Kernel::GetInstance()->GetGfx()->Persist(Writer);
+ Success &= BS_Kernel::GetInstance()->GetSfx()->Persist(Writer);
+ Success &= BS_Kernel::GetInstance()->GetInput()->Persist(Writer);
+ if (!Success)
+ {
+ BS_LOG_ERRORLN("Unable to persist modules for savegame file \"%s\".", Filename.c_str());
+ throw 0;
+ }
+
+ // Daten komprimieren.
+ vector<unsigned char> CompressionBuffer(Writer.GetDataSize() + (Writer.GetDataSize() + 500) / 1000 + 12);
+ uLongf CompressedLength = CompressionBuffer.size();
+ if (compress2(&CompressionBuffer[0], &CompressedLength, reinterpret_cast<const Bytef *>(Writer.GetData()), Writer.GetDataSize(), 6) != Z_OK)
+ {
+ BS_LOG_ERRORLN("Unable to compress savegame data in savegame file \"%s\".", Filename.c_str());
+ throw 0;
+ }
+
+ // Länge der komprimierten Daten und der unkomprimierten Daten in die Datei schreiben.
+ File << CompressedLength << " " << Writer.GetDataSize() << " ";
+
+ // Komprimierte Daten in die Datei schreiben.
+ File.write(reinterpret_cast<char *>(&CompressionBuffer[0]), CompressedLength);
+ if (!File.good())
+ {
+ BS_LOG_ERRORLN("Unable to write game data to savegame file \"%s\".", Filename.c_str());
+ throw 0;
+ }
+
+ // Screenshotdatei an die Datei anfügen.
+ if (BS_FileSystemUtil::GetInstance().FileExists(ScreenshotFilename))
+ {
+ ifstream ScreenshotFile(ScreenshotFilename.c_str(), ifstream::binary);
+
+ vector<char> Buffer(FILE_COPY_BUFFER_SIZE);
+ while (ScreenshotFile.good())
+ {
+ ScreenshotFile.read(&Buffer[0], Buffer.size());
+ File.write(&Buffer[0], ScreenshotFile.gcount());
+ }
+ }
+ else
+ {
+ BS_LOG_WARNINGLN("The screenshot file \"%s\" does not exist. Savegame is written without a screenshot.", Filename.c_str());
+ }
+
+ // Savegameinformationen für diesen Slot aktualisieren.
+ m_impl->ReadSlotSavegameInformation(SlotID);
+ }
+ catch(...)
+ {
+ BS_LOG_ERRORLN("An error occured while create savegame file \"%s\".", Filename.c_str());
+
+ // Es ist ein Fehler aufgetreten, die Spielstanddatei wird gelöscht, da sie keinen konsistenten Zustand besitzt.
+ ::remove(Filename.c_str());
+
+ // Misserfolg signalisieren.
+ return false;
+ }
+
+ // Erfolg signalisieren.
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+
+bool BS_PersistenceService::LoadGame(unsigned int SlotID)
+{
+ // Überprüfen, ob die Slot-ID zulässig ist.
+ if (SlotID >= SLOT_COUNT)
+ {
+ BS_LOG_ERRORLN("Tried to load from an invalid slot (%d). Only slot ids form 0 to %d are allowed.", SlotID, SLOT_COUNT - 1);
+ return false;
+ }
+
+ SavegameInformation & CurSavegameInfo = m_impl->m_SavegameInformations[SlotID];
+
+ // Überprüfen, ob der Slot belegt ist.
+ if (!CurSavegameInfo.IsOccupied)
+ {
+ BS_LOG_ERRORLN("Tried to load from an empty slot (%d).", SlotID);
+ return false;
+ }
+
+ // Überprüfen, ob der Spielstand im angegebenen Slot mit der aktuellen Engine-Version kompatibel ist.
+ // Im Debug-Modus wird dieser Test übersprungen. Für das Testen ist es hinderlich auf die Einhaltung dieser strengen Bedingung zu bestehen,
+ // da sich die Versions-ID bei jeder Codeänderung mitändert.
+#ifndef DEBUG
+ if (!CurSavegameInfo.IsCompatible)
+ {
+ BS_LOG_ERRORLN("Tried to load a savegame (%d) that is not compatible with this engine version.", SlotID);
+ return false;
+ }
+#endif
+
+ vector<unsigned char> UncompressedDataBuffer(CurSavegameInfo.GamedataUncompressedLength);
+ {
+ // Komprimierte gespeicherte Spieldaten laden.
+ vector<unsigned char> CompressedDataBuffer(CurSavegameInfo.GamedataLength);
+ {
+ ifstream File(GenerateSavegamePath(SlotID).c_str(), ifstream::binary);
+ File.seekg(CurSavegameInfo.GamedataOffset);
+ File.read(reinterpret_cast<char *>(&CompressedDataBuffer[0]), CurSavegameInfo.GamedataLength);
+ if (!File.good())
+ {
+ BS_LOG_ERRORLN("Unable to load the gamedata from the savegame file \"%s\".", CurSavegameInfo.Filename.c_str());
+ return false;
+ }
+ }
+
+ // Spieldaten dekomprimieren.
+ uLongf UncompressedBufferSize = UncompressedDataBuffer.size();
+ if (uncompress(reinterpret_cast<Bytef *>(&UncompressedDataBuffer[0]), &UncompressedBufferSize,
+ reinterpret_cast<Bytef *>(&CompressedDataBuffer[0]), CompressedDataBuffer.size()) != Z_OK)
+ {
+ BS_LOG_ERRORLN("Unable to decompress the gamedata from savegame file \"%s\".", CurSavegameInfo.Filename.c_str());
+ return false;
+ }
+ }
+
+ BS_InputPersistenceBlock Reader(&UncompressedDataBuffer[0], UncompressedDataBuffer.size());
+
+ // Einzelne Engine-Module depersistieren.
+ bool Success = true;
+ Success &= BS_Kernel::GetInstance()->GetScript()->Unpersist(Reader);
+ // Muss unbedingt nach Script passieren. Da sonst die bereits wiederhergestellten Regions per Garbage-Collection gekillt werden.
+ Success &= BS_RegionRegistry::GetInstance().Unpersist(Reader);
+ Success &= BS_Kernel::GetInstance()->GetGfx()->Unpersist(Reader);
+ Success &= BS_Kernel::GetInstance()->GetSfx()->Unpersist(Reader);
+ Success &= BS_Kernel::GetInstance()->GetInput()->Unpersist(Reader);
+
+ if (!Success)
+ {
+ BS_LOG_ERRORLN("Unable to unpersist the gamedata from savegame file \"%s\".", CurSavegameInfo.Filename.c_str());
+ return false;
+ }
+
+ return true;
+}
diff --git a/engines/sword25/kernel/persistenceservice.h b/engines/sword25/kernel/persistenceservice.h
new file mode 100755
index 0000000000..2693f4cc2e
--- /dev/null
+++ b/engines/sword25/kernel/persistenceservice.h
@@ -0,0 +1,71 @@
+// -----------------------------------------------------------------------------
+// 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_PERSISTENCESERVICE_H
+#define BS_PERSISTENCESERVICE_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include "kernel/common.h"
+#include "kernel/memlog_off.h"
+#include <string>
+#include <vector>
+#include "kernel/memlog_on.h"
+
+// -----------------------------------------------------------------------------
+// Class declaration
+// -----------------------------------------------------------------------------
+
+class BS_PersistenceService
+{
+public:
+ BS_PersistenceService();
+ virtual ~BS_PersistenceService();
+
+ // -----------------------------------------------------------------------------
+ // Singleton-Methode
+ // -----------------------------------------------------------------------------
+
+ static BS_PersistenceService & GetInstance();
+
+
+ // -----------------------------------------------------------------------------
+ // Interface
+ // -----------------------------------------------------------------------------
+
+ static unsigned int GetSlotCount();
+ static std::string GetSavegameDirectory();
+
+ void ReloadSlots();
+ bool IsSlotOccupied(unsigned int SlotID);
+ bool IsSavegameCompatible(unsigned int SlotID);
+ std::string & GetSavegameDescription(unsigned int SlotID);
+ std::string & GetSavegameFilename(unsigned int SlotID);
+
+ bool SaveGame(unsigned int SlotID, const std::string & ScreenshotFilename);
+ bool LoadGame(unsigned int SlotID);
+
+private:
+ struct Impl;
+ Impl * m_impl;
+};
+
+#endif
diff --git a/engines/sword25/kernel/resmanager.cpp b/engines/sword25/kernel/resmanager.cpp
new file mode 100755
index 0000000000..2e7ab87af0
--- /dev/null
+++ b/engines/sword25/kernel/resmanager.cpp
@@ -0,0 +1,293 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#include "resmanager.h"
+
+#include "resource.h"
+#include "resservice.h"
+#include "string.h"
+#include "../package/packagemanager.h"
+
+#define BS_LOG_PREFIX "RESOURCEMANAGER"
+
+BS_ResourceManager::~BS_ResourceManager()
+{
+ // Alle ungelockten Resourcen freigeben.
+ EmptyCache();
+
+ // Alle übriggebliebenen Resourcen sind nicht freigegeben worden, daher Warnungen ausgeben und freigeben.
+ std::list<BS_Resource*>::iterator Iter = m_Resources.begin();
+ for (; Iter != m_Resources.end(); ++Iter)
+ {
+ BS_LOG_WARNINGLN("Resource \"%s\" was not released.", (*Iter)->GetFileName().c_str());
+
+ // Lock-Count auf 0 setzen.
+ while ((*Iter)->GetLockCount() > 0) { (*Iter)->Release(); };
+
+ // Resource freigeben.
+ delete(*Iter);
+ }
+}
+
+BS_Resource* BS_ResourceManager::GetResourceByOrdinal(int Ord) const
+{
+ // Überprüfen ob der Index Ord innerhald der Listengrenzen liegt.
+ if (Ord < 0 || Ord >= GetResourceCount())
+ {
+ BS_LOG_ERRORLN("Resource ordinal (%d) out of bounds (0 - %d).", Ord, GetResourceCount() - 1);
+ return NULL;
+ }
+
+ // Liste durchlaufen und die Resource mit dem gewünschten Index zurückgeben.
+ int CurOrd = 0;
+ std::list<BS_Resource*>::const_iterator Iter = m_Resources.begin();
+ for (; Iter != m_Resources.end(); ++Iter, ++CurOrd)
+ {
+ if (CurOrd == Ord)
+ return (*Iter);
+ }
+
+ // Die Ausführung sollte nie an diesem Punkt ankommen.
+ BS_LOG_EXTERRORLN("Execution reached unexpected point.");
+ return NULL;
+}
+
+bool BS_ResourceManager::RegisterResourceService(BS_ResourceService* pService)
+{
+ if(!pService)
+ {
+ BS_LOG_ERRORLN("Can't register NULL resource service.");
+ return false;
+ }
+
+ m_ResourceServices.push_back(pService);
+
+ return true;
+}
+
+void BS_ResourceManager::DeleteResourcesIfNecessary()
+{
+ // Falls noch genügend Speicher frei ist, oder keine Ressourcen geladen sind, kann die Funktion vorzeitig beendet werden.
+ if (m_KernelPtr->GetUsedMemory() < m_MaxMemoryUsage || m_Resources.empty()) return;
+
+ // Solange Ressourcen löschen, bis der Speichernutzung des Prozesses unter den festgelegten Maximalwert fällt.
+ // Dabei wird die Liste von Hinten nach vorne durchlaufen um zunächst jene Resourcen freizugeben, deren
+ // Benutzung lange zurückliegt und sich somit am Ende der Liste befinden.
+ std::list<BS_Resource*>::iterator Iter = m_Resources.end();
+ do
+ {
+ --Iter;
+
+ // Die Resource darf nur freigegeben werden, wenn sie nicht gelockt ist.
+ if ((*Iter)->GetLockCount() == 0) Iter = DeleteResource(*Iter);
+ } while(Iter != m_Resources.begin() && m_KernelPtr->GetUsedMemory() > m_MaxMemoryUsage);
+}
+
+void BS_ResourceManager::EmptyCache()
+{
+ // Resourcenliste durchlaufen und alle nicht gelockten Resourcen freigeben
+ std::list<BS_Resource*>::iterator Iter = m_Resources.begin();
+ while (Iter != m_Resources.end())
+ {
+ if ((*Iter)->GetLockCount() == 0)
+ {
+ // Resource entfernen
+ Iter = DeleteResource(*Iter);
+ }
+ else
+ ++Iter;
+ }
+}
+
+BS_Resource* BS_ResourceManager::RequestResource(const std::string& FileName)
+{
+ // Absoluten, eindeutigen Pfad zur Datei erzeugen.
+ std::string UniqueFileName = GetUniqueFileName(FileName);
+ if (UniqueFileName == "")
+ return NULL;
+
+ // Feststellen, ob die Resource schon geladen ist.
+ // Wenn die Resource gefunden wurde wird sie an die Spitze der Resourcenliste gestellt, gelockt und zurückgegeben.
+ {
+ BS_Resource* pResource = GetResource(UniqueFileName);
+ if (pResource)
+ {
+ MoveToFront(pResource);
+ (pResource)->AddReference();
+ return pResource;
+ }
+ }
+
+ // Die Resource wurde nicht gefunden, muss also noch geladen werden.
+ if (m_LogCacheMiss) BS_LOG_WARNINGLN("\"%s\" was not precached.", UniqueFileName.c_str());
+
+ BS_Resource* pResource;
+ if (pResource = LoadResource(UniqueFileName))
+ {
+ pResource->AddReference();
+ return pResource;
+ }
+
+ return NULL;
+}
+
+bool BS_ResourceManager::PrecacheResource(const std::string& FileName, bool ForceReload)
+{
+ // Absoluten, eindeutigen Pfad zur Datei erzeugen.
+ std::string UniqueFileName = GetUniqueFileName(FileName);
+ if (UniqueFileName == "")
+ return false;
+
+ BS_Resource * ResourcePtr = GetResource(UniqueFileName);
+
+ if (ForceReload && ResourcePtr)
+ {
+ if (ResourcePtr->GetLockCount())
+ {
+ BS_LOG_ERRORLN("Could not force precaching of \"%s\". The resource is locked.", FileName.c_str());
+ return false;
+ }
+ else
+ {
+ DeleteResource(ResourcePtr);
+ ResourcePtr = 0;
+ }
+ }
+
+ if (!ResourcePtr && LoadResource(UniqueFileName) == NULL)
+ {
+ BS_LOG_ERRORLN("Could not precache \"%s\",", FileName.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+void BS_ResourceManager::MoveToFront(BS_Resource* pResource)
+{
+ // Resource aus der Liste löschen
+ m_Resources.erase(pResource->_Iterator);
+ // Resource an die Spitze der Liste setzen
+ m_Resources.push_front(pResource);
+ // Iterator aktualisieren
+ pResource->_Iterator = m_Resources.begin();
+}
+
+BS_Resource* BS_ResourceManager::LoadResource(const std::string& FileName)
+{
+ // ResourceService finden, der die Resource laden kann.
+ for(unsigned int i = 0; i < m_ResourceServices.size(); ++i)
+ {
+ if (m_ResourceServices[i]->CanLoadResource(FileName))
+ {
+ // Falls mehr Speicher belegt ist als gewünscht, muss Speicher freigegeben werden.
+ DeleteResourcesIfNecessary();
+
+ // Resource laden
+ BS_Resource* pResource;
+ if (!(pResource = m_ResourceServices[i]->LoadResource(FileName)))
+ {
+ BS_LOG_ERRORLN("Responsible service could not load resource \"%s\".", FileName.c_str());
+ return NULL;
+ }
+
+ // Resource an die Spitze der Resourcenliste stellen.
+ m_Resources.push_front(pResource);
+ pResource->_Iterator = m_Resources.begin();
+
+ // Resource in die Hashtabelle eintragen
+ m_ResourceHashTable[pResource->GetFileNameHash() % HASH_TABLE_BUCKETS].push_front(pResource);
+
+ return pResource;
+ }
+ }
+
+ BS_LOG_ERRORLN("Could not find a service that can load \"%s\".", FileName.c_str());
+ return NULL;
+}
+
+std::string BS_ResourceManager::GetUniqueFileName(const std::string& FileName) const
+{
+ // Pointer auf den PackageManager holen
+ BS_PackageManager* pPackage = (BS_PackageManager*) m_KernelPtr->GetService("package");
+ if (!pPackage)
+ {
+ BS_LOG_ERRORLN("Could not get package manager.");
+ return std::string("");
+ }
+
+ // Absoluten Pfad der Datei bekommen und somit die Eindeutigkeit des Dateinamens sicherstellen
+ std::string UniqueFileName = pPackage->GetAbsolutePath(FileName);
+ if (UniqueFileName == "")
+ BS_LOG_ERRORLN("Could not create absolute file name for \"%s\".", FileName.c_str());
+
+ return UniqueFileName;
+}
+
+std::list<BS_Resource*>::iterator BS_ResourceManager::DeleteResource(BS_Resource* pResource)
+{
+ // Resource aus der Hash-Tabelle entfernen
+ m_ResourceHashTable[pResource->GetFileNameHash() % HASH_TABLE_BUCKETS].remove(pResource);
+
+ BS_Resource* pDummy = pResource;
+
+ // Resource aus der Resourcenliste löschen
+ std::list<BS_Resource*>::iterator Result = m_Resources.erase(pResource->_Iterator);
+
+ // Resource freigeben
+ delete(pDummy);
+
+ // Iterator zurückgeben
+ return Result;
+}
+
+BS_Resource* BS_ResourceManager::GetResource(const std::string& UniqueFileName) const
+{
+ // Feststellen, ob die Resource schon geladen ist.
+ const std::list<BS_Resource*>& HashBucket = m_ResourceHashTable[BS_String::GetHash(UniqueFileName) % HASH_TABLE_BUCKETS];
+ {
+ std::list<BS_Resource*>::const_iterator Iter = HashBucket.begin();
+ for (; Iter != HashBucket.end(); ++Iter)
+ {
+ // Wenn die Resource gefunden wurde wird sie zurückgegeben.
+ if ((*Iter)->GetFileName() == UniqueFileName)
+ return *Iter;
+ }
+ }
+
+ // Resource wurde nicht gefunden, ist also nicht geladen
+ return NULL;
+}
+
+void BS_ResourceManager::DumpLockedResources()
+{
+ for (std::list<BS_Resource*>::iterator Iter = m_Resources.begin(); Iter != m_Resources.end(); ++Iter)
+ {
+ if ((*Iter)->GetLockCount() > 0)
+ {
+ BS_LOGLN("%s", (*Iter)->GetFileName().c_str());
+ }
+ }
+}
+
+void BS_ResourceManager::SetMaxMemoryUsage(unsigned int MaxMemoryUsage)
+{
+ m_MaxMemoryUsage = MaxMemoryUsage;
+ DeleteResourcesIfNecessary();
+} \ No newline at end of file
diff --git a/engines/sword25/kernel/resmanager.h b/engines/sword25/kernel/resmanager.h
new file mode 100755
index 0000000000..6bc6b2a8f8
--- /dev/null
+++ b/engines/sword25/kernel/resmanager.h
@@ -0,0 +1,185 @@
+// -----------------------------------------------------------------------------
+// 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_RESOURCEMANAGER_H
+#define BS_RESOURCEMANAGER_H
+
+// Includes
+#include "memlog_off.h"
+#include <vector>
+#include <list>
+#include "memlog_on.h"
+
+#include "common.h"
+
+// Klassendefinition
+class BS_ResourceService;
+class BS_Resource;
+class BS_Kernel;
+
+class BS_ResourceManager
+{
+friend BS_Kernel;
+
+public:
+ /**
+ @brief Fordert eine Resource an.
+ @param FileName Dateiname
+ @return Gibt die Resource zurück, falls erfolgreich, sonst NULL
+ */
+ BS_Resource* RequestResource(const std::string& FileName);
+
+ /**
+ @brief Lädt eine Resource in den Cache.
+ @param FileName der Dateiname der zu cachenden Resource
+ @param ForceReload gibt an, ob die Datei auch neu geladen werden soll, wenn sie bereits geladen wurde.
+ Dies ist nützlich bei Dateien, die sich in der Zwischenzeit verändert haben.
+ @return Gibt true zurück, wenn das Caching durchgeführt werden konnte, ansonsten false.
+ */
+ bool PrecacheResource(const std::string& FileName, bool ForceReload = false);
+
+ /**
+ @brief Gibt die Anzahl der geladenen Resourcen zurück.
+ */
+ int GetResourceCount() const { return static_cast<int>(m_Resources.size()); }
+
+ /**
+ @brief Gibt einen Pointer auf eine Resource anhand deren laufender Nummer zurück.
+ @param Ord laufende Nummer der Resource. Dieser Wert muss zwischen 0 und GetResourceCount() - 1 liegen.
+ @return Gibt einen Pointer auf die Resource zurück wenn erfolgreich, ansonsten NULL.
+ @remark Diese Methode ist nicht auf Geschwindigkeit optimiert und sollte nur für Debugzwecke eingesetzt werden.
+ */
+ BS_Resource* GetResourceByOrdinal(int Ord) const;
+
+ /**
+ @brief RegisterResourceService Diese Methode wird vom Konstruktor von
+ BS_ResourceService aufgerufen und trägt somit alle
+ Resource-Services in einen Liste des
+ Resource-Managers ein.
+ @param pService welches Service
+ @return gibt true zurück, falls erfolgreich
+ */
+ bool RegisterResourceService(BS_ResourceService* pService);
+
+ /**
+ * @brief gibt alle Resourcen frei, die nicht gelocked sind.
+ **/
+ void EmptyCache();
+
+ /**
+ @brief Gibt zurück wie viel Speicher die Engine maximal belegen soll.
+ */
+ int GetMaxMemoryUsage() const { return m_MaxMemoryUsage; }
+
+ /**
+ @brief Legt fest wie viel Speicher die Engine maximal belegen soll.
+
+ Wenn dieser Wert überschritten wird, werden Resourcen entladen um Platz zu schaffen. Dieser Wert ist als Richtgröße zu verstehen und nicht als feste Grenze.
+ Es ist unter KEINEN Umständen garantiert, dass die Engine tatsächlich nur so viel Speicher benutzt.
+ */
+ void SetMaxMemoryUsage(unsigned int MaxMemoryUsage);
+
+ /**
+ @brief Gibt an, ob eine Warnung ins Log geschrieben wird, wenn ein Cache-Miss auftritt.
+ Der Standardwert ist "false".
+ */
+ bool IsLogCacheMiss() const { return m_LogCacheMiss; }
+
+ /**
+ @brief Legt fest, ob eine Warnung ins Log geschrieben wird, wenn in Cache-Miss auftritt.
+ @param Flag wenn "true" wird die Warnung in Zukunft ausgegeben, ansonsten nicht.
+ */
+ void SetLogCacheMiss(bool Flag) { m_LogCacheMiss = Flag; }
+
+ /**
+ @brief Schreibt die Namen aller gelockten Resourcen in die Log-Datei.
+ */
+ void DumpLockedResources();
+
+private:
+ /**
+ @brief Erzeugt einen neuen Resource-Manager.
+ @param pKernel ein Pointer auf den Kernel.
+ @remark Nur der BS_Kernel darf Exemplare dieser Klasse erzeugen. Daher ist der Konstruktor private.
+ */
+ BS_ResourceManager(BS_Kernel* pKernel) :
+ m_KernelPtr(pKernel),
+ m_MaxMemoryUsage(100000000),
+ m_LogCacheMiss(false)
+ {};
+ virtual ~BS_ResourceManager();
+
+ enum
+ {
+ HASH_TABLE_BUCKETS = 256
+ };
+
+ /**
+ @brief Verschiebt eine Resource an die Spitze der Resourcenliste.
+ @param pResource die Resource
+ */
+ void MoveToFront(BS_Resource* pResource);
+
+ /**
+ @brief Lädt eine Resource und aktualisiert m_UsedMemory.
+
+ Die Resource darf nicht bereits geladen sein.
+
+ @param FileName der absolute und eindeutige Dateiname der zu ladenen Resource
+ @return Gibt einen Pointer auf die geladene Resource zurück wenn das Laden erfolgreich war, ansonsten NULL.
+ */
+ BS_Resource* LoadResource(const std::string& FileName);
+
+ /**
+ @brief Gibt zu einer Datei ihren absoluten, eindeutigen Pfad zurück.
+ @param FileName der Dateiname
+ @return Der absolute, eindeutige Pfad zur Datei inklusive des Dateinamens.<br>
+ Gibt einen leeren std::string zurück, wenn der Pfad nicht erzeugt werden konnte.
+ */
+ std::string GetUniqueFileName(const std::string& FileName) const;
+
+ /**
+ @brief Löscht eine Resource entfernt sie aus den Listen und aktualisiert m_UsedMemory.
+ @param pResource die zu löschende Resource
+ @return Gibt einen Iterator zurück, der auf die nächste Resource in der Resourcenliste zeigt.
+ */
+ std::list<BS_Resource*>::iterator DeleteResource(BS_Resource* pResource);
+
+ /**
+ @brief Holt einen Pointer zu einer geladenen Resource.
+ @param UniqueFileName der absolute, eindeutige Pfad zur Datei inklusive des Dateinamens.
+ @return Gibt einen Pointer auf die angeforderte Resource zurück, oder NULL, wenn die Resourcen nicht geladen ist.
+ */
+ BS_Resource* GetResource(const std::string& UniqueFileName) const;
+
+ /**
+ @brief Löscht solange Resourcen, bis der Prozess unter das angegebene Maximun an Speicherbelegung kommt.
+ */
+ void DeleteResourcesIfNecessary();
+
+ BS_Kernel* m_KernelPtr;
+ unsigned int m_MaxMemoryUsage;
+ std::vector<BS_ResourceService*> m_ResourceServices;
+ std::list<BS_Resource*> m_Resources;
+ std::list<BS_Resource*> m_ResourceHashTable[HASH_TABLE_BUCKETS];
+ bool m_LogCacheMiss;
+};
+
+#endif
+
diff --git a/engines/sword25/kernel/resource.cpp b/engines/sword25/kernel/resource.cpp
new file mode 100755
index 0000000000..bfcd5a54b4
--- /dev/null
+++ b/engines/sword25/kernel/resource.cpp
@@ -0,0 +1,45 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#include "resource.h"
+#include "string.h"
+#include "kernel.h"
+#include "package/packagemanager.h"
+
+#define BS_LOG_PREFIX "RESOURCE"
+
+BS_Resource::BS_Resource(const std::string& FileName, RESOURCE_TYPES Type) :
+ _Type(Type),
+ _RefCount(0)
+{
+ BS_ASSERT(BS_Kernel::GetInstance()->GetService("package"));
+
+ _FileName = static_cast<BS_PackageManager *>(BS_Kernel::GetInstance()->GetService("package"))->GetAbsolutePath(FileName);
+ _FileNameHash = BS_String::GetHash(FileName);
+};
+
+void BS_Resource::Release()
+{
+ if (_RefCount)
+ {
+ --_RefCount;
+ }
+ else
+ BS_LOG_WARNINGLN("Released unlocked resource \"%s\".", _FileName.c_str());
+}
diff --git a/engines/sword25/kernel/resource.h b/engines/sword25/kernel/resource.h
new file mode 100755
index 0000000000..5d6c542b07
--- /dev/null
+++ b/engines/sword25/kernel/resource.h
@@ -0,0 +1,97 @@
+// -----------------------------------------------------------------------------
+// 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_RESOURCE_H
+#define BS_RESOURCE_H
+
+#include "memlog_off.h"
+#include <list>
+#include "memlog_on.h"
+
+#include "common.h"
+
+class BS_Kernel;
+class BS_ResourceManager;
+
+class BS_Resource
+{
+friend BS_ResourceManager;
+
+public:
+ enum RESOURCE_TYPES
+ {
+ TYPE_UNKNOWN,
+ TYPE_BITMAP,
+ TYPE_ANIMATION,
+ TYPE_SOUND,
+ TYPE_FONT
+ };
+
+ BS_Resource(const std::string& UniqueFileName, RESOURCE_TYPES Type);
+
+ /**
+ * @brief `Lockt' die Resource, verhindert, dass sie freigegeben wird.
+ * @remarks Die Resource wird bereits `gelockt' initialisiert, sie muss also nach dem Anfordern nur
+ * gelockt werden, wenn sie mehrfach verwendet wird.
+ **/
+
+ void AddReference() { ++_RefCount; }
+
+ /**
+ * @brief Hebt ein vorhergehendes `lock' auf.
+ * @remarks Die Resource kann ruhig öfter freigegeben als `gelockt' werden, auch wenn das nicht gerade empfehlenswert ist.
+ **/
+
+ void Release();
+
+ /**
+ * @brief Gibt die Anzahl der aktuellen `locks' zurück.
+ * @return Die Zahl der `locks'.
+ **/
+
+ int GetLockCount() const { return _RefCount; }
+
+ /**
+ @brief Gibt den absoluten, eindeutigen Dateinamen der Resource zurück.
+ */
+
+ const std::string & GetFileName() const { return _FileName; }
+
+ /**
+ @brief Gibt den Hash des Dateinames der Resource zurück.
+ */
+ unsigned int GetFileNameHash() const { return _FileNameHash; }
+
+ /**
+ @brief Gibt den Typ der Ressource zurück.
+ */
+ unsigned int GetType() const { return _Type; }
+
+protected:
+ virtual ~BS_Resource() {};
+
+private:
+ std::string _FileName; //!< Der absolute Dateiname
+ unsigned int _FileNameHash; //!< Der Hashwert des Dateinames
+ unsigned int _RefCount; //!< Anzahl an Locks
+ unsigned int _Type; //!< Der Typ der Resource
+ std::list<BS_Resource*>::iterator _Iterator; //!< Der Iterator zeigt auf Position der Resource in der LRU-Liste
+};
+
+#endif
diff --git a/engines/sword25/kernel/resservice.h b/engines/sword25/kernel/resservice.h
new file mode 100755
index 0000000000..d2369c0d87
--- /dev/null
+++ b/engines/sword25/kernel/resservice.h
@@ -0,0 +1,110 @@
+// -----------------------------------------------------------------------------
+// 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_RESOURCESERVICE_H
+#define BS_RESOURCESERVICE_H
+
+// Includes
+#include "common.h"
+#include "service.h"
+#include "kernel.h"
+#include "resmanager.h"
+
+class BS_Resource;
+
+class BS_ResourceService : public BS_Service
+{
+public:
+ BS_ResourceService(BS_Kernel* pKernel) : BS_Service(pKernel)
+ {
+ BS_ResourceManager* pResource = pKernel->GetResourceManager();
+ pResource->RegisterResourceService(this);
+ }
+
+ virtual ~BS_ResourceService() {}
+
+
+ /**
+ @brief Lädt eine Resource.
+ @param FileName Dateiname
+ @return gibt die Resource zurück, falls erfolgreich, ansonsten NULL
+ */
+ virtual BS_Resource* LoadResource(const std::string& FileName) = 0;
+
+ /**
+ @brief CanLoadResource prüft, ob Resource vom Service geladen werden kann.
+ @param FileName Dateiname
+ @return true, falls Service Resource laden kann
+ @remark Überprüfung basiert auf dem Dateinamen, wenn das Dateiformat nicht passt, gibts Ärger.
+ */
+ virtual bool CanLoadResource(const std::string& FileName) = 0;
+
+protected:
+ // Hilfsmethoden für BS_ResourceService Klassen
+
+ /**
+ @brief Vergleicht zwei Strings, wobei der zweite String die Wildcards * und ? enthalten darf
+ @param String der erste Vergleichsstring. Dieser darf keine Wildcards enthalten.
+ @param Pattern der zweite Vergleichsstring. Dieser darf die Wildcards * und ? enthalten.
+ @return Gibt true zurück, wenn der String auf das Pattern passt, ansonsten false.
+ */
+ bool _WildCardStringMatch(const std::string& String, const std::string& Pattern)
+ {
+ return _WildCardStringMatchRecursion(String.c_str(), Pattern.c_str());
+ }
+
+private:
+ bool _WildCardStringMatchRecursion(const char* String, const char* Pattern)
+ {
+ // Rekursionsabschlüsse:
+ // 1. Der Pattern-String enthält nur noch * -> TRUE
+ if (*Pattern == '*')
+ {
+ // Es muss mit einer Kopie von Pattern gearbeitet werden um den aktuellen Zustand nicht zu zerstören
+ char* PatternCopy = (char*) Pattern;
+ while (*PatternCopy == '*') { PatternCopy++; }
+ if (!*PatternCopy) return true;
+ }
+ // 2. Der String ist zuende, das Pattern aber noch nicht -> FALSE
+ if (!*String && *Pattern) return false;
+ // 3. Der String ist zuende, also ist auch das Pattern zuende (s.o.) -> TRUE
+ if (!*String) return true;
+
+ // Rekursionsaufruf 1:
+ // Falls die beiden aktuellen Zeichen gleich sind, oder Pattern '?' ist wird das Ergebnis von restlichen String zurückgegeben
+ if (*String == *Pattern || *Pattern == '?') return _WildCardStringMatchRecursion(String + 1, Pattern + 1);
+
+ // Falls nicht, wird untersucht ob ein '*' vorliegt
+ if (*Pattern == '*')
+ {
+ // Rekursionsaufruf 2:
+ // Zunächst wird das Ergebnis von String und Pattern + 1 untersucht...
+ if (_WildCardStringMatchRecursion(String, Pattern + 1)) return true;
+ // Falls das fehlschlägt, wird das Ergebnis von String + 1 Pattern zurückgegeben
+ else return _WildCardStringMatchRecursion(String + 1, Pattern);
+ // Die Rekursion kehrt also immer wieder an diese Stelle zurück, bis das Zeichen in String,
+ // dem nach dem '*' in Pattern entspricht
+ }
+
+ // Wenn kein '*' in Pattern vorliegt, schlägt der Vergleich fehl
+ return false;
+ }
+};
+
+#endif
diff --git a/engines/sword25/kernel/service.h b/engines/sword25/kernel/service.h
new file mode 100755
index 0000000000..d79194f41a
--- /dev/null
+++ b/engines/sword25/kernel/service.h
@@ -0,0 +1,57 @@
+// -----------------------------------------------------------------------------
+// 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_Service
+ -------------
+ Dies ist die Basisklasse für alle Services der Engine.
+ Ein Service ist ein wesentlicher Bestandteil des Engine, z.B. die Graphiksystem.
+ Das Servicesystem macht es möglich mehrere verschiedene Services für ein System zu haben,
+ und je nach Betriebssystem einen passenden auszuwählen.
+ Denkbar wären z.B. zwei Graphiksysteme von denen eines hardwarebeschleunigt ist und ein
+ anderes nicht.
+ Die Services werden zur Laufzeit über die Kernelmethode NewService und NIEMALS mit new erzeugt.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef _BS_SERVICE_H
+#define _BS_SERVICE_H
+
+// Includes
+#include "common.h"
+
+// Klassendefinition
+class BS_Kernel;
+
+class BS_Service
+{
+private:
+ BS_Kernel* _pKernel;
+
+protected:
+ BS_Service(BS_Kernel* pKernel) : _pKernel(pKernel) {};
+
+ BS_Kernel* GetKernel() const { return _pKernel; }
+
+public:
+ virtual ~BS_Service(){};
+};
+
+#endif \ No newline at end of file
diff --git a/engines/sword25/kernel/service_ids.h b/engines/sword25/kernel/service_ids.h
new file mode 100755
index 0000000000..38ba941f5e
--- /dev/null
+++ b/engines/sword25/kernel/service_ids.h
@@ -0,0 +1,56 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+/*
+ service_ids.h
+ -------------
+ In dieser Datei sind alle Services verzeichnet.
+ JEDER neuer Service muss hier eingetragen werden, ansonsten kann er nicht mit
+ pKernel->NewService(..) instanziiert werden.
+
+ Autor: Malte Thiesen
+*/
+
+#include "common.h"
+
+BS_Service * BS_OpenGLGfx_CreateObject(BS_Kernel* pKernel);
+BS_Service * BS_PhysfsPackageManager_CreateObject(BS_Kernel* pKernel);
+BS_Service * BS_StdWinInput_CreateObject(BS_Kernel* pKernel);
+BS_Service * BS_FMODExSound_CreateObject(BS_Kernel* pKernel);
+BS_Service * BS_LuaScriptEngine_CreateObject(BS_Kernel* pKernel);
+BS_Service * BS_Geometry_CreateObject(BS_Kernel* pKernel);
+BS_Service * BS_OggTheora_CreateObject(BS_Kernel* pKernel);
+
+// Services müssen in dieser Tabelle eingetragen werden
+const BS_ServiceInfo BS_SERVICE_TABLE[] =
+{
+ // Die ersten beiden Parameter sind die Namen der Superclass und des Services.
+ // Der dritte Parameter ist die statische Methode der Klasse, die ein Objekt der Klasse erzeugt und zurückgibt.
+ // Beispiel:
+ // BS_ServiceInfo("Superclass", "Service", CreateMethod)
+ BS_ServiceInfo("gfx", "opengl", BS_OpenGLGfx_CreateObject),
+ BS_ServiceInfo("package", "physfs", BS_PhysfsPackageManager_CreateObject),
+ BS_ServiceInfo("input", "winapi", BS_StdWinInput_CreateObject),
+ BS_ServiceInfo("sfx", "fmodex", BS_FMODExSound_CreateObject),
+ BS_ServiceInfo("script", "lua", BS_LuaScriptEngine_CreateObject),
+ BS_ServiceInfo("geometry", "std", BS_Geometry_CreateObject),
+ BS_ServiceInfo("fmv", "oggtheora", BS_OggTheora_CreateObject),
+};
+
+const unsigned int BS_SERVICE_COUNT = sizeof(BS_SERVICE_TABLE) / sizeof(BS_ServiceInfo);
diff --git a/engines/sword25/kernel/string.h b/engines/sword25/kernel/string.h
new file mode 100755
index 0000000000..b6802d3075
--- /dev/null
+++ b/engines/sword25/kernel/string.h
@@ -0,0 +1,117 @@
+// -----------------------------------------------------------------------------
+// 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_STRING
+#define BS_STRING
+
+#include "memlog_off.h"
+#include <string>
+#include "memlog_on.h"
+
+namespace BS_String
+{
+ inline unsigned int GetHash(const std::string & Str)
+ {
+ unsigned int Result = 0;
+
+ for (unsigned int i = 0; i < Str.size(); i++)
+ Result = ((Result << 5) - Result) + Str[i];
+
+ return Result;
+ }
+
+ inline bool ToInt(const std::string & Str, int & Result)
+ {
+ std::string::const_iterator Iter = Str.begin();
+
+ // Whitespace überspringen
+ while (*Iter && (*Iter == ' ' || *Iter == '\t')) { ++Iter; }
+ if (Iter == Str.end()) return false;
+
+ // Vorzeichen auslesen, wenn vorhanden
+ bool IsNegative = false;
+ if (*Iter == '-')
+ {
+ IsNegative = true;
+ ++Iter;
+ }
+ else if (*Iter == '+')
+ ++Iter;
+
+ // Whitespace überspringen
+ while (*Iter && (*Iter == ' ' || *Iter == '\t')) { ++Iter; }
+ if (Iter ==Str.end()) return false;
+
+ // String in Ganzzahl umwandeln
+ Result = 0;
+ while (Iter != Str.end())
+ {
+ if (*Iter < '0' || *Iter > '9')
+ {
+ while (*Iter && (*Iter == ' ' || *Iter == '\t')) { ++Iter; }
+ if (Iter != Str.end()) return false;
+ break;
+ }
+ Result = (Result * 10) + (*Iter - '0');
+ ++Iter;
+ }
+
+ if (IsNegative) Result = -Result;
+
+ return true;
+ }
+
+ inline bool ToBool(const std::string & Str, bool & Result)
+ {
+ if (Str == "true" ||
+ Str == "TRUE")
+ {
+ Result = true;
+ return true;
+ }
+ else if (Str == "false" ||
+ Str == "FALSE")
+ {
+ Result = false;
+ return true;
+ }
+
+ return false;
+ }
+
+ inline void ToLower(std::string & Str)
+ {
+ static const unsigned char LowerCaseMap[256] =
+ {
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
+ 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
+ 64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95,
+ 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
+ 192,193,194,195,228,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,246,215,216,217,218,219,252,221,222,223,
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
+ };
+
+ for (unsigned int i = 0; i < Str.size(); ++i)
+ Str[i] = LowerCaseMap[Str[i]];
+ }
+}
+
+#endif
diff --git a/engines/sword25/kernel/timer.cpp b/engines/sword25/kernel/timer.cpp
new file mode 100755
index 0000000000..22eb1200f3
--- /dev/null
+++ b/engines/sword25/kernel/timer.cpp
@@ -0,0 +1,53 @@
+// -----------------------------------------------------------------------------
+// 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 WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "timer.h"
+
+#define BS_LOG_PREFIX "BS_TIMER"
+
+uint64_t BS_Timer::GetMicroTicks()
+{
+ HANDLE ThreadID = ::GetCurrentThread();
+
+ DWORD_PTR OldAffinityMask = ::SetThreadAffinityMask(ThreadID, 1);
+
+ uint64_t Frequency;
+ ::QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&Frequency));
+
+ uint64_t Tick;
+ ::QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&Tick));
+
+ ::SetThreadAffinityMask(ThreadID, OldAffinityMask);
+
+ return Tick * 1000000 / Frequency;
+}
+
+unsigned int BS_Timer::GetMilliTicks()
+{
+ return (unsigned int)(GetMicroTicks() / 1000);
+}
+
+bool BS_Timer::IsTimerAvaliable()
+{
+ LARGE_INTEGER Dummy;
+ return ::QueryPerformanceFrequency(&Dummy) ? true : false;
+}
diff --git a/engines/sword25/kernel/timer.h b/engines/sword25/kernel/timer.h
new file mode 100755
index 0000000000..52a7d70a83
--- /dev/null
+++ b/engines/sword25/kernel/timer.h
@@ -0,0 +1,69 @@
+// -----------------------------------------------------------------------------
+// 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_Timer
+ --------
+ Eine Klasse zum Auslesen des Systemtimers.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef BS_TIMER_H
+#define BS_TIMER_H
+
+// Includes
+#include "common.h"
+#include "bs_stdint.h"
+
+/**
+ @brief Eine Klasse zum Auslesen des Systemtimers.
+
+ Vor der Benutzung sollte immer mit IsTimerAvaliable() getestet werden, ob der Timer von der benutzten
+ Hardware unterstützt wird.
+*/
+class BS_Timer
+{
+public:
+ /**
+ @brief List den Systemtimer in Microsekunden aus.
+ @return Die Zahl vergangener Microsekunden seit dem Systemstart.<br>
+ */
+ static uint64_t GetMicroTicks();
+
+ /**
+ @brief List den Systemtimer in Millisekunden aus.
+ @return Die Zahl vergangener Millisekunden seit dem Systemstart.<br>
+ */
+ static unsigned int GetMilliTicks();
+
+ /**
+ @brief Prüft, ob der Timer auf der vorhandenen Hardware existiert.
+ @return Gibt false zurück, fals der Timer auf der vorhandenen Hardware nicht existiert.
+ */
+ static bool IsTimerAvaliable();
+
+private:
+ /**
+ @brief Initialisiert den Timer.
+ */
+ static void Init();
+};
+
+#endif
diff --git a/engines/sword25/kernel/win32window.cpp b/engines/sword25/kernel/win32window.cpp
new file mode 100755
index 0000000000..b5c519f206
--- /dev/null
+++ b/engines/sword25/kernel/win32window.cpp
@@ -0,0 +1,425 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#include "win32window.h"
+#include "../../projects/resource.h"
+
+#include "kernel/kernel.h"
+#include "input/inputengine.h"
+
+bool BS_Win32Window::_ClassRegistered = false;
+
+#define BS_LOG_PREFIX "WIN32WINDOW"
+
+
+// Konstanten
+// ----------
+static const UINT WINDOW_STYLE = WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
+static const UINT WINDOW_STYLE_EX = 0;
+static const UINT WINDOW_MAX_MESSAGES = 50;
+
+// Konstruktion/Destruktion
+// ------------------------
+BS_Win32Window::BS_Win32Window(int X, int Y, int Width, int Height, bool Visible)
+{
+ const char WINDOW_CLASS[] = "BSEngine-Class";
+
+ // Von negativen Fall ausgehen
+ _InitSuccess = false;
+
+ // Fensterklasse registrieren falls nötig
+ if (!_ClassRegistered)
+ {
+ //Fensterklasse
+ WNDCLASSEX wndclass;
+
+ //Werte der Fensterklasse festlegen
+ ZeroMemory(&wndclass, sizeof(WNDCLASSEX));
+ wndclass.cbSize = sizeof(WNDCLASSEX);
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+ wndclass.lpfnWndProc = BS_Win32Window::WindowProc;
+ wndclass.hInstance = GetModuleHandle(NULL);
+ wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
+ wndclass.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
+ wndclass.hCursor = NULL;
+ wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+ wndclass.lpszClassName = WINDOW_CLASS;
+
+ //Fensterklasse registrieren
+ if (!RegisterClassEx(&wndclass)) return;
+
+ _ClassRegistered = true;
+ }
+
+ //Fenster erstellen
+ if (!(_Window=CreateWindowEx(
+ WINDOW_STYLE_EX, // Erweiterte Darstellungsflags
+ WINDOW_CLASS, // Registrierter Fenstername
+ "", // Kein Fenstertitel
+ WINDOW_STYLE, // Darstellungsflags
+ 0,0, // Default-Position
+ 0,0, // Default-Grösse
+ NULL, // Kein Parent-Fenster
+ NULL, // Kein Menü
+ GetModuleHandle(NULL), // Instance-Handle
+ NULL)))
+ return;
+
+ // Fensterposition und Fenstergröße setzen
+ SetWidth(Width);
+ SetHeight(Height);
+ SetX(X);
+ SetY(Y);
+
+ // Fenstersichtbarkeit setzen
+ SetVisible(Visible);
+
+ // Icon setzen
+ HICON hIcon = LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1));
+ if (hIcon)
+ {
+ SendMessage(_Window, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
+ SendMessage(_Window, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);
+ }
+
+ // Erfolg signalisieren
+ _InitSuccess = true;
+ _WindowAlive = true;
+ _CloseWanted = false;
+}
+
+BS_Win32Window::~BS_Win32Window()
+{
+ // Fenster zerstören, falls dies nicht ohnehin schon passiert ist
+ if (_WindowAlive) DestroyWindow(_Window);
+}
+
+// Get-Methoden
+// ------------
+int BS_Win32Window::GetX()
+{
+ RECT Rect;
+ GetWindowRect(_Window, &Rect);
+ return Rect.left;
+}
+
+int BS_Win32Window::GetY()
+{
+ RECT Rect;
+ GetWindowRect(_Window, &Rect);
+ return Rect.top;
+}
+
+int BS_Win32Window::GetClientX()
+{
+ POINT Point = {0, 0};
+ ClientToScreen(_Window, &Point);
+ return Point.x;
+}
+
+int BS_Win32Window::GetClientY()
+{
+ POINT Point = {0, 0};
+ ClientToScreen(_Window, &Point);
+ return Point.y;
+}
+
+int BS_Win32Window::GetWidth()
+{
+ RECT Rect;
+ GetClientRect(_Window, &Rect);
+ return Rect.right - Rect.left;
+}
+
+int BS_Win32Window::GetHeight()
+{
+ RECT Rect;
+ GetClientRect(_Window, &Rect);
+ return Rect.bottom - Rect.top;
+}
+
+std::string BS_Win32Window::GetTitle()
+{
+ char String[512];
+ if (GetWindowText(_Window, String, sizeof(String)))
+ return std::string(String);
+
+ return std::string("");
+}
+
+bool BS_Win32Window::IsVisible()
+{
+ return IsWindowVisible(_Window) ? true : false;
+}
+
+bool BS_Win32Window::HasFocus()
+{
+ return GetForegroundWindow() == _Window ? true : false;
+}
+
+UINT BS_Win32Window::GetWindowHandle()
+{
+ return (UINT)_Window;
+}
+
+// Set Methoden
+// ------------
+
+void BS_Win32Window::SetX(int X)
+{
+ int RealX;
+ if (X == -1)
+ {
+ RECT Rect;
+ GetWindowRect(_Window, &Rect);
+ RealX = (GetSystemMetrics(SM_CXSCREEN) - (Rect.right - Rect.left)) / 2;
+ }
+ else
+ RealX = X;
+
+ SetWindowPos(_Window, NULL, RealX, GetY(), 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+}
+
+void BS_Win32Window::SetY(int Y)
+{
+ int RealY;
+ if (Y == -1)
+ {
+ RECT Rect;
+ GetWindowRect(_Window, &Rect);
+ RealY = (GetSystemMetrics(SM_CYSCREEN) - (Rect.bottom - Rect.top)) / 2;
+ }
+ else
+ RealY = Y;
+
+ SetWindowPos(_Window, NULL, GetX(), RealY, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+}
+
+void BS_Win32Window::SetWidth(int Width)
+{
+ RECT Rect = {0, 0, Width, GetHeight()};
+ AdjustWindowRectEx(&Rect, WINDOW_STYLE, false, WINDOW_STYLE_EX);
+ SetWindowPos(_Window, NULL, 0, 0, Rect.right - Rect.left, Rect.bottom - Rect.top, SWP_NOMOVE | SWP_NOZORDER);
+}
+
+void BS_Win32Window::SetHeight(int Height)
+{
+ RECT Rect = {0, 0, GetWidth(), Height};
+ AdjustWindowRectEx(&Rect, WINDOW_STYLE, false, WINDOW_STYLE_EX);
+ SetWindowPos(_Window, NULL, 0, 0, Rect.right - Rect.left, Rect.bottom - Rect.top, SWP_NOMOVE | SWP_NOZORDER);
+}
+
+void BS_Win32Window::SetVisible(bool Visible)
+{
+ ShowWindow(_Window, Visible ? SW_SHOW : SW_HIDE);
+}
+
+void BS_Win32Window::SetTitle(std::string Title)
+{
+ SetWindowText(_Window, Title.c_str());
+}
+
+// Asynchroner Message-Loop
+bool BS_Win32Window::ProcessMessages()
+{
+ for (UINT i = 0; i < WINDOW_MAX_MESSAGES; i++)
+ {
+ MSG msg;
+ if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
+ {
+ if (msg.message == WM_QUIT)
+ {
+ _WindowAlive = false;
+ return false;
+ }
+
+ // Alle Nachrichten zur Verarbeitung durch WindowProc vorbereiten
+ TranslateMessage(&msg);
+ // Nachricht an WindowProc übergeben
+ DispatchMessage(&msg);
+ }
+ else
+ return true;
+ }
+
+ return true;
+}
+
+// Synchroner Message-Loop
+bool BS_Win32Window::WaitForFocus()
+{
+ MSG msg;
+
+ // Fenster minimieren
+ ShowWindow(_Window, SW_MINIMIZE);
+
+ for (;;)
+ {
+ // Auf Nachricht warten
+ WaitMessage();
+ // Nachricht einlesen
+ GetMessage(&msg, NULL, 0, 0);
+ // Nachricht zur Verarbeitung durch WindowProc vorbereiten
+ TranslateMessage(&msg);
+ // Nachricht an WindowProc übergeben
+ DispatchMessage(&msg);
+
+ // Überprüfen ob das Fenster geschlossen wurde
+ if (msg.message == WM_QUIT)
+ {
+ _WindowAlive = false;
+ return false;
+ }
+
+ // Überprüfen, ob das Fenster den Focus wiedererlangt hat
+ if (HasFocus()) return true;
+ }
+}
+
+// Die WindowProc aller Fenster der Klasse
+LRESULT CALLBACK BS_Win32Window::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_PAINT:
+ ValidateRect(hwnd, NULL);
+ break;
+
+ case WM_DESTROY:
+ // Das Fenster wird zerstört
+ PostQuitMessage(0);
+ break;
+
+ case WM_CLOSE:
+ {
+ BS_Window * WindowPtr = BS_Kernel::GetInstance()->GetWindow();
+ if (WindowPtr) {
+ WindowPtr->SetCloseWanted(true);
+ }
+ break;
+ }
+
+ case WM_KEYDOWN:
+ {
+ // Tastendrücke, die für das Inputmodul interessant sind, werden diesem gemeldet.
+ BS_InputEngine * InputPtr = BS_Kernel::GetInstance()->GetInput();
+
+ if (InputPtr)
+ {
+ switch (wParam)
+ {
+ case VK_RETURN:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_ENTER);
+ break;
+
+ case VK_LEFT:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_LEFT);
+ break;
+
+ case VK_RIGHT:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_RIGHT);
+ break;
+
+ case VK_HOME:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_HOME);
+ break;
+
+ case VK_END:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_END);
+ break;
+
+ case VK_BACK:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_BACKSPACE);
+ break;
+
+ case VK_TAB:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_TAB);
+ break;
+
+ case VK_INSERT:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_INSERT);
+ break;
+
+ case VK_DELETE:
+ InputPtr->ReportCommand(BS_InputEngine::KEY_COMMAND_DELETE);
+ break;
+ }
+ }
+ break;
+ }
+
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ // Alle Tastendrücke werden ignoriert, damit Windows per DefWindowProc() nicht darauf
+ // reagieren kann und damit unerwartete Seiteneffekte auslöst.
+ // Zum Beispiel würden ALT und F10 Tastendrücke das "Menü" aktivieren und somit den Message-Loop zum Stillstand bringen.
+ break;
+
+ case WM_SYSCOMMAND:
+ // Verhindern, dass der Bildschirmschoner aktiviert wird, während das Spiel läuft
+ if (wParam != SC_SCREENSAVE) return DefWindowProc(hwnd,uMsg,wParam,lParam);
+ break;
+
+ case WM_CHAR:
+ {
+ unsigned char theChar = static_cast<unsigned char>(wParam & 0xff);
+
+ // Alle Zeichen, die keine Steuerzeichen sind, werden als Buchstaben dem Input-Service mitgeteilt.
+ if (theChar >= 32)
+ {
+ BS_InputEngine * InputPtr = BS_Kernel::GetInstance()->GetInput();
+ if (InputPtr) InputPtr->ReportCharacter(theChar);
+ }
+ }
+ break;
+
+ case WM_SETCURSOR:
+ {
+ // Der Systemcursor wird in der Client-Area des Fensters nicht angezeigt, jedoch in der nicht Client-Area, damit der Benutzer das Fenster wie gewohnt
+ // schließen und verschieben kann.
+
+ // Koordinaten des Cursors in der Client-Area berechnen.
+ POINT pt;
+ GetCursorPos(&pt);
+ ScreenToClient(hwnd, &pt);
+
+ // Feststellen, ob sich der Cursor in der Client-Area befindet.
+ // Get client rect
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+
+ // See if cursor is in client area
+ if(PtInRect(&rc, pt))
+ // In der Client-Area keinen Cursor anzeigen.
+ SetCursor(NULL);
+ else
+ // Ausserhalb der Client-Area den Cursor anzeigen.
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+
+ return TRUE;
+ }
+ break;
+
+ default:
+ // Um alle anderen Vorkommnisse kümmert sich Windows
+ return DefWindowProc(hwnd,uMsg,wParam,lParam);
+ }
+
+ return 0;
+}
diff --git a/engines/sword25/kernel/win32window.h b/engines/sword25/kernel/win32window.h
new file mode 100755
index 0000000000..e37892a0cb
--- /dev/null
+++ b/engines/sword25/kernel/win32window.h
@@ -0,0 +1,77 @@
+// -----------------------------------------------------------------------------
+// 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_Win32Window
+ -------------
+ Implementation des BS_Window Interfaces für Win32.
+ Zu den einzelnen Methoden bitte "window.h" konsultieren.
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef _BS_WIN32WINDOW_H
+#define _BS_WIN32WINDOW_H
+
+// Includes
+#include "memlog_off.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "memlog_on.h"
+
+#include "common.h"
+#include "window.h"
+
+// Klassendefinition
+class BS_Win32Window : public BS_Window
+{
+public:
+ BS_Win32Window(int X, int Y, int Width, int Height, bool Visible);
+ virtual ~BS_Win32Window();
+
+ bool IsVisible();
+ void SetVisible(bool Visible);
+ int GetX();
+ void SetX(int X);
+ int GetY();
+ void SetY(int X);
+ int GetClientX();
+ int GetClientY();
+ int GetWidth();
+ void SetWidth(int Width);
+ int GetHeight();
+ void SetHeight(int Height);
+ std::string GetTitle();
+ void SetTitle(std::string Title);
+ bool HasFocus();
+ UINT GetWindowHandle();
+ bool WaitForFocus();
+ bool ProcessMessages();
+
+private:
+ static bool _ClassRegistered;
+ bool _WindowAlive;
+ HWND _Window;
+ int _ClientXDelta;
+ int _ClientYDelta;
+
+ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+};
+
+#endif \ No newline at end of file
diff --git a/engines/sword25/kernel/wincodegenerator.cpp b/engines/sword25/kernel/wincodegenerator.cpp
new file mode 100755
index 0000000000..1c264ad17b
--- /dev/null
+++ b/engines/sword25/kernel/wincodegenerator.cpp
@@ -0,0 +1,72 @@
+// -----------------------------------------------------------------------------
+// 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 "md5.h"
+#include "wincodegenerator.h"
+using namespace std;
+
+// -----------------------------------------------------------------------------
+// Hilfsfunktionen und Konstanten
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ const char SECRET[] = "LSZNRVWQJHITMIEGESJMZAYVKGTCDT";
+
+ // -------------------------------------------------------------------------
+
+ string EncodeValue(unsigned int Value)
+ {
+ string Result;
+
+ for (unsigned int i = 0; i < 7; ++i)
+ {
+ Result.push_back(65 + Value % 26);
+ Value /= 26;
+ }
+
+ return Result;
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+string BS_WinCodeGenerator::GetWinCode()
+{
+ // Die System-ID generieren und als String codieren.
+ string SystemID = EncodeValue(GetSystemID());
+
+ // Den Hashwert der System-ID mit dem geheimen String berechnen.
+ BS_MD5 md5;
+ string HashData = SystemID + SECRET;
+ md5.Update(reinterpret_cast<const unsigned char *>(&HashData[0]), HashData.size());
+ unsigned char Digest[16];
+ md5.GetDigest(Digest);
+
+ // Die ersten 32-Bit des Digest werden aus dem Digest extrahiert. Zudem wird das oberste Bit ausmaskiert.
+ // So ist es einfacher den Code serverseitig zu überprüfen, da viele Scriptsprachen mit 32-Bit signed integern rechnen.
+ unsigned int ValidationHash = ((Digest[3] & 0x7f) << 24) + (Digest[2] << 16) + (Digest[1] << 8) + Digest[0];
+
+ // Der Code besteht aus der codierten System-ID und dem codierten Hash.
+ return SystemID + EncodeValue(ValidationHash);
+}
diff --git a/engines/sword25/kernel/wincodegenerator.h b/engines/sword25/kernel/wincodegenerator.h
new file mode 100755
index 0000000000..7e1ee78bd0
--- /dev/null
+++ b/engines/sword25/kernel/wincodegenerator.h
@@ -0,0 +1,43 @@
+// -----------------------------------------------------------------------------
+// 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_WIN_CODE_GENERATOR_H
+#define BS_WIN_CODE_GENERATOR_H
+
+// -----------------------------------------------------------------------------
+// Includes
+// -----------------------------------------------------------------------------
+
+#include <string>
+#include "common.h"
+
+// -----------------------------------------------------------------------------
+// Klassendefinition
+// -----------------------------------------------------------------------------
+
+class BS_WinCodeGenerator
+{
+public:
+ static std::string GetWinCode();
+
+private:
+ static unsigned int GetSystemID();
+};
+
+#endif
diff --git a/engines/sword25/kernel/wincodegenerator_win32.cpp b/engines/sword25/kernel/wincodegenerator_win32.cpp
new file mode 100755
index 0000000000..571a4b9f86
--- /dev/null
+++ b/engines/sword25/kernel/wincodegenerator_win32.cpp
@@ -0,0 +1,128 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <LMCons.h>
+
+#include <vector>
+using namespace std;
+
+#include "md5.h"
+#include "wincodegenerator.h"
+
+// -----------------------------------------------------------------------------
+// Hilfsfunktionen
+// -----------------------------------------------------------------------------
+
+namespace
+{
+ void AddedFixedDrivesEntropy(BS_MD5 & md5)
+ {
+ if (DWORD LogicalDrivesMask = ::GetLogicalDrives())
+ {
+ // Über alle Laufwerke iterieren.
+ char CurrentDriveLetter[] = "A:\\";
+ while (LogicalDrivesMask && CurrentDriveLetter[0] <= 'Z')
+ {
+ if (LogicalDrivesMask & 1)
+ {
+ // Nur feste Laufwerke werden betrachtet, ansonsten würde sich die System-ID ändern, wenn jemand einen USB-Stick ansteckt oder
+ // eine CD einlegt.
+ if (::GetDriveTypeA(CurrentDriveLetter) == DRIVE_FIXED)
+ {
+ // Laufwerksinformationen auslesen.
+ CHAR VolumeNameBuffer[MAX_PATH + 1];
+ DWORD SerialNumber;
+ DWORD MaximumComponentLength;
+ DWORD FileSystemFlags;
+ CHAR FileSystemNameBuffer[MAX_PATH + 1];
+ if (::GetVolumeInformationA(CurrentDriveLetter,
+ VolumeNameBuffer, sizeof(VolumeNameBuffer),
+ &SerialNumber,
+ &MaximumComponentLength,
+ &FileSystemFlags,
+ FileSystemNameBuffer, sizeof(FileSystemNameBuffer)))
+ {
+ // Als Entropie werden genutzt: Laufwerksbuchstabe, Laufwerksbezeichnung, Seriennummer und Dateisystemname.
+ md5.Update(reinterpret_cast<const unsigned char *>(CurrentDriveLetter), strlen(CurrentDriveLetter));
+ md5.Update(reinterpret_cast<const unsigned char *>(VolumeNameBuffer), strlen(VolumeNameBuffer));
+ md5.Update(reinterpret_cast<const unsigned char *>(&SerialNumber), sizeof(SerialNumber));
+ md5.Update(reinterpret_cast<const unsigned char *>(FileSystemNameBuffer), strlen(FileSystemNameBuffer));
+ }
+ }
+ }
+
+ LogicalDrivesMask >>= 1;
+ ++CurrentDriveLetter[0];
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------------
+
+ void AddUserNameEntropy(BS_MD5 & md5)
+ {
+ // Benutzernamen auslesen und als Entropie nutzen.
+ DWORD UserNameLength = UNLEN + 1;
+ CHAR UserName[UNLEN + 1];
+ if (::GetUserNameA(UserName, &UserNameLength))
+ {
+ md5.Update(reinterpret_cast<const unsigned char *>(&UserName[0]), strlen(UserName));
+ }
+ }
+
+ // -------------------------------------------------------------------------
+
+ void AddOSVersionEntropy(BS_MD5 & md5)
+ {
+ // Windows-Version auslesen und in die Einzelkomponenten MajorVersion, MinorVersion und Build aufspalten.
+ DWORD VersionInfo = ::GetVersion();
+
+ DWORD MajorVersion = (DWORD)(LOBYTE(LOWORD(VersionInfo)));
+ DWORD MinorVersion = (DWORD)(HIBYTE(LOWORD(VersionInfo)));
+ DWORD Build = 0;
+ if (VersionInfo < 0x80000000) Build = (DWORD)(HIWORD(VersionInfo));
+
+ // Diese drei Informationen als Entropie nutzen.
+ md5.Update(reinterpret_cast<const unsigned char *>(&MajorVersion), sizeof(DWORD));
+ md5.Update(reinterpret_cast<const unsigned char *>(&MinorVersion), sizeof(DWORD));
+ md5.Update(reinterpret_cast<const unsigned char *>(&Build), sizeof(DWORD));
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+unsigned int BS_WinCodeGenerator::GetSystemID()
+{
+ BS_MD5 md5;
+
+ AddedFixedDrivesEntropy(md5);
+ AddUserNameEntropy(md5);
+ AddOSVersionEntropy(md5);
+
+ unsigned char Digest[16];
+ md5.GetDigest(Digest);
+
+ return (Digest[3] << 24) + (Digest[2] << 16) + (Digest[1] << 8) + Digest[0];
+}
diff --git a/engines/sword25/kernel/window.cpp b/engines/sword25/kernel/window.cpp
new file mode 100755
index 0000000000..b7b6e0aa27
--- /dev/null
+++ b/engines/sword25/kernel/window.cpp
@@ -0,0 +1,53 @@
+// -----------------------------------------------------------------------------
+// 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
+// -----------------------------------------------------------------------------
+
+#include "window.h"
+
+// Alle Implementationen von BS_Window müssen hier eingetragen werden
+#include "win32window.h"
+
+// Erstellt ein Fenster des GUI des aktuellen Betriebssystems
+BS_Window* BS_Window::CreateBSWindow(int X, int Y, int Width, int Height, bool Visible)
+{
+ // Fenster erstellen
+ BS_Window* pWindow = (BS_Window*) new BS_Win32Window(X, Y, Width, Height, Visible);
+
+ // Falls das Fenster erfolgreich initialisiert wurde, wird ein Pointer auf das Fensterobjekt
+ // zurückgegeben
+ if (pWindow->_InitSuccess)
+ return pWindow;
+
+ // Ansonsten wird das Fensterobjekt zerstört und NULL zurückgegeben
+ delete pWindow;
+ return NULL;
+}
+
+// Gibt True zurück wenn das Fenster WM_CLOSE empfangen hat -
+// solange, bis RejectClose() aufgerufen wurde.
+bool BS_Window::CloseWanted()
+{
+ bool result = _CloseWanted;
+ _CloseWanted = false;
+ return result;
+}
+
+void BS_Window::SetCloseWanted(bool Wanted)
+{
+ _CloseWanted = Wanted;
+}
diff --git a/engines/sword25/kernel/window.h b/engines/sword25/kernel/window.h
new file mode 100755
index 0000000000..6a6121f247
--- /dev/null
+++ b/engines/sword25/kernel/window.h
@@ -0,0 +1,176 @@
+// -----------------------------------------------------------------------------
+// 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_Window
+ ---------
+ Simples Fensterklasseninterface.
+ Ist nur aus Gründen der Portabilität in einer Klasse gekapselt.
+ TODO: Für andere Betriebssysteme implementieren
+
+ Autor: Malte Thiesen
+*/
+
+#ifndef _BS_WINDOW_H
+#define _BS_WINDOW_H
+
+// Includes
+#include "common.h"
+
+// Klassendefinition
+/**
+ @brief Ein Simples Fensterklasseninterface.
+
+ Fenster werden ausschließlich mit BS_Window::CreateBSWindow() erstellt. BS_Window wählt
+ dann selbständig die richtige Klasse für das Betriebssystem aus.
+*/
+class BS_Window
+{
+protected:
+ bool _InitSuccess;
+ bool _CloseWanted;
+
+public:
+ virtual ~BS_Window(){};
+
+ /**
+ @brief Gibt den Sichtbarkeitsstatus des Fensters zurück
+ @return Gibt true zurück wenn das Fenster sichtbar ist, andernfalls false
+ */
+ virtual bool IsVisible() = 0;
+ /**
+ @brief Setzt den Sichtbarkeitsstatus des Fensters
+ @param Visible gibt an, ob das Fenster sichtbar oder versteckt sein soll
+ */
+ virtual void SetVisible(bool Visible) = 0;
+ /**
+ @brief Gibt die Position des Fensters auf der X-Achse zurück
+ @return Gibt die Position des Fensters auf der X-Achse zurück
+ */
+ virtual int GetX() = 0;
+ /**
+ @brief Setzt die Position des Fensters auf der X-Achse
+ @param X die X-Position des Fensters oder -1 für zentrierte Ausrichtung auf der X-Achse
+ */
+ virtual void SetX(int X) = 0;
+ /**
+ @brief Gibt die Position des Fensters auf der Y-Achse zurück
+ @return Gibt die Position des Fensters auf der Y-Achse zurück
+ */
+ virtual int GetY() = 0;
+ /**
+ @brief Setzt die Position des Fensters auf der Y-Achse
+ @param Y die Y-Position des Fensters oder -1 für zentrierte Ausrichtung auf der Y-Achse
+ */
+ virtual void SetY(int X) = 0;
+ /**
+ @brief Gibt die Position des Fensterinhaltes auf der X-Achse zurück
+ @return Gibt die Position des Fensterinhaltes auf der X-Achse zurück
+ */
+ virtual int GetClientX() = 0;
+ /**
+ @brief Gibt die Position des Fensterinhaltes auf der Y-Achse zurück
+ @return Gibt die Position des Fensterinhaltes auf der Y-Achse zurück
+ */
+ virtual int GetClientY() = 0;
+ /**
+ @brief Gibt die Breite des Fensters ohne Rahmen zurück
+ @return Gibt die Breite des Fensters ohne Rahmen zurück
+ */
+ virtual int GetWidth() = 0;
+ /**
+ @brief Setzt die Breite des Fensters ohne Rahmen
+ @param Width die Breite des Fensters ohne Rahmen
+ */
+ virtual void SetWidth(int Width) = 0;
+ /**
+ @brief Gibt die Höhe des Fensters ohne Rahmen und Kopfzeile zurück
+ @return Gibt die Höhe des Fensters ohne Rahmen und Kopfzeile zurück
+ */
+ virtual int GetHeight() = 0;
+ /**
+ @brief Setzt die Höhe des Fensters ohne Rahmen und Kopfzeile
+ @param Height die Höhe des Fensters ohne Rahmen und Kopfzeile
+ */
+ virtual void SetHeight(int Height) = 0;
+ /**
+ @brief Gibt den Titel der Fensters zurück
+ @return Gibt den Titel des Fenster zurück
+ */
+ virtual std::string GetTitle() = 0;
+ /**
+ @brief Setzt den Titel des Fensters
+ @param Title der neue Titel des Fensters
+ */
+ virtual void SetTitle(std::string Title) = 0;
+ /**
+ @brief Arbeitet die Windowmessages des Fensters ab.
+ Diese Methode sollte während des Main-Loops aufgerufen werden.
+ @return Gibt false zurück, falls das Fenster geschlossen wurde.
+ */
+ virtual bool ProcessMessages() = 0;
+ /**
+ @brief Pausiert die Applikation bis das Fenster wieder den Focus hat oder geschlossen wurde.
+ @return Gibt false zurück, falls das Fenster geschlossen wurde.
+ */
+ virtual bool WaitForFocus() = 0;
+ /**
+ @brief Gibt zurück, ob das Fenster den Focus hat.
+ @return Gibt true zurück, wenn das Fenster den Focus hat, ansonsten false
+ */
+ virtual bool HasFocus() = 0;
+ /**
+ @brief Gibt das Windowhandle, des Systems zurück.
+ @return Das Windowhandle des Fensters
+ @remark Wenn das Windowshandle benutzt wird, sind die entsprechenden Codeteile
+ natürlich nicht mehr portable.
+ */
+ virtual unsigned int GetWindowHandle() = 0;
+
+
+ /**
+ @brief Setzt den Rückgabewert für den nächsten Aufruf von CloseWanted. Sollte vom
+ Fenster selbst verwendet werden, wenn es geschlossen werden möchte. Dieser
+ Mechanismus erlaubt den Scripten abzufragen, wann das Hauptfenster geschlossen
+ werden soll, und sich entsprechend zu beenden, bzw. beim Nutzer nachzufragen.
+ **/
+ void SetCloseWanted(bool Wanted);
+ /**
+ @brief Gibt einmal den Wert des letztes Aufrufs von SetCloseWanted zurück,
+ und danach sofort wieder false, solange bis mit SetCloseWanted wieder
+ ein neuer Wert gesetzt wird.
+ **/
+ bool CloseWanted();
+
+
+ /**
+ @brief Erstellt eine neue Fensterinstanz.
+ @param X die X-Position des Fensters oder -1 für zentrierte Ausrichtung auf der X-Achse
+ @param Y des Y-Position des Fensters oder -1 für zentrierte Ausrichtung auf der Y-Achsen
+ @param Width die Breite des Fensters ohne Rahmen
+ @param Height die Höhe des Fensters ohne Rahmen und Kopfzeile
+ @param Visible gibt an, ob das Fenster dargestellt werden soll
+ @return Gibt einen Pointer auf ein Fensterobjekt zurück, oder NULL wenn das Erstellen
+ fehlgeschlagen ist.
+ @remark Das Fenster muss nach Benutzung mit delete freigegeben werden!
+ */
+ static BS_Window* CreateBSWindow(int X, int Y, int Width, int Height, bool Visible);
+};
+
+#endif \ No newline at end of file