You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/Common/ResFile.cpp

2045 lines
51 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : implementation file
#include "RenderDll_precompiled.h"
#include "ResFile.h"
#include "Pak/CryPakUtils.h"
CResFile CResFile::m_Root(nullptr);
CResFile CResFile::m_RootStream(nullptr);
int CResFile::m_nNumOpenResources = 0;
uint32 CResFile::m_nSizeComprDir;
uint32 CResFile::m_nMaxOpenResFiles = MAX_OPEN_RESFILES;
namespace
{
CryCriticalSection g_cResLock;
CryCriticalSection g_cAsyncResLock;
}
bool CResFile::IsStreaming()
{
if (m_RootStream.m_NextStream &&
m_RootStream.m_NextStream != m_RootStream.m_PrevStream)
{
return true;
}
return false;
}
// Directory garbage collector (must be executed in render thread)
void CResFile::Tick()
{
if (!m_RootStream.m_NextStream)
{
m_RootStream.m_NextStream = &m_RootStream;
m_RootStream.m_PrevStream = &m_RootStream;
}
//return;
AUTO_LOCK(g_cAsyncResLock);
int nCurFrame = gRenDev->m_nFrameSwapID;
uint32 nFrameDif = 300; // Release the directories in 300 frames (approx 10 secs)
CResFile* pRF, * pNext;
for (pRF = m_RootStream.m_PrevStream; pRF != &m_RootStream; pRF = pNext)
{
pNext = pRF->m_PrevStream;
assert(pRF->m_pStreamInfo);
if (!pRF->m_pStreamInfo)
{
pRF->UnlinkStream();
continue;
}
if (pRF->m_bDirStreaming || pRF->m_pStreamInfo->m_EntriesQueue.size())
{
continue; // Still streaming
}
if (nCurFrame - pRF->m_nLastTickStreamed > nFrameDif)
{
pRF->UnlinkStream();
pRF->mfReleaseDir();
}
}
}
void CResFile::mfTickStreaming()
{
m_nLastTickStreamed = gRenDev->m_nFrameSwapID;
UnlinkStream();
LinkStream(&m_RootStream);
}
void CResFile::mfDeactivate([[maybe_unused]] bool bReleaseDir)
{
AUTO_LOCK(g_cResLock); // Not thread safe without this
if (m_fileHandle != AZ::IO::InvalidHandle)
{
mfFlush();
gEnv->pCryPak->FClose(m_fileHandle);
m_fileHandle = AZ::IO::InvalidHandle;
}
if (m_bActive)
{
m_nNumOpenResources--;
}
m_bActive = false;
Unlink();
}
bool CResFile::mfActivate(bool bFirstTime)
{
AUTO_LOCK(g_cResLock); // Not thread safe without this
if (!m_bActive)
{
Relink(&m_Root);
if (m_nNumOpenResources >= (int)m_nMaxOpenResFiles)
{
if (m_nNumOpenResources)
{
CResFile* rf = m_Root.m_Prev;
assert(rf && (rf->m_fileHandle != AZ::IO::InvalidHandle || m_pStreamInfo));
rf->mfDeactivate(false);
}
}
LOADING_TIME_PROFILE_SECTION(iSystem);
CDebugAllowFileAccess dafa;
int nFlags = !m_pLookupDataMan || m_pLookupDataMan->IsReadOnly() ? 0 : AZ::IO::IArchive::FLAGS_NEVER_IN_PAK | AZ::IO::IArchive::FLAGS_PATH_REAL | AZ::IO::IArchive::FOPEN_ONDISK;
// don't open the file if we are trying to stream the data, defeats the idea of streaming it
if (!m_pStreamInfo)
{
if (!bFirstTime && m_szAccess[0] == 'w')
{
char szAcc[16];
azstrcpy(szAcc, AZ_ARRAY_SIZE(szAcc), m_szAccess);
szAcc[0] = 'r';
m_fileHandle = gEnv->pCryPak->FOpen(m_name.c_str(), szAcc, nFlags | AZ::IO::IArchive::FOPEN_HINT_DIRECT_OPERATION);
}
else
{
m_fileHandle = gEnv->pCryPak->FOpen(m_name.c_str(), m_szAccess, nFlags | AZ::IO::IArchive::FOPEN_HINT_DIRECT_OPERATION);
}
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("CResFile::Activate - Can't open resource file <%s>", m_name.c_str());
Unlink();
return false;
}
}
m_nNumOpenResources++;
m_bActive = true;
}
if (!bFirstTime && !m_bDirValid)
{
mfPrepareDir();
}
return true;
}
CResFile::CResFile(const char* name)
{
m_name = name;
m_fileHandle = AZ::IO::InvalidHandle;
m_bActive = false;
m_nOffsDir = 0;
m_bSwapEndianRead = false;
m_bSwapEndianWrite = false;
m_pLookupData = NULL;
m_pLookupDataMan = NULL;
m_Next = m_Prev = NULL;
m_NextStream = m_PrevStream = NULL;
m_pStreamInfo = NULL;
m_bDirty = false;
m_bDirValid = false;
m_bDirCompressed = false;
m_bDirStreaming = false;
m_pCompressedDir = NULL;
m_nComprDirSize = 0;
m_nNumFilesUnique = 0;
m_nNumFilesRef = 0;
m_bDirCompressed = false;
m_nOffset = OFFSET_BIG_POSITIVE;
// If the root hasn't been set up before and this isn't a statically created
// CResFile (like the root/root stream), then lazy init the resource list
if (!m_Root.m_Next && name)
{
m_Root.m_name = "Root";
m_RootStream.m_name = "RootStream";
m_Root.m_Next = &m_Root;
m_Root.m_Prev = &m_Root;
m_RootStream.m_NextStream = &m_RootStream;
m_RootStream.m_PrevStream = &m_RootStream;
}
}
CResFile::~CResFile()
{
if (this != &m_Root && this != &m_RootStream)
{
mfClose();
}
else
{
assert(CResFile::m_nNumOpenResources == 0);
}
}
void CResFile::mfSetError(const char* er, ...)
{
char buffer[1024];
va_list args;
va_start(args, er);
if (azvsnprintf(buffer, sizeof(buffer), er, args) == -1)
{
buffer[sizeof(buffer) - 1] = 0;
}
m_ermes = buffer;
va_end(args);
}
SResFileLookupData* CResFile::GetLookupData(bool bCreate, uint32 CRC, float fVersion) const
{
if (m_pLookupDataMan)
{
CCryNameTSCRC name = m_pLookupDataMan->AdjustName(m_name.c_str());
SResFileLookupData* pData = m_pLookupDataMan->GetData(name);
uint32 nMinor = (int)(((float)fVersion - (float)(int)fVersion) * 10.1f);
uint32 nMajor = (int)fVersion;
if (bCreate && (!pData || (CRC && pData->m_CRC32 != CRC) || pData->m_CacheMinorVer != nMinor || pData->m_CacheMajorVer != nMajor || pData->m_OffsetDir != m_nOffsDir || pData->m_NumOfFilesUnique != m_nNumFilesUnique || pData->m_NumOfFilesRef != m_nNumFilesRef))
{
m_pLookupDataMan->AddData(this, CRC);
pData = m_pLookupDataMan->GetData(name);
m_pLookupDataMan->MarkDirty(true);
assert(pData);
}
return pData;
}
return NULL;
}
const char* CResFile::mfGetError(void)
{
if (m_ermes.size())
{
return m_ermes.c_str();
}
else
{
return NULL;
}
}
int CResFile::mfGetResourceSize()
{
if (m_fileHandle == AZ::IO::InvalidHandle)
{
return 0;
}
AUTO_LOCK(g_cResLock); // Not thread safe without this
gEnv->pCryPak->FSeek(m_fileHandle, 0, SEEK_END);
uint64_t length = gEnv->pCryPak->FTell(m_fileHandle);
gEnv->pCryPak->FSeek(m_fileHandle, 0, SEEK_SET);
return aznumeric_cast<int>(length);
}
uint64 CResFile::mfGetModifTime()
{
if (!mfActivate(false))
{
return 0;
}
if (m_fileHandle == AZ::IO::InvalidHandle)
{
return 0;
}
return gEnv->pCryPak->GetModificationTime(m_fileHandle);
}
bool CResFile::mfFileExist(CCryNameTSCRC name)
{
SDirEntry* de = mfGetEntry(name);
if (!de)
{
return false;
}
assert(name == de->Name);
return true;
}
bool CResFile::mfFileExist(const char* name)
{
return mfFileExist(CCryNameTSCRC(name));
}
void CResStreamDirCallback::StreamAsyncOnComplete([[maybe_unused]] IReadStream* pStream, [[maybe_unused]] unsigned nError)
{
/*
SResStreamInfo *pStreamInfo = (SResStreamInfo*)pStream->GetUserData();
assert(pStreamInfo);
if (!pStreamInfo)
return;
SShaderCache *pCache = pStreamInfo->m_pCache;
CResFile *pRes = pStreamInfo->m_pRes;
IF(!pRes,0)return;
assert(pRes->m_bDirStreaming);
if (nError == )
pStreamInfo->m_nRequestCount--;
// are all requests processed ?
if (pStreamInfo->m_nRequestCount == 0)
{
// check if both requests were valid !
pRes->m_bDirValid = true;
}
*/
}
void CResStreamDirCallback::StreamOnComplete(IReadStream* pStream, unsigned nError)
{
SResStreamInfo* pStreamInfo = (SResStreamInfo*)pStream->GetUserData();
assert(pStreamInfo);
if (!pStreamInfo)
{
return;
}
CryAutoLock<CryCriticalSection> lock(pStreamInfo->m_StreamLock);
CResFile* pRes = pStreamInfo->m_pRes;
IF (!pRes, 0)
{
return;
}
assert(pRes->m_bDirStreaming);
if (!nError)
{
pStreamInfo->m_nDirRequestCount--;
}
for (std::vector<IReadStreamPtr>::iterator it = pStreamInfo->m_dirReadStreams.begin();
it != pStreamInfo->m_dirReadStreams.end(); ++it)
{
if (pStream == *it)
{
pStreamInfo->m_dirReadStreams.erase(it);
break;
}
}
// all requests processed ?
if (pStreamInfo->m_dirReadStreams.size() == 0)
{
// were all requests processed successfully
if (pStreamInfo->m_nDirRequestCount == 0)
{
// check if both requests were valid !
pRes->m_bDirValid = true;
}
pRes->m_bDirStreaming = false;
}
SShaderCache* pCache = pStreamInfo->m_pCache;
pCache->Release();
}
int CResFile::mfLoadDir(SResStreamInfo* pStreamInfo)
{
int nRes = 1;
if (pStreamInfo)
{
// if we are streaming the data, we need the lookup data to be valid!
if (m_pLookupData == NULL)
{
return -1;
}
mfTickStreaming();
if (m_bDirStreaming)
{
return -1;
}
m_bDirStreaming = true;
int nSizeDir = m_nNumFilesUnique * sizeof(SDirEntry);
int nSizeDirRef = m_nNumFilesRef * sizeof(SDirEntry);
if (nSizeDir)
{
m_Dir.resize(m_nNumFilesUnique);
StreamReadParams StrParams;
StrParams.nFlags = 0;
StrParams.dwUserData = (DWORD_PTR)pStreamInfo;
StrParams.nLoadTime = 1;
StrParams.nMaxLoadTime = 4;
StrParams.pBuffer = &m_Dir[0];
StrParams.nOffset = m_nOffsDir;
StrParams.nSize = nSizeDir;
pStreamInfo->m_pCache->AddRef();
CryAutoLock<CryCriticalSection> lock(pStreamInfo->m_StreamLock);
pStreamInfo->m_dirReadStreams.push_back(iSystem->GetStreamEngine()->StartRead(
eStreamTaskTypeShader, m_name.c_str(), &pStreamInfo->m_CallbackDir, &StrParams));
pStreamInfo->m_nDirRequestCount++;
}
if (nSizeDirRef)
{
m_DirRef.resize(m_nNumFilesRef);
StreamReadParams StrParams;
StrParams.nFlags = 0;
StrParams.dwUserData = (DWORD_PTR)pStreamInfo;
StrParams.nLoadTime = 1;
StrParams.nMaxLoadTime = 4;
StrParams.pBuffer = &m_DirRef[0];
StrParams.nOffset = m_nOffsDir + nSizeDir;
StrParams.nSize = nSizeDirRef;
pStreamInfo->m_pCache->AddRef();
CryAutoLock<CryCriticalSection> lock(pStreamInfo->m_StreamLock);
pStreamInfo->m_dirReadStreams.push_back(iSystem->GetStreamEngine()->StartRead(
eStreamTaskTypeShader, m_name.c_str(), &pStreamInfo->m_CallbackDir, &StrParams));
pStreamInfo->m_nDirRequestCount++;
}
nRes = -1;
}
else
{
if (gEnv->pCryPak->FSeek(m_fileHandle, m_nOffsDir, SEEK_SET) > 0)
{
mfSetError("Open - Directory reading error");
return 0;
}
int nSize = m_nNumFilesUnique * sizeof(SDirEntry);
//int nSizeDir = m_nComprDirSize ? m_nComprDirSize : nSize;
if (m_nNumFilesUnique)
{
m_Dir.resize(m_nNumFilesUnique);
if (gEnv->pCryPak->FReadRaw(&m_Dir[0], 1, nSize, m_fileHandle) != nSize)
{
mfSetError("Open - Directory reading error");
m_Dir.clear();
return 0;
}
}
if (m_nNumFilesRef)
{
nSize = m_nNumFilesRef * sizeof(SDirEntryRef);
//int nSizeDir = m_nComprDirSize ? m_nComprDirSize : nSize;
m_DirRef.resize(m_nNumFilesRef);
if (gEnv->pCryPak->FReadRaw(&m_DirRef[0], 1, nSize, m_fileHandle) != nSize)
{
mfSetError("Open - Directory reading error");
m_DirRef.clear();
return 0;
}
}
}
m_bDirValid = false;
if (!m_nComprDirSize && nRes == 1)
{
m_bDirValid = true;
if (m_bSwapEndianRead)
{
if (m_nNumFilesUnique)
{
SwapEndian(&m_Dir[0], (size_t)m_nNumFilesUnique, eBigEndian);
}
if (m_nNumFilesRef)
{
SwapEndian(&m_DirRef[0], (size_t)m_nNumFilesRef, eBigEndian);
}
}
}
return nRes;
}
bool CResFile::mfPrepareDir()
{
if (m_bDirValid)
{
return true;
}
assert(!m_Dir.size());
SDirEntry* pFileDir = NULL;
if (m_pCompressedDir)
{
assert(!m_Dir.size());
pFileDir = new SDirEntry[m_nNumFilesUnique];
if (m_version == RESVERSION_DEBUG)
{
memcpy(pFileDir, m_pCompressedDir, sizeof(SDirEntry) * m_nNumFilesUnique);
}
else
{
CryFatalError("Bad Version: %d!", m_version);
}
m_Dir.resize(m_nNumFilesUnique);
for (uint32 i = 0; i < m_nNumFilesUnique; i++)
{
SDirEntry* deS = &m_Dir[i];
SDirEntry& fdent = pFileDir[i];
if (m_bSwapEndianRead)
{
SwapEndian(fdent, eBigEndian);
}
deS->Name = fdent.Name;
deS->size = fdent.size;
deS->offset = fdent.offset;
deS->flags = fdent.flags;
}
m_nSizeComprDir += m_nComprDirSize;
m_bDirValid = true;
}
else
{
#ifndef NDEBUG
int nRes =
#endif
mfLoadDir(m_pStreamInfo);
assert(nRes);
}
return true;
}
void CResFile::mfReleaseDir()
{
// Never unload directory which wasn't flushed yet
if (m_bDirty)
{
return;
}
if (m_bDirStreaming)
{
return;
}
if (m_pStreamInfo && m_pStreamInfo->m_EntriesQueue.size())
{
return;
}
if (m_bDirValid)
{
uint32 i;
for (i = 0; i < m_Dir.size(); i++)
{
SDirEntry* de = &m_Dir[i];
assert(!(de->flags & RF_NOTSAVED));
mfCloseEntry(de, false);
}
m_DirOpen.clear();
//m_Dir.clear();
ResDir r;
m_Dir.swap(r);
m_bDirValid = false;
}
else
{
assert(!m_Dir.size());
}
}
int CResFile::mfOpen(int type, CResFileLookupDataMan* pMan, SResStreamInfo* pStreamInfo)
{
SFileResHeader frh;
SDirEntry fden;
PROFILE_FRAME(Resource_Open);
if (m_name.c_str()[0] == 0)
{
mfSetError("Open - No Resource name");
return 0;
}
int nRes = 1;
m_bSwapEndianWrite = (type & RA_ENDIANS) != 0;
m_bSwapEndianRead = m_bSwapEndianWrite;
m_pLookupDataMan = pMan;
type &= ~RA_ENDIANS;
if (type == RA_READ)
{
m_szAccess = "rb";
}
else
if (type == (RA_WRITE | RA_READ))
{
m_szAccess = "r+b";
}
else
if (type & RA_CREATE)
{
m_szAccess = "w+b";
}
else
{
mfSetError("Open - Wrong access mode");
return 0;
}
m_typeaccess = type;
if (type & RA_READ)
{
m_pStreamInfo = pStreamInfo;
}
mfActivate(true);
AUTO_LOCK(g_cResLock); // Not thread safe without this
if (!m_bActive)
{
if (type & (RA_WRITE | RA_CREATE))
{
bool fileExists = gEnv->pCryPak->IsFileExist(m_name.c_str());
if (fileExists)
{
m_ermes.clear();
mfActivate(true);
}
}
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("Open - Can't open resource file <%s>", m_name.c_str());
return 0;
}
}
if (type & RA_READ)
{
// check the preloaded dir data, to see if we can get the dir data from there
CCryNameTSCRC name = m_pLookupDataMan->AdjustName(m_name.c_str());
if (m_pLookupDataMan)
{
m_pLookupData = m_pLookupDataMan->GetData(name);
}
if (m_pLookupData)
{
m_version = m_pLookupDataMan->GetResVersion();
m_nNumFilesUnique = m_pLookupData->m_NumOfFilesUnique;
m_nNumFilesRef = m_pLookupData->m_NumOfFilesRef;
m_nOffsDir = m_pLookupData->m_OffsetDir;
m_nComprDirSize = 0;//m_pResDirData->size_dir;
}
else
{
// make sure lookupdata is available when we are streaming the data
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("Open - no file handle (lookupdata not found, while streaming data?)");
return 0;
}
// Detect file endianness automatically.
if (gEnv->pCryPak->FReadRaw(&frh, 1, sizeof(frh), m_fileHandle) != sizeof(frh))
{
mfSetError("Open - Reading fault");
return 0;
}
if (m_bSwapEndianRead)
{
SwapEndian(frh, eBigEndian);
}
if (frh.hid != IDRESHEADER)
{
mfSetError("Open - Wrong header MagicID");
return 0;
}
if (frh.ver != RESVERSION_DEBUG)
{
mfSetError("Open - Wrong version number");
return 0;
}
m_version = frh.ver;
if (!frh.num_files)
{
mfSetError("Open - Empty resource file");
return 0;
}
m_nNumFilesUnique = frh.num_files;
m_nNumFilesRef = frh.num_files_ref;
m_nOffsDir = frh.ofs_dir;
m_nComprDirSize = 0; //frh.size_dir;
}
if (pStreamInfo)
{
m_pStreamInfo->m_pRes = this;
}
m_bDirCompressed = false;
nRes = mfLoadDir(pStreamInfo);
}
else
{
frh.hid = IDRESHEADER;
int ver = RES_COMPRESSION;
frh.ver = ver;
frh.num_files = 0;
frh.ofs_dir = -1;
frh.num_files_ref = 0;
m_version = ver;
m_nOffsDir = sizeof(frh);
SFileResHeader frhTemp, * pFrh;
pFrh = &frh;
if (m_bSwapEndianWrite)
{
frhTemp = frh;
SwapEndian(frhTemp, eBigEndian);
pFrh = &frhTemp;
}
if (gEnv->pCryPak->FWrite(pFrh, 1, sizeof(frh), m_fileHandle) != sizeof(frh))
{
mfSetError("Open - Writing fault");
return 0;
}
m_nComprDirSize = 0;
m_bDirCompressed = false;
m_nNumFilesUnique = 0;
m_nNumFilesRef = 0;
m_pCompressedDir = NULL;
m_bDirValid = true;
}
return nRes;
}
bool CResFile::mfClose(void)
{
AUTO_LOCK(g_cResLock); // Not thread safe without this
assert(!m_bDirStreaming);
assert(!m_pStreamInfo || !m_pStreamInfo->m_EntriesQueue.size());
//if (m_bDirStreaming || (m_pStreamInfo && m_pStreamInfo->m_EntriesQueue.size()))
// Warning("Warning: CResFile::mfClose: Streaming task is in progress!");
UnlinkStream();
if (m_typeaccess != RA_READ)
{
mfFlush();
}
// Close the handle and release directory
mfDeactivate(true);
assert(!m_bDirty);
mfReleaseDir();
SAFE_DELETE_ARRAY(m_pCompressedDir);
return true;
}
struct ResDirSortByName
{
bool operator () (const SDirEntry& left, const SDirEntry& right) const
{
return left.Name < right.Name;
}
bool operator () (const CCryNameTSCRC left, const SDirEntry& right) const
{
return left < right.Name;
}
bool operator () (const SDirEntry& left, CCryNameTSCRC right) const
{
return left.Name < right;
}
};
struct ResDirRefSortByName
{
bool operator () (const SDirEntryRef& left, const SDirEntryRef& right) const
{
return left.Name < right.Name;
}
bool operator () (const CCryNameTSCRC left, const SDirEntryRef& right) const
{
return left < right.Name;
}
bool operator () (const SDirEntryRef& left, CCryNameTSCRC right) const
{
return left.Name < right;
}
};
struct ResDirOpenSortByName
{
bool operator () (const SDirEntryOpen& left, const SDirEntryOpen& right) const
{
return left.Name < right.Name;
}
bool operator () (const CCryNameTSCRC left, const SDirEntryOpen& right) const
{
return left < right.Name;
}
bool operator () (const SDirEntryOpen& left, CCryNameTSCRC right) const
{
return left.Name < right;
}
};
SDirEntryOpen* CResFile::mfGetOpenEntry(SDirEntry* de)
{
ResDirOpenIt it = std::lower_bound(m_DirOpen.begin(), m_DirOpen.end(), de->Name, ResDirOpenSortByName());
if (it != m_DirOpen.end() && de->Name == (*it).Name)
{
return &(*it);
}
return NULL;
}
SDirEntryOpen* CResFile::mfOpenEntry(SDirEntry* de, [[maybe_unused]] bool readingIntoEntryData)
{
SDirEntryOpen* pOE = NULL;
ResDirOpenIt it = std::lower_bound(m_DirOpen.begin(), m_DirOpen.end(), de->Name, ResDirOpenSortByName());
if (it == m_DirOpen.end() || de->Name != (*it).Name)
{
AUTO_LOCK(g_cAsyncResLock);
SDirEntryOpen OE;
OE.Name = de->Name;
OE.curOffset = 0;
OE.pData = NULL;
m_DirOpen.insert(it, OE);
it = std::lower_bound(m_DirOpen.begin(), m_DirOpen.end(), de->Name, ResDirOpenSortByName());
return &(*it);
}
pOE = &(*it);
pOE->curOffset = 0;
assert(pOE->pData || !readingIntoEntryData);
//SAFE_DELETE_ARRAY(pOE->pData);
return pOE;
}
bool CResFile::mfCloseEntry(SDirEntry* de, bool bEraseOpenEntry)
{
ResDirOpenIt it = std::lower_bound(m_DirOpen.begin(), m_DirOpen.end(), de->Name, ResDirOpenSortByName());
if (it == m_DirOpen.end() || de->Name != (*it).Name)
{
return false;
}
SDirEntryOpen& OE = (*it);
OE.curOffset = 0;
if (de->flags & RF_TEMPDATA)
{
if (OE.pData)
{
delete[] (char*)OE.pData;
OE.pData = NULL;
}
}
if (bEraseOpenEntry)
{
AUTO_LOCK(g_cAsyncResLock);
m_DirOpen.erase(it);
}
return true;
}
SDirEntry* CResFile::mfGetEntry(CCryNameTSCRC name, bool* pAsync)
{
if (pAsync)
{
*pAsync = m_bDirStreaming;
if (m_bDirStreaming)
{
return 0;
}
}
if (!m_Dir.size() || m_bDirStreaming)
{
if (!mfActivate(false))
{
return NULL;
}
if (!m_Dir.size() || m_bDirStreaming)
{
if (pAsync && m_bDirStreaming)
{
*pAsync = true;
}
return NULL;
}
}
ResDirIt it = std::lower_bound(m_Dir.begin(), m_Dir.end(), name, ResDirSortByName());
if (it != m_Dir.end() && name == (*it).Name)
{
assert(m_bDirValid);
return &(*it);
}
ResDirRefIt itRef = std::lower_bound(m_DirRef.begin(), m_DirRef.end(), name, ResDirRefSortByName());
if (itRef != m_DirRef.end() && name == (*itRef).Name)
{
assert(m_bDirValid);
SDirEntryRef& rref = (*itRef);
return &m_Dir[rref.ref];
}
return NULL;
}
int CResFile::mfFileClose(SDirEntry* de)
{
if (!(de->flags & RF_NOTSAVED))
{
mfCloseEntry(de);
}
return 0;
}
int CResFile::mfFileAdd(SDirEntry* de)
{
AUTO_LOCK(g_cResLock); // Not thread safe without this
assert(!m_pStreamInfo);
if (m_typeaccess == RA_READ)
{
mfSetError("FileAdd - wrong access mode");
return 0;
}
CCryNameTSCRC name = de->Name;
ResDirIt it = std::lower_bound(m_Dir.begin(), m_Dir.end(), name, ResDirSortByName());
if (it != m_Dir.end() && name == (*it).Name)
{
return m_Dir.size();
}
if (de->offset == 0)
{
de->offset = m_nOffset++;
}
if (de->size != 0)
{
if (!m_Dir.size())
{
mfActivate(false);
}
it = std::lower_bound(m_Dir.begin(), m_Dir.end(), name, ResDirSortByName());
if (it != m_Dir.end() && name == (*it).Name)
{
return m_Dir.size();
}
SDirEntry newDE;
newDE = *de;
newDE.flags |= RF_NOTSAVED;
m_Dir.insert(it, newDE);
m_bDirty = true;
}
return m_Dir.size();
}
// Lets unpack the entry asynchronously
void CResStreamCallback::StreamAsyncOnComplete(IReadStream* pStream, unsigned nError)
{
SResStreamEntry* pEntry = (SResStreamEntry*)pStream->GetUserData();
SResStreamInfo* pStreamInfo = pEntry->m_pParent;
assert(pStreamInfo);
if (!pStreamInfo)
{
return;
}
//CryHeapCheck();
CResFile* pRes = pStreamInfo->m_pRes;
assert(pRes->m_bDirValid);
if (nError)
{
pRes->mfSetError("FileRead - Error during streaming data");
return;
}
SDirEntry* pDE = pRes->mfGetEntry(pEntry->m_Name);
byte* pBuf = (byte*)pStream->GetBuffer();
assert(pBuf);
byte* pData = NULL;
int32 size;
{
size = pDE->size;
pData = new byte[size];
if (!pData)
{
pRes->mfSetError("FileRead - Allocation fault");
}
else
{
memcpy(pData, pBuf, size);
}
}
{
AUTO_LOCK(g_cAsyncResLock);
SDirEntryOpen* pOE = pRes->mfGetOpenEntry(pDE);
if (pOE)
{
pDE->flags |= RF_TEMPDATA;
pOE->nSize = size;
pOE->pData = pData;
}
else
{
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "mfGetOpenEntry() returned NULL, possibly because r_shadersAllowCompilation=1 and r_shadersAsyncActivation=1. Try r_shadersAsyncActivation=0 in your user.cfg.");
}
}
}
// Release the data synchronously
void CResStreamCallback::StreamOnComplete(IReadStream* pStream, unsigned nError)
{
SResStreamEntry* pEntry = (SResStreamEntry*)pStream->GetUserData();
SResStreamInfo* pStreamInfo = pEntry->m_pParent;
assert(pStreamInfo);
if (!pStreamInfo)
{
return;
}
SShaderCache* pCache = pStreamInfo->m_pCache;
uint32 i;
bool bFound = false;
CryAutoLock<CryCriticalSection> lock(pStreamInfo->m_StreamLock);
//CryHeapCheck();
if (!nError)
{
for (i = 0; i < pStreamInfo->m_EntriesQueue.size(); i++)
{
SResStreamEntry* pE = pStreamInfo->m_EntriesQueue[i];
if (pE == pEntry)
{
SAFE_DELETE(pE);
pStreamInfo->m_EntriesQueue.erase(pStreamInfo->m_EntriesQueue.begin() + i);
bFound = true;
break;
}
}
assert(bFound);
}
pCache->Release();
}
int CResFile::mfFileRead(SDirEntry* de)
{
uint32 size = 0;
SDirEntryOpen* pOE = mfOpenEntry(de);
if (pOE->pData)
{
return pOE->nSize;
}
if (!mfActivate(false))
{
return 0;
}
AUTO_LOCK(g_cResLock); // Not thread safe without this
//if (strstr(m_name, "FPVS") && m_Dir.size()==3)
{
//int nnn = 0;
}
if (m_pStreamInfo)
{
mfTickStreaming();
if (!m_bDirValid)
{
assert(m_bDirStreaming);
return -1;
}
CryAutoLock<CryCriticalSection> lock(m_pStreamInfo->m_StreamLock);
SResStreamEntry* pEntry;
{
//AUTO_LOCK(g_cAsyncResLock);
pEntry = m_pStreamInfo->AddEntry(de->Name);
if (!pEntry) // Already processing
{
return -1;
}
}
if (pOE->pData)
{
return pOE->nSize;
}
StreamReadParams StrParams;
StrParams.nFlags = 0;
StrParams.dwUserData = (DWORD_PTR)pEntry;
StrParams.nLoadTime = 1;
StrParams.nMaxLoadTime = 4;
// StrParams.nPriority = 0;
StrParams.pBuffer = NULL;
StrParams.nOffset = de->offset;
StrParams.nSize = de->size;
m_pStreamInfo->m_pCache->AddRef();
//Warning("Warning: CResFile::mfFileRead: '%s' Ref: %d", m_name.c_str(), n);
pEntry->m_readStream = iSystem->GetStreamEngine()->StartRead(eStreamTaskTypeShader, m_name.c_str(), &m_pStreamInfo->m_Callback, &StrParams);
return -1;
}
else
if (de->flags & RF_COMPRESS)
{
if (gEnv->pCryPak->FSeek(m_fileHandle, de->offset, SEEK_SET) > 0)
{
mfSetError("FileRead - Seek error");
return 0;
}
byte* buf = new byte[de->size];
if (!buf)
{
mfSetError("FileRead - Allocation fault");
return 0;
}
if (m_version == RESVERSION_DEBUG)
{
gEnv->pCryPak->FReadRaw(buf, de->size, 1, m_fileHandle);
pOE->pData = new byte[de->size - 20];
de->flags |= RF_TEMPDATA;
if (!pOE->pData)
{
SAFE_DELETE_ARRAY(buf);
mfSetError("FileRead - Allocation fault");
return 0;
}
memcpy(pOE->pData, &buf[10], de->size - 20);
}
else
{
CryFatalError("Bad Version: %d!", m_version);
return 0;
}
delete[] buf;
pOE->nSize = size;
return size;
}
pOE->pData = new byte[de->size];
pOE->nSize = de->size;
de->flags |= RF_TEMPDATA;
if (!pOE->pData)
{
mfSetError("FileRead - Allocation fault");
return 0;
}
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("FileRead - Invalid file handle");
return 0;
}
if (gEnv->pCryPak->FSeek(m_fileHandle, de->offset, SEEK_SET) > 0)
{
mfSetError("FileRead - Seek error");
return 0;
}
if (gEnv->pCryPak->FReadRaw(pOE->pData, 1, de->size, m_fileHandle) != de->size)
{
mfSetError("FileRead - Reading fault");
return 0;
}
//if (strstr(m_name, "FPVS") && m_Dir.size()==3)
{
//gEnv->pCryPak->FSeek(m_fileHandle, 0, SEEK_END);
//int nSize = gEnv->pCryPak->FTell(m_fileHandle);
//int nnn = 0;
}
return de->size;
}
byte* CResFile::mfFileReadCompressed(SDirEntry* de, uint32& nSizeDecomp, uint32& nSizeComp)
{
if (!mfActivate(false))
{
return NULL;
}
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("FileReadCompressed - Invalid file handle");
return 0;
}
if (de->flags & RF_COMPRESS)
{
if (de->offset >= 0x10000000)
{
return NULL;
}
if (gEnv->pCryPak->FSeek(m_fileHandle, de->offset, SEEK_SET) > 0)
{
mfSetError("FileReadCompressed - Seek error");
return 0;
}
byte* buf = new byte[de->size];
if (!buf)
{
mfSetError("FileRead - Allocation fault");
return 0;
}
if (m_version == RESVERSION_DEBUG)
{
gEnv->pCryPak->FReadRaw(buf, 10, 1, m_fileHandle);
gEnv->pCryPak->FReadRaw(buf, de->size - 20, 1, m_fileHandle);
nSizeDecomp = de->size - 20;
nSizeComp = de->size - 20;
}
else
{
CryFatalError("Bad Version: %d!", m_version);
return 0;
}
return buf;
}
nSizeComp = nSizeDecomp = de->size;
byte* buf = new byte[de->size];
if (gEnv->pCryPak->FSeek(m_fileHandle, de->offset, SEEK_SET) > 0)
{
mfSetError("FileReadCompressed - Seek error");
delete[] buf;
return 0;
}
if (gEnv->pCryPak->FReadRaw(buf, 1, de->size, m_fileHandle) != de->size)
{
mfSetError("FileRead - Reading fault");
delete[] buf;
return 0;
}
return buf;
}
int CResFile::mfFileRead(CCryNameTSCRC name)
{
SDirEntry* de = mfGetEntry(name);
if (!de)
{
mfSetError("FileRead - Wrong FileId");
return 0;
}
return mfFileRead(de);
}
int CResFile::mfFileRead(const char* name)
{
return mfFileRead(CCryNameTSCRC(name));
}
int CResFile::mfFileWrite(CCryNameTSCRC name, void* data)
{
SDirEntry* de = mfGetEntry(name);
if (!de)
{
mfSetError("FileWrite - Wrong FileId");
return 0;
}
if (!data)
{
mfSetError("FileWrite - Wrong data");
return 0;
}
if (!mfActivate(false))
{
return 0;
}
if (de->flags & RF_COMPRESS)
{
assert(0);
return 0;
}
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("FileWrite - Invalid file handle");
return 0;
}
if (gEnv->pCryPak->FSeek(m_fileHandle, de->offset, SEEK_SET) > 0)
{
mfSetError("FileWrite - Seek error");
return 0;
}
if (gEnv->pCryPak->FWrite(data, 1, de->size, m_fileHandle) != de->size)
{
mfSetError("FileWrite - Writing fault");
return 0;
}
return de->size;
}
void CResFile::mfFileRead2(SDirEntry* de, int size, void* buf)
{
if (!buf)
{
mfSetError("FileRead - Wrong data");
return;
}
SDirEntryOpen* pOE = mfOpenEntry(de, false);
if (pOE->pData)
{
memcpy(buf, (byte*)(pOE->pData) + pOE->curOffset, size);
pOE->curOffset += size;
return;
}
if (!mfActivate(false))
{
return;
}
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("FileRead2 - Invalid file handle");
return;
}
if (gEnv->pCryPak->FSeek(m_fileHandle, de->offset + pOE->curOffset, SEEK_SET) > 0)
{
mfSetError("FileRead2 - Seek error");
return;
}
if (gEnv->pCryPak->FReadRaw(buf, 1, size, m_fileHandle) != size)
{
mfSetError("FileRead - Reading fault");
return;
}
pOE->curOffset += size;
}
void CResFile::mfFileRead2(CCryNameTSCRC name, int size, void* buf)
{
SDirEntry* de = mfGetEntry(name);
if (!de)
{
mfSetError("FileRead2 - wrong file id");
return;
}
return mfFileRead2(de, size, buf);
}
void* CResFile::mfFileGetBuf(SDirEntry* de)
{
SDirEntryOpen* pOE = mfGetOpenEntry(de);
if (!pOE)
{
return NULL;
}
return pOE->pData;
}
void* CResFile::mfFileGetBuf(CCryNameTSCRC name)
{
SDirEntry* de = mfGetEntry(name);
if (!de)
{
mfSetError("FileGetBuf - wrong file id");
return NULL;
}
return mfFileGetBuf(de);
}
int CResFile::mfFileSeek(SDirEntry* de, int ofs, int type)
{
int m;
mfActivate(false);
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("FileSeek - Invalid file handle");
return -1;
}
AUTO_LOCK(g_cResLock); // Not thread safe without this
SDirEntryOpen* pOE = mfOpenEntry(de, false);
switch (type)
{
case SEEK_CUR:
pOE->curOffset += ofs;
m = gEnv->pCryPak->FSeek(m_fileHandle, de->offset + pOE->curOffset, SEEK_SET);
break;
case SEEK_SET:
m = gEnv->pCryPak->FSeek(m_fileHandle, de->offset + ofs, SEEK_SET);
pOE->curOffset = ofs;
break;
case SEEK_END:
pOE->curOffset = de->size - ofs;
m = gEnv->pCryPak->FSeek(m_fileHandle, de->offset + pOE->curOffset, SEEK_SET);
break;
default:
mfSetError("FileSeek - wrong seek type");
return -1;
}
return m;
}
int CResFile::mfFileSeek(CCryNameTSCRC name, int ofs, int type)
{
SDirEntry* de = mfGetEntry(name);
if (!de)
{
mfSetError("FileSeek - invalid file id");
return -1;
}
return mfFileSeek(de, ofs, type);
}
int CResFile::mfFileSeek(char* name, int ofs, int type)
{
return mfFileSeek(CCryNameTSCRC(name), ofs, type);
}
int CResFile::mfFileLength(SDirEntry* de)
{
return de->size;
}
int CResFile::mfFileLength(CCryNameTSCRC name)
{
SDirEntry* de = mfGetEntry(name);
if (!de)
{
mfSetError("FileLength - invalid file id");
return -1;
}
return mfFileLength(de);
}
int CResFile::mfFileLength(char* name)
{
return mfFileLength(CCryNameTSCRC(name));
}
int CResFile::mfFlushDir(long nOffset, [[maybe_unused]] bool bOptimise)
{
uint32 i;
#ifdef _DEBUG
// Check for sorted array and duplicated values
ResDir Sorted;
for (i = 0; i < m_Dir.size(); i++)
{
SDirEntry& DE = m_Dir[i];
ResDirIt it = std::lower_bound(Sorted.begin(), Sorted.end(), DE.Name, ResDirSortByName());
if (it != Sorted.end() && DE.Name == (*it).Name)
{
assert(0); // Duplicated value
continue;
}
Sorted.insert(it, DE);
}
assert(Sorted.size() == m_Dir.size());
for (i = 0; i < m_Dir.size(); i++)
{
SDirEntry& DE1 = m_Dir[i];
SDirEntry& DE2 = Sorted[i];
assert(DE1.Name == DE2.Name);
}
ResDirRef SortedRef;
for (i = 0; i < m_DirRef.size(); i++)
{
SDirEntryRef& DE = m_DirRef[i];
ResDirRefIt it = std::lower_bound(SortedRef.begin(), SortedRef.end(), DE.Name, ResDirRefSortByName());
if (it != SortedRef.end() && DE.Name == (*it).Name)
{
assert(0); // Duplicated value
continue;
}
SortedRef.insert(it, DE);
}
assert(SortedRef.size() == m_DirRef.size());
for (i = 0; i < m_DirRef.size(); i++)
{
SDirEntryRef& DE1 = m_DirRef[i];
SDirEntryRef& DE2 = SortedRef[i];
assert(DE1.Name == DE2.Name);
}
// Make sure references are correct
if (bOptimise)
{
for (i = 0; i < m_DirRef.size(); i++)
{
SDirEntryRef& r = m_DirRef[i];
assert(r.ref < m_Dir.size());
}
}
#endif
TArray<SDirEntry> FDir;
TArray<SDirEntryRef> FDirRef;
FDir.ReserveNoClear(m_Dir.size());
FDirRef.ReserveNoClear(m_DirRef.size());
for (i = 0; i < (int)m_Dir.size(); i++)
{
SDirEntry* de = &m_Dir[i];
SDirEntry& fden = FDir[i];
fden.Name = de->Name;
fden.size = de->size;
assert(de->offset > 0);
fden.offset = de->offset;
fden.flags = de->flags;
if (m_bSwapEndianWrite)
{
SwapEndian(fden, eBigEndian);
}
}
for (i = 0; i < (int)m_DirRef.size(); i++)
{
SDirEntryRef* de = &m_DirRef[i];
SDirEntryRef& fden = FDirRef[i];
fden.Name = de->Name;
fden.ref = de->ref;
assert(de->ref >= 0);
if (m_bSwapEndianWrite)
{
SwapEndian(fden, eBigEndian);
}
}
gEnv->pCryPak->FSeek(m_fileHandle, nOffset, SEEK_SET);
int sizeUn = FDir.Num() * sizeof(SDirEntry);
int sizeRef = FDirRef.Num() * sizeof(SDirEntryRef);
byte* buf = NULL;
if (m_bDirCompressed)
{
#if RES_COMPRESSION == RESVERSION_DEBUG
buf = new byte [sizeUn];
memcpy(buf, (byte*)&FDir[0], sizeUn);
#else
COMPILE_TIME_ASSERT(0);
#endif
}
else
{
buf = new byte[sizeUn + sizeRef];
memcpy(buf, &FDir[0], sizeUn);
if (sizeRef)
{
memcpy(&buf[sizeUn], &FDirRef[0], sizeRef);
}
}
if (gEnv->pCryPak->FWrite(buf, 1, sizeUn + sizeRef, m_fileHandle) != sizeUn + sizeRef)
{
mfSetError("FlushDir - Writing fault");
return false;
}
m_nOffsDir = nOffset;
m_nNumFilesUnique = FDir.Num();
m_nNumFilesRef = FDirRef.Num();
SAFE_DELETE_ARRAY(m_pCompressedDir);
if (m_bDirCompressed)
{
m_nComprDirSize = sizeUn;
m_pCompressedDir = new byte[sizeUn];
memcpy(m_pCompressedDir, buf, sizeUn);
}
SAFE_DELETE_ARRAY(buf);
m_bDirValid = true;
SResFileLookupData* pLookup = GetLookupData(false, 0, 0);
if (pLookup)
{
pLookup->m_NumOfFilesRef = m_nNumFilesRef;
pLookup->m_NumOfFilesUnique = m_nNumFilesUnique;
pLookup->m_OffsetDir = nOffset;
m_pLookupDataMan->MarkDirty(true);
m_pLookupDataMan->Flush();
}
return sizeUn + sizeRef;
}
int CResFile::mfFlush(bool bOptimise)
{
SFileResHeader frh;
PROFILE_FRAME(Resource_Flush);
// For compatibility with old builds
bOptimise = false;
int nSizeDir = m_DirRef.size() * sizeof(SDirEntryRef) + m_Dir.size() * sizeof(SDirEntry);
if (m_typeaccess == RA_READ)
{
mfSetError("Flush - wrong access mode");
return nSizeDir;
}
AUTO_LOCK(g_cResLock); // Not thread safe without this
if (m_pLookupDataMan)
{
m_pLookupDataMan->Flush();
}
if (!m_bDirty)
{
return nSizeDir;
}
m_bDirty = false;
if (!mfActivate(false))
{
return nSizeDir;
}
if (m_fileHandle == AZ::IO::InvalidHandle)
{
mfSetError("Flush - Invalid file handle");
return 0;
}
int i;
uint32 j;
int nSizeCompr = 0;
int nUpdate = 0;
int nSizeUpdate = 0;
const size_t numDirRefs = m_Dir.size();
TArray<int>* pRefs = NULL;
if (!bOptimise)
{
pRefs = new TArray<int>[numDirRefs];
}
// Make a list of all references
for (i = 0; i < (int)m_Dir.size(); i++)
{
SDirEntry* de = &m_Dir[i];
if (de->offset < 0)
{
assert(de->flags & RF_NOTSAVED);
bool bFound = false;
for (j = 0; j < m_Dir.size(); j++)
{
if (i == j)
{
continue;
}
SDirEntry* d = &m_Dir[j];
if (d->offset == -de->offset)
{
if (bOptimise)
{
SDirEntryRef r;
r.Name = de->Name;
r.ref = d->offset;
m_DirRef.push_back(r);
mfCloseEntry(de);
m_Dir.erase(m_Dir.begin() + i);
i--;
}
else
{
pRefs[j].AddElem(i);
}
bFound = true;
break;
}
}
assert(bFound);
}
}
nSizeDir = m_DirRef.size() * sizeof(SDirEntryRef) + m_Dir.size() * sizeof(SDirEntry);
const int nFiles = m_Dir.size();
long nSeek = m_nOffsDir;
for (i = 0; i < nFiles; i++)
{
SDirEntry* de = &m_Dir[i];
assert(de->offset >= 0);
if (de->flags & RF_NOTSAVED)
{
SDirEntryOpen* pOE = mfGetOpenEntry(de);
de->flags &= ~RF_NOTSAVED;
nUpdate++;
nSizeUpdate += de->size;
if (de->offset >= 0)
{
assert(pOE && pOE->pData);
if (!pOE || !pOE->pData)
{
continue;
}
gEnv->pCryPak->FSeek(m_fileHandle, nSeek, SEEK_SET);
if (de->flags & RF_COMPRESS)
{
byte* buf = NULL;
#if RES_COMPRESSION == RESVERSION_DEBUG
buf = new byte [de->size + 20];
memcpy(buf, ">>rawbuf>>", 10);
memcpy(buf + 10, (byte*)pOE->pData, de->size);
memcpy(buf + 10 + de->size, "<<rawbuf<<", 10);
de->size += 20;
#else
COMPILE_TIME_ASSERT(0);
#endif
if (gEnv->pCryPak->FWrite(buf, 1, de->size, m_fileHandle) != de->size)
{
mfSetError("Flush - Writing fault");
}
if (!(de->flags & RF_COMPRESSED))
{
delete[] buf;
}
nSizeCompr += de->size;
}
else
if (!pOE->pData || (gEnv->pCryPak->FWrite(pOE->pData, 1, de->size, m_fileHandle) != de->size))
{
mfSetError("Flush - Writing fault");
continue;
}
mfCloseEntry(de);
if (bOptimise)
{
for (j = 0; j < m_DirRef.size(); j++)
{
SDirEntryRef& r = m_DirRef[j];
if (r.ref == de->offset)
{
nUpdate++;
r.ref = i;
}
}
}
de->offset = nSeek;
nSeek += de->size;
}
}
// Update reference entries
if (pRefs)
{
PREFAST_ASSUME(i < numDirRefs);
for (j = 0; j < pRefs[i].Num(); j++)
{
nUpdate++;
SDirEntry* d = &m_Dir[pRefs[i][j]];
d->offset = de->offset;
d->size = de->size;
d->flags = de->flags;
d->flags &= ~RF_NOTSAVED;
}
}
}
SAFE_DELETE_ARRAY(pRefs);
if (!nUpdate)
{
return nSizeDir;
}
m_bDirCompressed = false; //bCompressDir;
int sizeDir = mfFlushDir(nSeek, bOptimise);
assert(sizeDir == nSizeDir);
frh.hid = IDRESHEADER;
int ver = RES_COMPRESSION;
frh.ver = ver;
frh.num_files = m_Dir.size();
frh.num_files_ref = m_DirRef.size();
frh.ofs_dir = nSeek;
//frh.size_dir = sizeDir;
m_version = ver;
SFileResHeader frhTemp, * pFrh;
pFrh = &frh;
if (m_bSwapEndianWrite)
{
frhTemp = frh;
SwapEndian(frhTemp, eBigEndian);
pFrh = &frhTemp;
}
gEnv->pCryPak->FSeek(m_fileHandle, 0, SEEK_SET);
if (gEnv->pCryPak->FWrite(pFrh, 1, sizeof(frh), m_fileHandle) != sizeof(frh))
{
mfSetError("Flush - Writing fault");
return nSizeDir;
}
gEnv->pCryPak->FFlush(m_fileHandle);
//if (strstr(m_name, "FPVS") && frh.num_files==4)
{
//gEnv->pCryPak->FSeek(m_fileHandle, 0, SEEK_END);
//int nSize = gEnv->pCryPak->FTell(m_fileHandle);
//mfDeactivate();
//int nnn = 0;
}
return sizeDir;
}
int CResFile::Size()
{
int nSize = sizeof(CResFile);
uint32 i;
for (i = 0; i < m_Dir.size(); i++)
{
SDirEntry& DE = m_Dir[i];
nSize += sizeof(SDirEntry);
SDirEntryOpen* pOE = mfGetOpenEntry(&DE);
if (pOE)
{
nSize += sizeof(SDirEntryOpen);
if (pOE->pData && (DE.flags & RF_TEMPDATA))
{
nSize += DE.size;
}
}
}
return nSize;
}
void CResFile::GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
pSizer->AddObject(m_Dir);
pSizer->AddObject(m_DirOpen);
}
ResDir* CResFile::mfGetDirectory()
{
return &m_Dir;
}
//======================================================================
void fpStripExtension (const char* const in, char* const out, const size_t bytes)
{
assert(in && out && (bytes || in == out)); // if this hits, check the call site
const size_t inlen = strlen(in);
ptrdiff_t len = inlen - 1;
if (len <= 1)
{
assert(bytes >= 2); // if this hits, bad buffer was passed in
cry_strcpy(out, bytes, in);
return;
}
while (in[len])
{
if (in[len] == '.')
{
int n = (int)len;
while (in[n] != 0)
{
if (in[n] == '+')
{
assert(bytes > inlen); // if this hits, bad buffer was passed in
cry_strcpy(out, bytes, in);
return;
}
n++;
}
break;
}
len--;
if (!len)
{
assert(bytes > inlen); // if this hits, bad buffer was passed in
cry_strcpy(out, bytes, in);
return;
}
}
assert(bytes > len); // if this hits, bad buffer was passed in
cry_strcpy(out, bytes, in, len);
}
//return a pointer to the last dot after the last slash
const char* fpGetExtension(const char* in)
{
if (!in)
{
return nullptr;
}
const char* ls1 = strrchr(in, '\\');
const char* ls2 = strrchr(in, '/');
const char* sb = in;
if (ls1)
{
sb = ls1;
}
if (ls2 > sb)
{
sb = ls2;
}
return strrchr(sb, '.');
}
void fpAddExtension(char* path, const char* extension, size_t bytes)
{
assert(path && extension && bytes); // if this hits, check the call site
char* src;
assert(*path); // if this hits, src underflow
src = path + strlen(path) - 1;
while (*src != '/' && src != path)
{
if (*src == '.')
{
return; // it has an extension
}
src--;
}
assert(bytes > strlen(path) + strlen(extension)); // if this hits, bad buffer was passed in
azstrcat(path, bytes, extension);
}
void fpConvertDOSToUnixName(char* dst, const char* src, [[maybe_unused]] size_t bytes)
{
assert(dst && src && bytes); // if this hits, check the call site
assert(bytes > strlen(src)); // if this hits, bad buffer was passed in
while (*src)
{
if (*src == '\\')
{
*dst = '/';
}
else
{
*dst = *src;
}
dst++;
src++;
}
*dst = 0;
}
void fpConvertUnixToDosName(char* dst, const char* src, [[maybe_unused]] size_t bytes)
{
assert(dst && src && bytes); // if this hits, check the call site
assert(bytes > strlen(src)); // if this hits, bad buffer was passed in
while (*src)
{
if (*src == '/')
{
*dst = '\\';
}
else
{
*dst = *src;
}
dst++;
src++;
}
*dst = 0;
}
void fpUsePath(const char* name, const char* path, char* dst, size_t bytes)
{
assert(name && dst && bytes); // if this hits, check the call site
if (!path)
{
assert(bytes > strlen(name)); // if this hits, bad buffer was passed in
azstrcpy(dst, bytes, name);
return;
}
assert(bytes > strlen(path)); // if this hits, bad buffer was passed in
azstrcpy(dst, bytes, path);
assert(*path); // if this hits, path underflow
char c = path[strlen(path) - 1];
if (c != '/' && c != '\\')
{
assert(bytes > strlen(path) + strlen(name) + 1); // it this hits, bad buffer was passed in
azstrcat(dst, bytes, "/");
}
else
{
assert(bytes > strlen(path) + strlen(name)); // it this hits, bad buffer was passed in
}
azstrcat(dst, bytes, name);
}
#include "TypeInfo_impl.h"
#include "ResFile_info.h"
#ifndef AZ_MONOLITHIC_BUILD
#include "Name_TypeInfo.h"
#endif