From a683a420a9e43705c972b5e74d55e319729e1a81 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Thu, 29 Jul 2010 19:53:02 +0000 Subject: SWORD25: Importing original sources svn-id: r53171 --- engines/sword25/kernel/resmanager.cpp | 293 ++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100755 engines/sword25/kernel/resmanager.cpp (limited to 'engines/sword25/kernel/resmanager.cpp') 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::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::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::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::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::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::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& HashBucket = m_ResourceHashTable[BS_String::GetHash(UniqueFileName) % HASH_TABLE_BUCKETS]; + { + std::list::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::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 -- cgit v1.2.3