csgo-2018-source/datacache/resourceaccesscontrol.cpp

227 lines
7.1 KiB
C++
Raw Permalink Normal View History

2021-07-25 12:11:47 +08:00
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "datacache/iresourceaccesscontrol.h"
#include "tier1/utlvector.h"
#include "tier1/utlstring.h"
#include "tier2/tier2.h"
#include "tier1/convar.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// NOTE: Necessary until we have all our resources wrangled.
//-----------------------------------------------------------------------------
static ConVar res_restrict_access( "res_restrict_access", "0" );
//-----------------------------------------------------------------------------
// Implementation class
//-----------------------------------------------------------------------------
class CResourceAccessControl : public CTier1AppSystem< IResourceAccessControl >
{
typedef CTier1AppSystem< IResourceAccessControl > BaseClass;
// Inherited from IAppSystem
public:
virtual void Shutdown();
// Inherited from IResourceAccessControl
public:
virtual ResourceList_t CreateResourceList( const char *pDebugName );
virtual void DestroyAllResourceLists( );
virtual void AddResource( ResourceList_t hResourceList, ResourceTypeOld_t nType, const char *pResourceName );
virtual void LimitAccess( ResourceList_t hResourceList );
virtual bool IsAccessAllowed( ResourceTypeOld_t nType, const char *pResource );
// Other public methods
public:
CResourceAccessControl();
private:
enum
{
MAX_THREADS = 16
};
struct ResourceInfo_t
{
CUtlString m_DebugName;
CUtlVector< CUtlString > m_Resources[RESOURCE_TYPE_OLD_COUNT];
};
bool ContainsResource( ResourceList_t hResourceList, ResourceTypeOld_t nType, const char *pResourceName );
int FindOrAddCurrentThreadID();
void FixupResourceName( const char *pResourceName, char *pBuf, int nBufLen );
CUtlVector< ResourceInfo_t > m_ResourceLists;
int m_pLimitAccess[MAX_THREADS];
unsigned long m_pThread[MAX_THREADS];
int m_nThreadCount;
CThreadMutex m_Mutex;
};
//-----------------------------------------------------------------------------
// Singleton
//-----------------------------------------------------------------------------
CResourceAccessControl g_ResourceAccessControl;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CResourceAccessControl, IResourceAccessControl,
RESOURCE_ACCESS_CONTROL_INTERFACE_VERSION, g_ResourceAccessControl );
//-----------------------------------------------------------------------------
// Resource type names
//-----------------------------------------------------------------------------
static const char *s_pResourceTypeName[] =
{
"vgui panel", // .res file
"material", // .vmt file
"model", // .mdl file
"particle system", // particle system
"game sound", // game sound
};
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CResourceAccessControl::CResourceAccessControl()
{
m_nThreadCount = 0;
memset( m_pLimitAccess, 0xFF, sizeof(m_pLimitAccess) );
memset( m_pThread, 0, sizeof(m_pThread) );
}
//-----------------------------------------------------------------------------
// Shutdown
//-----------------------------------------------------------------------------
void CResourceAccessControl::Shutdown()
{
DestroyAllResourceLists();
memset( m_pLimitAccess, 0xFF, sizeof(m_pLimitAccess) );
BaseClass::Shutdown();
}
//-----------------------------------------------------------------------------
// Creates a resource list
//-----------------------------------------------------------------------------
int CResourceAccessControl::FindOrAddCurrentThreadID()
{
unsigned long nThreadId = ThreadGetCurrentId();
for ( int i = 0; i < m_nThreadCount; ++i )
{
if ( m_pThread[i] == nThreadId )
return i;
}
if ( m_nThreadCount >= MAX_THREADS )
{
Error( "Exceeded maximum number of unique threads (%d) attempting to access datacache.\n", MAX_THREADS );
return -1;
}
m_Mutex.Lock();
int nIndex = m_nThreadCount;
m_pThread[m_nThreadCount++] = nThreadId;
m_Mutex.Unlock();
return nIndex;
}
//-----------------------------------------------------------------------------
// Fixes up the asset name
//-----------------------------------------------------------------------------
void CResourceAccessControl::FixupResourceName( const char *pResourceName, char *pBuf, int nBufLen )
{
Q_StripExtension( pResourceName, pBuf, nBufLen );
Q_FixSlashes( pBuf, '/' );
V_RemoveDotSlashes( pBuf, '/' );
}
//-----------------------------------------------------------------------------
// Creates a resource list
//-----------------------------------------------------------------------------
ResourceList_t CResourceAccessControl::CreateResourceList( const char *pDebugName )
{
int nIndex = m_ResourceLists.AddToTail();
m_ResourceLists[nIndex].m_DebugName.Set( pDebugName );
return (ResourceList_t)(intp)nIndex;
}
void CResourceAccessControl::DestroyAllResourceLists( )
{
m_ResourceLists.Purge();
memset( m_pLimitAccess, 0xFF, sizeof(m_pLimitAccess) );
}
bool CResourceAccessControl::ContainsResource( ResourceList_t hResourceList, ResourceTypeOld_t nType, const char *pResourceName )
{
char pBuf[MAX_PATH];
FixupResourceName( pResourceName, pBuf, sizeof(pBuf) );
int nIndex = size_cast< int >( (intp)hResourceList );
CUtlVector< CUtlString > &list = m_ResourceLists[nIndex].m_Resources[nType];
int nCount = list.Count();
for ( int i = 0; i < nCount; ++i )
{
if ( !Q_stricmp( pBuf, list[i].Get() ) )
return true;
}
return false;
}
void CResourceAccessControl::AddResource( ResourceList_t hResourceList, ResourceTypeOld_t nType, const char *pResourceName )
{
if ( ContainsResource( hResourceList, nType, pResourceName ) )
return;
int nIndex = size_cast< int >( (intp)hResourceList );
int nSubIndex = m_ResourceLists[nIndex].m_Resources[nType].AddToTail();
char pBuf[MAX_PATH];
FixupResourceName( pResourceName, pBuf, sizeof(pBuf) );
m_ResourceLists[nIndex].m_Resources[nType][nSubIndex].Set( pBuf );
}
void CResourceAccessControl::LimitAccess( ResourceList_t hResourceList )
{
if ( !res_restrict_access.GetInt() )
return;
int nIndex = FindOrAddCurrentThreadID();
if ( ( m_pLimitAccess[nIndex] >= 0 ) && ( hResourceList != RESOURCE_LIST_INVALID ) )
{
Warning( "Attempted to limit access while already limiting access!\n" );
return;
}
m_pLimitAccess[nIndex] = size_cast< int >( (intp)hResourceList );
}
bool CResourceAccessControl::IsAccessAllowed( ResourceTypeOld_t nType, const char *pResourceName )
{
int nIndex = FindOrAddCurrentThreadID();
if ( m_pLimitAccess[nIndex] < 0 )
return true;
int hResourceList = m_pLimitAccess[nIndex];
if ( ContainsResource( (ResourceList_t)( intp )hResourceList, nType, pResourceName ) )
return true;
COMPILE_TIME_ASSERT( ARRAYSIZE( s_pResourceTypeName ) == RESOURCE_TYPE_OLD_COUNT );
Warning( "Access to %s resource \"%s\" denied. Missing precache in %s?\n",
s_pResourceTypeName[nType], pResourceName, m_ResourceLists[hResourceList].m_DebugName.Get() );
return false;
}