mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-23 14:53:52 +00:00
292 lines
7.0 KiB
C++
292 lines
7.0 KiB
C++
#include "ResourceManager.h"
|
|
#include "VirtualDirectory.h"
|
|
#include "FileManager.h"
|
|
#include "HostFileSystem.h"
|
|
#include "HostMemoryBuffer.h"
|
|
#include "IOStream.h"
|
|
#include "MacBinary2.h"
|
|
#include "MacFileMem.h"
|
|
#include "MemReaderStream.h"
|
|
#include "MemoryManager.h"
|
|
#include "MMHandleBlock.h"
|
|
#include "ResourceCompiledTypeList.h"
|
|
#include "ResourceFile.h"
|
|
#include "PLPasStr.h"
|
|
#include "PLErrorCodes.h"
|
|
|
|
#include <vector>
|
|
|
|
namespace PortabilityLayer
|
|
{
|
|
struct MMHandleBlock;
|
|
|
|
class ResourceManagerImpl final : public ResourceManager
|
|
{
|
|
public:
|
|
ResourceManagerImpl();
|
|
|
|
void Init() override;
|
|
void Shutdown() override;
|
|
|
|
void SetResLoad(bool load) override;
|
|
|
|
ResourceFile *LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const override;
|
|
short OpenResFork(VirtualDirectory_t virtualDir, const PLPasStr &filename) override;
|
|
void CloseResFile(short ref) override;
|
|
PLError_t CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) override;
|
|
|
|
THandle<void> GetResource(const ResTypeID &resType, int id) override;
|
|
|
|
short GetCurrentResFile() const override;
|
|
void SetCurrentResFile(short ref) override;
|
|
|
|
void DissociateHandle(MMHandleBlock *hdl) const override;
|
|
const ResourceCompiledRef *ResourceForHandle(MMHandleBlock *hdl) const override;
|
|
|
|
static ResourceManagerImpl *GetInstance();
|
|
|
|
private:
|
|
struct ResFileSlot
|
|
{
|
|
short m_prevFile;
|
|
short m_nextFile;
|
|
ResourceFile *m_resourceFile;
|
|
};
|
|
|
|
void UnloadAndDestroyResourceFile(ResourceFile *rf);
|
|
|
|
std::vector<ResFileSlot> m_resFiles;
|
|
short m_firstResFile;
|
|
short m_lastResFile;
|
|
short m_currentResFile;
|
|
bool m_load;
|
|
|
|
static ResourceManagerImpl ms_instance;
|
|
};
|
|
|
|
ResourceManagerImpl::ResourceManagerImpl()
|
|
: m_currentResFile(-1)
|
|
, m_firstResFile(-1)
|
|
, m_lastResFile(-1)
|
|
, m_load(true)
|
|
{
|
|
}
|
|
|
|
void ResourceManagerImpl::Init()
|
|
{
|
|
m_currentResFile = OpenResFork(VirtualDirectories::kApplicationData, PSTR("ApplicationResources"));
|
|
}
|
|
|
|
void ResourceManagerImpl::Shutdown()
|
|
{
|
|
for (std::vector<ResFileSlot>::iterator it = m_resFiles.begin(), itEnd = m_resFiles.end(); it != itEnd; ++it)
|
|
{
|
|
if (it->m_resourceFile)
|
|
UnloadAndDestroyResourceFile(it->m_resourceFile);
|
|
}
|
|
|
|
m_resFiles.clear();
|
|
}
|
|
|
|
short ResourceManagerImpl::GetCurrentResFile() const
|
|
{
|
|
return m_currentResFile;
|
|
}
|
|
|
|
void ResourceManagerImpl::SetCurrentResFile(short ref)
|
|
{
|
|
m_currentResFile = ref;
|
|
}
|
|
|
|
void ResourceManagerImpl::DissociateHandle(MMHandleBlock *hdl) const
|
|
{
|
|
assert(hdl->m_rmSelfRef);
|
|
assert(hdl->m_rmSelfRef->m_handle == hdl);
|
|
hdl->m_rmSelfRef->m_handle = nullptr;
|
|
hdl->m_rmSelfRef = nullptr;
|
|
}
|
|
|
|
const ResourceCompiledRef *ResourceManagerImpl::ResourceForHandle(MMHandleBlock *hdl) const
|
|
{
|
|
return hdl->m_rmSelfRef;
|
|
}
|
|
|
|
void ResourceManagerImpl::UnloadAndDestroyResourceFile(ResourceFile *rf)
|
|
{
|
|
PortabilityLayer::MemoryManager *mm = PortabilityLayer::MemoryManager::GetInstance();
|
|
|
|
ResourceCompiledTypeList *rtls = nullptr;
|
|
size_t numRTLs = 0;
|
|
rf->GetAllResourceTypeLists(rtls, numRTLs);
|
|
|
|
for (size_t i = 0; i < numRTLs; i++)
|
|
{
|
|
const ResourceCompiledTypeList &rtl = rtls[i];
|
|
|
|
const size_t numRefs = rtl.m_numRefs;
|
|
for (size_t r = 0; r < numRefs; r++)
|
|
{
|
|
const ResourceCompiledRef &ref = rtl.m_firstRef[r];
|
|
if (MMHandleBlock *hdl = ref.m_handle)
|
|
mm->ReleaseHandle(hdl);
|
|
}
|
|
}
|
|
|
|
rf->Destroy();
|
|
}
|
|
|
|
ResourceManagerImpl *ResourceManagerImpl::GetInstance()
|
|
{
|
|
return &ms_instance;
|
|
}
|
|
|
|
void ResourceManagerImpl::SetResLoad(bool load)
|
|
{
|
|
m_load = load;
|
|
}
|
|
|
|
ResourceFile *ResourceManagerImpl::LoadResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename) const
|
|
{
|
|
IOStream *fStream = nullptr;
|
|
if (FileManager::GetInstance()->RawOpenFileResources(virtualDir, filename, EFilePermission_Read, true, GpFileCreationDispositions::kOpenExisting, fStream) != PLErrors::kNone)
|
|
return nullptr;
|
|
|
|
ResourceFile *resFile = ResourceFile::Create();
|
|
if (!resFile)
|
|
return nullptr;
|
|
|
|
bool loaded = resFile->Load(fStream);
|
|
fStream->Close();
|
|
|
|
if (!loaded)
|
|
{
|
|
resFile->Destroy();
|
|
return nullptr;
|
|
}
|
|
|
|
return resFile;
|
|
}
|
|
|
|
short ResourceManagerImpl::OpenResFork(VirtualDirectory_t virtualDir, const PLPasStr &filename)
|
|
{
|
|
const size_t numSlots = m_resFiles.size();
|
|
size_t resFileIndex = numSlots;
|
|
|
|
for (size_t i = 0; i < numSlots; i++)
|
|
{
|
|
if (m_resFiles[i].m_resourceFile == nullptr)
|
|
{
|
|
resFileIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (resFileIndex == 0x7fff)
|
|
return -1;
|
|
|
|
|
|
ResourceFile *resFile = LoadResFile(virtualDir, filename);
|
|
|
|
if (!resFile)
|
|
return -1;
|
|
|
|
ResFileSlot slot;
|
|
slot.m_resourceFile = resFile;
|
|
slot.m_prevFile = m_lastResFile;
|
|
slot.m_nextFile = -1;
|
|
|
|
if (resFileIndex == numSlots)
|
|
m_resFiles.push_back(slot);
|
|
else
|
|
m_resFiles[resFileIndex] = slot;
|
|
|
|
const short rfid = static_cast<short>(resFileIndex);
|
|
|
|
if (m_firstResFile < 0)
|
|
m_firstResFile = rfid;
|
|
|
|
if (m_lastResFile >= 0)
|
|
m_resFiles[m_lastResFile].m_nextFile = rfid;
|
|
|
|
m_lastResFile = rfid;
|
|
m_currentResFile = rfid; // Resource Manager is supposed to reset the search stack on new file open
|
|
|
|
return rfid;
|
|
}
|
|
|
|
void ResourceManagerImpl::CloseResFile(short ref)
|
|
{
|
|
ResFileSlot &slot = m_resFiles[ref];
|
|
|
|
assert(slot.m_resourceFile != nullptr);
|
|
|
|
slot.m_resourceFile->Destroy();
|
|
slot.m_resourceFile = nullptr;
|
|
|
|
if (m_lastResFile == ref)
|
|
m_lastResFile = slot.m_prevFile;
|
|
|
|
if (slot.m_prevFile >= 0)
|
|
{
|
|
ResFileSlot &prevFileSlot = m_resFiles[slot.m_prevFile];
|
|
prevFileSlot.m_nextFile = slot.m_nextFile;
|
|
}
|
|
|
|
if (slot.m_nextFile >= 0)
|
|
{
|
|
ResFileSlot &nextFileSlot = m_resFiles[slot.m_nextFile];
|
|
nextFileSlot.m_prevFile = slot.m_prevFile;
|
|
}
|
|
|
|
slot.m_nextFile = slot.m_prevFile = -1;
|
|
|
|
m_currentResFile = m_lastResFile;
|
|
}
|
|
|
|
PLError_t ResourceManagerImpl::CreateBlankResFile(VirtualDirectory_t virtualDir, const PLPasStr &filename)
|
|
{
|
|
const uint8_t blankResFileData[] = {
|
|
0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 30,
|
|
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, 28, 0, 30, 255, 255 };
|
|
|
|
PortabilityLayer::IOStream *stream = nullptr;
|
|
PLError_t error = FileManager::GetInstance()->RawOpenFileResources(virtualDir, filename, EFilePermission_Write, true, GpFileCreationDispositions::kCreateOrOverwrite, stream);
|
|
if (error)
|
|
return error;
|
|
|
|
if (stream->Write(blankResFileData, sizeof(blankResFileData)) != sizeof(blankResFileData))
|
|
{
|
|
stream->Close();
|
|
return PLErrors::kIOError;
|
|
}
|
|
|
|
stream->Close();
|
|
|
|
return PLErrors::kNone;
|
|
}
|
|
|
|
THandle<void> ResourceManagerImpl::GetResource(const ResTypeID &resType, int id)
|
|
{
|
|
short searchIndex = m_currentResFile;
|
|
while (searchIndex >= 0)
|
|
{
|
|
const ResFileSlot& slot = m_resFiles[searchIndex];
|
|
assert(slot.m_resourceFile);
|
|
|
|
THandle<void> resHdl = slot.m_resourceFile->GetResource(resType, id, m_load);
|
|
if (resHdl != nullptr)
|
|
return resHdl;
|
|
|
|
searchIndex = slot.m_prevFile;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
ResourceManagerImpl ResourceManagerImpl::ms_instance;
|
|
|
|
ResourceManager *ResourceManager::GetInstance() { return ResourceManagerImpl::GetInstance(); }
|
|
}
|