Files
GTASource/game/scene/DataFileMgr.cpp

778 lines
23 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
#include "scene/DataFileMgr.h"
#include "scene/DataFileMgr_parser.h"
// Rage headers
#include "fwsys/fileExts.h"
#include "parser/manager.h"
#include "parsercore/stream.h"
#include "streaming/streamingengine.h"
#include "streaming/streaminginfo.h"
#include "streaming/streamingmodule.h"
#include "streaming/streamingmodulemgr.h"
#include "string/stringutil.h"
#include "system/param.h"
#include "system/platform.h"
#include "system/nelem.h"
#include "scene/dlc_channel.h"
#include "scene/ExtraContent.h"
#include "scene/scene.h"
#include "control/leveldata.h"
#include "control/gamelogic.h"
#include "file/device_relative.h"
eDFMI_UnloadType CDataFileMount::sm_UnloadBehaviours[CDataFileMgr::INVALID_FILE];
atRangeArray<CDataFileMountInterface *, CDataFileMgr::INVALID_FILE> CDataFileMount::sm_Interfaces;
bool CDataFileMount::sm_overrideUnload = true;
eDFMI_UnloadType CDataFileMount::sm_unloadBehaviour = eDFMI_UnloadDefault;
XPARAM(usefatcuts);
bool CDataFileMgr::ChangeSetData::IsValid(bool executing) const
{
bool returnValue = true;
// Check if this changeset has any map associations
if (m_associatedMap.length() > 0)
{
s32 currLevelIdx = CGameLogic::GetCurrentLevelIndex();
s32 reqLevelIdx = CGameLogic::GetRequestedLevelIndex();
s32 associatedMapIdx = CScene::GetLevelsData().GetLevelIndexFromTitleName(m_associatedMap.c_str());
// If there's no transition just check for association
if (currLevelIdx == reqLevelIdx)
returnValue = associatedMapIdx == currLevelIdx;
else
{
// There's some form of transition, only allow changes for the current map to be reverted
if (associatedMapIdx == currLevelIdx)
returnValue = !executing;
else
returnValue = associatedMapIdx == reqLevelIdx;
}
if (!returnValue)
{
NOTFINAL_ONLY(Displayf("ChangeSetData::IsValid - change set is not valid due to map association with [%s] [%s]",
m_associatedMap.c_str(), CScene::GetLevelsData().GetFriendlyName(associatedMapIdx));)
}
}
return returnValue;
}
strIndex CDataFileMgr::ResourceReference::Resolve() const
{
// Get the module first.
char extension[sizeof(m_Extension)];
memcpy(extension, m_Extension, sizeof(m_Extension));
if (extension[0] == '#')
{
extension[0] = g_sysPlatform;
}
strStreamingModule *module = strStreamingEngine::GetInfo().GetModuleMgr().GetModuleFromFileExtension(extension);
if (module)
{
strLocalIndex slot = module->FindSlot(m_AssetName.c_str());
if (slot != -1)
{
return module->GetStreamingIndex(slot);
}
}
Assertf(false, "Unable to resolve %s.%s", m_AssetName.c_str(), m_Extension);
return strIndex();
}
CDataFileMgr::CDataFileMgr()
{
// Set up the environment variables.
m_EnvVariableMap.Insert(ATSTRINGHASH("PLATFORM", 0x02fbe482d), ConstString(RSG_PLATFORM_ID));
m_addingPatchFiles = false;
}
#if __BANK
bool CDataFileMgr::GetFatcuts()
{
return PARAM_usefatcuts.Get();
}
#endif // __BANK
FASTRETURNCHECK(const char *) CDataFileMgr::RemapDataFileName(const char *origFile, char *NOTFINAL_ONLY(outTargetBuffer), size_t NOTFINAL_ONLY(targetBufferSize))
{
#if !__FINAL
if (PARAM_usefatcuts.Get())
{
const char *filename = ASSET.FileName(origFile);
size_t string_length_of_path = filename - origFile;
if (PARAM_usefatcuts.Get())
{
Displayf("Testing %s", filename);
if (stricmp(filename, "common_cutscene.meta") == 0)
{
memcpy(outTargetBuffer, origFile, Min(string_length_of_path, targetBufferSize));
outTargetBuffer[Min(string_length_of_path, targetBufferSize)] = 0;
safecat(outTargetBuffer, "/", targetBufferSize);
safecat(outTargetBuffer, "common_cutscene_fat.meta", targetBufferSize);
return outTargetBuffer;
}
else if (stricmp(filename, "cuts.meta") == 0)
{
memcpy(outTargetBuffer, origFile, Min(string_length_of_path, targetBufferSize));
outTargetBuffer[Min(string_length_of_path, targetBufferSize)] = 0;
safecat(outTargetBuffer, "/", targetBufferSize);
safecat(outTargetBuffer, "cuts_fat.meta", targetBufferSize);
return outTargetBuffer;
}
}
}
#endif // !__FINAL
return origFile;
}
#if __ASSERT
void CDataFileMgr::VerifyXmlContents(ContentsOfDataFileXml& XmlContents, const char* pFilename) const
{
// Fill temporary array with change sets' enabled and disabled files.
atArray<const char*> tempArray;
for(int j=0; j<XmlContents.m_contentChangeSets.GetCount(); ++j)
{
const ContentChangeSet* pChangeSet = &(XmlContents.m_contentChangeSets[j]);
for(int i=0; i<pChangeSet->m_filesToEnable.GetCount(); ++i)
{
tempArray.PushAndGrow(pChangeSet->m_filesToEnable[i].c_str());
}
for(int i=0; i<pChangeSet->m_filesToDisable.GetCount(); ++i)
{
tempArray.PushAndGrow(pChangeSet->m_filesToDisable[i].c_str());
}
for(int k=0; k<pChangeSet->m_mapChangeSetData.GetCount(); ++k)
{
const ChangeSetData* pData = &(pChangeSet->m_mapChangeSetData[k]);
for(int i=0; i<pData->m_filesToEnable.GetCount(); ++i)
{
tempArray.PushAndGrow(pData->m_filesToEnable[i].c_str());
}
for(int i=0; i<pChangeSet->m_mapChangeSetData[k].m_filesToDisable.GetCount(); ++i)
{
tempArray.PushAndGrow(pData->m_filesToDisable[i].c_str());
}
}
}
// Check for actual data file dupes. Let's hope not.
for (int i = 0; i < XmlContents.m_dataFiles.GetCount(); ++i) {
for (int j = i+1; j < XmlContents.m_dataFiles.GetCount(); ++j) {
bool bFilesMatch = (strnicmp(XmlContents.m_dataFiles[i].m_filename, XmlContents.m_dataFiles[j].m_filename, 128) == 0);
Assertf(!bFilesMatch, "Duplicate data file '%s' in file '%s' (indices %i and %i)", XmlContents.m_dataFiles[i].m_filename, pFilename, i, j);
}
}
// Check if content.xml belongs to DLC device or title update.
bool isDLCorUpdate = ( !strnicmp(pFilename, "DLC", 3) || !strnicmp(pFilename, "update", 6) );
if(isDLCorUpdate)
{
// Automatically add the content.xml's folder to allowed ones.
AddDefaultAllowedFolders(XmlContents, pFilename);
}
// Check the temporary array for issues.
for(int i=0; i<tempArray.GetCount(); ++i)
{
// Disallowed folders.
if(XmlContents.m_allowedFolders.GetCount() && isDLCorUpdate)
{
Verifyf(IsInAllowedFolder(XmlContents, tempArray[i]), "Data file %s is not placed in one of the allowed folders", tempArray[i]);
}
// Duplicate entries.
for(int j=i+1; j<tempArray.GetCount(); ++j)
{
if(!Verifyf(strcmp(tempArray[i], tempArray[j]), "Duplicate entry of %s found in %s.", tempArray[i], pFilename))
{
break;
}
}
}
}
void CDataFileMgr::AddDefaultAllowedFolders(ContentsOfDataFileXml& XmlContents, const char* pFilename) const
{
if(const char* pChar = stristr(pFilename, ":")){
atString &pStr = XmlContents.m_allowedFolders.Grow();
pStr.Set(pFilename, RAGE_MAX_PATH, 0, static_cast<int>(pChar-pFilename)+1);
}
if(const char* pChar = stristr(pFilename, "CRC:"))
{
atString &pStr = XmlContents.m_allowedFolders.Grow();
pStr.Set(pFilename, RAGE_MAX_PATH, 0, static_cast<int>(pChar-pFilename));
pStr += ":";
}
}
bool CDataFileMgr::IsInAllowedFolder(const ContentsOfDataFileXml& XmlContents, const char* filePath) const
{
// If there are no specified folders then assume the file is setup correctly (for backwards compatibility)
if(XmlContents.m_allowedFolders.empty())
{
return true;
}
// Check if file lies within specified folders.
for(int k=0; k<XmlContents.m_allowedFolders.GetCount(); ++k)
{
if( !strnicmp(XmlContents.m_allowedFolders[k].c_str(), filePath, XmlContents.m_allowedFolders[k].GetLength()) )
{
return true;
}
}
return false;
}
bool CDataFileMgr::CheckCRCValidity(const DataFile* dataFile)
{
const DataFile* pFile = DATAFILEMGR.GetFirstFile(dataFile->m_fileType);
if( !strnicmp(pFile->m_filename, "commoncrc:", 10) && !strnicmp(dataFile->m_filename, "dlc", 3) )
{
char device[RAGE_MAX_PATH] = {0};
strncpy(device, dataFile->m_filename, static_cast<int>(strcspn(dataFile->m_filename, "/")) + 1);
bool isCompatPack = EXTRACONTENT.GetContentByDevice(device)->GetIsCompatibilityPack();
if(!stristr(dataFile->m_filename, "CRC:") && isCompatPack)
{
return false;
}
}
return true;
}
#endif // __ASSERT
void CDataFileMgr::Load(const char *pFilename, bool bCullOtherPlatformData /*= true*/)
{
ContentsOfDataFileXml XmlContents;
char FilenameWithoutExtension[256];
ASSET.RemoveExtensionFromPath(FilenameWithoutExtension, 256, pFilename);
parSettings s = PARSER.Settings();
s.SetFlag(parSettings::CULL_OTHER_PLATFORM_DATA, bCullOtherPlatformData);
//@@: location CDATAFILEMGR_LOAD_META_EXISTS
if (ASSET.Exists(FilenameWithoutExtension, "meta"))
{
PARSER.LoadObject(FilenameWithoutExtension, "meta", XmlContents, &s);
}
else if (ASSET.Exists(pFilename, META_FILE_EXT))
{
Verifyf(fwPsoStoreLoader::LoadDataIntoObject(pFilename, META_FILE_EXT, XmlContents), "Failed to load %s", pFilename);
}
else
{
PARSER.LoadObject(FilenameWithoutExtension, "xml", XmlContents, &s);
}
#if __ASSERT
// Check contents of content.xml for errors.
VerifyXmlContents(XmlContents, pFilename);
#endif // __ASSERT
for(int i=0;i<XmlContents.m_dataFiles.GetCount();i++)
{
const char* currentFile = XmlContents.m_dataFiles[i].m_filename;
//First check if this file should get replaced (ptfx/script/fatcuts etc)
char replacementPath[RAGE_MAX_PATH];
if(CFileLoader::CheckFileForReplacements(currentFile,replacementPath,RAGE_MAX_PATH))
{
Displayf("Changing %s",XmlContents.m_dataFiles[i].m_filename);
strcpy(XmlContents.m_dataFiles[i].m_filename,replacementPath);
Displayf("to %s",XmlContents.m_dataFiles[i].m_filename);
}
if(!fiDevice::CheckFileValidity(currentFile))
{
//Delete invalid files
Assertf(false,"invalid devicename in the datafile %s",currentFile);
XmlContents.m_dataFiles.Delete(i);
i--;
}
// Check if DLC files are properly CRC'd.
Assertf(CheckCRCValidity(&(XmlContents.m_dataFiles[i])), "%s in %s should be CRC'd but is not!", XmlContents.m_dataFiles[i].m_filename, pFilename);
}
// Check for any collisions between CCSs
for (int x = 0; x < XmlContents.m_contentChangeSets.GetCount(); x++)
{
ContentChangeSet& changeSet = XmlContents.m_contentChangeSets[x];
// If we have a collision we cache the collider, remove all its files from this content XML data preserving any other non colliding CCSs
ContentChangeSet* higherOrderCCS = m_contentChangeSets.Access(changeSet.m_changeSetName.c_str());
if (higherOrderCCS)
{
#if !__FINAL
// If we have a collision verify that the files identical between the two CCSs
if (higherOrderCCS->m_filesToEnable.GetCount() == changeSet.m_filesToEnable.GetCount())
{
char highOrderFile[256] = { 0 };
char lowOrderFile[256] = { 0 };
char* highOrderFileNoDevice = NULL;
char* lowOrderFileNoDevice = NULL;
for (u32 i = 0; i < higherOrderCCS->m_filesToEnable.GetCount(); i++)
{
formatf(highOrderFile, sizeof(highOrderFile), "%s", higherOrderCCS->m_filesToEnable[i].c_str());
formatf(lowOrderFile, sizeof(lowOrderFile), "%s", changeSet.m_filesToEnable[i].c_str());
highOrderFileNoDevice = strstr(highOrderFile, ":/");
lowOrderFileNoDevice = strstr(lowOrderFile, ":/");
if (strcmp(highOrderFileNoDevice, lowOrderFileNoDevice) != 0)
{
Assertf(0, "CDataFileMgr::Load - %s CCSs Collide but they are not identical, check order of files! [%s vs %s]",
changeSet.m_changeSetName.c_str(), highOrderFileNoDevice, lowOrderFileNoDevice);
break;
}
}
}
else
{
Assertf(0, "CDataFileMgr::Load - %s CCSs Collide but they are not identical, check file counts! [%i vs %i]",
changeSet.m_changeSetName.c_str(), higherOrderCCS->m_filesToEnable.GetCount(), changeSet.m_filesToEnable.GetCount());
}
#endif
atHashString newCollision = changeSet.m_changeSetName.c_str();
dlcDebugf3("CDataFileMgr::Load - There is a collision between CCSs [%s]", changeSet.m_changeSetName.c_str());
m_changeSetCollisions.PushAndGrow(newCollision, 1);
for (u32 i = 0; i < changeSet.m_filesToEnable.GetCount(); i++)
{
for (u32 j = 0; j < XmlContents.m_dataFiles.GetCount(); j++)
{
if (strcmp(XmlContents.m_dataFiles[j].m_filename, changeSet.m_filesToEnable[i].c_str()) == 0)
{
dlcDebugf3("CDataFileMgr::Load - Deleting file reference [%s]", XmlContents.m_dataFiles[j].m_filename);
XmlContents.m_dataFiles.Delete(j);
j--;
}
}
}
XmlContents.m_contentChangeSets.DeleteFast(x);
x--;
}
}
s32 index = 0;
const s32 numOfDisabledFiles = XmlContents.m_disabledFiles.GetCount();
while(index < numOfDisabledFiles)
{
// Printf("CDataFileMgr::Load - index = %d disabled_filename = %s\n", index, XmlContents.m_disabledFiles[index].c_str());
AddDisabledFile(XmlContents.m_disabledFiles[index].c_str());
index++;
}
const s32 numOfIncludedDataFiles = XmlContents.m_includedDataFiles.GetCount();
for (int x=0; x<numOfIncludedDataFiles; x++)
{
char fileBuffer[RAGE_MAX_PATH];
const char *dataFileName = XmlContents.m_includedDataFiles[x].c_str();
const char *mappedDataFile = RemapDataFileName(dataFileName, fileBuffer, sizeof(fileBuffer));
Load(mappedDataFile);
}
s32 xml_file_index = 0;
//@@: location CDATAFILEMGR_LOAD_GET_XML_COUNT
const s32 numOfIncludedXmlFiles = XmlContents.m_includedXmlFiles.GetCount();
while(xml_file_index < numOfIncludedXmlFiles)
{
index = 0;
const s32 numOfDataFilesInThisXmlFile = XmlContents.m_includedXmlFiles[xml_file_index].m_dataFiles.GetCount();
while (index < numOfDataFilesInThisXmlFile)
{
//Printf("CDataFileMgr::Load (included xml) - index = %d filetype = %d filename = %s\n", index, XmlContents.m_includedXmlFiles[xml_file_index].m_dataFiles[index].m_fileType,
// XmlContents.m_includedXmlFiles[xml_file_index].m_dataFiles[index].m_filename);
const DataFile &dataFile = XmlContents.m_includedXmlFiles[xml_file_index].m_dataFiles[index];
AddFile(dataFile,pFilename);
index++;
}
xml_file_index++;
}
index = 0;
const s32 numOfDataFiles = XmlContents.m_dataFiles.GetCount();
while(index < numOfDataFiles)
{
//Printf("CDataFileMgr::Load - index = %d filetype = %d filename = %s\n", index, XmlContents.m_dataFiles[index].m_fileType,
// XmlContents.m_dataFiles[index].m_filename);
AddFile(XmlContents.m_dataFiles[index],pFilename);
index++;
}
for (int x=0; x<XmlContents.m_contentChangeSets.GetCount(); x++)
{
ContentChangeSet &changeSet = XmlContents.m_contentChangeSets[x];
for(int y=0;y<changeSet.m_filesToEnable.GetCount();y++)
{
const char* currentFile = changeSet.m_filesToEnable[y].c_str();
char replacementPath[RAGE_MAX_PATH];
if(CFileLoader::CheckFileForReplacements(currentFile,replacementPath,RAGE_MAX_PATH))
{
Displayf("Changing %s",changeSet.m_filesToEnable[y].c_str());
changeSet.m_filesToEnable[y].Set(replacementPath,RAGE_MAX_PATH,0);
Displayf("to %s",changeSet.m_filesToEnable[y].c_str());
}
}
m_contentChangeSets[changeSet.m_changeSetName.c_str()] = changeSet;
}
const s32 numOfPatchFiles = XmlContents.m_patchFiles.GetCount();
for (int x = 0; x < numOfPatchFiles; x++)
{
const char* patchFileName = XmlContents.m_patchFiles[x].c_str();
PARSER.AddPatchFileToList(patchFileName);
}
}
void CDataFileMgr::GetCCSArchivesToEnable(atHashString changeSetName, bool execute, atMap<s32, bool>& archives)
{
if (ContentChangeSet* ccs = m_contentChangeSets.Access(changeSetName))
{
s32 imgIdx = -1;
char expandedFilename[RAGE_MAX_PATH] = { 0 };
for (s32 i = 0; i < ccs->m_filesToEnable.GetCount(); i++)
{
DATAFILEMGR.ExpandFilename(ccs->m_filesToEnable[i].c_str(), expandedFilename, sizeof(expandedFilename));
imgIdx = strPackfileManager::FindImage(expandedFilename);
if (imgIdx != -1 && archives.Access(imgIdx) == NULL)
archives.Insert(imgIdx, true);
}
for (s32 i = 0; i < ccs->m_mapChangeSetData.GetCount(); i++)
{
ChangeSetData& currData = ccs->m_mapChangeSetData[i];
if (currData.IsValid(execute))
{
for (s32 j = 0; j < currData.m_filesToEnable.GetCount(); j++)
{
DATAFILEMGR.ExpandFilename(currData.m_filesToEnable[j].c_str(), expandedFilename, sizeof(expandedFilename));
imgIdx = strPackfileManager::FindImage(expandedFilename);
if (imgIdx != -1 && archives.Access(imgIdx) == NULL)
archives.Insert(imgIdx, true);
}
}
}
}
}
void CDataFileMgr::DestroyDependentsGraph()
{
strStreamingEngine::GetInfo().DestroyDependentGraphs();
}
void CDataFileMgr::CreateDependentsGraph(atHashString changeSetName, bool execute)
{
if (ContentChangeSet* ccs = m_contentChangeSets.Access(changeSetName))
{
atArray<s32> filesToEnableCache;
atArray<s32> filesToInvalidateCache;
s32 imgIdx = -1;
char expandedFilename[RAGE_MAX_PATH] = { 0 };
for (s32 i = 0; i < ccs->m_mapChangeSetData.GetCount(); i++)
{
ChangeSetData& currData = ccs->m_mapChangeSetData[i];
if (currData.IsValid(execute))
{
for (s32 j = 0; j < currData.m_filesToEnable.GetCount(); j++)
{
DATAFILEMGR.ExpandFilename(currData.m_filesToEnable[j].c_str(), expandedFilename, sizeof(expandedFilename));
imgIdx = strPackfileManager::FindImage(expandedFilename);
if (imgIdx != -1)
{
filesToEnableCache.PushAndGrow(imgIdx, 1);
}
}
for (s32 j = 0; j < currData.m_filesToInvalidate.GetCount(); j++)
{
DATAFILEMGR.ExpandFilename(currData.m_filesToInvalidate[j].c_str(), expandedFilename, sizeof(expandedFilename));
imgIdx = strPackfileManager::FindImage(expandedFilename);
if (imgIdx != -1)
{
if (const atArray<s32>* associatedFiles = strStreamingEngine::GetInfo().GetPackfileRelationships(imgIdx))
{
for (s32 k = 0; k < associatedFiles->GetCount(); k++)
{
imgIdx = (*associatedFiles)[k];
if (imgIdx != -1)
filesToInvalidateCache.PushAndGrow(imgIdx, (u16)associatedFiles->GetCount());
}
}
else
{
filesToInvalidateCache.PushAndGrow(imgIdx, 1);
}
}
}
}
}
strStreamingEngine::GetInfo().CreateDependentsGraph(filesToEnableCache);
strStreamingEngine::GetInfo().CreateDependentsGraph(filesToInvalidateCache);
}
}
void CDataFileMgr::Unload(const char *pFilename, bool bCullOtherPlatformData /*= true*/)
{
ContentsOfDataFileXml XmlContents;
char FilenameWithoutExtension[256];
ASSET.RemoveExtensionFromPath(FilenameWithoutExtension, 256, pFilename);
parSettings s = PARSER.Settings();
s.SetFlag(parSettings::CULL_OTHER_PLATFORM_DATA, bCullOtherPlatformData);
if (ASSET.Exists(FilenameWithoutExtension, "meta"))
PARSER.LoadObject(FilenameWithoutExtension, "meta", XmlContents, &s);
else
PARSER.LoadObject(FilenameWithoutExtension, "xml", XmlContents, &s);
s32 index = 0;
const s32 numOfDisabledFiles = XmlContents.m_disabledFiles.GetCount();
while(index < numOfDisabledFiles)
{
RemoveDisabledFile(XmlContents.m_disabledFiles[index].c_str());
index++;
}
index = 0;
const s32 numOfDataFiles = XmlContents.m_dataFiles.GetCount();
while(index < numOfDataFiles)
{
RemoveFile(XmlContents.m_dataFiles[index].m_filename);
index++;
}
s32 xml_file_index = 0;
const s32 numOfIncludedXmlFiles = XmlContents.m_includedXmlFiles.GetCount();
while(xml_file_index < numOfIncludedXmlFiles)
{
index = 0;
const s32 numOfDataFilesInThisXmlFile = XmlContents.m_includedXmlFiles[xml_file_index].m_dataFiles.GetCount();
while (index < numOfDataFilesInThisXmlFile)
{
const DataFile &dataFile = XmlContents.m_includedXmlFiles[xml_file_index].m_dataFiles[index];
RemoveFile(dataFile.m_filename);
index++;
}
xml_file_index++;
}
for (int x = 0; x < XmlContents.m_contentChangeSets.GetCount(); x++)
{
ContentChangeSet& changeSet = XmlContents.m_contentChangeSets[x];
m_contentChangeSets.Delete(changeSet.m_changeSetName.c_str());
}
}
const CDataFileMgr::ContentChangeSet *CDataFileMgr::GetContentChangeSet(atHashString contentChangeSetName) const
{
return m_contentChangeSets.Access(contentChangeSetName);
}
CDataFileMgr::DataFile *CDataFileMgr::FindDataFile(atHashString fileName)
{
int count = m_dataFiles.GetCount();
for (int x=0; x<count; x++)
{
if (fileName == m_dataFiles[x].m_filename)
{
return &m_dataFiles[x];
}
}
return NULL;
}
void CDataFileMgr::ExpandFilename(const char *filename, char *outBuffer, size_t bufferSize)
{
// Copy the string, and find all special characters on the way.
// We'll copy the string into the target buffer first, including the variables. As we'll
// encounter the end of a varible, we'll make use of the fact that it's null-terminated at
// that point so we can easily look it up and replace it.
char *lastVarBegin = NULL;
bufferSize--;
while (*filename && bufferSize > 0)
{
char chr = *(filename++);
if (chr != '%')
{
*(outBuffer++) = chr;
bufferSize--;
}
else
{
// This could be the beginning or end of a variable.
if (!lastVarBegin)
{
// It's the beginning of a variable.
lastVarBegin = outBuffer;
*(outBuffer++) = chr;
bufferSize--;
}
else
{
// It's the end of a variable. Let's look it up.
// If it's two % signs right after one another, let's assume the user intended to
// to escape a single % sign.
if (lastVarBegin + 1 != outBuffer)
{
// We still need to terminate the buffer, it could contain data if we previously expanded
// a longer variable name with a shorter string.
*outBuffer = 0;
ConstString *var = m_EnvVariableMap.Access(atStringHash(&lastVarBegin[1]));
// If this doesn't resolve to a variable, just leave the string untouched, as DOS would do.
if (var)
{
// It IS a proper variable, so replace it.
size_t varLength = strlen(var->c_str());
bufferSize += outBuffer - lastVarBegin;
strncpy(lastVarBegin, var->c_str(), bufferSize);
bufferSize = Max((size_t) 0, bufferSize - varLength);
outBuffer = lastVarBegin + varLength;
}
}
lastVarBegin = NULL;
}
}
}
*outBuffer = 0;
}
void CDataFileMgr::RemoveMapDataFiles()
{
atArray<DataFile> dataFilesToKeep;
s32 numberOfEntries = m_dataFiles.GetCount();
s32 loop = 0;
for (loop = 0; loop < numberOfEntries; loop++)
{
if (m_dataFiles[loop].m_persistent)
{
dataFilesToKeep.PushAndGrow(m_dataFiles[loop]);
}
else
{
switch (m_dataFiles[loop].m_fileType)
{
case RPF_FILE :
case IDE_FILE :
case DELAYED_IDE_FILE :
case IPL_FILE :
case PERMANENT_ITYP_FILE :
// don't copy these types across to dataFilesToKeep
break;
default:
dataFilesToKeep.PushAndGrow(m_dataFiles[loop]);
break;
}
}
}
// Fix up the m_handle of all the entries in dataFilesToKeep
numberOfEntries = dataFilesToKeep.GetCount();
for (loop = 0; loop < numberOfEntries; loop++)
{
dataFilesToKeep[loop].m_handle = loop;
}
m_dataFiles.Reset();
m_dataFiles = dataFilesToKeep;
// Also clear the array of disabled files?
m_disabledFiles.Reset();
}
void CDataFileMgr::Clear()
{
m_dataFiles.Reset();
m_disabledFiles.Reset();
m_LockedFilesCount = 0;
m_LockedDisabledFilesCount = 0;
}
void CDataFileMgr::SnapshotFiles()
{
m_LockedFilesCount = m_dataFiles.GetCount();
m_LockedDisabledFilesCount = m_disabledFiles.GetCount();
}
void CDataFileMgr::RecallSnapshot()
{
m_dataFiles.Resize(m_LockedFilesCount);
m_disabledFiles.Resize(m_LockedDisabledFilesCount);
}
#if __BANK
void CDataFileMount::DebugOutputTable()
{
Displayf("=============================================");
Displayf("======= CDataFileMount interface table ======");
Displayf("=============================================");
#if PARSER_ALL_METADATA_HAS_NAMES
for(int i=0; i < sm_Interfaces.GetMaxCount(); ++i)
{
Displayf("[%s]: %s", parser_DataFileType_Strings[i], sm_Interfaces[i]? "valid":"NULL");
}
#else
Displayf("CAN'T DISPLAY LIST IF !PARSER_ALL_METADATA_HAS_NAMES");
#endif
Displayf("=============================================");
}
#endif