227 lines
7.1 KiB
C++
227 lines
7.1 KiB
C++
|
//===== 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;
|
|||
|
}
|