Skip to content
Permalink
Browse files

Reduce allocations for IFP loading

  • Loading branch information...
botder committed Sep 30, 2019
1 parent d447509 commit 438bac5fc723efd4632198355f963ae50ef944ab
@@ -38,32 +38,34 @@ void CClientIFP::Unlink()
}
}

bool CClientIFP::LoadIFP(const SString& strFile, const bool isRawData, const SString& strBlockName)
bool CClientIFP::Load(SString blockName, bool isRawData, SString input)
{
m_strBlockName = strBlockName;
m_strBlockName = std::move(blockName);
m_pVecAnimations = &m_pIFPAnimations->vecAnimations;

if (LoadIFPFile(strFile, isRawData))
if (isRawData)
{
m_u32Hashkey = HashString(strBlockName.ToLower());
return true;
if (!CFileReader::LoadFromBuffer(std::move(input)))
return false;
}
else
{
if (!CFileReader::LoadFromFile(std::move(input)))
return false;
}
return false;
}

bool CClientIFP::LoadIFPFile(const SString& strFile, const bool isRawData)
{
if (isRawData ? LoadDataBufferToMemory(strFile) : LoadFileToMemory(strFile))
bool success = ReadIFPByVersion();

if (success)
{
if (ReadIFPByVersion())
{
// We are freeing the file reader memory because we don't need to read it anymore.
// This function does not unload IFP, to unload ifp, use destroyElement from Lua
FreeFileReaderMemory();
return true;
}
m_u32Hashkey = HashString(m_strBlockName.ToLower());
}
return false;

// We are freeing the file reader memory because we don't need to read it anymore.
// This function does not unload IFP, to unload ifp, use destroyElement from Lua
FreeFileReaderMemory();

return success;
}

bool CClientIFP::ReadIFPByVersion()
@@ -202,7 +202,7 @@ class CClientIFP : public CClientEntity, CFileReader
void MarkAsUnloading() { m_bUnloading = true; }
bool IsUnloading() { return m_bUnloading; }

bool LoadIFP(const SString& strFile, const bool isRawData, const SString& strBlockName);
bool Load(SString blockName, bool isRawData, SString input);

const SString& GetBlockName() { return m_strBlockName; }
const unsigned int& GetBlockNameHash() { return m_u32Hashkey; }
@@ -216,7 +216,6 @@ class CClientIFP : public CClientEntity, CFileReader
void SetPosition(const CVector& vecPosition){};

private:
bool LoadIFPFile(const SString& strFile, const bool isRawData);
bool ReadIFPByVersion();
void ReadIFPVersion1();
void ReadIFPVersion2(bool bAnp3);
@@ -18,22 +18,22 @@ CFileReader::CFileReader()

void CFileReader::FreeFileReaderMemory()
{
std::vector<char>().swap(m_vecFileDataBuffer);
SString().swap(m_buffer);
m_u32BytesReadFromBuffer = 0;
}

void CFileReader::ReadBytes(void* pDestination, const std::uint32_t u32BytesToRead)
{
const std::uint32_t u32ReadOffset = m_u32BytesReadFromBuffer;
m_u32BytesReadFromBuffer += u32BytesToRead;
memcpy(pDestination, &m_vecFileDataBuffer[u32ReadOffset], u32BytesToRead);
memcpy(pDestination, m_buffer.data() + u32ReadOffset, u32BytesToRead);
}

void CFileReader::ReadStringNullTerminated(char* pDestination, const std::uint32_t u32BytesToRead)
{
const std::uint32_t u32ReadOffset = m_u32BytesReadFromBuffer;
m_u32BytesReadFromBuffer += u32BytesToRead;
memcpy(pDestination, &m_vecFileDataBuffer[u32ReadOffset], u32BytesToRead);
memcpy(pDestination, m_buffer.data() + u32ReadOffset, u32BytesToRead);
*(pDestination + (u32BytesToRead - 1)) = '\0';
}

@@ -42,36 +42,13 @@ void CFileReader::SkipBytes(const std::uint32_t u32BytesToSkip)
m_u32BytesReadFromBuffer += u32BytesToSkip;
}

bool CFileReader::LoadFileToMemory(const SString& strFilePath)
bool CFileReader::LoadFromFile(SString filePath) noexcept
{
std::ifstream fileStream(FromUTF8(strFilePath), std::ios::binary | std::ios::ate);
std::streamsize iFileSize = fileStream.tellg();
if (iFileSize == eIFSTREAM::SIZE_ERROR)
{
return false;
}

fileStream.seekg(0, std::ios::beg);
m_vecFileDataBuffer.resize(static_cast<size_t>(iFileSize), '\0');
if (fileStream.read(m_vecFileDataBuffer.data(), iFileSize))
{
return true;
}
return false;
return FileLoad(std::nothrow, filePath, m_buffer);
}

bool CFileReader::LoadDataBufferToMemory(const SString& buffer)
bool CFileReader::LoadFromBuffer(SString buffer) noexcept
{
std::streamsize iBufferSize = buffer.size();
if (iBufferSize == eIFSTREAM::SIZE_ERROR)
{
return false;
}

m_vecFileDataBuffer.resize(static_cast<size_t>(iBufferSize));
if (std::copy(buffer.begin(), buffer.end(), m_vecFileDataBuffer.data()))
{
return true;
}
return false;
m_buffer.swap(buffer);
return true;
}
@@ -21,8 +21,10 @@ class CFileReader
};

CFileReader();
bool LoadFileToMemory(const SString& strFilePath);
bool LoadDataBufferToMemory(const SString& buffer);

bool LoadFromFile(SString filePath) noexcept;
bool LoadFromBuffer(SString buffer) noexcept;

// Do not call any file reader functions after calling this function
void FreeFileReaderMemory();

@@ -31,7 +33,7 @@ class CFileReader
{
const std::uint32_t u32ReadOffset = m_u32BytesReadFromBuffer;
m_u32BytesReadFromBuffer += sizeof(T);
*pDestination = *reinterpret_cast<T*>(&m_vecFileDataBuffer[u32ReadOffset]);
*pDestination = *reinterpret_cast<T*>(m_buffer.data() + u32ReadOffset);
}

void ReadBytes(void* pDestination, const std::uint32_t u32BytesToRead);
@@ -40,13 +42,13 @@ class CFileReader

std::uint32_t GetRemainingBytesCount() const noexcept
{
if (static_cast<std::uint32_t>(m_vecFileDataBuffer.size()) > m_u32BytesReadFromBuffer)
return static_cast<std::uint32_t>(m_vecFileDataBuffer.size()) - m_u32BytesReadFromBuffer;
if (static_cast<std::uint32_t>(m_buffer.size()) > m_u32BytesReadFromBuffer)
return static_cast<std::uint32_t>(m_buffer.size()) - m_u32BytesReadFromBuffer;
else
return 0;
}

private:
std::vector<char> m_vecFileDataBuffer;
std::uint32_t m_u32BytesReadFromBuffer;
SString m_buffer;
std::uint32_t m_u32BytesReadFromBuffer;
};
@@ -10,27 +10,26 @@

#include <StdInc.h>

std::shared_ptr<CClientIFP> CIFPEngine::EngineLoadIFP(CResource* pResource, CClientManager* pManager, const SString& strFile, bool bIsRawData,
const SString& strBlockName)
std::shared_ptr<CClientIFP> CIFPEngine::LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input)
{
// Grab the resource root entity
CClientEntity* pRoot = pResource->GetResourceIFPRoot();
const unsigned int u32BlockNameHash = HashString(strBlockName.ToLower());
const unsigned int u32BlockNameHash = HashString(blockName.ToLower());

// Check whether the IFP blockname exists or not
if (g_pClientGame->GetIFPPointerFromMap(u32BlockNameHash) == nullptr)
{
// Create a IFP element
std::shared_ptr<CClientIFP> pIFP(new CClientIFP(pManager, INVALID_ELEMENT_ID));
std::shared_ptr<CClientIFP> pIFP(new CClientIFP(clientManager, INVALID_ELEMENT_ID));

// Try to load the IFP file
if (pIFP->LoadIFP(strFile, bIsRawData, strBlockName))
if (pIFP->Load(blockName, isRawInput, std::move(input)))
{
// We can use the map to retrieve correct IFP by block name later
g_pClientGame->InsertIFPPointerToMap(u32BlockNameHash, pIFP);

// Success loading the file. Set parent to IFP root
pIFP->SetParent(pRoot);
pIFP->SetParent(resource->GetResourceIFPRoot());

return pIFP;
}
}
@@ -23,8 +23,7 @@ class CIFPEngine
ALL
};

static std::shared_ptr<CClientIFP> EngineLoadIFP(CResource* pResource, CClientManager* pManager, const SString& strFile, bool bIsRawData,
const SString& strBlockName);
static std::shared_ptr<CClientIFP> LoadIFP(CResource* resource, CClientManager* clientManager, const SString& blockName, bool isRawInput, SString input);
static bool EngineReplaceAnimation(CClientEntity* pEntity, const SString& strInternalBlockName, const SString& strInternalAnimName,
const SString& strCustomBlockName, const SString& strCustomAnimName);
static bool EngineRestoreAnimation(CClientEntity* pEntity, const SString& strInternalBlockName, const SString& strInternalAnimName,
@@ -329,13 +329,13 @@ int CLuaEngineDefs::EngineLoadTXD(lua_State* luaVM)

int CLuaEngineDefs::EngineLoadIFP(lua_State* luaVM)
{
SString strFile = "";
SString strBlockName = "";
SString input;
SString blockName;

CScriptArgReader argStream(luaVM);
// Grab the IFP filename or data
argStream.ReadString(strFile);
argStream.ReadString(strBlockName);
argStream.ReadString(input);
argStream.ReadString(blockName);

if (!argStream.HasErrors())
{
@@ -347,30 +347,48 @@ int CLuaEngineDefs::EngineLoadIFP(lua_State* luaVM)
CResource* pResource = pLuaMain->GetResource();
if (pResource)
{
bool bIsRawData = CIFPEngine::IsIFPData(strFile);
SString strPath;
bool bIsRawData = CIFPEngine::IsIFPData(input);

// Do not proceed if the file path length appears too long to be real
if (!bIsRawData && input.size() > 32767)
{
argStream.SetCustomError("Corrupt IFP file data or file path too long", "Error loading IFP");
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
lua_pushboolean(luaVM, false);
return 1;
}

SString filePath;

// Is this a legal filepath?
if (bIsRawData || CResourceManager::ParseResourcePathInput(strFile, pResource, &strPath))
if (bIsRawData || CResourceManager::ParseResourcePathInput(input, pResource, &filePath))
{
std::shared_ptr<CClientIFP> pIFP = CIFPEngine::EngineLoadIFP(pResource, m_pManager, bIsRawData ? strFile : strPath, bIsRawData, strBlockName);
if (pIFP != nullptr)
std::shared_ptr<CClientIFP> pIFP = CIFPEngine::LoadIFP(pResource, m_pManager, std::move(blockName), bIsRawData, bIsRawData ? std::move(input) : std::move(filePath));

if (pIFP)
{
// Return the IFP element
lua_pushelement(luaVM, pIFP.get());
return 1;
}
else
argStream.SetCustomError(bIsRawData ? "raw data" : strFile, "Error loading IFP");
{
argStream.SetCustomError(bIsRawData ? "raw data" : input, "Error loading IFP");
}
}
else
argStream.SetCustomError(bIsRawData ? "raw data" : strFile, "Bad file path");
{
argStream.SetCustomError(bIsRawData ? "raw data" : input, "Bad file path");
}
}
}
}

if (argStream.HasErrors())
{
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
}

// We failed
lua_pushboolean(luaVM, false);
return 1;
}

0 comments on commit 438bac5

Please sign in to comment.
You can’t perform that action at this time.