Danbias/Code/Misc/Resource/ResourceManager.cpp

449 lines
10 KiB
C++
Raw Normal View History

/////////////////////////////////////////////////////////////////////
// Created by [Dennis Andersen] [2013]
/////////////////////////////////////////////////////////////////////
#include "ResourceManager.h"
#include "..\Utilities.h"
using namespace Oyster::Resource;
struct ::ResourceData
{
LoadFunction loadFnc;
UnloadFunction unloadFnc;
ResourceType resourcetype;
HRESOURCE resource;
unsigned int resourceSize;
int resourceID;
Utility::DynamicMemory::ReferenceCount referenceCount;
};
bool ReadFromFile(const wchar_t fileName[], const char openFlag[], std::string& outData, size_t elemSize, bool ANSI = false)
{
std::string sFilename;
std::wstring wsFile = fileName;
::Utility::String::WStringToString(wsFile, sFilename);
size_t bytesTotal = 0;
size_t bytesRead = 0;
FILE *stream;
if( fopen_s( &stream, sFilename.c_str(), openFlag ) == 0 )
{
//Get size of the file
fseek(stream, 0L, SEEK_END);
bytesTotal = ftell(stream);
fseek(stream, 0L, SEEK_SET);
fflush(stream);
//Sanity check
if(bytesTotal == 0) return false;
//Create the new byte buffer
char *buff = new char[bytesTotal + 1];
//Read the bytes to the end
bytesRead = fread_s( buff, bytesTotal, elemSize, bytesTotal ,stream );
fclose( stream );
//Did we read enough bytes (Get the bytes if we read with ANSI since the hidden characters is ignored)
if(!ANSI && bytesRead != bytesTotal) return false;
buff[bytesRead + 1];
outData.clear();
outData.resize(bytesRead);
memcpy(&outData[0], &buff[0], bytesRead);
delete [] buff;
}
else
{
std::string msg = "Failed to open file: \n";
msg.append(sFilename.c_str());
return false;
}
return true;
}
const wchar_t* FindResourceKey(std::map<std::wstring, ResourceData*>& resources, const HRESOURCE h)
{
for (auto i = resources.begin(); i != resources.end() ; i++)
{
if(i->second->resource == h)
{
return i->first.c_str();
}
}
return 0;
}
ResourceData* FindResource(std::map<std::wstring, ResourceData*>& resources, const HRESOURCE h)
{
for (auto i = resources.begin(); i != resources.end() ; i++)
{
if(i->second->resource == h)
{
return i->second;
}
}
return 0;
}
ResourceData* FindResource(std::map<std::wstring, ResourceData*>& resources, const wchar_t c[])
{
std::wstring temp = c;
auto t = resources.find(c);
if(t == resources.end()) return 0;
return t->second;
}
void SaveResource( std::map<std::wstring, ResourceData*>& resources, ResourceData* r, const std::wstring& key, bool addNew )
{
if(addNew)
{
resources[key] = r;
}
r->referenceCount.Incref();
}
bool Release(std::map<std::wstring, ResourceData*>& resources, ResourceData* resource)
{
if(resource->referenceCount.Decref() == 0)
{
const wchar_t* temp = FindResourceKey(resources, resource->resource);
switch (resource->resourcetype)
{
case Oyster::Resource::ResourceType_Byte_Raw:
case Oyster::Resource::ResourceType_Byte_ANSI:
case Oyster::Resource::ResourceType_Byte_UTF8:
case Oyster::Resource::ResourceType_Byte_UNICODE:
case Oyster::Resource::ResourceType_Byte_UTF16LE:
delete [] ((char*)resource->resource);
resource->resource = 0;
break;
2014-01-31 11:00:04 +01:00
case Oyster::Resource::ResourceType_CUSTOM:
resource->unloadFnc(resource->resource);
resource->resource = 0;
break;
}
if(temp) delete resources[temp];
return true;
}
return false;
}
ResourceData* Load(/*Out*/ResourceData* targetMem, /*in*/const wchar_t source[], /*in*/ResourceType type)
{
2014-01-31 11:00:04 +01:00
targetMem->resource = 0;
targetMem->loadFnc = 0;
targetMem->unloadFnc = 0;
targetMem->resourceID = 0;
targetMem->resourcetype = type;
targetMem->resourceSize = 0;
std::string sOut;
bool success = false;
switch (type)
{
case Oyster::Resource::ResourceType_Byte_Raw:
success = ReadFromFile(source, "rb", sOut, sizeof(char));
break;
case Oyster::Resource::ResourceType_Byte_ANSI:
success = ReadFromFile(source, "r", sOut, sizeof(char), true);
break;
case Oyster::Resource::ResourceType_Byte_UTF8:
success = ReadFromFile(source, "r, ccs=UTF-8", sOut, sizeof(char));
break;
case Oyster::Resource::ResourceType_Byte_UNICODE:
success = ReadFromFile(source, "r, ccs=UNICODE", sOut, sizeof(char));
break;
case Oyster::Resource::ResourceType_Byte_UTF16LE:
success = ReadFromFile(source, "r, ccs=UTF-16LE", sOut, sizeof(char));
break;
}
if(!success) return 0;
if(sOut.size())
{
char *data = new char[sOut.size()+1];
data[sOut.size()] = '\0';
memcpy(&data[0], &sOut[0], sOut.size());
targetMem->resource = (HRESOURCE&)data;
targetMem->loadFnc = 0;
targetMem->unloadFnc = 0;
targetMem->resourceID = 0;
targetMem->resourcetype = type;
}
return targetMem;
}
ResourceData* Load(/*Out*/ResourceData* targetMem, /*in*/const wchar_t source[], LoadFunction loadFnc, UnloadFunction unloadFnc)
{
2014-01-31 11:00:04 +01:00
targetMem->resource = 0;
targetMem->loadFnc = 0;
targetMem->unloadFnc = 0;
targetMem->resourceID = 0;
targetMem->resourcetype = ResourceType_CUSTOM;
targetMem->resourceSize = 0;
if(loadFnc)
{
targetMem->resource = loadFnc(source);
if(targetMem->resource)
{
targetMem->resourceSize = 0;
2014-01-31 11:00:04 +01:00
targetMem->resourcetype = ResourceType_CUSTOM;
targetMem->loadFnc = loadFnc;
targetMem->unloadFnc = unloadFnc;
}
}
return targetMem;
}
ResourceData* Reload(std::map<std::wstring, ResourceData*> resources, ResourceData* resource, const wchar_t* filename)
{
switch (resource->resourcetype)
{
case Oyster::Resource::ResourceType_Byte_Raw:
case Oyster::Resource::ResourceType_Byte_ANSI:
case Oyster::Resource::ResourceType_Byte_UTF8:
case Oyster::Resource::ResourceType_Byte_UNICODE:
case Oyster::Resource::ResourceType_Byte_UTF16LE:
if(Release(resources, resource))
return Load(resource, filename, resource->loadFnc, resource->unloadFnc);
break;
2014-01-31 11:00:04 +01:00
case Oyster::Resource::ResourceType_CUSTOM:
{
resource->unloadFnc(resource->resource);
HRESOURCE r = resource->loadFnc(filename);
if(!r) return 0;
resource->resource = r;
}
break;
}
return resource;
}
ResourceManager::ResourceManager()
{ }
ResourceManager::~ResourceManager()
{ Clean(); }
HBYTEARRAY ResourceManager::LoadBytes(const wchar_t filename[], ResourceType type, int customID, bool force)
{
if(!filename) return 0;
ResourceData *t = FindResource(this->resources, filename);
if(t)
{
if(force)
{
return (HBYTEARRAY)Reload(resources, t, filename )->resource;
}
else
{
//Add new reference
SaveResource(this->resources, t, filename, false);
return (HBYTEARRAY)t->resource;
}
}
else
{
t = Load(new ResourceData(), filename, type);
if(t)
{
t->resourceID = (customID);
SaveResource(this->resources, t, filename, true);
}
else
{
return 0;
}
}
return (HBYTE*)t->resource;
}
HRESOURCE ResourceManager::LoadResource(const wchar_t filename[], LoadFunction loadFnc, UnloadFunction unloadFnc, int customId, bool force)
{
if(!filename)
{
return 0;
}
2014-01-31 22:52:52 +01:00
if(!loadFnc || !unloadFnc)
{
return 0;
}
ResourceData *t = FindResource(this->resources, filename);
if(t)
{
2014-01-31 22:52:52 +01:00
t->loadFnc = loadFnc;
t->unloadFnc = unloadFnc;
if(force)
{
return ResourceManager::ReloadResource(filename);
}
else
{
//Add new reference
SaveResource(this->resources, t, filename, false);
return t->resource;
}
}
else
{
t = Load(new ResourceData(), filename, loadFnc, unloadFnc );
if(t)
{
t->resourceID = (customId);
SaveResource(this->resources, t, filename, true);
}
else
{
delete t;
}
}
if(!t)
{
return 0;
}
return (HRESOURCE)t->resource;
}
HRESOURCE ResourceManager::ReloadResource(const wchar_t filename[])
{
ResourceData *t = FindResource(this->resources, filename);
if(!t) return 0; //The resource has not been loaded
return Reload(this->resources, t, filename)->resource;
}
HRESOURCE ResourceManager::ReloadResource(HRESOURCE& resource)
{
ResourceData *t = FindResource(this->resources, resource);
if(!t) return 0;
return Reload(this->resources, t, FindResourceKey(this->resources, resource))->resource;
}
void ResourceManager::Clean()
{
if(this->resources.empty()) return;
auto i = this->resources.begin();
auto last = resources.end();
for (i; i != last; i++)
{
//Remove all the references
while (!Release(this->resources, i->second));
}
resources.clear();
}
void ResourceManager::ReleaseResource(const HRESOURCE& resourceData)
{
ResourceData *t = FindResource(this->resources, resourceData);
if(t)
{
if(Release(resources, t))
{
const wchar_t* temp = 0;
if((temp = FindResourceKey(resources, resourceData)))
{
std::wstring ws = std::wstring(temp);
delete resources[ws];
resources.erase(ws);
}
}
}
}
void ResourceManager::ReleaseResource(const wchar_t filename[])
{
ResourceData *t = FindResource(this->resources, filename);
if(t)
{
if(Release(resources, t))
{
delete resources[filename];
resources.erase(filename);
}
}
}
void ResourceManager::SetResourceId (const HRESOURCE& resourceData, unsigned int id)
{
ResourceData *t = FindResource(this->resources, resourceData);
if(t) t->resourceID = (id);
}
void ResourceManager::SetResourceId(const wchar_t c[], unsigned int id)
{
ResourceData *t = FindResource(this->resources, c);
if(t) t->resourceID = (id);
}
ResourceType ResourceManager::GetResourceType (const HRESOURCE& resourceData)
{
ResourceData *t = FindResource(this->resources, resourceData);
if(t) return t->resourcetype;
return ResourceType_INVALID;
}
ResourceType ResourceManager::GetResourceType (const wchar_t c[])
{
ResourceData *t = FindResource(this->resources, c);
if(t) return t->resourcetype;
return ResourceType_INVALID;
}
const wchar_t* ResourceManager::GetResourceFilename (const HRESOURCE& resourceData)
{
return FindResourceKey(this->resources, resourceData);
}
HRESOURCE ResourceManager::GetResourceHandle(const wchar_t filename[])
{
ResourceData *t = FindResource(this->resources, filename);
if(t) return t->resource;
return 0;
}
int ResourceManager::GetResourceId (const HRESOURCE& resourceData)
{
ResourceData *t = FindResource(this->resources, resourceData);
if(t) return t->resourceID;
return -1;
}
int ResourceManager::GetResourceId(const wchar_t c[])
{
ResourceData *t = FindResource(this->resources, c);
if(t) return t->resourceID;
return -1;
}